stacktrace.cc revision 3570
15217Ssaidi@eecs.umich.edu/*
213610Sgiacomo.gabrielli@arm.com * Copyright (c) 2005 The Regents of The University of Michigan
39920Syasuko.eckert@amd.com * All rights reserved.
49428SAndreas.Sandberg@ARM.com *
59428SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
69428SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
79428SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
89428SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
99428SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
109428SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
119428SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
129428SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
139428SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
149428SAndreas.Sandberg@ARM.com * this software without specific prior written permission.
155217Ssaidi@eecs.umich.edu *
165217Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175217Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185217Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195217Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205217Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215217Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225217Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235217Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245217Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255217Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265217Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275217Ssaidi@eecs.umich.edu *
285217Ssaidi@eecs.umich.edu * Authors: Nathan Binkert
295217Ssaidi@eecs.umich.edu */
305217Ssaidi@eecs.umich.edu
315217Ssaidi@eecs.umich.edu#include <string>
325217Ssaidi@eecs.umich.edu
335217Ssaidi@eecs.umich.edu#include "arch/sparc/isa_traits.hh"
345217Ssaidi@eecs.umich.edu#include "arch/sparc/stacktrace.hh"
355217Ssaidi@eecs.umich.edu#include "arch/sparc/vtophys.hh"
365217Ssaidi@eecs.umich.edu#include "base/bitfield.hh"
375217Ssaidi@eecs.umich.edu#include "base/trace.hh"
385217Ssaidi@eecs.umich.edu#include "cpu/base.hh"
395217Ssaidi@eecs.umich.edu#include "cpu/thread_context.hh"
405217Ssaidi@eecs.umich.edu#include "sim/system.hh"
415217Ssaidi@eecs.umich.edu
425217Ssaidi@eecs.umich.eduusing namespace std;
435217Ssaidi@eecs.umich.edunamespace SparcISA
4411793Sbrandon.potter@amd.com{
4511793Sbrandon.potter@amd.com    ProcessInfo::ProcessInfo(ThreadContext *_tc)
4613610Sgiacomo.gabrielli@arm.com        : tc(_tc)
4712334Sgabeblack@google.com    {
485217Ssaidi@eecs.umich.edu        Addr addr = 0;
496658Snate@binkert.org
509441SAndreas.Sandberg@ARM.com        VirtualPort *vp;
519441SAndreas.Sandberg@ARM.com
528232Snate@binkert.org        vp = tc->getVirtPort();
5311627Smichael.lebeane@amd.com
5413905Sgabeblack@google.com        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
5511627Smichael.lebeane@amd.com            panic("thread info not compiled into kernel\n");
569441SAndreas.Sandberg@ARM.com        thread_info_size = vp->readGtoH<int32_t>(addr);
575217Ssaidi@eecs.umich.edu
585217Ssaidi@eecs.umich.edu        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
595217Ssaidi@eecs.umich.edu            panic("thread info not compiled into kernel\n");
605217Ssaidi@eecs.umich.edu        task_struct_size = vp->readGtoH<int32_t>(addr);
615217Ssaidi@eecs.umich.edu
625217Ssaidi@eecs.umich.edu        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
635217Ssaidi@eecs.umich.edu            panic("thread info not compiled into kernel\n");
645217Ssaidi@eecs.umich.edu        task_off = vp->readGtoH<int32_t>(addr);
6513557Sgabeblack@google.com
6613557Sgabeblack@google.com        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
675217Ssaidi@eecs.umich.edu            panic("thread info not compiled into kernel\n");
685217Ssaidi@eecs.umich.edu        pid_off = vp->readGtoH<int32_t>(addr);
695217Ssaidi@eecs.umich.edu
705217Ssaidi@eecs.umich.edu        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
715217Ssaidi@eecs.umich.edu            panic("thread info not compiled into kernel\n");
725217Ssaidi@eecs.umich.edu        name_off = vp->readGtoH<int32_t>(addr);
735217Ssaidi@eecs.umich.edu
7413611Sgabeblack@google.com        tc->delVirtPort(vp);
7513611Sgabeblack@google.com    }
765217Ssaidi@eecs.umich.edu
775217Ssaidi@eecs.umich.edu    Addr
785217Ssaidi@eecs.umich.edu    ProcessInfo::task(Addr ksp) const
795217Ssaidi@eecs.umich.edu    {
8012109SRekai.GonzalezAlberquilla@arm.com        Addr base = ksp & ~0x3fff;
8112109SRekai.GonzalezAlberquilla@arm.com        if (base == ULL(0xfffffc0000000000))
8212109SRekai.GonzalezAlberquilla@arm.com            return 0;
8312109SRekai.GonzalezAlberquilla@arm.com
8412109SRekai.GonzalezAlberquilla@arm.com        Addr tsk;
8512109SRekai.GonzalezAlberquilla@arm.com
8612109SRekai.GonzalezAlberquilla@arm.com        VirtualPort *vp;
8712109SRekai.GonzalezAlberquilla@arm.com
8812109SRekai.GonzalezAlberquilla@arm.com        vp = tc->getVirtPort();
8912109SRekai.GonzalezAlberquilla@arm.com        tsk = vp->readGtoH<Addr>(base + task_off);
9013610Sgiacomo.gabrielli@arm.com        tc->delVirtPort(vp);
9113610Sgiacomo.gabrielli@arm.com
9213610Sgiacomo.gabrielli@arm.com        return tsk;
9313610Sgiacomo.gabrielli@arm.com    }
9413610Sgiacomo.gabrielli@arm.com
9513610Sgiacomo.gabrielli@arm.com    int
9613610Sgiacomo.gabrielli@arm.com    ProcessInfo::pid(Addr ksp) const
9713610Sgiacomo.gabrielli@arm.com    {
9813610Sgiacomo.gabrielli@arm.com        Addr task = this->task(ksp);
9913610Sgiacomo.gabrielli@arm.com        if (!task)
10013610Sgiacomo.gabrielli@arm.com            return -1;
1015217Ssaidi@eecs.umich.edu
10213557Sgabeblack@google.com        uint16_t pd;
10313557Sgabeblack@google.com
1045217Ssaidi@eecs.umich.edu        VirtualPort *vp;
1055217Ssaidi@eecs.umich.edu
1065217Ssaidi@eecs.umich.edu        vp = tc->getVirtPort();
1075217Ssaidi@eecs.umich.edu        pd = vp->readGtoH<uint16_t>(task + pid_off);
1085217Ssaidi@eecs.umich.edu        tc->delVirtPort(vp);
1099920Syasuko.eckert@amd.com
1109920Syasuko.eckert@amd.com        return pd;
11113622Sgabeblack@google.com    }
11213622Sgabeblack@google.com
1139920Syasuko.eckert@amd.com    string
1149920Syasuko.eckert@amd.com    ProcessInfo::name(Addr ksp) const
1159920Syasuko.eckert@amd.com    {
1169920Syasuko.eckert@amd.com        Addr task = this->task(ksp);
1177720Sgblack@eecs.umich.edu        if (!task)
1187720Sgblack@eecs.umich.edu            return "console";
1195712Shsul@eecs.umich.edu
1205712Shsul@eecs.umich.edu        char comm[256];
1215217Ssaidi@eecs.umich.edu        CopyStringOut(tc, comm, task + name_off, sizeof(comm));
1225217Ssaidi@eecs.umich.edu        if (!comm[0])
1235714Shsul@eecs.umich.edu            return "startup";
12411005Sandreas.sandberg@arm.com
12511005Sandreas.sandberg@arm.com        return comm;
12611005Sandreas.sandberg@arm.com    }
1275714Shsul@eecs.umich.edu
1285714Shsul@eecs.umich.edu    StackTrace::StackTrace()
1295714Shsul@eecs.umich.edu        : tc(0), stack(64)
1305217Ssaidi@eecs.umich.edu    {
1319428SAndreas.Sandberg@ARM.com    }
1329428SAndreas.Sandberg@ARM.com
13311627Smichael.lebeane@amd.com    StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
13411627Smichael.lebeane@amd.com        : tc(0), stack(64)
13511627Smichael.lebeane@amd.com    {
13611627Smichael.lebeane@amd.com        trace(_tc, inst);
13711627Smichael.lebeane@amd.com    }
13811627Smichael.lebeane@amd.com
13911627Smichael.lebeane@amd.com    StackTrace::~StackTrace()
14011627Smichael.lebeane@amd.com    {
14111627Smichael.lebeane@amd.com    }
14213905Sgabeblack@google.com
14311627Smichael.lebeane@amd.com    void
14411627Smichael.lebeane@amd.com    StackTrace::trace(ThreadContext *_tc, bool is_call)
14511627Smichael.lebeane@amd.com    {
14611627Smichael.lebeane@amd.com#if 0
14711627Smichael.lebeane@amd.com        tc = _tc;
14811627Smichael.lebeane@amd.com
14911627Smichael.lebeane@amd.com        bool usermode = (tc->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
15011627Smichael.lebeane@amd.com
15111627Smichael.lebeane@amd.com        Addr pc = tc->readNextPC();
15211627Smichael.lebeane@amd.com        bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
15311627Smichael.lebeane@amd.com            pc <= tc->getSystemPtr()->kernelEnd;
15411627Smichael.lebeane@amd.com
15511627Smichael.lebeane@amd.com        if (usermode) {
15611627Smichael.lebeane@amd.com            stack.push_back(user);
15711627Smichael.lebeane@amd.com            return;
15811627Smichael.lebeane@amd.com        }
15911627Smichael.lebeane@amd.com
16011627Smichael.lebeane@amd.com        if (!kernel) {
16111627Smichael.lebeane@amd.com            stack.push_back(console);
16211627Smichael.lebeane@amd.com            return;
16311627Smichael.lebeane@amd.com        }
16411627Smichael.lebeane@amd.com
16511627Smichael.lebeane@amd.com        SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
16613865Sgabeblack@google.com        Addr ksp = tc->readIntReg(TheISA::StackPointerReg);
1679428SAndreas.Sandberg@ARM.com        Addr bottom = ksp & ~0x3fff;
1689428SAndreas.Sandberg@ARM.com        Addr addr;
1699428SAndreas.Sandberg@ARM.com
17013557Sgabeblack@google.com        if (is_call) {
1719428SAndreas.Sandberg@ARM.com            if (!symtab->findNearestAddr(pc, addr))
17213611Sgabeblack@google.com                panic("could not find address %#x", pc);
1739428SAndreas.Sandberg@ARM.com
1749428SAndreas.Sandberg@ARM.com            stack.push_back(addr);
17510905Sandreas.sandberg@arm.com            pc = tc->readPC();
1769428SAndreas.Sandberg@ARM.com        }
17712109SRekai.GonzalezAlberquilla@arm.com
17812109SRekai.GonzalezAlberquilla@arm.com        Addr ra;
17912109SRekai.GonzalezAlberquilla@arm.com        int size;
18012109SRekai.GonzalezAlberquilla@arm.com
18112109SRekai.GonzalezAlberquilla@arm.com        while (ksp > bottom) {
18212109SRekai.GonzalezAlberquilla@arm.com            if (!symtab->findNearestAddr(pc, addr))
18313610Sgiacomo.gabrielli@arm.com                panic("could not find symbol for pc=%#x", pc);
18413610Sgiacomo.gabrielli@arm.com            assert(pc >= addr && "symbol botch: callpc < func");
18513610Sgiacomo.gabrielli@arm.com
18613610Sgiacomo.gabrielli@arm.com            stack.push_back(addr);
18713610Sgiacomo.gabrielli@arm.com
18813610Sgiacomo.gabrielli@arm.com            if (isEntry(addr))
18913557Sgabeblack@google.com                return;
1909428SAndreas.Sandberg@ARM.com
1919428SAndreas.Sandberg@ARM.com            if (decodePrologue(ksp, pc, addr, size, ra)) {
1929428SAndreas.Sandberg@ARM.com                if (!ra)
1939428SAndreas.Sandberg@ARM.com                    return;
1949920Syasuko.eckert@amd.com
19513622Sgabeblack@google.com                if (size <= 0) {
1969920Syasuko.eckert@amd.com                    stack.push_back(unknown);
1979920Syasuko.eckert@amd.com                    return;
1989920Syasuko.eckert@amd.com                }
1999920Syasuko.eckert@amd.com
2009920Syasuko.eckert@amd.com                pc = ra;
20110905Sandreas.sandberg@arm.com                ksp += size;
2029428SAndreas.Sandberg@ARM.com            } else {
2039428SAndreas.Sandberg@ARM.com                stack.push_back(unknown);
2049428SAndreas.Sandberg@ARM.com                return;
2059428SAndreas.Sandberg@ARM.com            }
2069428SAndreas.Sandberg@ARM.com
20710905Sandreas.sandberg@arm.com            bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
2089428SAndreas.Sandberg@ARM.com                pc <= tc->getSystemPtr()->kernelEnd;
2099428SAndreas.Sandberg@ARM.com            if (!kernel)
2109428SAndreas.Sandberg@ARM.com                return;
21113557Sgabeblack@google.com
2129428SAndreas.Sandberg@ARM.com            if (stack.size() >= 1000)
2139428SAndreas.Sandberg@ARM.com                panic("unwinding too far");
21410905Sandreas.sandberg@arm.com        }
2159428SAndreas.Sandberg@ARM.com
21613611Sgabeblack@google.com        panic("unwinding too far");
2179428SAndreas.Sandberg@ARM.com#endif
21812109SRekai.GonzalezAlberquilla@arm.com    }
21912109SRekai.GonzalezAlberquilla@arm.com
22012109SRekai.GonzalezAlberquilla@arm.com    bool
22112109SRekai.GonzalezAlberquilla@arm.com    StackTrace::isEntry(Addr addr)
22212109SRekai.GonzalezAlberquilla@arm.com    {
22312109SRekai.GonzalezAlberquilla@arm.com#if 0
22413610Sgiacomo.gabrielli@arm.com        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp12))
22513610Sgiacomo.gabrielli@arm.com            return true;
22613610Sgiacomo.gabrielli@arm.com
22713610Sgiacomo.gabrielli@arm.com        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp7))
22813610Sgiacomo.gabrielli@arm.com            return true;
22913610Sgiacomo.gabrielli@arm.com
23013557Sgabeblack@google.com        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp11))
2319428SAndreas.Sandberg@ARM.com            return true;
2329428SAndreas.Sandberg@ARM.com
2339428SAndreas.Sandberg@ARM.com        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp21))
2349428SAndreas.Sandberg@ARM.com            return true;
2359920Syasuko.eckert@amd.com
23613622Sgabeblack@google.com        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp9))
2379920Syasuko.eckert@amd.com            return true;
2389920Syasuko.eckert@amd.com
2399920Syasuko.eckert@amd.com        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp2))
2409920Syasuko.eckert@amd.com            return true;
2419920Syasuko.eckert@amd.com#endif
2429428SAndreas.Sandberg@ARM.com        return false;
24310905Sandreas.sandberg@arm.com    }
2449428SAndreas.Sandberg@ARM.com
2459428SAndreas.Sandberg@ARM.com    bool
2469428SAndreas.Sandberg@ARM.com    StackTrace::decodeStack(MachInst inst, int &disp)
2479428SAndreas.Sandberg@ARM.com    {
2489441SAndreas.Sandberg@ARM.com        // lda $sp, -disp($sp)
2499441SAndreas.Sandberg@ARM.com        //
2509441SAndreas.Sandberg@ARM.com        // Opcode<31:26> == 0x08
2519441SAndreas.Sandberg@ARM.com        // RA<25:21> == 30
2529441SAndreas.Sandberg@ARM.com        // RB<20:16> == 30
2539441SAndreas.Sandberg@ARM.com        // Disp<15:0>
2549441SAndreas.Sandberg@ARM.com        const MachInst mem_mask = 0xffff0000;
2559441SAndreas.Sandberg@ARM.com        const MachInst lda_pattern = 0x23de0000;
2569441SAndreas.Sandberg@ARM.com        const MachInst lda_disp_mask = 0x0000ffff;
2579441SAndreas.Sandberg@ARM.com
2589441SAndreas.Sandberg@ARM.com        // subq $sp, disp, $sp
2599441SAndreas.Sandberg@ARM.com        // addq $sp, disp, $sp
2609441SAndreas.Sandberg@ARM.com        //
2619441SAndreas.Sandberg@ARM.com        // Opcode<31:26> == 0x10
2629441SAndreas.Sandberg@ARM.com        // RA<25:21> == 30
2639441SAndreas.Sandberg@ARM.com        // Lit<20:13>
2649441SAndreas.Sandberg@ARM.com        // One<12> = 1
2659441SAndreas.Sandberg@ARM.com        // Func<11:5> == 0x20 (addq)
2669441SAndreas.Sandberg@ARM.com        // Func<11:5> == 0x29 (subq)
2679441SAndreas.Sandberg@ARM.com        // RC<4:0> == 30
2689441SAndreas.Sandberg@ARM.com        const MachInst intop_mask = 0xffe01fff;
2699441SAndreas.Sandberg@ARM.com        const MachInst addq_pattern = 0x43c0141e;
2709441SAndreas.Sandberg@ARM.com        const MachInst subq_pattern = 0x43c0153e;
2719441SAndreas.Sandberg@ARM.com        const MachInst intop_disp_mask = 0x001fe000;
2729441SAndreas.Sandberg@ARM.com        const int intop_disp_shift = 13;
2739441SAndreas.Sandberg@ARM.com
2749441SAndreas.Sandberg@ARM.com        if ((inst & mem_mask) == lda_pattern)
2759441SAndreas.Sandberg@ARM.com            disp = -sext<16>(inst & lda_disp_mask);
2769441SAndreas.Sandberg@ARM.com        else if ((inst & intop_mask) == addq_pattern)
2779441SAndreas.Sandberg@ARM.com            disp = -int((inst & intop_disp_mask) >> intop_disp_shift);
2789441SAndreas.Sandberg@ARM.com        else if ((inst & intop_mask) == subq_pattern)
2799441SAndreas.Sandberg@ARM.com            disp = int((inst & intop_disp_mask) >> intop_disp_shift);
2809441SAndreas.Sandberg@ARM.com        else
2819441SAndreas.Sandberg@ARM.com            return false;
282
283        return true;
284    }
285
286    bool
287    StackTrace::decodeSave(MachInst inst, int &reg, int &disp)
288    {
289        // lda $stq, disp($sp)
290        //
291        // Opcode<31:26> == 0x08
292        // RA<25:21> == ?
293        // RB<20:16> == 30
294        // Disp<15:0>
295        const MachInst stq_mask = 0xfc1f0000;
296        const MachInst stq_pattern = 0xb41e0000;
297        const MachInst stq_disp_mask = 0x0000ffff;
298        const MachInst reg_mask = 0x03e00000;
299        const int reg_shift = 21;
300
301        if ((inst & stq_mask) == stq_pattern) {
302            reg = (inst & reg_mask) >> reg_shift;
303            disp = sext<16>(inst & stq_disp_mask);
304        } else {
305            return false;
306        }
307
308        return true;
309    }
310
311    /*
312     * Decode the function prologue for the function we're in, and note
313     * which registers are stored where, and how large the stack frame is.
314     */
315    bool
316    StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
317                               int &size, Addr &ra)
318    {
319        size = 0;
320        ra = 0;
321
322        for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) {
323            MachInst inst;
324            CopyOut(tc, (uint8_t *)&inst, pc, sizeof(MachInst));
325
326            int reg, disp;
327            if (decodeStack(inst, disp)) {
328                if (size) {
329                    // panic("decoding frame size again");
330                    return true;
331                }
332                size += disp;
333            } else if (decodeSave(inst, reg, disp)) {
334                if (!ra && reg == ReturnAddressReg) {
335                    CopyOut(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
336                    if (!ra) {
337                        // panic("no return address value pc=%#x\n", pc);
338                        return false;
339                    }
340                }
341            }
342        }
343
344        return true;
345    }
346
347#if TRACING_ON
348    void
349    StackTrace::dump()
350    {
351        StringWrap name(tc->getCpuPtr()->name());
352        SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
353
354        DPRINTFN("------ Stack ------\n");
355
356        string symbol;
357        for (int i = 0, size = stack.size(); i < size; ++i) {
358            Addr addr = stack[size - i - 1];
359            if (addr == user)
360                symbol = "user";
361            else if (addr == console)
362                symbol = "console";
363            else if (addr == unknown)
364                symbol = "unknown";
365            else
366                symtab->findSymbol(addr, symbol);
367
368            DPRINTFN("%#x: %s\n", addr, symbol);
369        }
370    }
371#endif
372}
373