]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/mips/mips/db_trace.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / mips / mips / db_trace.c
1 /*-
2  * Copyright (c) 2004-2005, Juniper Networks, Inc.
3  * All rights reserved.
4  *
5  *      JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta
6  */
7
8 #include <sys/cdefs.h>
9 __FBSDID("$FreeBSD$");
10
11 #include <sys/param.h>
12 #include <sys/systm.h>
13 #include <sys/kdb.h>
14 #include <sys/proc.h>
15 #include <sys/stack.h>
16 #include <sys/sysent.h>
17
18 #include <machine/db_machdep.h>
19 #include <machine/md_var.h>
20 #include <machine/mips_opcode.h>
21 #include <machine/pcb.h>
22 #include <machine/trap.h>
23
24 #include <ddb/ddb.h>
25 #include <ddb/db_sym.h>
26
27 extern char _locore[];
28 extern char _locoreEnd[];
29 extern char edata[];
30
31 /*
32  * A function using a stack frame has the following instruction as the first
33  * one: addiu sp,sp,-<frame_size>
34  *
35  * We make use of this to detect starting address of a function. This works
36  * better than using 'j ra' instruction to signify end of the previous
37  * function (for e.g. functions like boot() or panic() do not actually
38  * emit a 'j ra' instruction).
39  *
40  * XXX the abi does not require that the addiu instruction be the first one.
41  */
42 #define MIPS_START_OF_FUNCTION(ins)     (((ins) & 0xffff8000) == 0x27bd8000)
43
44 /*
45  * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction
46  *
47  * XXX gcc doesn't do this for functions with __noreturn__ attribute.
48  */
49 #define MIPS_END_OF_FUNCTION(ins)       ((ins) == 0x03e00008)
50
51 /*
52  * kdbpeekD(addr) - skip one word starting at 'addr', then read the second word
53  */
54 #define kdbpeekD(addr)  kdbpeek(((int *)(addr)) + 1)
55
56 /*
57  * Functions ``special'' enough to print by name
58  */
59 #ifdef __STDC__
60 #define Name(_fn)  { (void*)_fn, # _fn }
61 #else
62 #define Name(_fn) { _fn, "_fn"}
63 #endif
64 static struct {
65         void *addr;
66         char *name;
67 }      names[] = {
68
69         Name(trap),
70         Name(MipsKernGenException),
71         Name(MipsUserGenException),
72         Name(MipsKernIntr),
73         Name(MipsUserIntr),
74         Name(cpu_switch),
75         {
76                 0, 0
77         }
78 };
79
80 /*
81  * Map a function address to a string name, if known; or a hex string.
82  */
83 static char *
84 fn_name(uintptr_t addr)
85 {
86         static char buf[17];
87         int i = 0;
88
89         db_expr_t diff;
90         c_db_sym_t sym;
91         char *symname;
92
93         diff = 0;
94         symname = NULL;
95         sym = db_search_symbol((db_addr_t)addr, DB_STGY_ANY, &diff);
96         db_symbol_values(sym, (const char **)&symname, (db_expr_t *)0);
97         if (symname && diff == 0)
98                 return (symname);
99
100         for (i = 0; names[i].name; i++)
101                 if (names[i].addr == (void *)addr)
102                         return (names[i].name);
103         sprintf(buf, "%jx", (uintmax_t)addr);
104         return (buf);
105 }
106
107 void
108 stacktrace_subr(register_t pc, register_t sp, register_t ra,
109         int (*printfn) (const char *,...))
110 {
111         InstFmt i;
112         /*
113          * Arrays for a0..a3 registers and flags if content
114          * of these registers is valid, e.g. obtained from the stack
115          */
116         int valid_args[4];
117         uintptr_t args[4];
118         uintptr_t va, subr;
119         unsigned instr, mask;
120         unsigned int frames = 0;
121         int more, stksize, j;
122
123 /* Jump here when done with a frame, to start a new one */
124 loop:
125
126         /*
127          * Invalidate arguments values
128          */
129         valid_args[0] = 0;
130         valid_args[1] = 0;
131         valid_args[2] = 0;
132         valid_args[3] = 0;
133 /* Jump here after a nonstandard (interrupt handler) frame */
134         stksize = 0;
135         subr = 0;
136         if (frames++ > 100) {
137                 (*printfn) ("\nstackframe count exceeded\n");
138                 /* return breaks stackframe-size heuristics with gcc -O2 */
139                 goto finish;    /* XXX */
140         }
141         /* check for bad SP: could foul up next frame */
142         /*XXX MIPS64 bad: this hard-coded SP is lame */
143         if (sp & 3 || (uintptr_t)sp < 0x80000000u) {
144                 (*printfn) ("SP 0x%x: not in kernel\n", sp);
145                 ra = 0;
146                 subr = 0;
147                 goto done;
148         }
149 #define Between(x, y, z) \
150                 ( ((x) <= (y)) && ((y) < (z)) )
151 #define pcBetween(a,b) \
152                 Between((uintptr_t)a, pc, (uintptr_t)b)
153
154         /*
155          * Check for current PC in  exception handler code that don't have a
156          * preceding "j ra" at the tail of the preceding function. Depends
157          * on relative ordering of functions in exception.S, swtch.S.
158          */
159         if (pcBetween(MipsKernGenException, MipsUserGenException))
160                 subr = (uintptr_t)MipsKernGenException;
161         else if (pcBetween(MipsUserGenException, MipsKernIntr))
162                 subr = (uintptr_t)MipsUserGenException;
163         else if (pcBetween(MipsKernIntr, MipsUserIntr))
164                 subr = (uintptr_t)MipsKernIntr;
165         else if (pcBetween(MipsUserIntr, MipsTLBInvalidException))
166                 subr = (uintptr_t)MipsUserIntr;
167         else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException))
168                 subr = (uintptr_t)MipsTLBInvalidException;
169         else if (pcBetween(fork_trampoline, savectx))
170                 subr = (uintptr_t)fork_trampoline;
171         else if (pcBetween(savectx, cpu_throw))
172                 subr = (uintptr_t)savectx;
173         else if (pcBetween(cpu_throw, cpu_switch))
174                 subr = (uintptr_t)cpu_throw;
175         else if (pcBetween(cpu_switch, MipsSwitchFPState))
176                 subr = (uintptr_t)cpu_switch;
177         else if (pcBetween(_locore, _locoreEnd)) {
178                 subr = (uintptr_t)_locore;
179                 ra = 0;
180                 goto done;
181         }
182         /* check for bad PC */
183         /*XXX MIPS64 bad: These hard coded constants are lame */
184         if (pc & 3 || pc < (uintptr_t)0x80000000) {
185                 (*printfn) ("PC 0x%x: not in kernel\n", pc);
186                 ra = 0;
187                 goto done;
188         }
189         /*
190          * Find the beginning of the current subroutine by scanning
191          * backwards from the current PC for the end of the previous
192          * subroutine.
193          */
194         if (!subr) {
195                 va = pc - sizeof(int);
196                 while (1) {
197                         instr = kdbpeek((int *)va);
198
199                         if (MIPS_START_OF_FUNCTION(instr))
200                                 break;
201
202                         if (MIPS_END_OF_FUNCTION(instr)) {
203                                 /* skip over branch-delay slot instruction */
204                                 va += 2 * sizeof(int);
205                                 break;
206                         }
207
208                         va -= sizeof(int);
209                 }
210
211                 /* skip over nulls which might separate .o files */
212                 while ((instr = kdbpeek((int *)va)) == 0)
213                         va += sizeof(int);
214                 subr = va;
215         }
216         /* scan forwards to find stack size and any saved registers */
217         stksize = 0;
218         more = 3;
219         mask = 0;
220         for (va = subr; more; va += sizeof(int),
221             more = (more == 3) ? 3 : more - 1) {
222                 /* stop if hit our current position */
223                 if (va >= pc)
224                         break;
225                 instr = kdbpeek((int *)va);
226                 i.word = instr;
227                 switch (i.JType.op) {
228                 case OP_SPECIAL:
229                         switch (i.RType.func) {
230                         case OP_JR:
231                         case OP_JALR:
232                                 more = 2;       /* stop after next instruction */
233                                 break;
234
235                         case OP_SYSCALL:
236                         case OP_BREAK:
237                                 more = 1;       /* stop now */
238                         };
239                         break;
240
241                 case OP_BCOND:
242                 case OP_J:
243                 case OP_JAL:
244                 case OP_BEQ:
245                 case OP_BNE:
246                 case OP_BLEZ:
247                 case OP_BGTZ:
248                         more = 2;       /* stop after next instruction */
249                         break;
250
251                 case OP_COP0:
252                 case OP_COP1:
253                 case OP_COP2:
254                 case OP_COP3:
255                         switch (i.RType.rs) {
256                         case OP_BCx:
257                         case OP_BCy:
258                                 more = 2;       /* stop after next instruction */
259                         };
260                         break;
261
262                 case OP_SW:
263                         /* look for saved registers on the stack */
264                         if (i.IType.rs != 29)
265                                 break;
266                         /* only restore the first one */
267                         if (mask & (1 << i.IType.rt))
268                                 break;
269                         mask |= (1 << i.IType.rt);
270                         switch (i.IType.rt) {
271                         case 4:/* a0 */
272                                 args[0] = kdbpeek((int *)(sp + (short)i.IType.imm));
273                                 valid_args[0] = 1;
274                                 break;
275
276                         case 5:/* a1 */
277                                 args[1] = kdbpeek((int *)(sp + (short)i.IType.imm));
278                                 valid_args[1] = 1;
279                                 break;
280
281                         case 6:/* a2 */
282                                 args[2] = kdbpeek((int *)(sp + (short)i.IType.imm));
283                                 valid_args[2] = 1;
284                                 break;
285
286                         case 7:/* a3 */
287                                 args[3] = kdbpeek((int *)(sp + (short)i.IType.imm));
288                                 valid_args[3] = 1;
289                                 break;
290
291                         case 31:        /* ra */
292                                 ra = kdbpeek((int *)(sp + (short)i.IType.imm));
293                         }
294                         break;
295
296                 case OP_SD:
297                         /* look for saved registers on the stack */
298                         if (i.IType.rs != 29)
299                                 break;
300                         /* only restore the first one */
301                         if (mask & (1 << i.IType.rt))
302                                 break;
303                         mask |= (1 << i.IType.rt);
304                         switch (i.IType.rt) {
305                         case 4:/* a0 */
306                                 args[0] = kdbpeekD((int *)(sp + (short)i.IType.imm));
307                                 valid_args[0] = 1;
308                                 break;
309
310                         case 5:/* a1 */
311                                 args[1] = kdbpeekD((int *)(sp + (short)i.IType.imm));
312                                 valid_args[1] = 1;
313                                 break;
314
315                         case 6:/* a2 */
316                                 args[2] = kdbpeekD((int *)(sp + (short)i.IType.imm));
317                                 valid_args[2] = 1;
318                                 break;
319
320                         case 7:/* a3 */
321                                 args[3] = kdbpeekD((int *)(sp + (short)i.IType.imm));
322                                 valid_args[3] = 1;
323                                 break;
324
325                         case 31:        /* ra */
326                                 ra = kdbpeekD((int *)(sp + (short)i.IType.imm));
327                         }
328                         break;
329
330                 case OP_ADDI:
331                 case OP_ADDIU:
332                         /* look for stack pointer adjustment */
333                         if (i.IType.rs != 29 || i.IType.rt != 29)
334                                 break;
335                         stksize = -((short)i.IType.imm);
336                 }
337         }
338
339 done:
340         (*printfn) ("%s+%x (", fn_name(subr), pc - subr);
341         for (j = 0; j < 4; j ++) {
342                 if (j > 0)
343                         (*printfn)(",");
344                 if (valid_args[j])
345                         (*printfn)("%x", args[j]);
346                 else
347                         (*printfn)("?");
348         }
349
350         (*printfn) (") ra %x sp %x sz %d\n", ra, sp, stksize);
351
352         if (ra) {
353                 if (pc == ra && stksize == 0)
354                         (*printfn) ("stacktrace: loop!\n");
355                 else {
356                         pc = ra;
357                         sp += stksize;
358                         ra = 0;
359                         goto loop;
360                 }
361         } else {
362 finish:
363                 if (curproc)
364                         (*printfn) ("pid %d\n", curproc->p_pid);
365                 else
366                         (*printfn) ("curproc NULL\n");
367         }
368 }
369
370
371 int
372 db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
373 {
374
375         return(0);
376 }
377
378
379 int
380 db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
381 {
382
383         return(0);
384 }
385
386
387 void
388 db_md_list_watchpoints()
389 {
390 }
391
392 void
393 db_trace_self(void)
394 {
395         db_trace_thread (curthread, -1);
396         return;
397 }
398
399 int
400 db_trace_thread(struct thread *thr, int count)
401 {
402         register_t pc, ra, sp;
403         struct pcb *ctx;
404
405         if (thr == curthread) {
406                 sp = (register_t)(intptr_t)__builtin_frame_address(0);
407                 ra = (register_t)(intptr_t)__builtin_return_address(0);
408
409                 __asm __volatile(
410                         "jal 99f\n"
411                         "nop\n"
412                         "99:\n"
413                          "move %0, $31\n" /* get ra */
414                          "move $31, %1\n" /* restore ra */
415                          : "=r" (pc)
416                          : "r" (ra));
417
418         } else {
419                 ctx = kdb_thr_ctx(thr);
420                 sp = (register_t)ctx->pcb_context[PREG_SP];
421                 pc = (register_t)ctx->pcb_context[PREG_PC];
422                 ra = (register_t)ctx->pcb_context[PREG_RA];
423         }
424
425         stacktrace_subr(pc, sp, ra,
426             (int (*) (const char *, ...))db_printf);
427
428         return (0);
429 }
430
431 void
432 db_show_mdpcpu(struct pcpu *pc)
433 {
434
435         db_printf("ipis         = 0x%x\n", pc->pc_pending_ipis);
436         db_printf("next ASID    = %d\n", pc->pc_next_asid);
437         db_printf("GENID        = %d\n", pc->pc_asid_generation);
438         return;
439 }