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