1178172Simp/*- 2178172Simp * Copyright (c) 2004-2005, Juniper Networks, Inc. 3178172Simp * All rights reserved. 4178172Simp * 5250940Smarcel * Redistribution and use in source and binary forms, with or without 6250940Smarcel * modification, are permitted provided that the following conditions 7250940Smarcel * are met: 8250940Smarcel * 1. Redistributions of source code must retain the above copyright 9250940Smarcel * notice, this list of conditions and the following disclaimer. 10250940Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11250940Smarcel * notice, this list of conditions and the following disclaimer in the 12250940Smarcel * documentation and/or other materials provided with the distribution. 13250940Smarcel * 14250940Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15250940Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16250940Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17250940Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18250940Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19250940Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20250940Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21250940Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22250940Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23250940Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24250940Smarcel * SUCH DAMAGE. 25250940Smarcel * 26178172Simp * JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta 27178172Simp */ 28178172Simp 29178172Simp#include <sys/cdefs.h> 30178172Simp__FBSDID("$FreeBSD$"); 31178172Simp 32178172Simp#include <sys/param.h> 33178172Simp#include <sys/systm.h> 34178172Simp#include <sys/kdb.h> 35178172Simp#include <sys/proc.h> 36178172Simp#include <sys/stack.h> 37178172Simp#include <sys/sysent.h> 38178172Simp 39178172Simp#include <machine/db_machdep.h> 40178172Simp#include <machine/md_var.h> 41202046Simp#include <machine/mips_opcode.h> 42178172Simp#include <machine/pcb.h> 43202046Simp#include <machine/trap.h> 44178172Simp 45178172Simp#include <ddb/ddb.h> 46202046Simp#include <ddb/db_sym.h> 47178172Simp 48202046Simpextern char _locore[]; 49202046Simpextern char _locoreEnd[]; 50202046Simpextern char edata[]; 51202046Simp 52202046Simp/* 53202046Simp * A function using a stack frame has the following instruction as the first 54228091Sgonzo * one: [d]addiu sp,sp,-<frame_size> 55202046Simp * 56202046Simp * We make use of this to detect starting address of a function. This works 57202046Simp * better than using 'j ra' instruction to signify end of the previous 58202046Simp * function (for e.g. functions like boot() or panic() do not actually 59202046Simp * emit a 'j ra' instruction). 60202046Simp * 61202046Simp * XXX the abi does not require that the addiu instruction be the first one. 62202046Simp */ 63228091Sgonzo#define MIPS_START_OF_FUNCTION(ins) ((((ins) & 0xffff8000) == 0x27bd8000) \ 64228091Sgonzo || (((ins) & 0xffff8000) == 0x67bd8000)) 65202046Simp 66202046Simp/* 67202046Simp * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction 68202046Simp * 69202046Simp * XXX gcc doesn't do this for functions with __noreturn__ attribute. 70202046Simp */ 71202046Simp#define MIPS_END_OF_FUNCTION(ins) ((ins) == 0x03e00008) 72202046Simp 73230094Sgonzo#if defined(__mips_n64) 74230094Sgonzo# define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ 75230094Sgonzo ((vm_offset_t)(reg) >= MIPS_XKPHYS_START)) 76230094Sgonzo#else 77230094Sgonzo# define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ 78230094Sgonzo ((vm_offset_t)(reg) >= MIPS_KSEG0_START)) 79230094Sgonzo#endif 80202046Simp 81202046Simp/* 82202046Simp * Functions ``special'' enough to print by name 83202046Simp */ 84202046Simp#ifdef __STDC__ 85202046Simp#define Name(_fn) { (void*)_fn, # _fn } 86202046Simp#else 87202046Simp#define Name(_fn) { _fn, "_fn"} 88202046Simp#endif 89202046Simpstatic struct { 90202046Simp void *addr; 91202046Simp char *name; 92202046Simp} names[] = { 93202046Simp 94202046Simp Name(trap), 95202046Simp Name(MipsKernGenException), 96202046Simp Name(MipsUserGenException), 97202046Simp Name(MipsKernIntr), 98202046Simp Name(MipsUserIntr), 99202046Simp Name(cpu_switch), 100202046Simp { 101202046Simp 0, 0 102202046Simp } 103202046Simp}; 104202046Simp 105202046Simp/* 106202046Simp * Map a function address to a string name, if known; or a hex string. 107202046Simp */ 108202046Simpstatic char * 109202046Simpfn_name(uintptr_t addr) 110202046Simp{ 111202046Simp static char buf[17]; 112202046Simp int i = 0; 113202046Simp 114202046Simp db_expr_t diff; 115202046Simp c_db_sym_t sym; 116202046Simp char *symname; 117202046Simp 118202046Simp diff = 0; 119202046Simp symname = NULL; 120202046Simp sym = db_search_symbol((db_addr_t)addr, DB_STGY_ANY, &diff); 121202046Simp db_symbol_values(sym, (const char **)&symname, (db_expr_t *)0); 122202046Simp if (symname && diff == 0) 123202046Simp return (symname); 124202046Simp 125202046Simp for (i = 0; names[i].name; i++) 126202046Simp if (names[i].addr == (void *)addr) 127202046Simp return (names[i].name); 128202046Simp sprintf(buf, "%jx", (uintmax_t)addr); 129202046Simp return (buf); 130202046Simp} 131202046Simp 132202046Simpvoid 133202046Simpstacktrace_subr(register_t pc, register_t sp, register_t ra, 134202046Simp int (*printfn) (const char *,...)) 135202046Simp{ 136202046Simp InstFmt i; 137202046Simp /* 138202046Simp * Arrays for a0..a3 registers and flags if content 139202046Simp * of these registers is valid, e.g. obtained from the stack 140202046Simp */ 141202046Simp int valid_args[4]; 142202046Simp uintptr_t args[4]; 143202046Simp uintptr_t va, subr; 144202046Simp unsigned instr, mask; 145202046Simp unsigned int frames = 0; 146202046Simp int more, stksize, j; 147202046Simp 148202046Simp/* Jump here when done with a frame, to start a new one */ 149202046Simploop: 150202046Simp 151202046Simp /* 152202046Simp * Invalidate arguments values 153202046Simp */ 154202046Simp valid_args[0] = 0; 155202046Simp valid_args[1] = 0; 156202046Simp valid_args[2] = 0; 157202046Simp valid_args[3] = 0; 158202046Simp/* Jump here after a nonstandard (interrupt handler) frame */ 159202046Simp stksize = 0; 160202046Simp subr = 0; 161202046Simp if (frames++ > 100) { 162202046Simp (*printfn) ("\nstackframe count exceeded\n"); 163202046Simp /* return breaks stackframe-size heuristics with gcc -O2 */ 164202046Simp goto finish; /* XXX */ 165202046Simp } 166202046Simp /* check for bad SP: could foul up next frame */ 167202046Simp /*XXX MIPS64 bad: this hard-coded SP is lame */ 168230094Sgonzo if (!MIPS_IS_VALID_KERNELADDR(sp)) { 169230094Sgonzo (*printfn) ("SP 0x%jx: not in kernel\n", sp); 170202046Simp ra = 0; 171202046Simp subr = 0; 172202046Simp goto done; 173202046Simp } 174202046Simp#define Between(x, y, z) \ 175202046Simp ( ((x) <= (y)) && ((y) < (z)) ) 176202046Simp#define pcBetween(a,b) \ 177202046Simp Between((uintptr_t)a, pc, (uintptr_t)b) 178202046Simp 179202046Simp /* 180202046Simp * Check for current PC in exception handler code that don't have a 181202046Simp * preceding "j ra" at the tail of the preceding function. Depends 182202046Simp * on relative ordering of functions in exception.S, swtch.S. 183202046Simp */ 184202046Simp if (pcBetween(MipsKernGenException, MipsUserGenException)) 185202046Simp subr = (uintptr_t)MipsKernGenException; 186202046Simp else if (pcBetween(MipsUserGenException, MipsKernIntr)) 187202046Simp subr = (uintptr_t)MipsUserGenException; 188202046Simp else if (pcBetween(MipsKernIntr, MipsUserIntr)) 189202046Simp subr = (uintptr_t)MipsKernIntr; 190205360Sneel else if (pcBetween(MipsUserIntr, MipsTLBInvalidException)) 191202046Simp subr = (uintptr_t)MipsUserIntr; 192205360Sneel else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) 193205360Sneel subr = (uintptr_t)MipsTLBInvalidException; 194204997Sneel else if (pcBetween(fork_trampoline, savectx)) 195204997Sneel subr = (uintptr_t)fork_trampoline; 196210096Simp else if (pcBetween(savectx, cpu_throw)) 197204997Sneel subr = (uintptr_t)savectx; 198210096Simp else if (pcBetween(cpu_throw, cpu_switch)) 199204997Sneel subr = (uintptr_t)cpu_throw; 200202046Simp else if (pcBetween(cpu_switch, MipsSwitchFPState)) 201202046Simp subr = (uintptr_t)cpu_switch; 202202046Simp else if (pcBetween(_locore, _locoreEnd)) { 203202046Simp subr = (uintptr_t)_locore; 204202046Simp ra = 0; 205202046Simp goto done; 206202046Simp } 207202046Simp /* check for bad PC */ 208202046Simp /*XXX MIPS64 bad: These hard coded constants are lame */ 209230094Sgonzo if (!MIPS_IS_VALID_KERNELADDR(pc)) { 210230094Sgonzo (*printfn) ("PC 0x%jx: not in kernel\n", pc); 211202046Simp ra = 0; 212202046Simp goto done; 213202046Simp } 214202046Simp /* 215202046Simp * Find the beginning of the current subroutine by scanning 216202046Simp * backwards from the current PC for the end of the previous 217202046Simp * subroutine. 218202046Simp */ 219202046Simp if (!subr) { 220202046Simp va = pc - sizeof(int); 221202046Simp while (1) { 222202046Simp instr = kdbpeek((int *)va); 223202046Simp 224202046Simp if (MIPS_START_OF_FUNCTION(instr)) 225202046Simp break; 226202046Simp 227202046Simp if (MIPS_END_OF_FUNCTION(instr)) { 228202046Simp /* skip over branch-delay slot instruction */ 229202046Simp va += 2 * sizeof(int); 230202046Simp break; 231202046Simp } 232202046Simp 233202046Simp va -= sizeof(int); 234202046Simp } 235202046Simp 236202046Simp /* skip over nulls which might separate .o files */ 237202046Simp while ((instr = kdbpeek((int *)va)) == 0) 238202046Simp va += sizeof(int); 239202046Simp subr = va; 240202046Simp } 241202046Simp /* scan forwards to find stack size and any saved registers */ 242202046Simp stksize = 0; 243202046Simp more = 3; 244202046Simp mask = 0; 245202046Simp for (va = subr; more; va += sizeof(int), 246202046Simp more = (more == 3) ? 3 : more - 1) { 247202046Simp /* stop if hit our current position */ 248202046Simp if (va >= pc) 249202046Simp break; 250202046Simp instr = kdbpeek((int *)va); 251202046Simp i.word = instr; 252202046Simp switch (i.JType.op) { 253202046Simp case OP_SPECIAL: 254202046Simp switch (i.RType.func) { 255202046Simp case OP_JR: 256202046Simp case OP_JALR: 257202046Simp more = 2; /* stop after next instruction */ 258202046Simp break; 259202046Simp 260202046Simp case OP_SYSCALL: 261202046Simp case OP_BREAK: 262202046Simp more = 1; /* stop now */ 263297793Spfg } 264202046Simp break; 265202046Simp 266202046Simp case OP_BCOND: 267202046Simp case OP_J: 268202046Simp case OP_JAL: 269202046Simp case OP_BEQ: 270202046Simp case OP_BNE: 271202046Simp case OP_BLEZ: 272202046Simp case OP_BGTZ: 273202046Simp more = 2; /* stop after next instruction */ 274202046Simp break; 275202046Simp 276202046Simp case OP_COP0: 277202046Simp case OP_COP1: 278202046Simp case OP_COP2: 279202046Simp case OP_COP3: 280202046Simp switch (i.RType.rs) { 281202046Simp case OP_BCx: 282202046Simp case OP_BCy: 283202046Simp more = 2; /* stop after next instruction */ 284297793Spfg } 285202046Simp break; 286202046Simp 287202046Simp case OP_SW: 288202046Simp /* look for saved registers on the stack */ 289202046Simp if (i.IType.rs != 29) 290202046Simp break; 291202046Simp /* only restore the first one */ 292202046Simp if (mask & (1 << i.IType.rt)) 293202046Simp break; 294202046Simp mask |= (1 << i.IType.rt); 295202046Simp switch (i.IType.rt) { 296202046Simp case 4:/* a0 */ 297202046Simp args[0] = kdbpeek((int *)(sp + (short)i.IType.imm)); 298202046Simp valid_args[0] = 1; 299202046Simp break; 300202046Simp 301202046Simp case 5:/* a1 */ 302202046Simp args[1] = kdbpeek((int *)(sp + (short)i.IType.imm)); 303202046Simp valid_args[1] = 1; 304202046Simp break; 305202046Simp 306202046Simp case 6:/* a2 */ 307202046Simp args[2] = kdbpeek((int *)(sp + (short)i.IType.imm)); 308202046Simp valid_args[2] = 1; 309202046Simp break; 310202046Simp 311202046Simp case 7:/* a3 */ 312202046Simp args[3] = kdbpeek((int *)(sp + (short)i.IType.imm)); 313202046Simp valid_args[3] = 1; 314202046Simp break; 315202046Simp 316202046Simp case 31: /* ra */ 317202046Simp ra = kdbpeek((int *)(sp + (short)i.IType.imm)); 318202046Simp } 319202046Simp break; 320202046Simp 321202046Simp case OP_SD: 322202046Simp /* look for saved registers on the stack */ 323202046Simp if (i.IType.rs != 29) 324202046Simp break; 325202046Simp /* only restore the first one */ 326202046Simp if (mask & (1 << i.IType.rt)) 327202046Simp break; 328202046Simp mask |= (1 << i.IType.rt); 329202046Simp switch (i.IType.rt) { 330202046Simp case 4:/* a0 */ 331230094Sgonzo args[0] = kdbpeekd((int *)(sp + (short)i.IType.imm)); 332202046Simp valid_args[0] = 1; 333202046Simp break; 334202046Simp 335202046Simp case 5:/* a1 */ 336230094Sgonzo args[1] = kdbpeekd((int *)(sp + (short)i.IType.imm)); 337202046Simp valid_args[1] = 1; 338202046Simp break; 339202046Simp 340202046Simp case 6:/* a2 */ 341230094Sgonzo args[2] = kdbpeekd((int *)(sp + (short)i.IType.imm)); 342202046Simp valid_args[2] = 1; 343202046Simp break; 344202046Simp 345202046Simp case 7:/* a3 */ 346230094Sgonzo args[3] = kdbpeekd((int *)(sp + (short)i.IType.imm)); 347202046Simp valid_args[3] = 1; 348202046Simp break; 349202046Simp 350202046Simp case 31: /* ra */ 351230094Sgonzo ra = kdbpeekd((int *)(sp + (short)i.IType.imm)); 352202046Simp } 353202046Simp break; 354202046Simp 355202046Simp case OP_ADDI: 356202046Simp case OP_ADDIU: 357228091Sgonzo case OP_DADDI: 358228091Sgonzo case OP_DADDIU: 359202046Simp /* look for stack pointer adjustment */ 360202046Simp if (i.IType.rs != 29 || i.IType.rt != 29) 361202046Simp break; 362202046Simp stksize = -((short)i.IType.imm); 363202046Simp } 364202046Simp } 365202046Simp 366202046Simpdone: 367202046Simp (*printfn) ("%s+%x (", fn_name(subr), pc - subr); 368202046Simp for (j = 0; j < 4; j ++) { 369202046Simp if (j > 0) 370202046Simp (*printfn)(","); 371202046Simp if (valid_args[j]) 372202046Simp (*printfn)("%x", args[j]); 373202046Simp else 374202046Simp (*printfn)("?"); 375202046Simp } 376202046Simp 377230094Sgonzo (*printfn) (") ra %jx sp %jx sz %d\n", ra, sp, stksize); 378202046Simp 379202046Simp if (ra) { 380202046Simp if (pc == ra && stksize == 0) 381202046Simp (*printfn) ("stacktrace: loop!\n"); 382202046Simp else { 383202046Simp pc = ra; 384202046Simp sp += stksize; 385202046Simp ra = 0; 386202046Simp goto loop; 387202046Simp } 388202046Simp } else { 389202046Simpfinish: 390202046Simp if (curproc) 391202046Simp (*printfn) ("pid %d\n", curproc->p_pid); 392202046Simp else 393202046Simp (*printfn) ("curproc NULL\n"); 394202046Simp } 395202046Simp} 396202046Simp 397202046Simp 398178172Simpint 399178172Simpdb_md_set_watchpoint(db_expr_t addr, db_expr_t size) 400178172Simp{ 401178172Simp 402178172Simp return(0); 403178172Simp} 404178172Simp 405178172Simp 406178172Simpint 407209935Sjchandradb_md_clr_watchpoint(db_expr_t addr, db_expr_t size) 408178172Simp{ 409178172Simp 410178172Simp return(0); 411178172Simp} 412178172Simp 413178172Simp 414178172Simpvoid 415178172Simpdb_md_list_watchpoints() 416178172Simp{ 417178172Simp} 418178172Simp 419178172Simpvoid 420178172Simpdb_trace_self(void) 421178172Simp{ 422178172Simp db_trace_thread (curthread, -1); 423178172Simp return; 424178172Simp} 425178172Simp 426178172Simpint 427178172Simpdb_trace_thread(struct thread *thr, int count) 428178172Simp{ 429202046Simp register_t pc, ra, sp; 430178172Simp struct pcb *ctx; 431178172Simp 432202046Simp if (thr == curthread) { 433209935Sjchandra sp = (register_t)(intptr_t)__builtin_frame_address(0); 434209935Sjchandra ra = (register_t)(intptr_t)__builtin_return_address(0); 435202046Simp 436202046Simp __asm __volatile( 437202046Simp "jal 99f\n" 438202046Simp "nop\n" 439202046Simp "99:\n" 440202046Simp "move %0, $31\n" /* get ra */ 441202046Simp "move $31, %1\n" /* restore ra */ 442202046Simp : "=r" (pc) 443202046Simp : "r" (ra)); 444202046Simp 445204997Sneel } else { 446204997Sneel ctx = kdb_thr_ctx(thr); 447249881Simp sp = (register_t)ctx->pcb_context[PCB_REG_SP]; 448249881Simp pc = (register_t)ctx->pcb_context[PCB_REG_PC]; 449249881Simp ra = (register_t)ctx->pcb_context[PCB_REG_RA]; 450202046Simp } 451202046Simp 452202046Simp stacktrace_subr(pc, sp, ra, 453202046Simp (int (*) (const char *, ...))db_printf); 454202046Simp 455202046Simp return (0); 456178172Simp} 457178172Simp 458178172Simpvoid 459178172Simpdb_show_mdpcpu(struct pcpu *pc) 460178172Simp{ 461178172Simp 462208392Sjhb db_printf("ipis = 0x%x\n", pc->pc_pending_ipis); 463178172Simp db_printf("next ASID = %d\n", pc->pc_next_asid); 464208392Sjhb db_printf("GENID = %d\n", pc->pc_asid_generation); 465178172Simp return; 466178172Simp} 467