stacktrace.cc revision 2684
11917SN/A/*
21917SN/A * Copyright (c) 2005 The Regents of The University of Michigan
31917SN/A * All rights reserved.
41917SN/A *
51917SN/A * Redistribution and use in source and binary forms, with or without
61917SN/A * modification, are permitted provided that the following conditions are
71917SN/A * met: redistributions of source code must retain the above copyright
81917SN/A * notice, this list of conditions and the following disclaimer;
91917SN/A * redistributions in binary form must reproduce the above copyright
101917SN/A * notice, this list of conditions and the following disclaimer in the
111917SN/A * documentation and/or other materials provided with the distribution;
121917SN/A * neither the name of the copyright holders nor the names of its
131917SN/A * contributors may be used to endorse or promote products derived from
141917SN/A * this software without specific prior written permission.
151917SN/A *
161917SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171917SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181917SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191917SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201917SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211917SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221917SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231917SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241917SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251917SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261917SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Nathan Binkert
291917SN/A */
301917SN/A
311917SN/A#include <string>
321917SN/A
331917SN/A#include "arch/alpha/isa_traits.hh"
341917SN/A#include "arch/alpha/stacktrace.hh"
351917SN/A#include "arch/alpha/vtophys.hh"
361917SN/A#include "base/bitfield.hh"
371917SN/A#include "base/trace.hh"
381917SN/A#include "cpu/base.hh"
392680Sktlim@umich.edu#include "cpu/thread_context.hh"
402235SN/A#include "sim/system.hh"
411917SN/A
421917SN/Ausing namespace std;
432107SN/Ausing namespace AlphaISA;
441917SN/A
452680Sktlim@umich.eduProcessInfo::ProcessInfo(ThreadContext *_tc)
462680Sktlim@umich.edu    : tc(_tc)
471917SN/A{
481917SN/A    Addr addr = 0;
491917SN/A
502684Ssaidi@eecs.umich.edu    VirtualPort *vp;
512684Ssaidi@eecs.umich.edu
522684Ssaidi@eecs.umich.edu    vp = tc->getVirtPort();
532684Ssaidi@eecs.umich.edu
542680Sktlim@umich.edu    if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
551917SN/A        panic("thread info not compiled into kernel\n");
562684Ssaidi@eecs.umich.edu    thread_info_size = vp->readGtoH<int32_t>(addr);
571917SN/A
582680Sktlim@umich.edu    if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
591917SN/A        panic("thread info not compiled into kernel\n");
602684Ssaidi@eecs.umich.edu    task_struct_size = vp->readGtoH<int32_t>(addr);
611917SN/A
622680Sktlim@umich.edu    if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
631917SN/A        panic("thread info not compiled into kernel\n");
642684Ssaidi@eecs.umich.edu    task_off = vp->readGtoH<int32_t>(addr);
651917SN/A
662680Sktlim@umich.edu    if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
671917SN/A        panic("thread info not compiled into kernel\n");
682684Ssaidi@eecs.umich.edu    pid_off = vp->readGtoH<int32_t>(addr);
691917SN/A
702680Sktlim@umich.edu    if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
711917SN/A        panic("thread info not compiled into kernel\n");
722684Ssaidi@eecs.umich.edu    name_off = vp->readGtoH<int32_t>(addr);
732684Ssaidi@eecs.umich.edu
742684Ssaidi@eecs.umich.edu    tc->delVirtPort(vp);
751917SN/A}
761917SN/A
771917SN/AAddr
781917SN/AProcessInfo::task(Addr ksp) const
791917SN/A{
801917SN/A    Addr base = ksp & ~0x3fff;
811917SN/A    if (base == ULL(0xfffffc0000000000))
821917SN/A        return 0;
831917SN/A
842684Ssaidi@eecs.umich.edu    Addr tsk;
852684Ssaidi@eecs.umich.edu
862684Ssaidi@eecs.umich.edu    VirtualPort *vp;
872684Ssaidi@eecs.umich.edu
882684Ssaidi@eecs.umich.edu    vp = tc->getVirtPort();
892684Ssaidi@eecs.umich.edu    tsk = vp->readGtoH<Addr>(base + task_off);
902684Ssaidi@eecs.umich.edu    tc->delVirtPort(vp);
912684Ssaidi@eecs.umich.edu
922684Ssaidi@eecs.umich.edu    return tsk;
931917SN/A}
941917SN/A
951917SN/Aint
961917SN/AProcessInfo::pid(Addr ksp) const
971917SN/A{
981917SN/A    Addr task = this->task(ksp);
991917SN/A    if (!task)
1001917SN/A        return -1;
1011917SN/A
1022684Ssaidi@eecs.umich.edu    uint16_t pd;
1032684Ssaidi@eecs.umich.edu
1042684Ssaidi@eecs.umich.edu    VirtualPort *vp;
1052684Ssaidi@eecs.umich.edu
1062684Ssaidi@eecs.umich.edu    vp = tc->getVirtPort();
1072684Ssaidi@eecs.umich.edu    pd = vp->readGtoH<uint16_t>(task + pid_off);
1082684Ssaidi@eecs.umich.edu    tc->delVirtPort(vp);
1092684Ssaidi@eecs.umich.edu
1102684Ssaidi@eecs.umich.edu    return pd;
1111917SN/A}
1121917SN/A
1131917SN/Astring
1141917SN/AProcessInfo::name(Addr ksp) const
1151917SN/A{
1161917SN/A    Addr task = this->task(ksp);
1171917SN/A    if (!task)
1181917SN/A        return "console";
1191917SN/A
1201917SN/A    char comm[256];
1212680Sktlim@umich.edu    CopyStringOut(tc, comm, task + name_off, sizeof(comm));
1221917SN/A    if (!comm[0])
1231917SN/A        return "startup";
1241917SN/A
1251917SN/A    return comm;
1261917SN/A}
1271917SN/A
1281977SN/AStackTrace::StackTrace()
1292680Sktlim@umich.edu    : tc(0), stack(64)
1301917SN/A{
1311977SN/A}
1321977SN/A
1332680Sktlim@umich.eduStackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
1342680Sktlim@umich.edu    : tc(0), stack(64)
1351977SN/A{
1362680Sktlim@umich.edu    trace(_tc, inst);
1371977SN/A}
1381977SN/A
1391977SN/AStackTrace::~StackTrace()
1401977SN/A{
1411977SN/A}
1421977SN/A
1431977SN/Avoid
1442680Sktlim@umich.eduStackTrace::trace(ThreadContext *_tc, bool is_call)
1451977SN/A{
1462680Sktlim@umich.edu    tc = _tc;
1471977SN/A
1482680Sktlim@umich.edu    bool usermode = (tc->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
1491917SN/A
1502680Sktlim@umich.edu    Addr pc = tc->readNextPC();
1512680Sktlim@umich.edu    bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
1522680Sktlim@umich.edu        pc <= tc->getSystemPtr()->kernelEnd;
1531917SN/A
1541917SN/A    if (usermode) {
1551977SN/A        stack.push_back(user);
1561917SN/A        return;
1571917SN/A    }
1581917SN/A
1591917SN/A    if (!kernel) {
1601977SN/A        stack.push_back(console);
1611917SN/A        return;
1621917SN/A    }
1631917SN/A
1642680Sktlim@umich.edu    SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
1652680Sktlim@umich.edu    Addr ksp = tc->readIntReg(TheISA::StackPointerReg);
1661917SN/A    Addr bottom = ksp & ~0x3fff;
1671917SN/A    Addr addr;
1681917SN/A
1691917SN/A    if (is_call) {
1701917SN/A        if (!symtab->findNearestAddr(pc, addr))
1711917SN/A            panic("could not find address %#x", pc);
1721917SN/A
1731917SN/A        stack.push_back(addr);
1742680Sktlim@umich.edu        pc = tc->readPC();
1751917SN/A    }
1761917SN/A
1771917SN/A    Addr ra;
1781917SN/A    int size;
1791917SN/A
1801917SN/A    while (ksp > bottom) {
1811917SN/A        if (!symtab->findNearestAddr(pc, addr))
1821917SN/A            panic("could not find symbol for pc=%#x", pc);
1831917SN/A        assert(pc >= addr && "symbol botch: callpc < func");
1841917SN/A
1851917SN/A        stack.push_back(addr);
1861917SN/A
1871917SN/A        if (isEntry(addr))
1881917SN/A            return;
1891917SN/A
1901917SN/A        if (decodePrologue(ksp, pc, addr, size, ra)) {
1911917SN/A            if (!ra)
1921917SN/A                return;
1931917SN/A
1941977SN/A            if (size <= 0) {
1951977SN/A                stack.push_back(unknown);
1961977SN/A                return;
1971977SN/A            }
1981977SN/A
1991917SN/A            pc = ra;
2001917SN/A            ksp += size;
2011917SN/A        } else {
2021977SN/A            stack.push_back(unknown);
2031917SN/A            return;
2041917SN/A        }
2051917SN/A
2062680Sktlim@umich.edu        bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
2072680Sktlim@umich.edu            pc <= tc->getSystemPtr()->kernelEnd;
2081917SN/A        if (!kernel)
2091917SN/A            return;
2101977SN/A
2111977SN/A        if (stack.size() >= 1000)
2121977SN/A            panic("unwinding too far");
2131917SN/A    }
2141917SN/A
2151917SN/A    panic("unwinding too far");
2161917SN/A}
2171917SN/A
2181917SN/Abool
2191917SN/AStackTrace::isEntry(Addr addr)
2201917SN/A{
2212680Sktlim@umich.edu    if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp12))
2221917SN/A        return true;
2231917SN/A
2242680Sktlim@umich.edu    if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp7))
2251917SN/A        return true;
2261917SN/A
2272680Sktlim@umich.edu    if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp11))
2281917SN/A        return true;
2291917SN/A
2302680Sktlim@umich.edu    if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp21))
2311917SN/A        return true;
2321917SN/A
2332680Sktlim@umich.edu    if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp9))
2341917SN/A        return true;
2351917SN/A
2362680Sktlim@umich.edu    if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp2))
2371917SN/A        return true;
2381917SN/A
2391917SN/A    return false;
2401917SN/A}
2411917SN/A
2421917SN/Abool
2431917SN/AStackTrace::decodeStack(MachInst inst, int &disp)
2441917SN/A{
2451917SN/A    // lda $sp, -disp($sp)
2461917SN/A    //
2471917SN/A    // Opcode<31:26> == 0x08
2481917SN/A    // RA<25:21> == 30
2491917SN/A    // RB<20:16> == 30
2501917SN/A    // Disp<15:0>
2511917SN/A    const MachInst mem_mask = 0xffff0000;
2521917SN/A    const MachInst lda_pattern = 0x23de0000;
2531917SN/A    const MachInst lda_disp_mask = 0x0000ffff;
2541917SN/A
2551917SN/A    // subq $sp, disp, $sp
2561917SN/A    // addq $sp, disp, $sp
2571917SN/A    //
2581917SN/A    // Opcode<31:26> == 0x10
2591917SN/A    // RA<25:21> == 30
2601917SN/A    // Lit<20:13>
2611917SN/A    // One<12> = 1
2621917SN/A    // Func<11:5> == 0x20 (addq)
2631917SN/A    // Func<11:5> == 0x29 (subq)
2641917SN/A    // RC<4:0> == 30
2651917SN/A    const MachInst intop_mask = 0xffe01fff;
2661917SN/A    const MachInst addq_pattern = 0x43c0141e;
2671917SN/A    const MachInst subq_pattern = 0x43c0153e;
2681917SN/A    const MachInst intop_disp_mask = 0x001fe000;
2691917SN/A    const int intop_disp_shift = 13;
2701917SN/A
2711917SN/A    if ((inst & mem_mask) == lda_pattern)
2721917SN/A        disp = -sext<16>(inst & lda_disp_mask);
2731917SN/A    else if ((inst & intop_mask) == addq_pattern)
2741917SN/A        disp = -int((inst & intop_disp_mask) >> intop_disp_shift);
2751917SN/A    else if ((inst & intop_mask) == subq_pattern)
2761917SN/A        disp = int((inst & intop_disp_mask) >> intop_disp_shift);
2771917SN/A    else
2781917SN/A        return false;
2791917SN/A
2801917SN/A    return true;
2811917SN/A}
2821917SN/A
2831917SN/Abool
2841917SN/AStackTrace::decodeSave(MachInst inst, int &reg, int &disp)
2851917SN/A{
2861917SN/A    // lda $stq, disp($sp)
2871917SN/A    //
2881917SN/A    // Opcode<31:26> == 0x08
2891917SN/A    // RA<25:21> == ?
2901917SN/A    // RB<20:16> == 30
2911917SN/A    // Disp<15:0>
2921917SN/A    const MachInst stq_mask = 0xfc1f0000;
2931917SN/A    const MachInst stq_pattern = 0xb41e0000;
2941917SN/A    const MachInst stq_disp_mask = 0x0000ffff;
2951917SN/A    const MachInst reg_mask = 0x03e00000;
2961917SN/A    const int reg_shift = 21;
2971917SN/A
2981917SN/A    if ((inst & stq_mask) == stq_pattern) {
2991917SN/A        reg = (inst & reg_mask) >> reg_shift;
3001917SN/A        disp = sext<16>(inst & stq_disp_mask);
3011917SN/A    } else {
3021917SN/A        return false;
3031917SN/A    }
3041917SN/A
3051917SN/A    return true;
3061917SN/A}
3071917SN/A
3081917SN/A/*
3091917SN/A * Decode the function prologue for the function we're in, and note
3101917SN/A * which registers are stored where, and how large the stack frame is.
3111917SN/A */
3121917SN/Abool
3131917SN/AStackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
3141917SN/A                           int &size, Addr &ra)
3151917SN/A{
3161917SN/A    size = 0;
3171917SN/A    ra = 0;
3181917SN/A
3191917SN/A    for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) {
3201917SN/A        MachInst inst;
3212680Sktlim@umich.edu        CopyOut(tc, (uint8_t *)&inst, pc, sizeof(MachInst));
3221917SN/A
3231917SN/A        int reg, disp;
3241917SN/A        if (decodeStack(inst, disp)) {
3251917SN/A            if (size) {
3261917SN/A                // panic("decoding frame size again");
3271917SN/A                return true;
3281917SN/A            }
3291917SN/A            size += disp;
3301917SN/A        } else if (decodeSave(inst, reg, disp)) {
3311917SN/A            if (!ra && reg == ReturnAddressReg) {
3322680Sktlim@umich.edu                CopyOut(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
3331917SN/A                if (!ra) {
3341917SN/A                    // panic("no return address value pc=%#x\n", pc);
3351917SN/A                    return false;
3361917SN/A                }
3371917SN/A            }
3381917SN/A        }
3391917SN/A    }
3401917SN/A
3411917SN/A    return true;
3421917SN/A}
3431917SN/A
3441917SN/A#if TRACING_ON
3451917SN/Avoid
3461917SN/AStackTrace::dump()
3471917SN/A{
3482680Sktlim@umich.edu    StringWrap name(tc->getCpuPtr()->name());
3492680Sktlim@umich.edu    SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
3501917SN/A
3511917SN/A    DPRINTFN("------ Stack ------\n");
3521917SN/A
3531917SN/A    string symbol;
3541917SN/A    for (int i = 0, size = stack.size(); i < size; ++i) {
3551917SN/A        Addr addr = stack[size - i - 1];
3561977SN/A        if (addr == user)
3571917SN/A            symbol = "user";
3581977SN/A        else if (addr == console)
3591917SN/A            symbol = "console";
3601977SN/A        else if (addr == unknown)
3611917SN/A            symbol = "unknown";
3621917SN/A        else
3631917SN/A            symtab->findSymbol(addr, symbol);
3641917SN/A
3651917SN/A        DPRINTFN("%#x: %s\n", addr, symbol);
3661917SN/A    }
3671917SN/A}
3681917SN/A#endif
369