1220747Snwhitehorn/*- 2220747Snwhitehorn * Copyright (c) 2004-2005, Juniper Networks, Inc. 3220747Snwhitehorn * All rights reserved. 4220747Snwhitehorn * 5220747Snwhitehorn * JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta 6220747Snwhitehorn */ 7220747Snwhitehorn 8220747Snwhitehorn#include <sys/cdefs.h> 9220747Snwhitehorn__FBSDID("$FreeBSD$"); 10220747Snwhitehorn 11220747Snwhitehorn#include <sys/param.h> 12220747Snwhitehorn#include <sys/systm.h> 13220747Snwhitehorn#include <sys/kdb.h> 14220747Snwhitehorn#include <sys/proc.h> 15220747Snwhitehorn#include <sys/stack.h> 16220747Snwhitehorn#include <sys/sysent.h> 17220747Snwhitehorn 18220747Snwhitehorn#include <machine/db_machdep.h> 19220747Snwhitehorn#include <machine/md_var.h> 20220747Snwhitehorn#include <machine/mips_opcode.h> 21220747Snwhitehorn#include <machine/pcb.h> 22220747Snwhitehorn#include <machine/trap.h> 23220747Snwhitehorn 24220747Snwhitehorn#include <ddb/ddb.h> 25220747Snwhitehorn#include <ddb/db_sym.h> 26220747Snwhitehorn 27220747Snwhitehornextern char _locore[]; 28220747Snwhitehornextern char _locoreEnd[]; 29220747Snwhitehornextern char edata[]; 30220747Snwhitehorn 31220747Snwhitehorn/* 32220747Snwhitehorn * A function using a stack frame has the following instruction as the first 33220747Snwhitehorn * one: addiu sp,sp,-<frame_size> 34220747Snwhitehorn * 35220747Snwhitehorn * We make use of this to detect starting address of a function. This works 36220747Snwhitehorn * better than using 'j ra' instruction to signify end of the previous 37220747Snwhitehorn * function (for e.g. functions like boot() or panic() do not actually 38220747Snwhitehorn * emit a 'j ra' instruction). 39220747Snwhitehorn * 40220747Snwhitehorn * XXX the abi does not require that the addiu instruction be the first one. 41220747Snwhitehorn */ 42220747Snwhitehorn#define MIPS_START_OF_FUNCTION(ins) (((ins) & 0xffff8000) == 0x27bd8000) 43220747Snwhitehorn 44220747Snwhitehorn/* 45220747Snwhitehorn * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction 46220747Snwhitehorn * 47220747Snwhitehorn * XXX gcc doesn't do this for functions with __noreturn__ attribute. 48220747Snwhitehorn */ 49220747Snwhitehorn#define MIPS_END_OF_FUNCTION(ins) ((ins) == 0x03e00008) 50220747Snwhitehorn 51220747Snwhitehorn/* 52220747Snwhitehorn * kdbpeekD(addr) - skip one word starting at 'addr', then read the second word 53220747Snwhitehorn */ 54220747Snwhitehorn#define kdbpeekD(addr) kdbpeek(((int *)(addr)) + 1) 55220747Snwhitehorn 56220747Snwhitehorn/* 57220747Snwhitehorn * Functions ``special'' enough to print by name 58220747Snwhitehorn */ 59220747Snwhitehorn#ifdef __STDC__ 60220747Snwhitehorn#define Name(_fn) { (void*)_fn, # _fn } 61220747Snwhitehorn#else 62220747Snwhitehorn#define Name(_fn) { _fn, "_fn"} 63220747Snwhitehorn#endif 64220747Snwhitehornstatic struct { 65220747Snwhitehorn void *addr; 66220747Snwhitehorn char *name; 67220747Snwhitehorn} names[] = { 68220747Snwhitehorn 69220747Snwhitehorn Name(trap), 70220747Snwhitehorn Name(MipsKernGenException), 71220747Snwhitehorn Name(MipsUserGenException), 72220747Snwhitehorn Name(MipsKernIntr), 73220747Snwhitehorn Name(MipsUserIntr), 74220747Snwhitehorn Name(cpu_switch), 75220747Snwhitehorn { 76220747Snwhitehorn 0, 0 77220747Snwhitehorn } 78220747Snwhitehorn}; 79220747Snwhitehorn 80220747Snwhitehorn/* 81220747Snwhitehorn * Map a function address to a string name, if known; or a hex string. 82220747Snwhitehorn */ 83220747Snwhitehornstatic char * 84220747Snwhitehornfn_name(uintptr_t addr) 85220747Snwhitehorn{ 86220747Snwhitehorn static char buf[17]; 87220747Snwhitehorn int i = 0; 88220747Snwhitehorn 89220747Snwhitehorn db_expr_t diff; 90220747Snwhitehorn c_db_sym_t sym; 91220747Snwhitehorn char *symname; 92220747Snwhitehorn 93220747Snwhitehorn diff = 0; 94220747Snwhitehorn symname = NULL; 95220747Snwhitehorn sym = db_search_symbol((db_addr_t)addr, DB_STGY_ANY, &diff); 96220747Snwhitehorn db_symbol_values(sym, (const char **)&symname, (db_expr_t *)0); 97220747Snwhitehorn if (symname && diff == 0) 98220747Snwhitehorn return (symname); 99220747Snwhitehorn 100220747Snwhitehorn for (i = 0; names[i].name; i++) 101220747Snwhitehorn if (names[i].addr == (void *)addr) 102220747Snwhitehorn return (names[i].name); 103220747Snwhitehorn sprintf(buf, "%jx", (uintmax_t)addr); 104220747Snwhitehorn return (buf); 105220747Snwhitehorn} 106220747Snwhitehorn 107220747Snwhitehornvoid 108220747Snwhitehornstacktrace_subr(register_t pc, register_t sp, register_t ra, 109220747Snwhitehorn int (*printfn) (const char *,...)) 110220747Snwhitehorn{ 111220747Snwhitehorn InstFmt i; 112220747Snwhitehorn /* 113 * Arrays for a0..a3 registers and flags if content 114 * of these registers is valid, e.g. obtained from the stack 115 */ 116 int valid_args[4]; 117 uintptr_t args[4]; 118 uintptr_t va, subr; 119 unsigned instr, mask; 120 unsigned int frames = 0; 121 int more, stksize, j; 122 123/* Jump here when done with a frame, to start a new one */ 124loop: 125 126 /* 127 * Invalidate arguments values 128 */ 129 valid_args[0] = 0; 130 valid_args[1] = 0; 131 valid_args[2] = 0; 132 valid_args[3] = 0; 133/* Jump here after a nonstandard (interrupt handler) frame */ 134 stksize = 0; 135 subr = 0; 136 if (frames++ > 100) { 137 (*printfn) ("\nstackframe count exceeded\n"); 138 /* return breaks stackframe-size heuristics with gcc -O2 */ 139 goto finish; /* XXX */ 140 } 141 /* check for bad SP: could foul up next frame */ 142 /*XXX MIPS64 bad: this hard-coded SP is lame */ 143 if (sp & 3 || (uintptr_t)sp < 0x80000000u) { 144 (*printfn) ("SP 0x%x: not in kernel\n", sp); 145 ra = 0; 146 subr = 0; 147 goto done; 148 } 149#define Between(x, y, z) \ 150 ( ((x) <= (y)) && ((y) < (z)) ) 151#define pcBetween(a,b) \ 152 Between((uintptr_t)a, pc, (uintptr_t)b) 153 154 /* 155 * Check for current PC in exception handler code that don't have a 156 * preceding "j ra" at the tail of the preceding function. Depends 157 * on relative ordering of functions in exception.S, swtch.S. 158 */ 159 if (pcBetween(MipsKernGenException, MipsUserGenException)) 160 subr = (uintptr_t)MipsKernGenException; 161 else if (pcBetween(MipsUserGenException, MipsKernIntr)) 162 subr = (uintptr_t)MipsUserGenException; 163 else if (pcBetween(MipsKernIntr, MipsUserIntr)) 164 subr = (uintptr_t)MipsKernIntr; 165 else if (pcBetween(MipsUserIntr, MipsTLBInvalidException)) 166 subr = (uintptr_t)MipsUserIntr; 167 else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) 168 subr = (uintptr_t)MipsTLBInvalidException; 169 else if (pcBetween(fork_trampoline, savectx)) 170 subr = (uintptr_t)fork_trampoline; 171 else if (pcBetween(savectx, cpu_throw)) 172 subr = (uintptr_t)savectx; 173 else if (pcBetween(cpu_throw, cpu_switch)) 174 subr = (uintptr_t)cpu_throw; 175 else if (pcBetween(cpu_switch, MipsSwitchFPState)) 176 subr = (uintptr_t)cpu_switch; 177 else if (pcBetween(_locore, _locoreEnd)) { 178 subr = (uintptr_t)_locore; 179 ra = 0; 180 goto done; 181 } 182 /* check for bad PC */ 183 /*XXX MIPS64 bad: These hard coded constants are lame */ 184 if (pc & 3 || pc < (uintptr_t)0x80000000) { 185 (*printfn) ("PC 0x%x: not in kernel\n", pc); 186 ra = 0; 187 goto done; 188 } 189 /* 190 * Find the beginning of the current subroutine by scanning 191 * backwards from the current PC for the end of the previous 192 * subroutine. 193 */ 194 if (!subr) { 195 va = pc - sizeof(int); 196 while (1) { 197 instr = kdbpeek((int *)va); 198 199 if (MIPS_START_OF_FUNCTION(instr)) 200 break; 201 202 if (MIPS_END_OF_FUNCTION(instr)) { 203 /* skip over branch-delay slot instruction */ 204 va += 2 * sizeof(int); 205 break; 206 } 207 208 va -= sizeof(int); 209 } 210 211 /* skip over nulls which might separate .o files */ 212 while ((instr = kdbpeek((int *)va)) == 0) 213 va += sizeof(int); 214 subr = va; 215 } 216 /* scan forwards to find stack size and any saved registers */ 217 stksize = 0; 218 more = 3; 219 mask = 0; 220 for (va = subr; more; va += sizeof(int), 221 more = (more == 3) ? 3 : more - 1) { 222 /* stop if hit our current position */ 223 if (va >= pc) 224 break; 225 instr = kdbpeek((int *)va); 226 i.word = instr; 227 switch (i.JType.op) { 228 case OP_SPECIAL: 229 switch (i.RType.func) { 230 case OP_JR: 231 case OP_JALR: 232 more = 2; /* stop after next instruction */ 233 break; 234 235 case OP_SYSCALL: 236 case OP_BREAK: 237 more = 1; /* stop now */ 238 }; 239 break; 240 241 case OP_BCOND: 242 case OP_J: 243 case OP_JAL: 244 case OP_BEQ: 245 case OP_BNE: 246 case OP_BLEZ: 247 case OP_BGTZ: 248 more = 2; /* stop after next instruction */ 249 break; 250 251 case OP_COP0: 252 case OP_COP1: 253 case OP_COP2: 254 case OP_COP3: 255 switch (i.RType.rs) { 256 case OP_BCx: 257 case OP_BCy: 258 more = 2; /* stop after next instruction */ 259 }; 260 break; 261 262 case OP_SW: 263 /* look for saved registers on the stack */ 264 if (i.IType.rs != 29) 265 break; 266 /* only restore the first one */ 267 if (mask & (1 << i.IType.rt)) 268 break; 269 mask |= (1 << i.IType.rt); 270 switch (i.IType.rt) { 271 case 4:/* a0 */ 272 args[0] = kdbpeek((int *)(sp + (short)i.IType.imm)); 273 valid_args[0] = 1; 274 break; 275 276 case 5:/* a1 */ 277 args[1] = kdbpeek((int *)(sp + (short)i.IType.imm)); 278 valid_args[1] = 1; 279 break; 280 281 case 6:/* a2 */ 282 args[2] = kdbpeek((int *)(sp + (short)i.IType.imm)); 283 valid_args[2] = 1; 284 break; 285 286 case 7:/* a3 */ 287 args[3] = kdbpeek((int *)(sp + (short)i.IType.imm)); 288 valid_args[3] = 1; 289 break; 290 291 case 31: /* ra */ 292 ra = kdbpeek((int *)(sp + (short)i.IType.imm)); 293 } 294 break; 295 296 case OP_SD: 297 /* look for saved registers on the stack */ 298 if (i.IType.rs != 29) 299 break; 300 /* only restore the first one */ 301 if (mask & (1 << i.IType.rt)) 302 break; 303 mask |= (1 << i.IType.rt); 304 switch (i.IType.rt) { 305 case 4:/* a0 */ 306 args[0] = kdbpeekD((int *)(sp + (short)i.IType.imm)); 307 valid_args[0] = 1; 308 break; 309 310 case 5:/* a1 */ 311 args[1] = kdbpeekD((int *)(sp + (short)i.IType.imm)); 312 valid_args[1] = 1; 313 break; 314 315 case 6:/* a2 */ 316 args[2] = kdbpeekD((int *)(sp + (short)i.IType.imm)); 317 valid_args[2] = 1; 318 break; 319 320 case 7:/* a3 */ 321 args[3] = kdbpeekD((int *)(sp + (short)i.IType.imm)); 322 valid_args[3] = 1; 323 break; 324 325 case 31: /* ra */ 326 ra = kdbpeekD((int *)(sp + (short)i.IType.imm)); 327 } 328 break; 329 330 case OP_ADDI: 331 case OP_ADDIU: 332 /* look for stack pointer adjustment */ 333 if (i.IType.rs != 29 || i.IType.rt != 29) 334 break; 335 stksize = -((short)i.IType.imm); 336 } 337 } 338 339done: 340 (*printfn) ("%s+%x (", fn_name(subr), pc - subr); 341 for (j = 0; j < 4; j ++) { 342 if (j > 0) 343 (*printfn)(","); 344 if (valid_args[j]) 345 (*printfn)("%x", args[j]); 346 else 347 (*printfn)("?"); 348 } 349 350 (*printfn) (") ra %x sp %x sz %d\n", ra, sp, stksize); 351 352 if (ra) { 353 if (pc == ra && stksize == 0) 354 (*printfn) ("stacktrace: loop!\n"); 355 else { 356 pc = ra; 357 sp += stksize; 358 ra = 0; 359 goto loop; 360 } 361 } else { 362finish: 363 if (curproc) 364 (*printfn) ("pid %d\n", curproc->p_pid); 365 else 366 (*printfn) ("curproc NULL\n"); 367 } 368} 369 370 371int 372db_md_set_watchpoint(db_expr_t addr, db_expr_t size) 373{ 374 375 return(0); 376} 377 378 379int 380db_md_clr_watchpoint(db_expr_t addr, db_expr_t size) 381{ 382 383 return(0); 384} 385 386 387void 388db_md_list_watchpoints() 389{ 390} 391 392void 393db_trace_self(void) 394{ 395 db_trace_thread (curthread, -1); 396 return; 397} 398 399int 400db_trace_thread(struct thread *thr, int count) 401{ 402 register_t pc, ra, sp; 403 struct pcb *ctx; 404 405 if (thr == curthread) { 406 sp = (register_t)(intptr_t)__builtin_frame_address(0); 407 ra = (register_t)(intptr_t)__builtin_return_address(0); 408 409 __asm __volatile( 410 "jal 99f\n" 411 "nop\n" 412 "99:\n" 413 "move %0, $31\n" /* get ra */ 414 "move $31, %1\n" /* restore ra */ 415 : "=r" (pc) 416 : "r" (ra)); 417 418 } else { 419 ctx = kdb_thr_ctx(thr); 420 sp = (register_t)ctx->pcb_context[PREG_SP]; 421 pc = (register_t)ctx->pcb_context[PREG_PC]; 422 ra = (register_t)ctx->pcb_context[PREG_RA]; 423 } 424 425 stacktrace_subr(pc, sp, ra, 426 (int (*) (const char *, ...))db_printf); 427 428 return (0); 429} 430 431void 432db_show_mdpcpu(struct pcpu *pc) 433{ 434 435 db_printf("ipis = 0x%x\n", pc->pc_pending_ipis); 436 db_printf("next ASID = %d\n", pc->pc_next_asid); 437 db_printf("GENID = %d\n", pc->pc_asid_generation); 438 return; 439} 440