]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/mips/db_trace.c
MFV r313676: libpcap 1.8.1
[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 static void
83 stacktrace_subr(register_t pc, register_t sp, register_t ra)
84 {
85         InstFmt i;
86         /*
87          * Arrays for a0..a3 registers and flags if content
88          * of these registers is valid, e.g. obtained from the stack
89          */
90         int valid_args[4];
91         register_t args[4];
92         register_t va, subr, cause, badvaddr;
93         unsigned instr, mask;
94         unsigned int frames = 0;
95         int more, stksize, j;
96         register_t      next_ra;
97         bool trapframe;
98
99 /* Jump here when done with a frame, to start a new one */
100 loop:
101
102         /*
103          * Invalidate arguments values
104          */
105         valid_args[0] = 0;
106         valid_args[1] = 0;
107         valid_args[2] = 0;
108         valid_args[3] = 0;
109         next_ra = 0;
110         stksize = 0;
111         subr = 0;
112         trapframe = false;
113         if (frames++ > 100) {
114                 db_printf("\nstackframe count exceeded\n");
115                 return;
116         }
117
118         /* Check for bad SP: could foul up next frame. */
119         if (!MIPS_IS_VALID_KERNELADDR(sp)) {
120                 db_printf("SP 0x%jx: not in kernel\n", (uintmax_t)sp);
121                 ra = 0;
122                 subr = 0;
123                 goto done;
124         }
125 #define Between(x, y, z) \
126                 ( ((x) <= (y)) && ((y) < (z)) )
127 #define pcBetween(a,b) \
128                 Between((uintptr_t)a, pc, (uintptr_t)b)
129
130         /*
131          * Check for current PC in  exception handler code that don't have a
132          * preceding "j ra" at the tail of the preceding function. Depends
133          * on relative ordering of functions in exception.S, swtch.S.
134          */
135         if (pcBetween(MipsKernGenException, MipsUserGenException)) {
136                 subr = (uintptr_t)MipsKernGenException;
137                 trapframe = true;
138         } else if (pcBetween(MipsUserGenException, MipsKernIntr))
139                 subr = (uintptr_t)MipsUserGenException;
140         else if (pcBetween(MipsKernIntr, MipsUserIntr)) {
141                 subr = (uintptr_t)MipsKernIntr;
142                 trapframe = true;
143         } else if (pcBetween(MipsUserIntr, MipsTLBInvalidException))
144                 subr = (uintptr_t)MipsUserIntr;
145         else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) {
146                 subr = (uintptr_t)MipsTLBInvalidException;
147                 if (pc == (uintptr_t)MipsKStackOverflow)
148                         trapframe = true;
149         } else if (pcBetween(fork_trampoline, savectx))
150                 subr = (uintptr_t)fork_trampoline;
151         else if (pcBetween(savectx, cpu_throw))
152                 subr = (uintptr_t)savectx;
153         else if (pcBetween(cpu_throw, cpu_switch))
154                 subr = (uintptr_t)cpu_throw;
155         else if (pcBetween(cpu_switch, MipsSwitchFPState))
156                 subr = (uintptr_t)cpu_switch;
157         else if (pcBetween(_locore, _locoreEnd)) {
158                 subr = (uintptr_t)_locore;
159                 ra = 0;
160                 goto done;
161         }
162
163         /* Check for bad PC. */
164         if (!MIPS_IS_VALID_KERNELADDR(pc)) {
165                 db_printf("PC 0x%jx: not in kernel\n", (uintmax_t)pc);
166                 ra = 0;
167                 goto done;
168         }
169
170         /*
171          * For a trapframe, skip to the output and afterwards pull the
172          * previous registers out of the trapframe instead of decoding
173          * the function prologue.
174          */
175         if (trapframe)
176                 goto done;
177
178         /*
179          * Find the beginning of the current subroutine by scanning
180          * backwards from the current PC for the end of the previous
181          * subroutine.
182          */
183         if (!subr) {
184                 va = pc - sizeof(int);
185                 while (1) {
186                         instr = kdbpeek((int *)va);
187
188                         if (MIPS_START_OF_FUNCTION(instr))
189                                 break;
190
191                         if (MIPS_END_OF_FUNCTION(instr)) {
192                                 /* skip over branch-delay slot instruction */
193                                 va += 2 * sizeof(int);
194                                 break;
195                         }
196
197                         va -= sizeof(int);
198                 }
199
200                 /* skip over nulls which might separate .o files */
201                 while ((instr = kdbpeek((int *)va)) == 0)
202                         va += sizeof(int);
203                 subr = va;
204         }
205         /* scan forwards to find stack size and any saved registers */
206         stksize = 0;
207         more = 3;
208         mask = 0;
209         for (va = subr; more; va += sizeof(int),
210             more = (more == 3) ? 3 : more - 1) {
211                 /* stop if hit our current position */
212                 if (va >= pc)
213                         break;
214                 instr = kdbpeek((int *)va);
215                 i.word = instr;
216                 switch (i.JType.op) {
217                 case OP_SPECIAL:
218                         switch (i.RType.func) {
219                         case OP_JR:
220                         case OP_JALR:
221                                 more = 2;       /* stop after next instruction */
222                                 break;
223
224                         case OP_SYSCALL:
225                         case OP_BREAK:
226                                 more = 1;       /* stop now */
227                         }
228                         break;
229
230                 case OP_BCOND:
231                 case OP_J:
232                 case OP_JAL:
233                 case OP_BEQ:
234                 case OP_BNE:
235                 case OP_BLEZ:
236                 case OP_BGTZ:
237                         more = 2;       /* stop after next instruction */
238                         break;
239
240                 case OP_COP0:
241                 case OP_COP1:
242                 case OP_COP2:
243                 case OP_COP3:
244                         switch (i.RType.rs) {
245                         case OP_BCx:
246                         case OP_BCy:
247                                 more = 2;       /* stop after next instruction */
248                         }
249                         break;
250
251                 case OP_SW:
252                         /* look for saved registers on the stack */
253                         if (i.IType.rs != 29)
254                                 break;
255                         /*
256                          * only restore the first one except RA for
257                          * MipsKernGenException case
258                          */
259                         if (mask & (1 << i.IType.rt)) {
260                                 if (subr == (uintptr_t)MipsKernGenException &&
261                                     i.IType.rt == 31)
262                                         next_ra = kdbpeek((int *)(sp +
263                                             (short)i.IType.imm));
264                                 break;
265                         }
266                         mask |= (1 << i.IType.rt);
267                         switch (i.IType.rt) {
268                         case 4:/* a0 */
269                                 args[0] = kdbpeek((int *)(sp + (short)i.IType.imm));
270                                 valid_args[0] = 1;
271                                 break;
272
273                         case 5:/* a1 */
274                                 args[1] = kdbpeek((int *)(sp + (short)i.IType.imm));
275                                 valid_args[1] = 1;
276                                 break;
277
278                         case 6:/* a2 */
279                                 args[2] = kdbpeek((int *)(sp + (short)i.IType.imm));
280                                 valid_args[2] = 1;
281                                 break;
282
283                         case 7:/* a3 */
284                                 args[3] = kdbpeek((int *)(sp + (short)i.IType.imm));
285                                 valid_args[3] = 1;
286                                 break;
287
288                         case 31:        /* ra */
289                                 ra = kdbpeek((int *)(sp + (short)i.IType.imm));
290                         }
291                         break;
292
293                 case OP_SD:
294                         /* look for saved registers on the stack */
295                         if (i.IType.rs != 29)
296                                 break;
297                         /* only restore the first one */
298                         if (mask & (1 << i.IType.rt))
299                                 break;
300                         mask |= (1 << i.IType.rt);
301                         switch (i.IType.rt) {
302                         case 4:/* a0 */
303                                 args[0] = kdbpeekd((int *)(sp + (short)i.IType.imm));
304                                 valid_args[0] = 1;
305                                 break;
306
307                         case 5:/* a1 */
308                                 args[1] = kdbpeekd((int *)(sp + (short)i.IType.imm));
309                                 valid_args[1] = 1;
310                                 break;
311
312                         case 6:/* a2 */
313                                 args[2] = kdbpeekd((int *)(sp + (short)i.IType.imm));
314                                 valid_args[2] = 1;
315                                 break;
316
317                         case 7:/* a3 */
318                                 args[3] = kdbpeekd((int *)(sp + (short)i.IType.imm));
319                                 valid_args[3] = 1;
320                                 break;
321
322                         case 31:        /* ra */
323                                 ra = kdbpeekd((int *)(sp + (short)i.IType.imm));
324                         }
325                         break;
326
327                 case OP_ADDI:
328                 case OP_ADDIU:
329                 case OP_DADDI:
330                 case OP_DADDIU:
331                         /* look for stack pointer adjustment */
332                         if (i.IType.rs != 29 || i.IType.rt != 29)
333                                 break;
334                         stksize = -((short)i.IType.imm);
335                 }
336         }
337
338 done:
339         db_printsym(pc, DB_STGY_PROC);
340         db_printf(" (");
341         for (j = 0; j < 4; j ++) {
342                 if (j > 0)
343                         db_printf(",");
344                 if (valid_args[j])
345                         db_printf("%jx", (uintmax_t)(u_register_t)args[j]);
346                 else
347                         db_printf("?");
348         }
349
350         db_printf(") ra %jx sp %jx sz %d\n",
351             (uintmax_t)(u_register_t) ra,
352             (uintmax_t)(u_register_t) sp,
353             stksize);
354
355         if (trapframe) {
356 #define TF_REG(base, reg)       ((base) + CALLFRAME_SIZ + ((reg) * SZREG))
357 #if defined(__mips_n64) || defined(__mips_n32)
358                 pc = kdbpeekd((int *)TF_REG(sp, PC));
359                 ra = kdbpeekd((int *)TF_REG(sp, RA));
360                 sp = kdbpeekd((int *)TF_REG(sp, SP));
361                 cause = kdbpeekd((int *)TF_REG(sp, CAUSE));
362                 badvaddr = kdbpeekd((int *)TF_REG(sp, BADVADDR));
363 #else
364                 pc = kdbpeek((int *)TF_REG(sp, PC));
365                 ra = kdbpeek((int *)TF_REG(sp, RA));
366                 sp = kdbpeek((int *)TF_REG(sp, SP));
367                 cause = kdbpeek((int *)TF_REG(sp, CAUSE));
368                 badvaddr = kdbpeek((int *)TF_REG(sp, BADVADDR));
369 #endif
370 #undef TF_REG
371                 db_printf("--- exception, cause %jx badvaddr %jx ---\n",
372                     (uintmax_t)cause, (uintmax_t)badvaddr);
373                 goto loop;
374         } else if (ra) {
375                 if (pc == ra && stksize == 0)
376                         db_printf("stacktrace: loop!\n");
377                 else {
378                         pc = ra;
379                         sp += stksize;
380                         ra = next_ra;
381                         goto loop;
382                 }
383         }
384 }
385
386
387 int
388 db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
389 {
390
391         return(0);
392 }
393
394
395 int
396 db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
397 {
398
399         return(0);
400 }
401
402
403 void
404 db_md_list_watchpoints()
405 {
406 }
407
408 void
409 db_trace_self(void)
410 {
411         register_t pc, ra, sp;
412
413         sp = (register_t)(intptr_t)__builtin_frame_address(0);
414         ra = (register_t)(intptr_t)__builtin_return_address(0);
415
416         __asm __volatile(
417                 "jal 99f\n"
418                 "nop\n"
419                 "99:\n"
420                  "move %0, $31\n" /* get ra */
421                  "move $31, %1\n" /* restore ra */
422                  : "=r" (pc)
423                  : "r" (ra));
424         stacktrace_subr(pc, sp, ra);
425         return;
426 }
427
428 int
429 db_trace_thread(struct thread *thr, int count)
430 {
431         register_t pc, ra, sp;
432         struct pcb *ctx;
433
434         ctx = kdb_thr_ctx(thr);
435         sp = (register_t)ctx->pcb_context[PCB_REG_SP];
436         pc = (register_t)ctx->pcb_context[PCB_REG_PC];
437         ra = (register_t)ctx->pcb_context[PCB_REG_RA];
438         stacktrace_subr(pc, sp, ra);
439
440         return (0);
441 }
442
443 void
444 db_show_mdpcpu(struct pcpu *pc)
445 {
446
447         db_printf("ipis         = 0x%x\n", pc->pc_pending_ipis);
448         db_printf("next ASID    = %d\n", pc->pc_next_asid);
449         db_printf("GENID        = %d\n", pc->pc_asid_generation);
450         return;
451 }