]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/mips/db_trace.c
Merge ^/head r311306 through r311313.
[FreeBSD/FreeBSD.git] / sys / mips / mips / db_trace.c
1 /*-
2  * Copyright (c) 2004-2005, Juniper Networks, Inc.
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
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *      JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kdb.h>
35 #include <sys/proc.h>
36 #include <sys/stack.h>
37 #include <sys/sysent.h>
38
39 #include <machine/asm.h>
40 #include <machine/db_machdep.h>
41 #include <machine/md_var.h>
42 #include <machine/mips_opcode.h>
43 #include <machine/pcb.h>
44 #include <machine/trap.h>
45
46 #include <ddb/ddb.h>
47 #include <ddb/db_sym.h>
48
49 extern char _locore[];
50 extern char _locoreEnd[];
51 extern char edata[];
52
53 /*
54  * A function using a stack frame has the following instruction as the first
55  * one: [d]addiu sp,sp,-<frame_size>
56  *
57  * We make use of this to detect starting address of a function. This works
58  * better than using 'j ra' instruction to signify end of the previous
59  * function (for e.g. functions like boot() or panic() do not actually
60  * emit a 'j ra' instruction).
61  *
62  * XXX the abi does not require that the addiu instruction be the first one.
63  */
64 #define MIPS_START_OF_FUNCTION(ins)     ((((ins) & 0xffff8000) == 0x27bd8000) \
65         || (((ins) & 0xffff8000) == 0x67bd8000))
66
67 /*
68  * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction
69  *
70  * XXX gcc doesn't do this for functions with __noreturn__ attribute.
71  */
72 #define MIPS_END_OF_FUNCTION(ins)       ((ins) == 0x03e00008)
73
74 #if defined(__mips_n64)
75 #       define  MIPS_IS_VALID_KERNELADDR(reg)   ((((reg) & 3) == 0) && \
76                                         ((vm_offset_t)(reg) >= MIPS_XKPHYS_START))
77 #else
78 #       define  MIPS_IS_VALID_KERNELADDR(reg)   ((((reg) & 3) == 0) && \
79                                         ((vm_offset_t)(reg) >= MIPS_KSEG0_START))
80 #endif
81
82 /*
83  * Functions ``special'' enough to print by name
84  */
85 #ifdef __STDC__
86 #define Name(_fn)  { (void*)_fn, # _fn }
87 #else
88 #define Name(_fn) { _fn, "_fn"}
89 #endif
90 static struct {
91         void *addr;
92         char *name;
93 }      names[] = {
94
95         Name(trap),
96         Name(MipsKernGenException),
97         Name(MipsUserGenException),
98         Name(MipsKernIntr),
99         Name(MipsUserIntr),
100         Name(cpu_switch),
101         {
102                 0, 0
103         }
104 };
105
106 /*
107  * Map a function address to a string name, if known; or a hex string.
108  */
109 static const char *
110 fn_name(uintptr_t addr)
111 {
112         static char buf[17];
113         int i = 0;
114
115         db_expr_t diff;
116         c_db_sym_t sym;
117         const char *symname;
118
119         diff = 0;
120         symname = NULL;
121         sym = db_search_symbol((db_addr_t)addr, DB_STGY_ANY, &diff);
122         db_symbol_values(sym, &symname, NULL);
123         if (symname && diff == 0)
124                 return (symname);
125
126         for (i = 0; names[i].name; i++)
127                 if (names[i].addr == (void *)addr)
128                         return (names[i].name);
129         sprintf(buf, "%jx", (uintmax_t)addr);
130         return (buf);
131 }
132
133 void
134 stacktrace_subr(register_t pc, register_t sp, register_t ra,
135         int (*printfn) (const char *,...))
136 {
137         InstFmt i;
138         /*
139          * Arrays for a0..a3 registers and flags if content
140          * of these registers is valid, e.g. obtained from the stack
141          */
142         int valid_args[4];
143         register_t args[4];
144         register_t va, subr, cause, badvaddr;
145         unsigned instr, mask;
146         unsigned int frames = 0;
147         int more, stksize, j;
148         register_t      next_ra;
149         bool trapframe;
150
151 /* Jump here when done with a frame, to start a new one */
152 loop:
153
154         /*
155          * Invalidate arguments values
156          */
157         valid_args[0] = 0;
158         valid_args[1] = 0;
159         valid_args[2] = 0;
160         valid_args[3] = 0;
161         next_ra = 0;
162         stksize = 0;
163         subr = 0;
164         trapframe = false;
165         if (frames++ > 100) {
166                 (*printfn) ("\nstackframe count exceeded\n");
167                 /* return breaks stackframe-size heuristics with gcc -O2 */
168                 goto finish;    /* XXX */
169         }
170         /* check for bad SP: could foul up next frame */
171         /*XXX MIPS64 bad: this hard-coded SP is lame */
172         if (!MIPS_IS_VALID_KERNELADDR(sp)) {
173                 (*printfn) ("SP 0x%jx: not in kernel\n", sp);
174                 ra = 0;
175                 subr = 0;
176                 goto done;
177         }
178 #define Between(x, y, z) \
179                 ( ((x) <= (y)) && ((y) < (z)) )
180 #define pcBetween(a,b) \
181                 Between((uintptr_t)a, pc, (uintptr_t)b)
182
183         /*
184          * Check for current PC in  exception handler code that don't have a
185          * preceding "j ra" at the tail of the preceding function. Depends
186          * on relative ordering of functions in exception.S, swtch.S.
187          */
188         if (pcBetween(MipsKernGenException, MipsUserGenException)) {
189                 subr = (uintptr_t)MipsKernGenException;
190                 trapframe = true;
191         } else if (pcBetween(MipsUserGenException, MipsKernIntr))
192                 subr = (uintptr_t)MipsUserGenException;
193         else if (pcBetween(MipsKernIntr, MipsUserIntr)) {
194                 subr = (uintptr_t)MipsKernIntr;
195                 trapframe = true;
196         } else if (pcBetween(MipsUserIntr, MipsTLBInvalidException))
197                 subr = (uintptr_t)MipsUserIntr;
198         else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) {
199                 subr = (uintptr_t)MipsTLBInvalidException;
200                 if (pc == (uintptr_t)MipsKStackOverflow)
201                         trapframe = true;
202         } else if (pcBetween(fork_trampoline, savectx))
203                 subr = (uintptr_t)fork_trampoline;
204         else if (pcBetween(savectx, cpu_throw))
205                 subr = (uintptr_t)savectx;
206         else if (pcBetween(cpu_throw, cpu_switch))
207                 subr = (uintptr_t)cpu_throw;
208         else if (pcBetween(cpu_switch, MipsSwitchFPState))
209                 subr = (uintptr_t)cpu_switch;
210         else if (pcBetween(_locore, _locoreEnd)) {
211                 subr = (uintptr_t)_locore;
212                 ra = 0;
213                 goto done;
214         }
215         /* check for bad PC */
216         /*XXX MIPS64 bad: These hard coded constants are lame */
217         if (!MIPS_IS_VALID_KERNELADDR(pc)) {
218                 (*printfn) ("PC 0x%jx: not in kernel\n", pc);
219                 ra = 0;
220                 goto done;
221         }
222
223         /*
224          * For a trapframe, skip to the output and afterwards pull the
225          * previous registers out of the trapframe instead of decoding
226          * the function prologue.
227          */
228         if (trapframe)
229                 goto done;
230
231         /*
232          * Find the beginning of the current subroutine by scanning
233          * backwards from the current PC for the end of the previous
234          * subroutine.
235          */
236         if (!subr) {
237                 va = pc - sizeof(int);
238                 while (1) {
239                         instr = kdbpeek((int *)va);
240
241                         if (MIPS_START_OF_FUNCTION(instr))
242                                 break;
243
244                         if (MIPS_END_OF_FUNCTION(instr)) {
245                                 /* skip over branch-delay slot instruction */
246                                 va += 2 * sizeof(int);
247                                 break;
248                         }
249
250                         va -= sizeof(int);
251                 }
252
253                 /* skip over nulls which might separate .o files */
254                 while ((instr = kdbpeek((int *)va)) == 0)
255                         va += sizeof(int);
256                 subr = va;
257         }
258         /* scan forwards to find stack size and any saved registers */
259         stksize = 0;
260         more = 3;
261         mask = 0;
262         for (va = subr; more; va += sizeof(int),
263             more = (more == 3) ? 3 : more - 1) {
264                 /* stop if hit our current position */
265                 if (va >= pc)
266                         break;
267                 instr = kdbpeek((int *)va);
268                 i.word = instr;
269                 switch (i.JType.op) {
270                 case OP_SPECIAL:
271                         switch (i.RType.func) {
272                         case OP_JR:
273                         case OP_JALR:
274                                 more = 2;       /* stop after next instruction */
275                                 break;
276
277                         case OP_SYSCALL:
278                         case OP_BREAK:
279                                 more = 1;       /* stop now */
280                         }
281                         break;
282
283                 case OP_BCOND:
284                 case OP_J:
285                 case OP_JAL:
286                 case OP_BEQ:
287                 case OP_BNE:
288                 case OP_BLEZ:
289                 case OP_BGTZ:
290                         more = 2;       /* stop after next instruction */
291                         break;
292
293                 case OP_COP0:
294                 case OP_COP1:
295                 case OP_COP2:
296                 case OP_COP3:
297                         switch (i.RType.rs) {
298                         case OP_BCx:
299                         case OP_BCy:
300                                 more = 2;       /* stop after next instruction */
301                         }
302                         break;
303
304                 case OP_SW:
305                         /* look for saved registers on the stack */
306                         if (i.IType.rs != 29)
307                                 break;
308                         /*
309                          * only restore the first one except RA for
310                          * MipsKernGenException case
311                          */
312                         if (mask & (1 << i.IType.rt)) {
313                                 if (subr == (uintptr_t)MipsKernGenException &&
314                                     i.IType.rt == 31)
315                                         next_ra = kdbpeek((int *)(sp +
316                                             (short)i.IType.imm));
317                                 break;
318                         }
319                         mask |= (1 << i.IType.rt);
320                         switch (i.IType.rt) {
321                         case 4:/* a0 */
322                                 args[0] = kdbpeek((int *)(sp + (short)i.IType.imm));
323                                 valid_args[0] = 1;
324                                 break;
325
326                         case 5:/* a1 */
327                                 args[1] = kdbpeek((int *)(sp + (short)i.IType.imm));
328                                 valid_args[1] = 1;
329                                 break;
330
331                         case 6:/* a2 */
332                                 args[2] = kdbpeek((int *)(sp + (short)i.IType.imm));
333                                 valid_args[2] = 1;
334                                 break;
335
336                         case 7:/* a3 */
337                                 args[3] = kdbpeek((int *)(sp + (short)i.IType.imm));
338                                 valid_args[3] = 1;
339                                 break;
340
341                         case 31:        /* ra */
342                                 ra = kdbpeek((int *)(sp + (short)i.IType.imm));
343                         }
344                         break;
345
346                 case OP_SD:
347                         /* look for saved registers on the stack */
348                         if (i.IType.rs != 29)
349                                 break;
350                         /* only restore the first one */
351                         if (mask & (1 << i.IType.rt))
352                                 break;
353                         mask |= (1 << i.IType.rt);
354                         switch (i.IType.rt) {
355                         case 4:/* a0 */
356                                 args[0] = kdbpeekd((int *)(sp + (short)i.IType.imm));
357                                 valid_args[0] = 1;
358                                 break;
359
360                         case 5:/* a1 */
361                                 args[1] = kdbpeekd((int *)(sp + (short)i.IType.imm));
362                                 valid_args[1] = 1;
363                                 break;
364
365                         case 6:/* a2 */
366                                 args[2] = kdbpeekd((int *)(sp + (short)i.IType.imm));
367                                 valid_args[2] = 1;
368                                 break;
369
370                         case 7:/* a3 */
371                                 args[3] = kdbpeekd((int *)(sp + (short)i.IType.imm));
372                                 valid_args[3] = 1;
373                                 break;
374
375                         case 31:        /* ra */
376                                 ra = kdbpeekd((int *)(sp + (short)i.IType.imm));
377                         }
378                         break;
379
380                 case OP_ADDI:
381                 case OP_ADDIU:
382                 case OP_DADDI:
383                 case OP_DADDIU:
384                         /* look for stack pointer adjustment */
385                         if (i.IType.rs != 29 || i.IType.rt != 29)
386                                 break;
387                         stksize = -((short)i.IType.imm);
388                 }
389         }
390
391 done:
392         (*printfn) ("%s+%x (", fn_name(subr), pc - subr);
393         for (j = 0; j < 4; j ++) {
394                 if (j > 0)
395                         (*printfn)(",");
396                 if (valid_args[j])
397                         (*printfn)("%jx", (uintmax_t)(u_register_t)args[j]);
398                 else
399                         (*printfn)("?");
400         }
401
402         (*printfn) (") ra %jx sp %jx sz %d\n",
403             (uintmax_t)(u_register_t) ra,
404             (uintmax_t)(u_register_t) sp,
405             stksize);
406
407         if (trapframe) {
408 #define TF_REG(base, reg)       ((base) + CALLFRAME_SIZ + ((reg) * SZREG))
409 #if defined(__mips_n64) || defined(__mips_n32)
410                 pc = kdbpeekd((int *)TF_REG(sp, PC));
411                 ra = kdbpeekd((int *)TF_REG(sp, RA));
412                 sp = kdbpeekd((int *)TF_REG(sp, SP));
413                 cause = kdbpeekd((int *)TF_REG(sp, CAUSE));
414                 badvaddr = kdbpeekd((int *)TF_REG(sp, BADVADDR));
415 #else
416                 pc = kdbpeek((int *)TF_REG(sp, PC));
417                 ra = kdbpeek((int *)TF_REG(sp, RA));
418                 sp = kdbpeek((int *)TF_REG(sp, SP));
419                 cause = kdbpeek((int *)TF_REG(sp, CAUSE));
420                 badvaddr = kdbpeek((int *)TF_REG(sp, BADVADDR));
421 #endif
422 #undef TF_REG
423                 (*printfn) ("--- exception, cause %jx badvaddr %jx ---\n",
424                     (uintmax_t)cause, (uintmax_t)badvaddr);
425                 goto loop;
426         } else if (ra) {
427                 if (pc == ra && stksize == 0)
428                         (*printfn) ("stacktrace: loop!\n");
429                 else {
430                         pc = ra;
431                         sp += stksize;
432                         ra = next_ra;
433                         goto loop;
434                 }
435         } else {
436 finish:
437                 if (curproc)
438                         (*printfn) ("pid %d\n", curproc->p_pid);
439                 else
440                         (*printfn) ("curproc NULL\n");
441         }
442 }
443
444
445 int
446 db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
447 {
448
449         return(0);
450 }
451
452
453 int
454 db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
455 {
456
457         return(0);
458 }
459
460
461 void
462 db_md_list_watchpoints()
463 {
464 }
465
466 void
467 db_trace_self(void)
468 {
469         register_t pc, ra, sp;
470
471         sp = (register_t)(intptr_t)__builtin_frame_address(0);
472         ra = (register_t)(intptr_t)__builtin_return_address(0);
473
474         __asm __volatile(
475                 "jal 99f\n"
476                 "nop\n"
477                 "99:\n"
478                  "move %0, $31\n" /* get ra */
479                  "move $31, %1\n" /* restore ra */
480                  : "=r" (pc)
481                  : "r" (ra));
482         stacktrace_subr(pc, sp, ra, db_printf);
483         return;
484 }
485
486 int
487 db_trace_thread(struct thread *thr, int count)
488 {
489         register_t pc, ra, sp;
490         struct pcb *ctx;
491
492         ctx = kdb_thr_ctx(thr);
493         sp = (register_t)ctx->pcb_context[PCB_REG_SP];
494         pc = (register_t)ctx->pcb_context[PCB_REG_PC];
495         ra = (register_t)ctx->pcb_context[PCB_REG_RA];
496         stacktrace_subr(pc, sp, ra, db_printf);
497
498         return (0);
499 }
500
501 void
502 db_show_mdpcpu(struct pcpu *pc)
503 {
504
505         db_printf("ipis         = 0x%x\n", pc->pc_pending_ipis);
506         db_printf("next ASID    = %d\n", pc->pc_next_asid);
507         db_printf("GENID        = %d\n", pc->pc_asid_generation);
508         return;
509 }