stacktrace.cc revision 3570
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/sparc/isa_traits.hh"
34#include "arch/sparc/stacktrace.hh"
35#include "arch/sparc/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;
43namespace SparcISA
44{
45    ProcessInfo::ProcessInfo(ThreadContext *_tc)
46        : tc(_tc)
47    {
48        Addr addr = 0;
49
50        VirtualPort *vp;
51
52        vp = tc->getVirtPort();
53
54        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
55            panic("thread info not compiled into kernel\n");
56        thread_info_size = vp->readGtoH<int32_t>(addr);
57
58        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
59            panic("thread info not compiled into kernel\n");
60        task_struct_size = vp->readGtoH<int32_t>(addr);
61
62        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
63            panic("thread info not compiled into kernel\n");
64        task_off = vp->readGtoH<int32_t>(addr);
65
66        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
67            panic("thread info not compiled into kernel\n");
68        pid_off = vp->readGtoH<int32_t>(addr);
69
70        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
71            panic("thread info not compiled into kernel\n");
72        name_off = vp->readGtoH<int32_t>(addr);
73
74        tc->delVirtPort(vp);
75    }
76
77    Addr
78    ProcessInfo::task(Addr ksp) const
79    {
80        Addr base = ksp & ~0x3fff;
81        if (base == ULL(0xfffffc0000000000))
82            return 0;
83
84        Addr tsk;
85
86        VirtualPort *vp;
87
88        vp = tc->getVirtPort();
89        tsk = vp->readGtoH<Addr>(base + task_off);
90        tc->delVirtPort(vp);
91
92        return tsk;
93    }
94
95    int
96    ProcessInfo::pid(Addr ksp) const
97    {
98        Addr task = this->task(ksp);
99        if (!task)
100            return -1;
101
102        uint16_t pd;
103
104        VirtualPort *vp;
105
106        vp = tc->getVirtPort();
107        pd = vp->readGtoH<uint16_t>(task + pid_off);
108        tc->delVirtPort(vp);
109
110        return pd;
111    }
112
113    string
114    ProcessInfo::name(Addr ksp) const
115    {
116        Addr task = this->task(ksp);
117        if (!task)
118            return "console";
119
120        char comm[256];
121        CopyStringOut(tc, comm, task + name_off, sizeof(comm));
122        if (!comm[0])
123            return "startup";
124
125        return comm;
126    }
127
128    StackTrace::StackTrace()
129        : tc(0), stack(64)
130    {
131    }
132
133    StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
134        : tc(0), stack(64)
135    {
136        trace(_tc, inst);
137    }
138
139    StackTrace::~StackTrace()
140    {
141    }
142
143    void
144    StackTrace::trace(ThreadContext *_tc, bool is_call)
145    {
146#if 0
147        tc = _tc;
148
149        bool usermode = (tc->readMiscReg(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#endif
218    }
219
220    bool
221    StackTrace::isEntry(Addr addr)
222    {
223#if 0
224        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp12))
225            return true;
226
227        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp7))
228            return true;
229
230        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp11))
231            return true;
232
233        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp21))
234            return true;
235
236        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp9))
237            return true;
238
239        if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp2))
240            return true;
241#endif
242        return false;
243    }
244
245    bool
246    StackTrace::decodeStack(MachInst inst, int &disp)
247    {
248        // lda $sp, -disp($sp)
249        //
250        // Opcode<31:26> == 0x08
251        // RA<25:21> == 30
252        // RB<20:16> == 30
253        // Disp<15:0>
254        const MachInst mem_mask = 0xffff0000;
255        const MachInst lda_pattern = 0x23de0000;
256        const MachInst lda_disp_mask = 0x0000ffff;
257
258        // subq $sp, disp, $sp
259        // addq $sp, disp, $sp
260        //
261        // Opcode<31:26> == 0x10
262        // RA<25:21> == 30
263        // Lit<20:13>
264        // One<12> = 1
265        // Func<11:5> == 0x20 (addq)
266        // Func<11:5> == 0x29 (subq)
267        // RC<4:0> == 30
268        const MachInst intop_mask = 0xffe01fff;
269        const MachInst addq_pattern = 0x43c0141e;
270        const MachInst subq_pattern = 0x43c0153e;
271        const MachInst intop_disp_mask = 0x001fe000;
272        const int intop_disp_shift = 13;
273
274        if ((inst & mem_mask) == lda_pattern)
275            disp = -sext<16>(inst & lda_disp_mask);
276        else if ((inst & intop_mask) == addq_pattern)
277            disp = -int((inst & intop_disp_mask) >> intop_disp_shift);
278        else if ((inst & intop_mask) == subq_pattern)
279            disp = int((inst & intop_disp_mask) >> intop_disp_shift);
280        else
281            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