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
3111793Sbrandon.potter@amd.com#include "arch/alpha/stacktrace.hh"
3211793Sbrandon.potter@amd.com
331917SN/A#include <string>
341917SN/A
351917SN/A#include "arch/alpha/isa_traits.hh"
361917SN/A#include "arch/alpha/vtophys.hh"
371917SN/A#include "base/bitfield.hh"
381917SN/A#include "base/trace.hh"
391917SN/A#include "cpu/base.hh"
402680Sktlim@umich.edu#include "cpu/thread_context.hh"
418706Sandreas.hansson@arm.com#include "mem/fs_translating_port_proxy.hh"
422235SN/A#include "sim/system.hh"
431917SN/A
441917SN/Ausing namespace std;
451917SN/A
465569Snate@binkert.orgnamespace AlphaISA {
475569Snate@binkert.org
485569Snate@binkert.orgProcessInfo::ProcessInfo(ThreadContext *_tc)
495569Snate@binkert.org    : tc(_tc)
501917SN/A{
515569Snate@binkert.org    Addr addr = 0;
5214020Sgabeblack@google.com    PortProxy &vp = tc->getVirtProxy();
535569Snate@binkert.org    SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
541917SN/A
555569Snate@binkert.org    if (!symtab->findAddress("thread_info_size", addr))
565569Snate@binkert.org        panic("thread info not compiled into kernel\n");
5713893Sgabeblack@google.com    thread_info_size = vp.read<int32_t>(addr, GuestByteOrder);
582684Ssaidi@eecs.umich.edu
595569Snate@binkert.org    if (!symtab->findAddress("task_struct_size", addr))
605569Snate@binkert.org        panic("thread info not compiled into kernel\n");
6113893Sgabeblack@google.com    task_struct_size = vp.read<int32_t>(addr, GuestByteOrder);
622684Ssaidi@eecs.umich.edu
635569Snate@binkert.org    if (!symtab->findAddress("thread_info_task", addr))
645569Snate@binkert.org        panic("thread info not compiled into kernel\n");
6513893Sgabeblack@google.com    task_off = vp.read<int32_t>(addr, GuestByteOrder);
661917SN/A
675569Snate@binkert.org    if (!symtab->findAddress("task_struct_pid", addr))
685569Snate@binkert.org        panic("thread info not compiled into kernel\n");
6913893Sgabeblack@google.com    pid_off = vp.read<int32_t>(addr, GuestByteOrder);
701917SN/A
715569Snate@binkert.org    if (!symtab->findAddress("task_struct_comm", addr))
725569Snate@binkert.org        panic("thread info not compiled into kernel\n");
7313893Sgabeblack@google.com    name_off = vp.read<int32_t>(addr, GuestByteOrder);
745569Snate@binkert.org}
751917SN/A
765569Snate@binkert.orgAddr
775569Snate@binkert.orgProcessInfo::task(Addr ksp) const
785569Snate@binkert.org{
795569Snate@binkert.org    Addr base = ksp & ~0x3fff;
805569Snate@binkert.org    if (base == ULL(0xfffffc0000000000))
815569Snate@binkert.org        return 0;
821917SN/A
835569Snate@binkert.org    Addr tsk;
845569Snate@binkert.org
8514020Sgabeblack@google.com    PortProxy &vp = tc->getVirtProxy();
8613893Sgabeblack@google.com    tsk = vp.read<Addr>(base + task_off, GuestByteOrder);
875569Snate@binkert.org
885569Snate@binkert.org    return tsk;
895569Snate@binkert.org}
905569Snate@binkert.org
915569Snate@binkert.orgint
925569Snate@binkert.orgProcessInfo::pid(Addr ksp) const
935569Snate@binkert.org{
945569Snate@binkert.org    Addr task = this->task(ksp);
955569Snate@binkert.org    if (!task)
965569Snate@binkert.org        return -1;
975569Snate@binkert.org
985569Snate@binkert.org    uint16_t pd;
995569Snate@binkert.org
10014020Sgabeblack@google.com    PortProxy &vp = tc->getVirtProxy();
10113893Sgabeblack@google.com    pd = vp.read<uint16_t>(task + pid_off, GuestByteOrder);
1025569Snate@binkert.org
1035569Snate@binkert.org    return pd;
1045569Snate@binkert.org}
1055569Snate@binkert.org
1065569Snate@binkert.orgstring
1075569Snate@binkert.orgProcessInfo::name(Addr ksp) const
1085569Snate@binkert.org{
1095569Snate@binkert.org    Addr task = this->task(ksp);
1105569Snate@binkert.org    if (!task)
1115569Snate@binkert.org        return "console";
1125569Snate@binkert.org
1135569Snate@binkert.org    char comm[256];
11414018Sgabeblack@google.com    tc->getVirtProxy().readString(comm, task + name_off, sizeof(comm));
1155569Snate@binkert.org    if (!comm[0])
1165569Snate@binkert.org        return "startup";
1175569Snate@binkert.org
1185569Snate@binkert.org    return comm;
1195569Snate@binkert.org}
1205569Snate@binkert.org
1215569Snate@binkert.orgStackTrace::StackTrace()
1225569Snate@binkert.org    : tc(0), stack(64)
1235569Snate@binkert.org{
1245569Snate@binkert.org}
1255569Snate@binkert.org
12610417Sandreas.hansson@arm.comStackTrace::StackTrace(ThreadContext *_tc, const StaticInstPtr &inst)
1275569Snate@binkert.org    : tc(0), stack(64)
1285569Snate@binkert.org{
1295569Snate@binkert.org    trace(_tc, inst);
1305569Snate@binkert.org}
1315569Snate@binkert.org
1325569Snate@binkert.orgStackTrace::~StackTrace()
1335569Snate@binkert.org{
1345569Snate@binkert.org}
1355569Snate@binkert.org
1365569Snate@binkert.orgvoid
1375569Snate@binkert.orgStackTrace::trace(ThreadContext *_tc, bool is_call)
1385569Snate@binkert.org{
1395569Snate@binkert.org    tc = _tc;
1405569Snate@binkert.org
1415569Snate@binkert.org    System *sys = tc->getSystemPtr();
1425569Snate@binkert.org
1435569Snate@binkert.org    bool usermode =
1445569Snate@binkert.org        (tc->readMiscRegNoEffect(IPR_DTB_CM) & 0x18) != 0;
1455569Snate@binkert.org
14612644Sgabeblack@google.com    Addr pc = tc->pcState().npc();
1475569Snate@binkert.org    bool kernel = sys->kernelStart <= pc && pc <= sys->kernelEnd;
1485569Snate@binkert.org
1495569Snate@binkert.org    if (usermode) {
1505569Snate@binkert.org        stack.push_back(user);
1515569Snate@binkert.org        return;
1521917SN/A    }
1531917SN/A
1545569Snate@binkert.org    if (!kernel) {
1555569Snate@binkert.org        stack.push_back(console);
1565569Snate@binkert.org        return;
1571917SN/A    }
1581917SN/A
1595569Snate@binkert.org    SymbolTable *symtab = sys->kernelSymtab;
1605569Snate@binkert.org    Addr ksp = tc->readIntReg(StackPointerReg);
1615569Snate@binkert.org    Addr bottom = ksp & ~0x3fff;
1621917SN/A
1635569Snate@binkert.org    if (is_call) {
1645569Snate@binkert.org        Addr addr;
1655569Snate@binkert.org        if (!symtab->findNearestAddr(pc, addr))
1665569Snate@binkert.org            panic("could not find address %#x", pc);
1671917SN/A
1685569Snate@binkert.org        stack.push_back(addr);
1697720Sgblack@eecs.umich.edu        pc = tc->pcState().pc();
1701917SN/A    }
1711917SN/A
1725569Snate@binkert.org    while (ksp > bottom) {
1735569Snate@binkert.org        Addr addr;
1745569Snate@binkert.org        if (!symtab->findNearestAddr(pc, addr))
1755569Snate@binkert.org            panic("could not find symbol for pc=%#x", pc);
1765569Snate@binkert.org        assert(pc >= addr && "symbol botch: callpc < func");
1771917SN/A
1785569Snate@binkert.org        stack.push_back(addr);
1791917SN/A
1805569Snate@binkert.org        if (isEntry(addr))
1811917SN/A            return;
1823570Sgblack@eecs.umich.edu
1833570Sgblack@eecs.umich.edu        Addr ra;
1843570Sgblack@eecs.umich.edu        int size;
1855569Snate@binkert.org        if (decodePrologue(ksp, pc, addr, size, ra)) {
1865569Snate@binkert.org            if (!ra)
1871917SN/A                return;
1881917SN/A
1895569Snate@binkert.org            if (size <= 0) {
1901977SN/A                stack.push_back(unknown);
1911977SN/A                return;
1921977SN/A            }
1931977SN/A
1945569Snate@binkert.org            pc = ra;
1955569Snate@binkert.org            ksp += size;
1965569Snate@binkert.org        } else {
1975569Snate@binkert.org            stack.push_back(unknown);
1985569Snate@binkert.org            return;
1991917SN/A        }
2001917SN/A
2019550Sandreas.hansson@arm.com        kernel = sys->kernelStart <= pc && pc <= sys->kernelEnd;
2025569Snate@binkert.org        if (!kernel)
2035569Snate@binkert.org            return;
2045569Snate@binkert.org
2055569Snate@binkert.org        if (stack.size() >= 1000)
2065569Snate@binkert.org            panic("unwinding too far");
2071917SN/A    }
2081917SN/A
2095569Snate@binkert.org    panic("unwinding too far");
2105569Snate@binkert.org}
2111917SN/A
2125569Snate@binkert.orgbool
2135569Snate@binkert.orgStackTrace::isEntry(Addr addr)
2145569Snate@binkert.org{
2155569Snate@binkert.org    if (addr == tc->readMiscRegNoEffect(IPR_PALtemp12))
2165569Snate@binkert.org        return true;
2171917SN/A
2185569Snate@binkert.org    if (addr == tc->readMiscRegNoEffect(IPR_PALtemp7))
2195569Snate@binkert.org        return true;
2201917SN/A
2215569Snate@binkert.org    if (addr == tc->readMiscRegNoEffect(IPR_PALtemp11))
2225569Snate@binkert.org        return true;
2231917SN/A
2245569Snate@binkert.org    if (addr == tc->readMiscRegNoEffect(IPR_PALtemp21))
2255569Snate@binkert.org        return true;
2261917SN/A
2275569Snate@binkert.org    if (addr == tc->readMiscRegNoEffect(IPR_PALtemp9))
2285569Snate@binkert.org        return true;
2291917SN/A
2305569Snate@binkert.org    if (addr == tc->readMiscRegNoEffect(IPR_PALtemp2))
2315569Snate@binkert.org        return true;
2325569Snate@binkert.org
2335569Snate@binkert.org    return false;
2345569Snate@binkert.org}
2355569Snate@binkert.org
2365569Snate@binkert.orgbool
2375569Snate@binkert.orgStackTrace::decodeStack(MachInst inst, int &disp)
2385569Snate@binkert.org{
2395569Snate@binkert.org    // lda $sp, -disp($sp)
2405569Snate@binkert.org    //
2415569Snate@binkert.org    // Opcode<31:26> == 0x08
2425569Snate@binkert.org    // RA<25:21> == 30
2435569Snate@binkert.org    // RB<20:16> == 30
2445569Snate@binkert.org    // Disp<15:0>
2455569Snate@binkert.org    const MachInst mem_mask = 0xffff0000;
2465569Snate@binkert.org    const MachInst lda_pattern = 0x23de0000;
2475569Snate@binkert.org    const MachInst lda_disp_mask = 0x0000ffff;
2485569Snate@binkert.org
2495569Snate@binkert.org    // subq $sp, disp, $sp
2505569Snate@binkert.org    // addq $sp, disp, $sp
2515569Snate@binkert.org    //
2525569Snate@binkert.org    // Opcode<31:26> == 0x10
2535569Snate@binkert.org    // RA<25:21> == 30
2545569Snate@binkert.org    // Lit<20:13>
2555569Snate@binkert.org    // One<12> = 1
2565569Snate@binkert.org    // Func<11:5> == 0x20 (addq)
2575569Snate@binkert.org    // Func<11:5> == 0x29 (subq)
2585569Snate@binkert.org    // RC<4:0> == 30
2595569Snate@binkert.org    const MachInst intop_mask = 0xffe01fff;
2605569Snate@binkert.org    const MachInst addq_pattern = 0x43c0141e;
2615569Snate@binkert.org    const MachInst subq_pattern = 0x43c0153e;
2625569Snate@binkert.org    const MachInst intop_disp_mask = 0x001fe000;
2635569Snate@binkert.org    const int intop_disp_shift = 13;
2645569Snate@binkert.org
2655569Snate@binkert.org    if ((inst & mem_mask) == lda_pattern)
2665569Snate@binkert.org        disp = -sext<16>(inst & lda_disp_mask);
2675569Snate@binkert.org    else if ((inst & intop_mask) == addq_pattern)
2685569Snate@binkert.org        disp = -int((inst & intop_disp_mask) >> intop_disp_shift);
2695569Snate@binkert.org    else if ((inst & intop_mask) == subq_pattern)
2705569Snate@binkert.org        disp = int((inst & intop_disp_mask) >> intop_disp_shift);
2715569Snate@binkert.org    else
2725569Snate@binkert.org        return false;
2735569Snate@binkert.org
2745569Snate@binkert.org    return true;
2755569Snate@binkert.org}
2765569Snate@binkert.org
2775569Snate@binkert.orgbool
2785569Snate@binkert.orgStackTrace::decodeSave(MachInst inst, int &reg, int &disp)
2795569Snate@binkert.org{
2805569Snate@binkert.org    // lda $stq, disp($sp)
2815569Snate@binkert.org    //
2825569Snate@binkert.org    // Opcode<31:26> == 0x08
2835569Snate@binkert.org    // RA<25:21> == ?
2845569Snate@binkert.org    // RB<20:16> == 30
2855569Snate@binkert.org    // Disp<15:0>
2865569Snate@binkert.org    const MachInst stq_mask = 0xfc1f0000;
2875569Snate@binkert.org    const MachInst stq_pattern = 0xb41e0000;
2885569Snate@binkert.org    const MachInst stq_disp_mask = 0x0000ffff;
2895569Snate@binkert.org    const MachInst reg_mask = 0x03e00000;
2905569Snate@binkert.org    const int reg_shift = 21;
2915569Snate@binkert.org
2925569Snate@binkert.org    if ((inst & stq_mask) == stq_pattern) {
2935569Snate@binkert.org        reg = (inst & reg_mask) >> reg_shift;
2945569Snate@binkert.org        disp = sext<16>(inst & stq_disp_mask);
2955569Snate@binkert.org    } else {
2961917SN/A        return false;
2971917SN/A    }
2981917SN/A
2995569Snate@binkert.org    return true;
3005569Snate@binkert.org}
3011917SN/A
3025569Snate@binkert.org/*
3035569Snate@binkert.org * Decode the function prologue for the function we're in, and note
3045569Snate@binkert.org * which registers are stored where, and how large the stack frame is.
3055569Snate@binkert.org */
3065569Snate@binkert.orgbool
3075569Snate@binkert.orgStackTrace::decodePrologue(Addr sp, Addr callpc, Addr func, int &size,
3085569Snate@binkert.org                           Addr &ra)
3095569Snate@binkert.org{
3105569Snate@binkert.org    size = 0;
3115569Snate@binkert.org    ra = 0;
3121917SN/A
3135569Snate@binkert.org    for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) {
31414018Sgabeblack@google.com        MachInst inst = tc->getVirtProxy().read<MachInst>(pc);
3151917SN/A
3165569Snate@binkert.org        int reg, disp;
3175569Snate@binkert.org        if (decodeStack(inst, disp)) {
3185569Snate@binkert.org            if (size) {
3195569Snate@binkert.org                // panic("decoding frame size again");
3205569Snate@binkert.org                return true;
3215569Snate@binkert.org            }
3225569Snate@binkert.org            size += disp;
3235569Snate@binkert.org        } else if (decodeSave(inst, reg, disp)) {
3245569Snate@binkert.org            if (!ra && reg == ReturnAddressReg) {
32514018Sgabeblack@google.com                ra = tc->getVirtProxy().read<Addr>(sp + disp);
3265569Snate@binkert.org                if (!ra) {
3275569Snate@binkert.org                    // panic("no return address value pc=%#x\n", pc);
3285569Snate@binkert.org                    return false;
3291917SN/A                }
3301917SN/A            }
3311917SN/A        }
3321917SN/A    }
3331917SN/A
3345569Snate@binkert.org    return true;
3355569Snate@binkert.org}
3365569Snate@binkert.org
3373570Sgblack@eecs.umich.edu#if TRACING_ON
3385569Snate@binkert.orgvoid
3395569Snate@binkert.orgStackTrace::dump()
3405569Snate@binkert.org{
3415569Snate@binkert.org    StringWrap name(tc->getCpuPtr()->name());
3425569Snate@binkert.org    SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
3433570Sgblack@eecs.umich.edu
3445569Snate@binkert.org    DPRINTFN("------ Stack ------\n");
3453570Sgblack@eecs.umich.edu
3465569Snate@binkert.org    string symbol;
3475569Snate@binkert.org    for (int i = 0, size = stack.size(); i < size; ++i) {
3485569Snate@binkert.org        Addr addr = stack[size - i - 1];
3495569Snate@binkert.org        if (addr == user)
3505569Snate@binkert.org            symbol = "user";
3515569Snate@binkert.org        else if (addr == console)
3525569Snate@binkert.org            symbol = "console";
3535569Snate@binkert.org        else if (addr == unknown)
3545569Snate@binkert.org            symbol = "unknown";
3555569Snate@binkert.org        else
3565569Snate@binkert.org            symtab->findSymbol(addr, symbol);
3573570Sgblack@eecs.umich.edu
3585569Snate@binkert.org        DPRINTFN("%#x: %s\n", addr, symbol);
3593570Sgblack@eecs.umich.edu    }
3605569Snate@binkert.org}
3613570Sgblack@eecs.umich.edu#endif
3625569Snate@binkert.org
3635569Snate@binkert.org} // namespace AlphaISA
364