stacktrace.cc revision 4172:141705d83494
1/*
2 * Copyright (c) 2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Nathan Binkert
29 */
30
31#include <string>
32
33#include "arch/alpha/isa_traits.hh"
34#include "arch/alpha/stacktrace.hh"
35#include "arch/alpha/vtophys.hh"
36#include "base/bitfield.hh"
37#include "base/trace.hh"
38#include "cpu/base.hh"
39#include "cpu/thread_context.hh"
40#include "sim/system.hh"
41
42using namespace std;
43
44namespace AlphaISA
45{
46    ProcessInfo::ProcessInfo(ThreadContext *_tc)
47        : tc(_tc)
48    {
49        Addr addr = 0;
50
51        VirtualPort *vp;
52
53        vp = tc->getVirtPort();
54
55        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
56            panic("thread info not compiled into kernel\n");
57        thread_info_size = vp->readGtoH<int32_t>(addr);
58
59        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
60            panic("thread info not compiled into kernel\n");
61        task_struct_size = vp->readGtoH<int32_t>(addr);
62
63        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
64            panic("thread info not compiled into kernel\n");
65        task_off = vp->readGtoH<int32_t>(addr);
66
67        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
68            panic("thread info not compiled into kernel\n");
69        pid_off = vp->readGtoH<int32_t>(addr);
70
71        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
72            panic("thread info not compiled into kernel\n");
73        name_off = vp->readGtoH<int32_t>(addr);
74
75        tc->delVirtPort(vp);
76    }
77
78    Addr
79    ProcessInfo::task(Addr ksp) const
80    {
81        Addr base = ksp & ~0x3fff;
82        if (base == ULL(0xfffffc0000000000))
83            return 0;
84
85        Addr tsk;
86
87        VirtualPort *vp;
88
89        vp = tc->getVirtPort();
90        tsk = vp->readGtoH<Addr>(base + task_off);
91        tc->delVirtPort(vp);
92
93        return tsk;
94    }
95
96    int
97    ProcessInfo::pid(Addr ksp) const
98    {
99        Addr task = this->task(ksp);
100        if (!task)
101            return -1;
102
103        uint16_t pd;
104
105        VirtualPort *vp;
106
107        vp = tc->getVirtPort();
108        pd = vp->readGtoH<uint16_t>(task + pid_off);
109        tc->delVirtPort(vp);
110
111        return pd;
112    }
113
114    string
115    ProcessInfo::name(Addr ksp) const
116    {
117        Addr task = this->task(ksp);
118        if (!task)
119            return "console";
120
121        char comm[256];
122        CopyStringOut(tc, comm, task + name_off, sizeof(comm));
123        if (!comm[0])
124            return "startup";
125
126        return comm;
127    }
128
129    StackTrace::StackTrace()
130        : tc(0), stack(64)
131    {
132    }
133
134    StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
135        : tc(0), stack(64)
136    {
137        trace(_tc, inst);
138    }
139
140    StackTrace::~StackTrace()
141    {
142    }
143
144    void
145    StackTrace::trace(ThreadContext *_tc, bool is_call)
146    {
147        tc = _tc;
148
149        bool usermode = (tc->readMiscRegNoEffect(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
150
151        Addr pc = tc->readNextPC();
152        bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
153            pc <= tc->getSystemPtr()->kernelEnd;
154
155        if (usermode) {
156            stack.push_back(user);
157            return;
158        }
159
160        if (!kernel) {
161            stack.push_back(console);
162            return;
163        }
164
165        SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
166        Addr ksp = tc->readIntReg(TheISA::StackPointerReg);
167        Addr bottom = ksp & ~0x3fff;
168        Addr addr;
169
170        if (is_call) {
171            if (!symtab->findNearestAddr(pc, addr))
172                panic("could not find address %#x", pc);
173
174            stack.push_back(addr);
175            pc = tc->readPC();
176        }
177
178        Addr ra;
179        int size;
180
181        while (ksp > bottom) {
182            if (!symtab->findNearestAddr(pc, addr))
183                panic("could not find symbol for pc=%#x", pc);
184            assert(pc >= addr && "symbol botch: callpc < func");
185
186            stack.push_back(addr);
187
188            if (isEntry(addr))
189                return;
190
191            if (decodePrologue(ksp, pc, addr, size, ra)) {
192                if (!ra)
193                    return;
194
195                if (size <= 0) {
196                    stack.push_back(unknown);
197                    return;
198                }
199
200                pc = ra;
201                ksp += size;
202            } else {
203                stack.push_back(unknown);
204                return;
205            }
206
207            bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
208                pc <= tc->getSystemPtr()->kernelEnd;
209            if (!kernel)
210                return;
211
212            if (stack.size() >= 1000)
213                panic("unwinding too far");
214        }
215
216        panic("unwinding too far");
217    }
218
219    bool
220    StackTrace::isEntry(Addr addr)
221    {
222        if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp12))
223            return true;
224
225        if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp7))
226            return true;
227
228        if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp11))
229            return true;
230
231        if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp21))
232            return true;
233
234        if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp9))
235            return true;
236
237        if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp2))
238            return true;
239
240        return false;
241    }
242
243    bool
244    StackTrace::decodeStack(MachInst inst, int &disp)
245    {
246        // lda $sp, -disp($sp)
247        //
248        // Opcode<31:26> == 0x08
249        // RA<25:21> == 30
250        // RB<20:16> == 30
251        // Disp<15:0>
252        const MachInst mem_mask = 0xffff0000;
253        const MachInst lda_pattern = 0x23de0000;
254        const MachInst lda_disp_mask = 0x0000ffff;
255
256        // subq $sp, disp, $sp
257        // addq $sp, disp, $sp
258        //
259        // Opcode<31:26> == 0x10
260        // RA<25:21> == 30
261        // Lit<20:13>
262        // One<12> = 1
263        // Func<11:5> == 0x20 (addq)
264        // Func<11:5> == 0x29 (subq)
265        // RC<4:0> == 30
266        const MachInst intop_mask = 0xffe01fff;
267        const MachInst addq_pattern = 0x43c0141e;
268        const MachInst subq_pattern = 0x43c0153e;
269        const MachInst intop_disp_mask = 0x001fe000;
270        const int intop_disp_shift = 13;
271
272        if ((inst & mem_mask) == lda_pattern)
273            disp = -sext<16>(inst & lda_disp_mask);
274        else if ((inst & intop_mask) == addq_pattern)
275            disp = -int((inst & intop_disp_mask) >> intop_disp_shift);
276        else if ((inst & intop_mask) == subq_pattern)
277            disp = int((inst & intop_disp_mask) >> intop_disp_shift);
278        else
279            return false;
280
281        return true;
282    }
283
284    bool
285    StackTrace::decodeSave(MachInst inst, int &reg, int &disp)
286    {
287        // lda $stq, disp($sp)
288        //
289        // Opcode<31:26> == 0x08
290        // RA<25:21> == ?
291        // RB<20:16> == 30
292        // Disp<15:0>
293        const MachInst stq_mask = 0xfc1f0000;
294        const MachInst stq_pattern = 0xb41e0000;
295        const MachInst stq_disp_mask = 0x0000ffff;
296        const MachInst reg_mask = 0x03e00000;
297        const int reg_shift = 21;
298
299        if ((inst & stq_mask) == stq_pattern) {
300            reg = (inst & reg_mask) >> reg_shift;
301            disp = sext<16>(inst & stq_disp_mask);
302        } else {
303            return false;
304        }
305
306        return true;
307    }
308
309    /*
310     * Decode the function prologue for the function we're in, and note
311     * which registers are stored where, and how large the stack frame is.
312     */
313    bool
314    StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
315                               int &size, Addr &ra)
316    {
317        size = 0;
318        ra = 0;
319
320        for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) {
321            MachInst inst;
322            CopyOut(tc, (uint8_t *)&inst, pc, sizeof(MachInst));
323
324            int reg, disp;
325            if (decodeStack(inst, disp)) {
326                if (size) {
327                    // panic("decoding frame size again");
328                    return true;
329                }
330                size += disp;
331            } else if (decodeSave(inst, reg, disp)) {
332                if (!ra && reg == ReturnAddressReg) {
333                    CopyOut(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
334                    if (!ra) {
335                        // panic("no return address value pc=%#x\n", pc);
336                        return false;
337                    }
338                }
339            }
340        }
341
342        return true;
343    }
344
345#if TRACING_ON
346    void
347    StackTrace::dump()
348    {
349        StringWrap name(tc->getCpuPtr()->name());
350        SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
351
352        DPRINTFN("------ Stack ------\n");
353
354        string symbol;
355        for (int i = 0, size = stack.size(); i < size; ++i) {
356            Addr addr = stack[size - i - 1];
357            if (addr == user)
358                symbol = "user";
359            else if (addr == console)
360                symbol = "console";
361            else if (addr == unknown)
362                symbol = "unknown";
363            else
364                symtab->findSymbol(addr, symbol);
365
366            DPRINTFN("%#x: %s\n", addr, symbol);
367        }
368    }
369#endif
370}
371