]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/mips/db_trace.c
MFV r330102: ntp 4.2.8p11
[FreeBSD/FreeBSD.git] / sys / mips / mips / db_trace.c
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  * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction
71  *
72  * XXX gcc doesn't do this for functions with __noreturn__ attribute.
73  */
74 #define MIPS_END_OF_FUNCTION(ins)       ((ins) == 0x03e00008)
75
76 #if defined(__mips_n64)
77 #       define  MIPS_IS_VALID_KERNELADDR(reg)   ((((reg) & 3) == 0) && \
78                                         ((vm_offset_t)(reg) >= MIPS_XKPHYS_START))
79 #else
80 #       define  MIPS_IS_VALID_KERNELADDR(reg)   ((((reg) & 3) == 0) && \
81                                         ((vm_offset_t)(reg) >= MIPS_KSEG0_START))
82 #endif
83
84 static void
85 stacktrace_subr(register_t pc, register_t sp, register_t ra)
86 {
87         InstFmt i;
88         /*
89          * Arrays for a0..a3 registers and flags if content
90          * of these registers is valid, e.g. obtained from the stack
91          */
92         int valid_args[4];
93         register_t args[4];
94         register_t va, subr, cause, badvaddr;
95         unsigned instr, mask;
96         unsigned int frames = 0;
97         int more, stksize, j;
98         register_t      next_ra;
99         bool trapframe;
100
101 /* Jump here when done with a frame, to start a new one */
102 loop:
103
104         /*
105          * Invalidate arguments values
106          */
107         valid_args[0] = 0;
108         valid_args[1] = 0;
109         valid_args[2] = 0;
110         valid_args[3] = 0;
111         next_ra = 0;
112         stksize = 0;
113         subr = 0;
114         trapframe = false;
115         if (frames++ > 100) {
116                 db_printf("\nstackframe count exceeded\n");
117                 return;
118         }
119
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);
123                 ra = 0;
124                 subr = 0;
125                 goto done;
126         }
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)
131
132         /*
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.
136          */
137         if (pcBetween(MipsKernGenException, MipsUserGenException)) {
138                 subr = (uintptr_t)MipsKernGenException;
139                 trapframe = true;
140         } else if (pcBetween(MipsUserGenException, MipsKernIntr))
141                 subr = (uintptr_t)MipsUserGenException;
142         else if (pcBetween(MipsKernIntr, MipsUserIntr)) {
143                 subr = (uintptr_t)MipsKernIntr;
144                 trapframe = true;
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)
150                         trapframe = true;
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;
161                 ra = 0;
162                 goto done;
163         }
164
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);
168                 ra = 0;
169                 goto done;
170         }
171
172         /*
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.
176          */
177         if (trapframe)
178                 goto done;
179
180         /*
181          * Find the beginning of the current subroutine by scanning
182          * backwards from the current PC for the end of the previous
183          * subroutine.
184          */
185         if (!subr) {
186                 va = pc - sizeof(int);
187                 while (1) {
188                         instr = kdbpeek((int *)va);
189
190                         if (MIPS_START_OF_FUNCTION(instr))
191                                 break;
192
193                         if (MIPS_END_OF_FUNCTION(instr)) {
194                                 /* skip over branch-delay slot instruction */
195                                 va += 2 * sizeof(int);
196                                 break;
197                         }
198
199                         va -= sizeof(int);
200                 }
201
202                 /* skip over nulls which might separate .o files */
203                 while ((instr = kdbpeek((int *)va)) == 0)
204                         va += sizeof(int);
205                 subr = va;
206         }
207         /* scan forwards to find stack size and any saved registers */
208         stksize = 0;
209         more = 3;
210         mask = 0;
211         for (va = subr; more; va += sizeof(int),
212             more = (more == 3) ? 3 : more - 1) {
213                 /* stop if hit our current position */
214                 if (va >= pc)
215                         break;
216                 instr = kdbpeek((int *)va);
217                 i.word = instr;
218                 switch (i.JType.op) {
219                 case OP_SPECIAL:
220                         switch (i.RType.func) {
221                         case OP_JR:
222                         case OP_JALR:
223                                 more = 2;       /* stop after next instruction */
224                                 break;
225
226                         case OP_SYSCALL:
227                         case OP_BREAK:
228                                 more = 1;       /* stop now */
229                         }
230                         break;
231
232                 case OP_BCOND:
233                 case OP_J:
234                 case OP_JAL:
235                 case OP_BEQ:
236                 case OP_BNE:
237                 case OP_BLEZ:
238                 case OP_BGTZ:
239                         more = 2;       /* stop after next instruction */
240                         break;
241
242                 case OP_COP0:
243                 case OP_COP1:
244                 case OP_COP2:
245                 case OP_COP3:
246                         switch (i.RType.rs) {
247                         case OP_BCx:
248                         case OP_BCy:
249                                 more = 2;       /* stop after next instruction */
250                         }
251                         break;
252
253                 case OP_SW:
254                         /* look for saved registers on the stack */
255                         if (i.IType.rs != 29)
256                                 break;
257                         /*
258                          * only restore the first one except RA for
259                          * MipsKernGenException case
260                          */
261                         if (mask & (1 << i.IType.rt)) {
262                                 if (subr == (uintptr_t)MipsKernGenException &&
263                                     i.IType.rt == 31)
264                                         next_ra = kdbpeek((int *)(sp +
265                                             (short)i.IType.imm));
266                                 break;
267                         }
268                         mask |= (1 << i.IType.rt);
269                         switch (i.IType.rt) {
270                         case 4:/* a0 */
271                                 args[0] = kdbpeek((int *)(sp + (short)i.IType.imm));
272                                 valid_args[0] = 1;
273                                 break;
274
275                         case 5:/* a1 */
276                                 args[1] = kdbpeek((int *)(sp + (short)i.IType.imm));
277                                 valid_args[1] = 1;
278                                 break;
279
280                         case 6:/* a2 */
281                                 args[2] = kdbpeek((int *)(sp + (short)i.IType.imm));
282                                 valid_args[2] = 1;
283                                 break;
284
285                         case 7:/* a3 */
286                                 args[3] = kdbpeek((int *)(sp + (short)i.IType.imm));
287                                 valid_args[3] = 1;
288                                 break;
289
290                         case 31:        /* ra */
291                                 ra = kdbpeek((int *)(sp + (short)i.IType.imm));
292                         }
293                         break;
294
295                 case OP_SD:
296                         /* look for saved registers on the stack */
297                         if (i.IType.rs != 29)
298                                 break;
299                         /* only restore the first one */
300                         if (mask & (1 << i.IType.rt))
301                                 break;
302                         mask |= (1 << i.IType.rt);
303                         switch (i.IType.rt) {
304                         case 4:/* a0 */
305                                 args[0] = kdbpeekd((int *)(sp + (short)i.IType.imm));
306                                 valid_args[0] = 1;
307                                 break;
308
309                         case 5:/* a1 */
310                                 args[1] = kdbpeekd((int *)(sp + (short)i.IType.imm));
311                                 valid_args[1] = 1;
312                                 break;
313
314                         case 6:/* a2 */
315                                 args[2] = kdbpeekd((int *)(sp + (short)i.IType.imm));
316                                 valid_args[2] = 1;
317                                 break;
318
319                         case 7:/* a3 */
320                                 args[3] = kdbpeekd((int *)(sp + (short)i.IType.imm));
321                                 valid_args[3] = 1;
322                                 break;
323
324                         case 31:        /* ra */
325                                 ra = kdbpeekd((int *)(sp + (short)i.IType.imm));
326                         }
327                         break;
328
329                 case OP_ADDI:
330                 case OP_ADDIU:
331                 case OP_DADDI:
332                 case OP_DADDIU:
333                         /* look for stack pointer adjustment */
334                         if (i.IType.rs != 29 || i.IType.rt != 29)
335                                 break;
336                         stksize = -((short)i.IType.imm);
337                 }
338         }
339
340 done:
341         db_printsym(pc, DB_STGY_PROC);
342         db_printf(" (");
343         for (j = 0; j < 4; j ++) {
344                 if (j > 0)
345                         db_printf(",");
346                 if (valid_args[j])
347                         db_printf("%jx", (uintmax_t)(u_register_t)args[j]);
348                 else
349                         db_printf("?");
350         }
351
352         db_printf(") ra %jx sp %jx sz %d\n",
353             (uintmax_t)(u_register_t) ra,
354             (uintmax_t)(u_register_t) sp,
355             stksize);
356
357         if (trapframe) {
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));
365 #else
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));
371 #endif
372 #undef TF_REG
373                 db_printf("--- exception, cause %jx badvaddr %jx ---\n",
374                     (uintmax_t)cause, (uintmax_t)badvaddr);
375                 goto loop;
376         } else if (ra) {
377                 if (pc == ra && stksize == 0)
378                         db_printf("stacktrace: loop!\n");
379                 else {
380                         pc = ra;
381                         sp += stksize;
382                         ra = next_ra;
383                         goto loop;
384                 }
385         }
386 }
387
388
389 int
390 db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
391 {
392
393         return(0);
394 }
395
396
397 int
398 db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
399 {
400
401         return(0);
402 }
403
404
405 void
406 db_md_list_watchpoints()
407 {
408 }
409
410 void
411 db_trace_self(void)
412 {
413         register_t pc, ra, sp;
414
415         sp = (register_t)(intptr_t)__builtin_frame_address(0);
416         ra = (register_t)(intptr_t)__builtin_return_address(0);
417
418         __asm __volatile(
419                 "jal 99f\n"
420                 "nop\n"
421                 "99:\n"
422                  "move %0, $31\n" /* get ra */
423                  "move $31, %1\n" /* restore ra */
424                  : "=r" (pc)
425                  : "r" (ra));
426         stacktrace_subr(pc, sp, ra);
427         return;
428 }
429
430 int
431 db_trace_thread(struct thread *thr, int count)
432 {
433         register_t pc, ra, sp;
434         struct pcb *ctx;
435
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);
441
442         return (0);
443 }
444
445 void
446 db_show_mdpcpu(struct pcpu *pc)
447 {
448
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);
452         return;
453 }