2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2004-2005, Juniper Networks, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
38 #include <sys/stack.h>
39 #include <sys/sysent.h>
41 #include <machine/asm.h>
42 #include <machine/db_machdep.h>
43 #include <machine/md_var.h>
44 #include <machine/mips_opcode.h>
45 #include <machine/pcb.h>
46 #include <machine/trap.h>
49 #include <ddb/db_sym.h>
51 extern char _locore[];
52 extern char _locoreEnd[];
56 * A function using a stack frame has the following instruction as the first
57 * one: [d]addiu sp,sp,-<frame_size>
59 * We make use of this to detect starting address of a function. This works
60 * better than using 'j ra' instruction to signify end of the previous
61 * function (for e.g. functions like boot() or panic() do not actually
62 * emit a 'j ra' instruction).
64 * XXX the abi does not require that the addiu instruction be the first one.
66 #define MIPS_START_OF_FUNCTION(ins) ((((ins) & 0xffff8000) == 0x27bd8000) \
67 || (((ins) & 0xffff8000) == 0x67bd8000))
70 * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction
72 * XXX gcc doesn't do this for functions with __noreturn__ attribute.
74 #define MIPS_END_OF_FUNCTION(ins) ((ins) == 0x03e00008)
76 #if defined(__mips_n64)
77 # define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \
78 ((vm_offset_t)(reg) >= MIPS_XKPHYS_START))
80 # define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \
81 ((vm_offset_t)(reg) >= MIPS_KSEG0_START))
85 stacktrace_subr(register_t pc, register_t sp, register_t ra)
89 * Arrays for a0..a3 registers and flags if content
90 * of these registers is valid, e.g. obtained from the stack
94 register_t va, subr, cause, badvaddr;
96 unsigned int frames = 0;
101 /* Jump here when done with a frame, to start a new one */
105 * Invalidate arguments values
115 if (frames++ > 100) {
116 db_printf("\nstackframe count exceeded\n");
120 /* Check for bad SP: could foul up next frame. */
121 if (!MIPS_IS_VALID_KERNELADDR(sp)) {
122 db_printf("SP 0x%jx: not in kernel\n", (uintmax_t)sp);
127 #define Between(x, y, z) \
128 ( ((x) <= (y)) && ((y) < (z)) )
129 #define pcBetween(a,b) \
130 Between((uintptr_t)a, pc, (uintptr_t)b)
133 * Check for current PC in exception handler code that don't have a
134 * preceding "j ra" at the tail of the preceding function. Depends
135 * on relative ordering of functions in exception.S, swtch.S.
137 if (pcBetween(MipsKernGenException, MipsUserGenException)) {
138 subr = (uintptr_t)MipsKernGenException;
140 } else if (pcBetween(MipsUserGenException, MipsKernIntr))
141 subr = (uintptr_t)MipsUserGenException;
142 else if (pcBetween(MipsKernIntr, MipsUserIntr)) {
143 subr = (uintptr_t)MipsKernIntr;
145 } else if (pcBetween(MipsUserIntr, MipsTLBInvalidException))
146 subr = (uintptr_t)MipsUserIntr;
147 else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) {
148 subr = (uintptr_t)MipsTLBInvalidException;
149 if (pc == (uintptr_t)MipsKStackOverflow)
151 } else if (pcBetween(fork_trampoline, savectx))
152 subr = (uintptr_t)fork_trampoline;
153 else if (pcBetween(savectx, cpu_throw))
154 subr = (uintptr_t)savectx;
155 else if (pcBetween(cpu_throw, cpu_switch))
156 subr = (uintptr_t)cpu_throw;
157 else if (pcBetween(cpu_switch, MipsSwitchFPState))
158 subr = (uintptr_t)cpu_switch;
159 else if (pcBetween(_locore, _locoreEnd)) {
160 subr = (uintptr_t)_locore;
165 /* Check for bad PC. */
166 if (!MIPS_IS_VALID_KERNELADDR(pc)) {
167 db_printf("PC 0x%jx: not in kernel\n", (uintmax_t)pc);
173 * For a trapframe, skip to the output and afterwards pull the
174 * previous registers out of the trapframe instead of decoding
175 * the function prologue.
181 * Find the beginning of the current subroutine by scanning
182 * backwards from the current PC for the end of the previous
186 va = pc - sizeof(int);
188 instr = kdbpeek((int *)va);
190 if (MIPS_START_OF_FUNCTION(instr))
193 if (MIPS_END_OF_FUNCTION(instr)) {
194 /* skip over branch-delay slot instruction */
195 va += 2 * sizeof(int);
202 /* skip over nulls which might separate .o files */
203 while ((instr = kdbpeek((int *)va)) == 0)
207 /* scan forwards to find stack size and any saved registers */
211 for (va = subr; more; va += sizeof(int),
212 more = (more == 3) ? 3 : more - 1) {
213 /* stop if hit our current position */
216 instr = kdbpeek((int *)va);
218 switch (i.JType.op) {
220 switch (i.RType.func) {
223 more = 2; /* stop after next instruction */
228 more = 1; /* stop now */
239 more = 2; /* stop after next instruction */
246 switch (i.RType.rs) {
249 more = 2; /* stop after next instruction */
254 /* look for saved registers on the stack */
255 if (i.IType.rs != 29)
258 * only restore the first one except RA for
259 * MipsKernGenException case
261 if (mask & (1 << i.IType.rt)) {
262 if (subr == (uintptr_t)MipsKernGenException &&
264 next_ra = kdbpeek((int *)(sp +
265 (short)i.IType.imm));
268 mask |= (1 << i.IType.rt);
269 switch (i.IType.rt) {
271 args[0] = kdbpeek((int *)(sp + (short)i.IType.imm));
276 args[1] = kdbpeek((int *)(sp + (short)i.IType.imm));
281 args[2] = kdbpeek((int *)(sp + (short)i.IType.imm));
286 args[3] = kdbpeek((int *)(sp + (short)i.IType.imm));
291 ra = kdbpeek((int *)(sp + (short)i.IType.imm));
296 /* look for saved registers on the stack */
297 if (i.IType.rs != 29)
299 /* only restore the first one */
300 if (mask & (1 << i.IType.rt))
302 mask |= (1 << i.IType.rt);
303 switch (i.IType.rt) {
305 args[0] = kdbpeekd((int *)(sp + (short)i.IType.imm));
310 args[1] = kdbpeekd((int *)(sp + (short)i.IType.imm));
315 args[2] = kdbpeekd((int *)(sp + (short)i.IType.imm));
320 args[3] = kdbpeekd((int *)(sp + (short)i.IType.imm));
325 ra = kdbpeekd((int *)(sp + (short)i.IType.imm));
333 /* look for stack pointer adjustment */
334 if (i.IType.rs != 29 || i.IType.rt != 29)
336 stksize = -((short)i.IType.imm);
341 db_printsym(pc, DB_STGY_PROC);
343 for (j = 0; j < 4; j ++) {
347 db_printf("%jx", (uintmax_t)(u_register_t)args[j]);
352 db_printf(") ra %jx sp %jx sz %d\n",
353 (uintmax_t)(u_register_t) ra,
354 (uintmax_t)(u_register_t) sp,
358 #define TF_REG(base, reg) ((base) + CALLFRAME_SIZ + ((reg) * SZREG))
359 #if defined(__mips_n64) || defined(__mips_n32)
360 pc = kdbpeekd((int *)TF_REG(sp, PC));
361 ra = kdbpeekd((int *)TF_REG(sp, RA));
362 sp = kdbpeekd((int *)TF_REG(sp, SP));
363 cause = kdbpeekd((int *)TF_REG(sp, CAUSE));
364 badvaddr = kdbpeekd((int *)TF_REG(sp, BADVADDR));
366 pc = kdbpeek((int *)TF_REG(sp, PC));
367 ra = kdbpeek((int *)TF_REG(sp, RA));
368 sp = kdbpeek((int *)TF_REG(sp, SP));
369 cause = kdbpeek((int *)TF_REG(sp, CAUSE));
370 badvaddr = kdbpeek((int *)TF_REG(sp, BADVADDR));
373 db_printf("--- exception, cause %jx badvaddr %jx ---\n",
374 (uintmax_t)cause, (uintmax_t)badvaddr);
377 if (pc == ra && stksize == 0)
378 db_printf("stacktrace: loop!\n");
390 db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
398 db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
406 db_md_list_watchpoints()
413 register_t pc, ra, sp;
415 sp = (register_t)(intptr_t)__builtin_frame_address(0);
416 ra = (register_t)(intptr_t)__builtin_return_address(0);
422 "move %0, $31\n" /* get ra */
423 "move $31, %1\n" /* restore ra */
426 stacktrace_subr(pc, sp, ra);
431 db_trace_thread(struct thread *thr, int count)
433 register_t pc, ra, sp;
436 ctx = kdb_thr_ctx(thr);
437 sp = (register_t)ctx->pcb_context[PCB_REG_SP];
438 pc = (register_t)ctx->pcb_context[PCB_REG_PC];
439 ra = (register_t)ctx->pcb_context[PCB_REG_RA];
440 stacktrace_subr(pc, sp, ra);
446 db_show_mdpcpu(struct pcpu *pc)
449 db_printf("ipis = 0x%x\n", pc->pc_pending_ipis);
450 db_printf("next ASID = %d\n", pc->pc_next_asid);
451 db_printf("GENID = %d\n", pc->pc_asid_generation);