Add in files from merge-bare-iron, get them compiling in FS and SE mode
[gem5.git] / src / arch / mips / stacktrace.cc
1 /*
2 * Copyright \e.A\eN) 2007 MIPS Technologies, Inc. All Rights Reserved
3 *
4 * This software is part of the M5 simulator.
5 *
6 * THIS IS A LEGAL AGREEMENT. BY DOWNLOADING, USING, COPYING, CREATING
7 * DERIVATIVE WORKS, AND/OR DISTRIBUTING THIS SOFTWARE YOU ARE AGREEING
8 * TO THESE TERMS AND CONDITIONS.
9 *
10 * Permission is granted to use, copy, create derivative works and
11 * distribute this software and such derivative works for any purpose,
12 * so long as (1) the copyright notice above, this grant of permission,
13 * and the disclaimer below appear in all copies and derivative works
14 * made, (2) the copyright notice above is augmented as appropriate to
15 * reflect the addition of any new copyrightable work in a derivative
16 * work (e.g., Copyright \e.A\eN) <Publication Year> Copyright Owner), and (3)
17 * the name of MIPS Technologies, Inc. (\e$B!H\e(BMIPS\e$B!I\e(B) is not used in any
18 * advertising or publicity pertaining to the use or distribution of
19 * this software without specific, written prior authorization.
20 *
21 * THIS SOFTWARE IS PROVIDED \e$B!H\e(BAS IS.\e$B!I\e(B MIPS MAKES NO WARRANTIES AND
22 * DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, STATUTORY, IMPLIED OR
23 * OTHERWISE, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
25 * NON-INFRINGEMENT OF THIRD PARTY RIGHTS, REGARDING THIS SOFTWARE.
26 * IN NO EVENT SHALL MIPS BE LIABLE FOR ANY DAMAGES, INCLUDING DIRECT,
27 * INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL, OR PUNITIVE DAMAGES OF
28 * ANY KIND OR NATURE, ARISING OUT OF OR IN CONNECTION WITH THIS AGREEMENT,
29 * THIS SOFTWARE AND/OR THE USE OF THIS SOFTWARE, WHETHER SUCH LIABILITY
30 * IS ASSERTED ON THE BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE OR
31 * STRICT LIABILITY), OR OTHERWISE, EVEN IF MIPS HAS BEEN WARNED OF THE
32 * POSSIBILITY OF ANY SUCH LOSS OR DAMAGE IN ADVANCE.
33 *
34 * Authors: Nathan L. Binkert
35 */
36
37 #include <string>
38
39 #include "arch/mips/isa_traits.hh"
40 #include "arch/mips/stacktrace.hh"
41 #include "arch/mips/vtophys.hh"
42 #include "base/bitfield.hh"
43 #include "base/trace.hh"
44 #include "cpu/base.hh"
45 #include "cpu/thread_context.hh"
46 #include "sim/system.hh"
47
48 using namespace std;
49 using namespace MipsISA;
50
51 ProcessInfo::ProcessInfo(ThreadContext *_tc)
52 : tc(_tc)
53 {
54 // Addr addr = 0;
55
56 VirtualPort *vp;
57
58 vp = tc->getVirtPort();
59
60 // if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
61 // panic("thread info not compiled into kernel\n");
62 // thread_info_size = vp->readGtoH<int32_t>(addr);
63
64 // if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
65 // panic("thread info not compiled into kernel\n");
66 // task_struct_size = vp->readGtoH<int32_t>(addr);
67
68 // if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
69 // panic("thread info not compiled into kernel\n");
70 // task_off = vp->readGtoH<int32_t>(addr);
71
72 // if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
73 // panic("thread info not compiled into kernel\n");
74 // pid_off = vp->readGtoH<int32_t>(addr);
75
76 // if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
77 // panic("thread info not compiled into kernel\n");
78 // name_off = vp->readGtoH<int32_t>(addr);
79
80 tc->delVirtPort(vp);
81 }
82
83 Addr
84 ProcessInfo::task(Addr ksp) const
85 {
86 Addr base = ksp & ~0x3fff;
87 if (base == ULL(0xfffffc0000000000))
88 return 0;
89
90 Addr tsk;
91
92 VirtualPort *vp;
93
94 vp = tc->getVirtPort();
95 tsk = vp->readGtoH<Addr>(base + task_off);
96 tc->delVirtPort(vp);
97
98 return tsk;
99 }
100
101 int
102 ProcessInfo::pid(Addr ksp) const
103 {
104 Addr task = this->task(ksp);
105 if (!task)
106 return -1;
107
108 uint16_t pd;
109
110 VirtualPort *vp;
111
112 vp = tc->getVirtPort();
113 pd = vp->readGtoH<uint16_t>(task + pid_off);
114 tc->delVirtPort(vp);
115
116 return pd;
117 }
118
119 string
120 ProcessInfo::name(Addr ksp) const
121 {
122 Addr task = this->task(ksp);
123 if (!task)
124 return "console";
125
126 char comm[256];
127 CopyStringOut(tc, comm, task + name_off, sizeof(comm));
128 if (!comm[0])
129 return "startup";
130
131 return comm;
132 }
133
134 StackTrace::StackTrace()
135 : tc(0), stack(64)
136 {
137 }
138
139 StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
140 : tc(0), stack(64)
141 {
142 trace(_tc, inst);
143 }
144
145 StackTrace::~StackTrace()
146 {
147 }
148
149 void
150 StackTrace::trace(ThreadContext *_tc, bool is_call)
151 {
152 tc = _tc;
153 /* FIXME - Jaidev - What is IPR_DTB_CM in Alpha? */
154 bool usermode = 0;
155 //(tc->readMiscReg(MipsISA::IPR_DTB_CM) & 0x18) != 0;
156
157 // Addr pc = tc->readNextPC();
158 // bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
159 // pc <= tc->getSystemPtr()->kernelEnd;
160
161 if (usermode) {
162 stack.push_back(user);
163 return;
164 }
165
166 // if (!kernel) {
167 // stack.push_back(console);
168 // return;
169 // }
170
171 // SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
172 // Addr ksp = tc->readIntReg(TheISA::StackPointerReg);
173 // Addr bottom = ksp & ~0x3fff;
174 // Addr addr;
175
176 // if (is_call) {
177 // if (!symtab->findNearestAddr(pc, addr))
178 // panic("could not find address %#x", pc);
179
180 // stack.push_back(addr);
181 // pc = tc->readPC();
182 // }
183
184 // Addr ra;
185 // int size;
186
187 // while (ksp > bottom) {
188 // if (!symtab->findNearestAddr(pc, addr))
189 // panic("could not find symbol for pc=%#x", pc);
190 // assert(pc >= addr && "symbol botch: callpc < func");
191
192 // stack.push_back(addr);
193
194 // if (isEntry(addr))
195 // return;
196
197 // if (decodePrologue(ksp, pc, addr, size, ra)) {
198 // if (!ra)
199 // return;
200
201 // if (size <= 0) {
202 // stack.push_back(unknown);
203 // return;
204 // }
205
206 // pc = ra;
207 // ksp += size;
208 // } else {
209 // stack.push_back(unknown);
210 // return;
211 // }
212
213 // bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
214 // pc <= tc->getSystemPtr()->kernelEnd;
215 // if (!kernel)
216 // return;
217
218 // if (stack.size() >= 1000)
219 // panic("unwinding too far");
220 // }
221
222 // panic("unwinding too far");
223 }
224
225 bool
226 StackTrace::isEntry(Addr addr)
227 {
228 /* if (addr == tc->readMiscReg(MipsISA::IPR_PALtemp2))
229 return true;*/
230
231 return false;
232 }
233
234 bool
235 StackTrace::decodeStack(MachInst inst, int &disp)
236 {
237 // lda $sp, -disp($sp)
238 //
239 // Opcode<31:26> == 0x08
240 // RA<25:21> == 30
241 // RB<20:16> == 30
242 // Disp<15:0>
243 const MachInst mem_mask = 0xffff0000;
244 const MachInst lda_pattern = 0x23de0000;
245 const MachInst lda_disp_mask = 0x0000ffff;
246
247 // subq $sp, disp, $sp
248 // addq $sp, disp, $sp
249 //
250 // Opcode<31:26> == 0x10
251 // RA<25:21> == 30
252 // Lit<20:13>
253 // One<12> = 1
254 // Func<11:5> == 0x20 (addq)
255 // Func<11:5> == 0x29 (subq)
256 // RC<4:0> == 30
257 const MachInst intop_mask = 0xffe01fff;
258 const MachInst addq_pattern = 0x43c0141e;
259 const MachInst subq_pattern = 0x43c0153e;
260 const MachInst intop_disp_mask = 0x001fe000;
261 const int intop_disp_shift = 13;
262
263 if ((inst & mem_mask) == lda_pattern)
264 disp = -sext<16>(inst & lda_disp_mask);
265 else if ((inst & intop_mask) == addq_pattern)
266 disp = -int((inst & intop_disp_mask) >> intop_disp_shift);
267 else if ((inst & intop_mask) == subq_pattern)
268 disp = int((inst & intop_disp_mask) >> intop_disp_shift);
269 else
270 return false;
271
272 return true;
273 }
274
275 bool
276 StackTrace::decodeSave(MachInst inst, int &reg, int &disp)
277 {
278 // lda $stq, disp($sp)
279 //
280 // Opcode<31:26> == 0x08
281 // RA<25:21> == ?
282 // RB<20:16> == 30
283 // Disp<15:0>
284 const MachInst stq_mask = 0xfc1f0000;
285 const MachInst stq_pattern = 0xb41e0000;
286 const MachInst stq_disp_mask = 0x0000ffff;
287 const MachInst reg_mask = 0x03e00000;
288 const int reg_shift = 21;
289
290 if ((inst & stq_mask) == stq_pattern) {
291 reg = (inst & reg_mask) >> reg_shift;
292 disp = sext<16>(inst & stq_disp_mask);
293 } else {
294 return false;
295 }
296
297 return true;
298 }
299
300 /*
301 * Decode the function prologue for the function we're in, and note
302 * which registers are stored where, and how large the stack frame is.
303 */
304 bool
305 StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
306 int &size, Addr &ra)
307 {
308 size = 0;
309 ra = 0;
310
311 for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) {
312 MachInst inst;
313 CopyOut(tc, (uint8_t *)&inst, pc, sizeof(MachInst));
314
315 int reg, disp;
316 if (decodeStack(inst, disp)) {
317 if (size) {
318 // panic("decoding frame size again");
319 return true;
320 }
321 size += disp;
322 } else if (decodeSave(inst, reg, disp)) {
323 if (!ra && reg == ReturnAddressReg) {
324 CopyOut(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
325 if (!ra) {
326 // panic("no return address value pc=%#x\n", pc);
327 return false;
328 }
329 }
330 }
331 }
332
333 return true;
334 }
335
336 #if TRACING_ON
337 void
338 StackTrace::dump()
339 {
340 StringWrap name(tc->getCpuPtr()->name());
341 // SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
342
343 DPRINTFN("------ Stack ------\n");
344
345 // string symbol;
346 // for (int i = 0, size = stack.size(); i < size; ++i) {
347 // Addr addr = stack[size - i - 1];
348 // if (addr == user)
349 // symbol = "user";
350 // else if (addr == console)
351 // symbol = "console";
352 // else if (addr == unknown)
353 // symbol = "unknown";
354 // else
355 // symtab->findSymbol(addr, symbol);
356
357 // DPRINTFN("%#x: %s\n", addr, symbol);
358 // }
359 }
360 #endif