db_trace.c revision 208392
1178172Simp/*- 2178172Simp * Copyright (c) 2004-2005, Juniper Networks, Inc. 3178172Simp * All rights reserved. 4178172Simp * 5178172Simp * JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta 6178172Simp */ 7178172Simp 8178172Simp#include <sys/cdefs.h> 9178172Simp__FBSDID("$FreeBSD: head/sys/mips/mips/db_trace.c 208392 2010-05-21 17:17:56Z jhb $"); 10178172Simp 11178172Simp#include <sys/param.h> 12178172Simp#include <sys/systm.h> 13178172Simp#include <sys/kdb.h> 14178172Simp#include <sys/proc.h> 15178172Simp#include <sys/stack.h> 16178172Simp#include <sys/sysent.h> 17178172Simp 18178172Simp#include <machine/db_machdep.h> 19178172Simp#include <machine/md_var.h> 20202046Simp#include <machine/mips_opcode.h> 21178172Simp#include <machine/pcb.h> 22202046Simp#include <machine/trap.h> 23178172Simp 24178172Simp#include <ddb/ddb.h> 25202046Simp#include <ddb/db_sym.h> 26178172Simp 27202046Simpextern char _locore[]; 28202046Simpextern char _locoreEnd[]; 29202046Simpextern char edata[]; 30202046Simp 31202046Simp/* 32202046Simp * A function using a stack frame has the following instruction as the first 33202046Simp * one: addiu sp,sp,-<frame_size> 34202046Simp * 35202046Simp * We make use of this to detect starting address of a function. This works 36202046Simp * better than using 'j ra' instruction to signify end of the previous 37202046Simp * function (for e.g. functions like boot() or panic() do not actually 38202046Simp * emit a 'j ra' instruction). 39202046Simp * 40202046Simp * XXX the abi does not require that the addiu instruction be the first one. 41202046Simp */ 42202046Simp#define MIPS_START_OF_FUNCTION(ins) (((ins) & 0xffff8000) == 0x27bd8000) 43202046Simp 44202046Simp/* 45202046Simp * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction 46202046Simp * 47202046Simp * XXX gcc doesn't do this for functions with __noreturn__ attribute. 48202046Simp */ 49202046Simp#define MIPS_END_OF_FUNCTION(ins) ((ins) == 0x03e00008) 50202046Simp 51202046Simp/* 52202046Simp * kdbpeekD(addr) - skip one word starting at 'addr', then read the second word 53202046Simp */ 54202046Simp#define kdbpeekD(addr) kdbpeek(((int *)(addr)) + 1) 55202046Simp 56202046Simp/* 57202046Simp * Functions ``special'' enough to print by name 58202046Simp */ 59202046Simp#ifdef __STDC__ 60202046Simp#define Name(_fn) { (void*)_fn, # _fn } 61202046Simp#else 62202046Simp#define Name(_fn) { _fn, "_fn"} 63202046Simp#endif 64202046Simpstatic struct { 65202046Simp void *addr; 66202046Simp char *name; 67202046Simp} names[] = { 68202046Simp 69202046Simp Name(trap), 70202046Simp Name(MipsKernGenException), 71202046Simp Name(MipsUserGenException), 72202046Simp Name(MipsKernIntr), 73202046Simp Name(MipsUserIntr), 74202046Simp Name(cpu_switch), 75202046Simp { 76202046Simp 0, 0 77202046Simp } 78202046Simp}; 79202046Simp 80202046Simp/* 81202046Simp * Map a function address to a string name, if known; or a hex string. 82202046Simp */ 83202046Simpstatic char * 84202046Simpfn_name(uintptr_t addr) 85202046Simp{ 86202046Simp static char buf[17]; 87202046Simp int i = 0; 88202046Simp 89202046Simp db_expr_t diff; 90202046Simp c_db_sym_t sym; 91202046Simp char *symname; 92202046Simp 93202046Simp diff = 0; 94202046Simp symname = NULL; 95202046Simp sym = db_search_symbol((db_addr_t)addr, DB_STGY_ANY, &diff); 96202046Simp db_symbol_values(sym, (const char **)&symname, (db_expr_t *)0); 97202046Simp if (symname && diff == 0) 98202046Simp return (symname); 99202046Simp 100202046Simp for (i = 0; names[i].name; i++) 101202046Simp if (names[i].addr == (void *)addr) 102202046Simp return (names[i].name); 103202046Simp sprintf(buf, "%jx", (uintmax_t)addr); 104202046Simp return (buf); 105202046Simp} 106202046Simp 107202046Simpvoid 108202046Simpstacktrace_subr(register_t pc, register_t sp, register_t ra, 109202046Simp int (*printfn) (const char *,...)) 110202046Simp{ 111202046Simp InstFmt i; 112202046Simp /* 113202046Simp * Arrays for a0..a3 registers and flags if content 114202046Simp * of these registers is valid, e.g. obtained from the stack 115202046Simp */ 116202046Simp int valid_args[4]; 117202046Simp uintptr_t args[4]; 118202046Simp uintptr_t va, subr; 119202046Simp unsigned instr, mask; 120202046Simp unsigned int frames = 0; 121202046Simp int more, stksize, j; 122202046Simp 123202046Simp/* Jump here when done with a frame, to start a new one */ 124202046Simploop: 125202046Simp 126202046Simp /* 127202046Simp * Invalidate arguments values 128202046Simp */ 129202046Simp valid_args[0] = 0; 130202046Simp valid_args[1] = 0; 131202046Simp valid_args[2] = 0; 132202046Simp valid_args[3] = 0; 133202046Simp/* Jump here after a nonstandard (interrupt handler) frame */ 134202046Simp stksize = 0; 135202046Simp subr = 0; 136202046Simp if (frames++ > 100) { 137202046Simp (*printfn) ("\nstackframe count exceeded\n"); 138202046Simp /* return breaks stackframe-size heuristics with gcc -O2 */ 139202046Simp goto finish; /* XXX */ 140202046Simp } 141202046Simp /* check for bad SP: could foul up next frame */ 142202046Simp /*XXX MIPS64 bad: this hard-coded SP is lame */ 143202046Simp if (sp & 3 || sp < 0x80000000) { 144202046Simp (*printfn) ("SP 0x%x: not in kernel\n", sp); 145202046Simp ra = 0; 146202046Simp subr = 0; 147202046Simp goto done; 148202046Simp } 149202046Simp#define Between(x, y, z) \ 150202046Simp ( ((x) <= (y)) && ((y) < (z)) ) 151202046Simp#define pcBetween(a,b) \ 152202046Simp Between((uintptr_t)a, pc, (uintptr_t)b) 153202046Simp 154202046Simp /* 155202046Simp * Check for current PC in exception handler code that don't have a 156202046Simp * preceding "j ra" at the tail of the preceding function. Depends 157202046Simp * on relative ordering of functions in exception.S, swtch.S. 158202046Simp */ 159202046Simp if (pcBetween(MipsKernGenException, MipsUserGenException)) 160202046Simp subr = (uintptr_t)MipsKernGenException; 161202046Simp else if (pcBetween(MipsUserGenException, MipsKernIntr)) 162202046Simp subr = (uintptr_t)MipsUserGenException; 163202046Simp else if (pcBetween(MipsKernIntr, MipsUserIntr)) 164202046Simp subr = (uintptr_t)MipsKernIntr; 165205360Sneel else if (pcBetween(MipsUserIntr, MipsTLBInvalidException)) 166202046Simp subr = (uintptr_t)MipsUserIntr; 167205360Sneel else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) 168205360Sneel subr = (uintptr_t)MipsTLBInvalidException; 169204997Sneel else if (pcBetween(fork_trampoline, savectx)) 170204997Sneel subr = (uintptr_t)fork_trampoline; 171204997Sneel else if (pcBetween(savectx, mips_cpu_throw)) 172204997Sneel subr = (uintptr_t)savectx; 173204997Sneel else if (pcBetween(mips_cpu_throw, cpu_switch)) 174204997Sneel subr = (uintptr_t)cpu_throw; 175202046Simp else if (pcBetween(cpu_switch, MipsSwitchFPState)) 176202046Simp subr = (uintptr_t)cpu_switch; 177202046Simp else if (pcBetween(_locore, _locoreEnd)) { 178202046Simp subr = (uintptr_t)_locore; 179202046Simp ra = 0; 180202046Simp goto done; 181202046Simp } 182202046Simp /* check for bad PC */ 183202046Simp /*XXX MIPS64 bad: These hard coded constants are lame */ 184207645Sneel if (pc & 3 || pc < (uintptr_t)0x80000000) { 185202046Simp (*printfn) ("PC 0x%x: not in kernel\n", pc); 186202046Simp ra = 0; 187202046Simp goto done; 188202046Simp } 189202046Simp /* 190202046Simp * Find the beginning of the current subroutine by scanning 191202046Simp * backwards from the current PC for the end of the previous 192202046Simp * subroutine. 193202046Simp */ 194202046Simp if (!subr) { 195202046Simp va = pc - sizeof(int); 196202046Simp while (1) { 197202046Simp instr = kdbpeek((int *)va); 198202046Simp 199202046Simp if (MIPS_START_OF_FUNCTION(instr)) 200202046Simp break; 201202046Simp 202202046Simp if (MIPS_END_OF_FUNCTION(instr)) { 203202046Simp /* skip over branch-delay slot instruction */ 204202046Simp va += 2 * sizeof(int); 205202046Simp break; 206202046Simp } 207202046Simp 208202046Simp va -= sizeof(int); 209202046Simp } 210202046Simp 211202046Simp /* skip over nulls which might separate .o files */ 212202046Simp while ((instr = kdbpeek((int *)va)) == 0) 213202046Simp va += sizeof(int); 214202046Simp subr = va; 215202046Simp } 216202046Simp /* scan forwards to find stack size and any saved registers */ 217202046Simp stksize = 0; 218202046Simp more = 3; 219202046Simp mask = 0; 220202046Simp for (va = subr; more; va += sizeof(int), 221202046Simp more = (more == 3) ? 3 : more - 1) { 222202046Simp /* stop if hit our current position */ 223202046Simp if (va >= pc) 224202046Simp break; 225202046Simp instr = kdbpeek((int *)va); 226202046Simp i.word = instr; 227202046Simp switch (i.JType.op) { 228202046Simp case OP_SPECIAL: 229202046Simp switch (i.RType.func) { 230202046Simp case OP_JR: 231202046Simp case OP_JALR: 232202046Simp more = 2; /* stop after next instruction */ 233202046Simp break; 234202046Simp 235202046Simp case OP_SYSCALL: 236202046Simp case OP_BREAK: 237202046Simp more = 1; /* stop now */ 238202046Simp }; 239202046Simp break; 240202046Simp 241202046Simp case OP_BCOND: 242202046Simp case OP_J: 243202046Simp case OP_JAL: 244202046Simp case OP_BEQ: 245202046Simp case OP_BNE: 246202046Simp case OP_BLEZ: 247202046Simp case OP_BGTZ: 248202046Simp more = 2; /* stop after next instruction */ 249202046Simp break; 250202046Simp 251202046Simp case OP_COP0: 252202046Simp case OP_COP1: 253202046Simp case OP_COP2: 254202046Simp case OP_COP3: 255202046Simp switch (i.RType.rs) { 256202046Simp case OP_BCx: 257202046Simp case OP_BCy: 258202046Simp more = 2; /* stop after next instruction */ 259202046Simp }; 260202046Simp break; 261202046Simp 262202046Simp case OP_SW: 263202046Simp /* look for saved registers on the stack */ 264202046Simp if (i.IType.rs != 29) 265202046Simp break; 266202046Simp /* only restore the first one */ 267202046Simp if (mask & (1 << i.IType.rt)) 268202046Simp break; 269202046Simp mask |= (1 << i.IType.rt); 270202046Simp switch (i.IType.rt) { 271202046Simp case 4:/* a0 */ 272202046Simp args[0] = kdbpeek((int *)(sp + (short)i.IType.imm)); 273202046Simp valid_args[0] = 1; 274202046Simp break; 275202046Simp 276202046Simp case 5:/* a1 */ 277202046Simp args[1] = kdbpeek((int *)(sp + (short)i.IType.imm)); 278202046Simp valid_args[1] = 1; 279202046Simp break; 280202046Simp 281202046Simp case 6:/* a2 */ 282202046Simp args[2] = kdbpeek((int *)(sp + (short)i.IType.imm)); 283202046Simp valid_args[2] = 1; 284202046Simp break; 285202046Simp 286202046Simp case 7:/* a3 */ 287202046Simp args[3] = kdbpeek((int *)(sp + (short)i.IType.imm)); 288202046Simp valid_args[3] = 1; 289202046Simp break; 290202046Simp 291202046Simp case 31: /* ra */ 292202046Simp ra = kdbpeek((int *)(sp + (short)i.IType.imm)); 293202046Simp } 294202046Simp break; 295202046Simp 296202046Simp case OP_SD: 297202046Simp /* look for saved registers on the stack */ 298202046Simp if (i.IType.rs != 29) 299202046Simp break; 300202046Simp /* only restore the first one */ 301202046Simp if (mask & (1 << i.IType.rt)) 302202046Simp break; 303202046Simp mask |= (1 << i.IType.rt); 304202046Simp switch (i.IType.rt) { 305202046Simp case 4:/* a0 */ 306202046Simp args[0] = kdbpeekD((int *)(sp + (short)i.IType.imm)); 307202046Simp valid_args[0] = 1; 308202046Simp break; 309202046Simp 310202046Simp case 5:/* a1 */ 311202046Simp args[1] = kdbpeekD((int *)(sp + (short)i.IType.imm)); 312202046Simp valid_args[1] = 1; 313202046Simp break; 314202046Simp 315202046Simp case 6:/* a2 */ 316202046Simp args[2] = kdbpeekD((int *)(sp + (short)i.IType.imm)); 317202046Simp valid_args[2] = 1; 318202046Simp break; 319202046Simp 320202046Simp case 7:/* a3 */ 321202046Simp args[3] = kdbpeekD((int *)(sp + (short)i.IType.imm)); 322202046Simp valid_args[3] = 1; 323202046Simp break; 324202046Simp 325202046Simp case 31: /* ra */ 326202046Simp ra = kdbpeekD((int *)(sp + (short)i.IType.imm)); 327202046Simp } 328202046Simp break; 329202046Simp 330202046Simp case OP_ADDI: 331202046Simp case OP_ADDIU: 332202046Simp /* look for stack pointer adjustment */ 333202046Simp if (i.IType.rs != 29 || i.IType.rt != 29) 334202046Simp break; 335202046Simp stksize = -((short)i.IType.imm); 336202046Simp } 337202046Simp } 338202046Simp 339202046Simpdone: 340202046Simp (*printfn) ("%s+%x (", fn_name(subr), pc - subr); 341202046Simp for (j = 0; j < 4; j ++) { 342202046Simp if (j > 0) 343202046Simp (*printfn)(","); 344202046Simp if (valid_args[j]) 345202046Simp (*printfn)("%x", args[j]); 346202046Simp else 347202046Simp (*printfn)("?"); 348202046Simp } 349202046Simp 350202998Sneel (*printfn) (") ra %x sp %x sz %d\n", ra, sp, stksize); 351202046Simp 352202046Simp if (ra) { 353202046Simp if (pc == ra && stksize == 0) 354202046Simp (*printfn) ("stacktrace: loop!\n"); 355202046Simp else { 356202046Simp pc = ra; 357202046Simp sp += stksize; 358202046Simp ra = 0; 359202046Simp goto loop; 360202046Simp } 361202046Simp } else { 362202046Simpfinish: 363202046Simp if (curproc) 364202046Simp (*printfn) ("pid %d\n", curproc->p_pid); 365202046Simp else 366202046Simp (*printfn) ("curproc NULL\n"); 367202046Simp } 368202046Simp} 369202046Simp 370202046Simp 371178172Simpint 372178172Simpdb_md_set_watchpoint(db_expr_t addr, db_expr_t size) 373178172Simp{ 374178172Simp 375178172Simp return(0); 376178172Simp} 377178172Simp 378178172Simp 379178172Simpint 380178172Simpdb_md_clr_watchpoint( db_expr_t addr, db_expr_t size) 381178172Simp{ 382178172Simp 383178172Simp return(0); 384178172Simp} 385178172Simp 386178172Simp 387178172Simpvoid 388178172Simpdb_md_list_watchpoints() 389178172Simp{ 390178172Simp} 391178172Simp 392178172Simpvoid 393178172Simpdb_trace_self(void) 394178172Simp{ 395178172Simp db_trace_thread (curthread, -1); 396178172Simp return; 397178172Simp} 398178172Simp 399178172Simpint 400178172Simpdb_trace_thread(struct thread *thr, int count) 401178172Simp{ 402202046Simp register_t pc, ra, sp; 403178172Simp struct pcb *ctx; 404178172Simp 405202046Simp if (thr == curthread) { 406202046Simp sp = (register_t)__builtin_frame_address(0); 407202046Simp ra = (register_t)__builtin_return_address(0); 408202046Simp 409202046Simp __asm __volatile( 410202046Simp "jal 99f\n" 411202046Simp "nop\n" 412202046Simp "99:\n" 413202046Simp "move %0, $31\n" /* get ra */ 414202046Simp "move $31, %1\n" /* restore ra */ 415202046Simp : "=r" (pc) 416202046Simp : "r" (ra)); 417202046Simp 418204997Sneel } else { 419204997Sneel ctx = kdb_thr_ctx(thr); 420202046Simp sp = (register_t)ctx->pcb_context[PREG_SP]; 421202046Simp pc = (register_t)ctx->pcb_context[PREG_PC]; 422202046Simp ra = (register_t)ctx->pcb_context[PREG_RA]; 423202046Simp } 424202046Simp 425202046Simp stacktrace_subr(pc, sp, ra, 426202046Simp (int (*) (const char *, ...))db_printf); 427202046Simp 428202046Simp return (0); 429178172Simp} 430178172Simp 431178172Simpvoid 432178172Simpdb_show_mdpcpu(struct pcpu *pc) 433178172Simp{ 434178172Simp 435208392Sjhb db_printf("ipis = 0x%x\n", pc->pc_pending_ipis); 436178172Simp db_printf("next ASID = %d\n", pc->pc_next_asid); 437208392Sjhb db_printf("GENID = %d\n", pc->pc_asid_generation); 438178172Simp return; 439178172Simp} 440