stacktrace.cc revision 2665:a124942bacb8
12600SN/A/*
22600SN/A * Copyright (c) 2005 The Regents of The University of Michigan
32600SN/A * All rights reserved.
42600SN/A *
52600SN/A * Redistribution and use in source and binary forms, with or without
62600SN/A * modification, are permitted provided that the following conditions are
72600SN/A * met: redistributions of source code must retain the above copyright
82600SN/A * notice, this list of conditions and the following disclaimer;
92600SN/A * redistributions in binary form must reproduce the above copyright
102600SN/A * notice, this list of conditions and the following disclaimer in the
112600SN/A * documentation and/or other materials provided with the distribution;
122600SN/A * neither the name of the copyright holders nor the names of its
132600SN/A * contributors may be used to endorse or promote products derived from
142600SN/A * this software without specific prior written permission.
152600SN/A *
162600SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172600SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182600SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192600SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202600SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212600SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222600SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232600SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242600SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252600SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262600SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Nathan Binkert
292600SN/A */
302600SN/A
312600SN/A#include <string>
322600SN/A
332600SN/A#include "arch/alpha/isa_traits.hh"
342600SN/A#include "arch/alpha/stacktrace.hh"
352600SN/A#include "arch/alpha/vtophys.hh"
362680Sktlim@umich.edu#include "base/bitfield.hh"
372600SN/A#include "base/trace.hh"
382600SN/A#include "cpu/base.hh"
392600SN/A#include "cpu/exec_context.hh"
402600SN/A#include "sim/system.hh"
412600SN/A
422600SN/Ausing namespace std;
432600SN/Ausing namespace AlphaISA;
442600SN/A
452600SN/AProcessInfo::ProcessInfo(ExecContext *_xc)
462600SN/A    : xc(_xc)
472600SN/A{
483114Sgblack@eecs.umich.edu    Addr addr = 0;
492680Sktlim@umich.edu
502600SN/A    if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
512680Sktlim@umich.edu        panic("thread info not compiled into kernel\n");
522600SN/A    thread_info_size = gtoh(xc->getVirtPort()->read<int32_t>(addr));
532600SN/A
542600SN/A    if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
552600SN/A        panic("thread info not compiled into kernel\n");
562600SN/A    task_struct_size = gtoh(xc->getVirtPort()->read<int32_t>(addr));
572600SN/A
582600SN/A    if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
592680Sktlim@umich.edu        panic("thread info not compiled into kernel\n");
602600SN/A    task_off = gtoh(xc->getVirtPort()->read<int32_t>(addr));
612600SN/A
622600SN/A    if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
632600SN/A        panic("thread info not compiled into kernel\n");
642600SN/A    pid_off = gtoh(xc->getVirtPort()->read<int32_t>(addr));
652600SN/A
662600SN/A    if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
672600SN/A        panic("thread info not compiled into kernel\n");
682600SN/A    name_off = gtoh(xc->getVirtPort()->read<int32_t>(addr));
692600SN/A}
702600SN/A
712600SN/AAddr
722600SN/AProcessInfo::task(Addr ksp) const
732600SN/A{
742600SN/A    Addr base = ksp & ~0x3fff;
752600SN/A    if (base == ULL(0xfffffc0000000000))
762600SN/A        return 0;
772600SN/A
782600SN/A    return gtoh(xc->getVirtPort()->read<Addr>(base + task_off));
792600SN/A}
802600SN/A
812600SN/Aint
822600SN/AProcessInfo::pid(Addr ksp) const
835748SSteve.Reinhardt@amd.com{
842600SN/A    Addr task = this->task(ksp);
852600SN/A    if (!task)
862600SN/A        return -1;
872600SN/A
882600SN/A    return gtoh(xc->getVirtPort()->read<uint16_t>(task + pid_off));
892600SN/A}
902600SN/A
912600SN/Astring
922600SN/AProcessInfo::name(Addr ksp) const
932600SN/A{
942600SN/A    Addr task = this->task(ksp);
952600SN/A    if (!task)
962600SN/A        return "console";
972600SN/A
982600SN/A    char comm[256];
992600SN/A    CopyStringOut(xc, comm, task + name_off, sizeof(comm));
1002600SN/A    if (!comm[0])
1012600SN/A        return "startup";
1022600SN/A
1032600SN/A    return comm;
1042600SN/A}
1052600SN/A
1062600SN/AStackTrace::StackTrace()
1072600SN/A    : xc(0), stack(64)
1082600SN/A{
1092600SN/A}
1102600SN/A
1112600SN/AStackTrace::StackTrace(ExecContext *_xc, StaticInstPtr inst)
1122600SN/A    : xc(0), stack(64)
1132600SN/A{
1142600SN/A    trace(_xc, inst);
1152600SN/A}
1162600SN/A
1172600SN/AStackTrace::~StackTrace()
1182600SN/A{
1192600SN/A}
1202600SN/A
1212600SN/Avoid
1222600SN/AStackTrace::trace(ExecContext *_xc, bool is_call)
1232600SN/A{
1242600SN/A    xc = _xc;
1252600SN/A
1265513SMichael.Adler@intel.com    bool usermode = (xc->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
1272600SN/A
1282600SN/A    Addr pc = xc->readNextPC();
1292600SN/A    bool kernel = xc->getSystemPtr()->kernelStart <= pc &&
1302600SN/A        pc <= xc->getSystemPtr()->kernelEnd;
1312600SN/A
1322600SN/A    if (usermode) {
1332600SN/A        stack.push_back(user);
1342600SN/A        return;
1352600SN/A    }
1362600SN/A
1372600SN/A    if (!kernel) {
1382600SN/A        stack.push_back(console);
1392600SN/A        return;
1402600SN/A    }
1412600SN/A
1422600SN/A    SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab;
1432600SN/A    Addr ksp = xc->readIntReg(TheISA::StackPointerReg);
1442600SN/A    Addr bottom = ksp & ~0x3fff;
1452600SN/A    Addr addr;
1462600SN/A
1472600SN/A    if (is_call) {
1482600SN/A        if (!symtab->findNearestAddr(pc, addr))
1492600SN/A            panic("could not find address %#x", pc);
1502600SN/A
1512600SN/A        stack.push_back(addr);
1522600SN/A        pc = xc->readPC();
1532600SN/A    }
1542600SN/A
1552600SN/A    Addr ra;
1565513SMichael.Adler@intel.com    int size;
1572600SN/A
1582600SN/A    while (ksp > bottom) {
1592600SN/A        if (!symtab->findNearestAddr(pc, addr))
1602600SN/A            panic("could not find symbol for pc=%#x", pc);
1612600SN/A        assert(pc >= addr && "symbol botch: callpc < func");
1622600SN/A
1632600SN/A        stack.push_back(addr);
1642600SN/A
1652600SN/A        if (isEntry(addr))
1662600SN/A            return;
1672600SN/A
1682600SN/A        if (decodePrologue(ksp, pc, addr, size, ra)) {
1692600SN/A            if (!ra)
1702600SN/A                return;
1712600SN/A
1722600SN/A            if (size <= 0) {
1732600SN/A                stack.push_back(unknown);
1742600SN/A                return;
1752600SN/A            }
1762600SN/A
1772600SN/A            pc = ra;
1782600SN/A            ksp += size;
1792600SN/A        } else {
1802600SN/A            stack.push_back(unknown);
1812600SN/A            return;
1822600SN/A        }
1832600SN/A
1842600SN/A        bool kernel = xc->getSystemPtr()->kernelStart <= pc &&
1852600SN/A            pc <= xc->getSystemPtr()->kernelEnd;
1862600SN/A        if (!kernel)
1872600SN/A            return;
1882600SN/A
1892600SN/A        if (stack.size() >= 1000)
1902600SN/A            panic("unwinding too far");
1912600SN/A    }
1922600SN/A
1932600SN/A    panic("unwinding too far");
1942600SN/A}
1952600SN/A
1962600SN/Abool
1972600SN/AStackTrace::isEntry(Addr addr)
1982600SN/A{
1992600SN/A    if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp12))
2002600SN/A        return true;
2012600SN/A
2022600SN/A    if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp7))
2032600SN/A        return true;
2042600SN/A
2052600SN/A    if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp11))
2062600SN/A        return true;
2072600SN/A
2082600SN/A    if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp21))
2092600SN/A        return true;
2102600SN/A
2112600SN/A    if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp9))
2122600SN/A        return true;
2132600SN/A
2142600SN/A    if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp2))
2152600SN/A        return true;
2162600SN/A
2172600SN/A    return false;
2182600SN/A}
2192600SN/A
2202600SN/Abool
2212600SN/AStackTrace::decodeStack(MachInst inst, int &disp)
2222600SN/A{
2232600SN/A    // lda $sp, -disp($sp)
2242600SN/A    //
2252600SN/A    // Opcode<31:26> == 0x08
2262600SN/A    // RA<25:21> == 30
2272600SN/A    // RB<20:16> == 30
2282600SN/A    // Disp<15:0>
2292600SN/A    const MachInst mem_mask = 0xffff0000;
2302600SN/A    const MachInst lda_pattern = 0x23de0000;
2312600SN/A    const MachInst lda_disp_mask = 0x0000ffff;
2322600SN/A
2332600SN/A    // subq $sp, disp, $sp
2342600SN/A    // addq $sp, disp, $sp
2352600SN/A    //
2362600SN/A    // Opcode<31:26> == 0x10
2372600SN/A    // RA<25:21> == 30
2382600SN/A    // Lit<20:13>
2392600SN/A    // One<12> = 1
2402600SN/A    // Func<11:5> == 0x20 (addq)
2412600SN/A    // Func<11:5> == 0x29 (subq)
2422600SN/A    // RC<4:0> == 30
2432600SN/A    const MachInst intop_mask = 0xffe01fff;
2442600SN/A    const MachInst addq_pattern = 0x43c0141e;
2452600SN/A    const MachInst subq_pattern = 0x43c0153e;
2462600SN/A    const MachInst intop_disp_mask = 0x001fe000;
2472600SN/A    const int intop_disp_shift = 13;
2482600SN/A
2492600SN/A    if ((inst & mem_mask) == lda_pattern)
2502600SN/A        disp = -sext<16>(inst & lda_disp_mask);
2512600SN/A    else if ((inst & intop_mask) == addq_pattern)
2522600SN/A        disp = -int((inst & intop_disp_mask) >> intop_disp_shift);
2532600SN/A    else if ((inst & intop_mask) == subq_pattern)
2542600SN/A        disp = int((inst & intop_disp_mask) >> intop_disp_shift);
2552600SN/A    else
2562600SN/A        return false;
2572600SN/A
2582600SN/A    return true;
2592600SN/A}
2602600SN/A
2612600SN/Abool
2622600SN/AStackTrace::decodeSave(MachInst inst, int &reg, int &disp)
2632600SN/A{
2642600SN/A    // lda $stq, disp($sp)
2652600SN/A    //
2662600SN/A    // Opcode<31:26> == 0x08
2672600SN/A    // RA<25:21> == ?
2682600SN/A    // RB<20:16> == 30
2692600SN/A    // Disp<15:0>
2702600SN/A    const MachInst stq_mask = 0xfc1f0000;
2712600SN/A    const MachInst stq_pattern = 0xb41e0000;
2722600SN/A    const MachInst stq_disp_mask = 0x0000ffff;
2732600SN/A    const MachInst reg_mask = 0x03e00000;
2742600SN/A    const int reg_shift = 21;
2752600SN/A
2762600SN/A    if ((inst & stq_mask) == stq_pattern) {
2772600SN/A        reg = (inst & reg_mask) >> reg_shift;
2782600SN/A        disp = sext<16>(inst & stq_disp_mask);
2792600SN/A    } else {
2802600SN/A        return false;
2812600SN/A    }
2822600SN/A
2832600SN/A    return true;
2842600SN/A}
2852600SN/A
2862600SN/A/*
2872600SN/A * Decode the function prologue for the function we're in, and note
2882600SN/A * which registers are stored where, and how large the stack frame is.
2892600SN/A */
2902600SN/Abool
2912600SN/AStackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
2922600SN/A                           int &size, Addr &ra)
2932600SN/A{
2942600SN/A    size = 0;
2952600SN/A    ra = 0;
2962600SN/A
2972600SN/A    for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) {
2982600SN/A        MachInst inst;
2992600SN/A        CopyOut(xc, (uint8_t *)&inst, pc, sizeof(MachInst));
3002600SN/A
3012600SN/A        int reg, disp;
3022600SN/A        if (decodeStack(inst, disp)) {
3032600SN/A            if (size) {
3042600SN/A                // panic("decoding frame size again");
3052600SN/A                return true;
3062600SN/A            }
3072600SN/A            size += disp;
3082600SN/A        } else if (decodeSave(inst, reg, disp)) {
3092600SN/A            if (!ra && reg == ReturnAddressReg) {
3102600SN/A                CopyOut(xc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
3112600SN/A                if (!ra) {
3122600SN/A                    // panic("no return address value pc=%#x\n", pc);
3132600SN/A                    return false;
3142600SN/A                }
3152600SN/A            }
3162600SN/A        }
3172600SN/A    }
3182600SN/A
3192600SN/A    return true;
3202600SN/A}
3212600SN/A
3222600SN/A#if TRACING_ON
3232600SN/Avoid
3245154Sgblack@eecs.umich.eduStackTrace::dump()
3255154Sgblack@eecs.umich.edu{
3265154Sgblack@eecs.umich.edu    StringWrap name(xc->getCpuPtr()->name());
3272600SN/A    SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab;
3282600SN/A
3292600SN/A    DPRINTFN("------ Stack ------\n");
3302600SN/A
3312600SN/A    string symbol;
3322600SN/A    for (int i = 0, size = stack.size(); i < size; ++i) {
3332600SN/A        Addr addr = stack[size - i - 1];
3342600SN/A        if (addr == user)
3352600SN/A            symbol = "user";
3362600SN/A        else if (addr == console)
3372600SN/A            symbol = "console";
3382600SN/A        else if (addr == unknown)
3392600SN/A            symbol = "unknown";
3402600SN/A        else
3412600SN/A            symtab->findSymbol(addr, symbol);
3422600SN/A
343        DPRINTFN("%#x: %s\n", addr, symbol);
344    }
345}
346#endif
347