1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2004-2005, Juniper Networks, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
15 *
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
26 * SUCH DAMAGE.
27 *
28 * JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta
29 */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kdb.h>
37 #include <sys/proc.h>
38 #include <sys/stack.h>
39 #include <sys/sysent.h>
40
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>
47
48 #include <ddb/ddb.h>
49 #include <ddb/db_sym.h>
50
51 extern char _locore[];
52 extern char _locoreEnd[];
53 extern char edata[];
54
55 /*
56 * A function using a stack frame has the following instruction as the first
57 * one: [d]addiu sp,sp,-<frame_size>
58 *
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).
63 *
64 * XXX the abi does not require that the addiu instruction be the first one.
65 */
66 #define MIPS_START_OF_FUNCTION(ins) ((((ins) & 0xffff8000) == 0x27bd8000) \
67 || (((ins) & 0xffff8000) == 0x67bd8000))
68
69 /*
70 * LLD will insert invalid instruction traps between functions.
71 * Currently this is 0xefefefef but it may change in the future.
72 */
73 #define MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(ins) ((ins) == 0xefefefef)
74
75 #if defined(__mips_n64)
76 # define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \
77 ((vm_offset_t)(reg) >= MIPS_XKPHYS_START))
78 #else
79 # define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \
80 ((vm_offset_t)(reg) >= MIPS_KSEG0_START))
81 #endif
82
83 static void
84 stacktrace_subr(register_t pc, register_t sp, register_t ra)
85 {
86 InstFmt i;
87 /*
88 * Arrays for a0..a3 registers and flags if content
89 * of these registers is valid, e.g. obtained from the stack
90 */
91 int valid_args[4];
92 register_t args[4];
93 register_t va, subr, cause, badvaddr;
94 unsigned instr, mask;
95 unsigned int frames = 0;
96 int more, stksize, j;
97 register_t next_ra;
98 bool trapframe;
99
100 /* Jump here when done with a frame, to start a new one */
101 loop:
102
103 /*
104 * Invalidate arguments values
105 */
106 valid_args[0] = 0;
107 valid_args[1] = 0;
108 valid_args[2] = 0;
109 valid_args[3] = 0;
110 next_ra = 0;
111 stksize = 0;
112 subr = 0;
113 trapframe = false;
114 if (frames++ > 100) {
115 db_printf("\nstackframe count exceeded\n");
116 return;
117 }
118
119 /* Check for bad SP: could foul up next frame. */
120 if (!MIPS_IS_VALID_KERNELADDR(sp)) {
121 db_printf("SP 0x%jx: not in kernel\n", (uintmax_t)sp);
122 ra = 0;
123 subr = 0;
124 goto done;
125 }
126 #define Between(x, y, z) \
127 ( ((x) <= (y)) && ((y) < (z)) )
128 #define pcBetween(a,b) \
129 Between((uintptr_t)a, pc, (uintptr_t)b)
130
131 /*
132 * Check for current PC in exception handler code that don't have a
133 * preceding "j ra" at the tail of the preceding function. Depends
134 * on relative ordering of functions in exception.S, swtch.S.
135 */
136 if (pcBetween(MipsKernGenException, MipsUserGenException)) {
137 subr = (uintptr_t)MipsKernGenException;
138 trapframe = true;
139 } else if (pcBetween(MipsUserGenException, MipsKernIntr))
140 subr = (uintptr_t)MipsUserGenException;
141 else if (pcBetween(MipsKernIntr, MipsUserIntr)) {
142 subr = (uintptr_t)MipsKernIntr;
143 trapframe = true;
144 } else if (pcBetween(MipsUserIntr, MipsTLBInvalidException))
145 subr = (uintptr_t)MipsUserIntr;
146 else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) {
147 subr = (uintptr_t)MipsTLBInvalidException;
148 if (pc == (uintptr_t)MipsKStackOverflow)
149 trapframe = true;
150 } else if (pcBetween(fork_trampoline, savectx))
151 subr = (uintptr_t)fork_trampoline;
152 else if (pcBetween(savectx, cpu_throw))
153 subr = (uintptr_t)savectx;
154 else if (pcBetween(cpu_throw, cpu_switch))
155 subr = (uintptr_t)cpu_throw;
156 else if (pcBetween(cpu_switch, MipsSwitchFPState))
157 subr = (uintptr_t)cpu_switch;
158 else if (pcBetween(_locore, _locoreEnd)) {
159 subr = (uintptr_t)_locore;
160 ra = 0;
161 goto done;
162 }
163
164 /* Check for bad PC. */
165 if (!MIPS_IS_VALID_KERNELADDR(pc)) {
166 db_printf("PC 0x%jx: not in kernel\n", (uintmax_t)pc);
167 ra = 0;
168 goto done;
169 }
170
171 /*
172 * For a trapframe, skip to the output and afterwards pull the
173 * previous registers out of the trapframe instead of decoding
174 * the function prologue.
175 */
176 if (trapframe)
177 goto done;
178
179 /*
180 * Find the beginning of the current subroutine by scanning
181 * backwards from the current PC for the end of the previous
182 * subroutine.
183 */
184 if (!subr) {
185 va = pc;
186 while (1) {
187 instr = kdbpeek((int *)va);
188
189 /* LLD fills padding between functions with 0xefefefef */
190 if (MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(instr))
191 break;
192
193 if (MIPS_START_OF_FUNCTION(instr))
194 break;
195
196 va -= sizeof(int);
197 }
198
199 /*
200 * Skip over nulls/trap padding which might separate
201 * object files or functions.
202 */
203 instr = kdbpeek((int *)va);
204 while (instr == 0 || MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(instr)) {
205 va += sizeof(int);
206 instr = kdbpeek((int *)va);
207 }
208 subr = va;
209 }
210
211 /* scan forwards to find stack size and any saved registers */
212 stksize = 0;
213 more = 3;
214 mask = 0;
215 for (va = subr; more; va += sizeof(int),
216 more = (more == 3) ? 3 : more - 1) {
217 /* stop if hit our current position */
218 if (va >= pc)
219 break;
220 instr = kdbpeek((int *)va);
221 i.word = instr;
222 switch (i.JType.op) {
223 case OP_SPECIAL:
224 switch (i.RType.func) {
225 case OP_JR:
226 case OP_JALR:
227 more = 2; /* stop after next instruction */
228 break;
229
230 case OP_SYSCALL:
231 case OP_BREAK:
232 more = 1; /* stop now */
233 }
234 break;
235
236 case OP_BCOND:
237 case OP_J:
238 case OP_JAL:
239 case OP_BEQ:
240 case OP_BNE:
241 case OP_BLEZ:
242 case OP_BGTZ:
243 more = 2; /* stop after next instruction */
244 break;
245
246 case OP_COP0:
247 case OP_COP1:
248 case OP_COP2:
249 case OP_COP3:
250 switch (i.RType.rs) {
251 case OP_BCx:
252 case OP_BCy:
253 more = 2; /* stop after next instruction */
254 }
255 break;
256
257 case OP_SW:
258 /* look for saved registers on the stack */
259 if (i.IType.rs != 29)
260 break;
261 /*
262 * only restore the first one except RA for
263 * MipsKernGenException case
264 */
265 if (mask & (1 << i.IType.rt)) {
266 if (subr == (uintptr_t)MipsKernGenException &&
267 i.IType.rt == 31)
268 next_ra = kdbpeek((int *)(sp +
269 (short)i.IType.imm));
270 break;
271 }
272 mask |= (1 << i.IType.rt);
273 switch (i.IType.rt) {
274 case 4:/* a0 */
275 args[0] = kdbpeek((int *)(sp + (short)i.IType.imm));
276 valid_args[0] = 1;
277 break;
278
279 case 5:/* a1 */
280 args[1] = kdbpeek((int *)(sp + (short)i.IType.imm));
281 valid_args[1] = 1;
282 break;
283
284 case 6:/* a2 */
285 args[2] = kdbpeek((int *)(sp + (short)i.IType.imm));
286 valid_args[2] = 1;
287 break;
288
289 case 7:/* a3 */
290 args[3] = kdbpeek((int *)(sp + (short)i.IType.imm));
291 valid_args[3] = 1;
292 break;
293
294 case 31: /* ra */
295 ra = kdbpeek((int *)(sp + (short)i.IType.imm));
296 }
297 break;
298
299 case OP_SD:
300 /* look for saved registers on the stack */
301 if (i.IType.rs != 29)
302 break;
303 /* only restore the first one */
304 if (mask & (1 << i.IType.rt))
305 break;
306 mask |= (1 << i.IType.rt);
307 switch (i.IType.rt) {
308 case 4:/* a0 */
309 args[0] = kdbpeekd((int *)(sp + (short)i.IType.imm));
310 valid_args[0] = 1;
311 break;
312
313 case 5:/* a1 */
314 args[1] = kdbpeekd((int *)(sp + (short)i.IType.imm));
315 valid_args[1] = 1;
316 break;
317
318 case 6:/* a2 */
319 args[2] = kdbpeekd((int *)(sp + (short)i.IType.imm));
320 valid_args[2] = 1;
321 break;
322
323 case 7:/* a3 */
324 args[3] = kdbpeekd((int *)(sp + (short)i.IType.imm));
325 valid_args[3] = 1;
326 break;
327
328 case 31: /* ra */
329 ra = kdbpeekd((int *)(sp + (short)i.IType.imm));
330 }
331 break;
332
333 case OP_ADDI:
334 case OP_ADDIU:
335 case OP_DADDI:
336 case OP_DADDIU:
337 /* look for stack pointer adjustment */
338 if (i.IType.rs != 29 || i.IType.rt != 29)
339 break;
340 stksize = -((short)i.IType.imm);
341 }
342 }
343
344 done:
345 db_printsym(pc, DB_STGY_PROC);
346 db_printf(" (");
347 for (j = 0; j < 4; j ++) {
348 if (j > 0)
349 db_printf(",");
350 if (valid_args[j])
351 db_printf("%jx", (uintmax_t)(u_register_t)args[j]);
352 else
353 db_printf("?");
354 }
355
356 db_printf(") ra %jx sp %jx sz %d\n",
357 (uintmax_t)(u_register_t) ra,
358 (uintmax_t)(u_register_t) sp,
359 stksize);
360
361 if (trapframe) {
362 #define TF_REG(base, reg) ((base) + CALLFRAME_SIZ + ((reg) * SZREG))
363 #if defined(__mips_n64) || defined(__mips_n32)
364 pc = kdbpeekd((int *)TF_REG(sp, PC));
365 ra = kdbpeekd((int *)TF_REG(sp, RA));
366 sp = kdbpeekd((int *)TF_REG(sp, SP));
367 cause = kdbpeekd((int *)TF_REG(sp, CAUSE));
368 badvaddr = kdbpeekd((int *)TF_REG(sp, BADVADDR));
369 #else
370 pc = kdbpeek((int *)TF_REG(sp, PC));
371 ra = kdbpeek((int *)TF_REG(sp, RA));
372 sp = kdbpeek((int *)TF_REG(sp, SP));
373 cause = kdbpeek((int *)TF_REG(sp, CAUSE));
374 badvaddr = kdbpeek((int *)TF_REG(sp, BADVADDR));
375 #endif
376 #undef TF_REG
377 db_printf("--- exception, cause %jx badvaddr %jx ---\n",
378 (uintmax_t)cause, (uintmax_t)badvaddr);
379 goto loop;
380 } else if (ra) {
381 /*
382 * We subtract two instructions from ra to convert it
383 * from a return address to a calling address,
384 * accounting for the delay slot.
385 */
386 register_t next_pc = ra - 2 * sizeof(int);
387 if (pc == next_pc && stksize == 0)
388 db_printf("stacktrace: loop!\n");
389 else {
390 pc = next_pc;
391 sp += stksize;
392 ra = next_ra;
393 goto loop;
394 }
395 }
396 }
397
398 void
399 db_md_list_watchpoints()
400 {
401 }
402
403 void
404 db_trace_self(void)
405 {
406 register_t pc, ra, sp;
407
408 sp = (register_t)(intptr_t)__builtin_frame_address(0);
409 ra = (register_t)(intptr_t)__builtin_return_address(0);
410
411 __asm __volatile(
412 "jal 99f\n"
413 "nop\n"
414 "99:\n"
415 "move %0, $31\n" /* get ra */
416 "move $31, %1\n" /* restore ra */
417 : "=r" (pc)
418 : "r" (ra));
419 stacktrace_subr(pc, sp, ra);
420 return;
421 }
422
423 int
424 db_trace_thread(struct thread *thr, int count)
425 {
426 register_t pc, ra, sp;
427 struct pcb *ctx;
428
429 ctx = kdb_thr_ctx(thr);
430 sp = (register_t)ctx->pcb_context[PCB_REG_SP];
431 pc = (register_t)ctx->pcb_context[PCB_REG_PC];
432 ra = (register_t)ctx->pcb_context[PCB_REG_RA];
433 stacktrace_subr(pc, sp, ra);
434
435 return (0);
436 }
437
438 void
439 db_show_mdpcpu(struct pcpu *pc)
440 {
441
442 db_printf("ipis = 0x%x\n", pc->pc_pending_ipis);
443 db_printf("next ASID = %d\n", pc->pc_next_asid);
444 db_printf("GENID = %d\n", pc->pc_asid_generation);
445 return;
446 }
Cache object: 43278118cfa81b09c9e460c2d3e4262c
|