2 * Copyright (c) 2004-2005, Juniper Networks, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/systm.h>
36 #include <sys/stack.h>
37 #include <sys/sysent.h>
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>
47 #include <ddb/db_sym.h>
49 extern char _locore[];
50 extern char _locoreEnd[];
54 * A function using a stack frame has the following instruction as the first
55 * one: [d]addiu sp,sp,-<frame_size>
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).
62 * XXX the abi does not require that the addiu instruction be the first one.
64 #define MIPS_START_OF_FUNCTION(ins) ((((ins) & 0xffff8000) == 0x27bd8000) \
65 || (((ins) & 0xffff8000) == 0x67bd8000))
68 * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction
70 * XXX gcc doesn't do this for functions with __noreturn__ attribute.
72 #define MIPS_END_OF_FUNCTION(ins) ((ins) == 0x03e00008)
74 #if defined(__mips_n64)
75 # define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \
76 ((vm_offset_t)(reg) >= MIPS_XKPHYS_START))
78 # define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \
79 ((vm_offset_t)(reg) >= MIPS_KSEG0_START))
83 * Functions ``special'' enough to print by name
86 #define Name(_fn) { (void*)_fn, # _fn }
88 #define Name(_fn) { _fn, "_fn"}
96 Name(MipsKernGenException),
97 Name(MipsUserGenException),
107 * Map a function address to a string name, if known; or a hex string.
110 fn_name(uintptr_t addr)
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)
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);
134 stacktrace_subr(register_t pc, register_t sp, register_t ra,
135 int (*printfn) (const char *,...))
139 * Arrays for a0..a3 registers and flags if content
140 * of these registers is valid, e.g. obtained from the stack
144 register_t va, subr, cause, badvaddr;
145 unsigned instr, mask;
146 unsigned int frames = 0;
147 int more, stksize, j;
151 /* Jump here when done with a frame, to start a new one */
155 * Invalidate arguments values
165 if (frames++ > 100) {
166 (*printfn) ("\nstackframe count exceeded\n");
167 /* return breaks stackframe-size heuristics with gcc -O2 */
168 goto finish; /* XXX */
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);
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)
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.
188 if (pcBetween(MipsKernGenException, MipsUserGenException)) {
189 subr = (uintptr_t)MipsKernGenException;
191 } else if (pcBetween(MipsUserGenException, MipsKernIntr))
192 subr = (uintptr_t)MipsUserGenException;
193 else if (pcBetween(MipsKernIntr, MipsUserIntr)) {
194 subr = (uintptr_t)MipsKernIntr;
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)
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;
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);
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.
232 * Find the beginning of the current subroutine by scanning
233 * backwards from the current PC for the end of the previous
237 va = pc - sizeof(int);
239 instr = kdbpeek((int *)va);
241 if (MIPS_START_OF_FUNCTION(instr))
244 if (MIPS_END_OF_FUNCTION(instr)) {
245 /* skip over branch-delay slot instruction */
246 va += 2 * sizeof(int);
253 /* skip over nulls which might separate .o files */
254 while ((instr = kdbpeek((int *)va)) == 0)
258 /* scan forwards to find stack size and any saved registers */
262 for (va = subr; more; va += sizeof(int),
263 more = (more == 3) ? 3 : more - 1) {
264 /* stop if hit our current position */
267 instr = kdbpeek((int *)va);
269 switch (i.JType.op) {
271 switch (i.RType.func) {
274 more = 2; /* stop after next instruction */
279 more = 1; /* stop now */
290 more = 2; /* stop after next instruction */
297 switch (i.RType.rs) {
300 more = 2; /* stop after next instruction */
305 /* look for saved registers on the stack */
306 if (i.IType.rs != 29)
309 * only restore the first one except RA for
310 * MipsKernGenException case
312 if (mask & (1 << i.IType.rt)) {
313 if (subr == (uintptr_t)MipsKernGenException &&
315 next_ra = kdbpeek((int *)(sp +
316 (short)i.IType.imm));
319 mask |= (1 << i.IType.rt);
320 switch (i.IType.rt) {
322 args[0] = kdbpeek((int *)(sp + (short)i.IType.imm));
327 args[1] = kdbpeek((int *)(sp + (short)i.IType.imm));
332 args[2] = kdbpeek((int *)(sp + (short)i.IType.imm));
337 args[3] = kdbpeek((int *)(sp + (short)i.IType.imm));
342 ra = kdbpeek((int *)(sp + (short)i.IType.imm));
347 /* look for saved registers on the stack */
348 if (i.IType.rs != 29)
350 /* only restore the first one */
351 if (mask & (1 << i.IType.rt))
353 mask |= (1 << i.IType.rt);
354 switch (i.IType.rt) {
356 args[0] = kdbpeekd((int *)(sp + (short)i.IType.imm));
361 args[1] = kdbpeekd((int *)(sp + (short)i.IType.imm));
366 args[2] = kdbpeekd((int *)(sp + (short)i.IType.imm));
371 args[3] = kdbpeekd((int *)(sp + (short)i.IType.imm));
376 ra = kdbpeekd((int *)(sp + (short)i.IType.imm));
384 /* look for stack pointer adjustment */
385 if (i.IType.rs != 29 || i.IType.rt != 29)
387 stksize = -((short)i.IType.imm);
392 (*printfn) ("%s+%x (", fn_name(subr), pc - subr);
393 for (j = 0; j < 4; j ++) {
397 (*printfn)("%jx", (uintmax_t)(u_register_t)args[j]);
402 (*printfn) (") ra %jx sp %jx sz %d\n",
403 (uintmax_t)(u_register_t) ra,
404 (uintmax_t)(u_register_t) sp,
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));
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));
423 (*printfn) ("--- exception, cause %jx badvaddr %jx ---\n",
424 (uintmax_t)cause, (uintmax_t)badvaddr);
427 if (pc == ra && stksize == 0)
428 (*printfn) ("stacktrace: loop!\n");
438 (*printfn) ("pid %d\n", curproc->p_pid);
440 (*printfn) ("curproc NULL\n");
446 db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
454 db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
462 db_md_list_watchpoints()
469 register_t pc, ra, sp;
471 sp = (register_t)(intptr_t)__builtin_frame_address(0);
472 ra = (register_t)(intptr_t)__builtin_return_address(0);
478 "move %0, $31\n" /* get ra */
479 "move $31, %1\n" /* restore ra */
482 stacktrace_subr(pc, sp, ra, db_printf);
487 db_trace_thread(struct thread *thr, int count)
489 register_t pc, ra, sp;
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);
502 db_show_mdpcpu(struct pcpu *pc)
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);