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.3/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 48extern char _locore[]; 49extern char _locoreEnd[]; 50extern 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 89static 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 */ 108static char * 109fn_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 132void 133stacktrace_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 */ 149loop: 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 366done: 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 { 389finish: 390 if (curproc) 391 (*printfn) ("pid %d\n", curproc->p_pid); 392 else 393 (*printfn) ("curproc NULL\n"); 394 } 395} 396 397 398int 399db_md_set_watchpoint(db_expr_t addr, db_expr_t size) 400{ 401 402 return(0); 403} 404 405 406int 407db_md_clr_watchpoint(db_expr_t addr, db_expr_t size) 408{ 409 410 return(0); 411} 412 413 414void 415db_md_list_watchpoints() 416{ 417} 418 419void 420db_trace_self(void) 421{ 422 db_trace_thread (curthread, -1); 423 return; 424} 425 426int 427db_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 458void 459db_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} 467