16fc729afSOlivier Houchard /* $NetBSD: db_trace.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $ */ 26fc729afSOlivier Houchard 3d8315c79SWarner Losh /*- 46fc729afSOlivier Houchard * Copyright (c) 2000, 2001 Ben Harris 56fc729afSOlivier Houchard * Copyright (c) 1996 Scott K. Stevens 66fc729afSOlivier Houchard * 76fc729afSOlivier Houchard * Mach Operating System 86fc729afSOlivier Houchard * Copyright (c) 1991,1990 Carnegie Mellon University 96fc729afSOlivier Houchard * All Rights Reserved. 106fc729afSOlivier Houchard * 116fc729afSOlivier Houchard * Permission to use, copy, modify and distribute this software and its 126fc729afSOlivier Houchard * documentation is hereby granted, provided that both the copyright 136fc729afSOlivier Houchard * notice and this permission notice appear in all copies of the 146fc729afSOlivier Houchard * software, derivative works or modified versions, and any portions 156fc729afSOlivier Houchard * thereof, and that both notices appear in supporting documentation. 166fc729afSOlivier Houchard * 176fc729afSOlivier Houchard * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 186fc729afSOlivier Houchard * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 196fc729afSOlivier Houchard * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 206fc729afSOlivier Houchard * 216fc729afSOlivier Houchard * Carnegie Mellon requests users of this software to return to 226fc729afSOlivier Houchard * 236fc729afSOlivier Houchard * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 246fc729afSOlivier Houchard * School of Computer Science 256fc729afSOlivier Houchard * Carnegie Mellon University 266fc729afSOlivier Houchard * Pittsburgh PA 15213-3890 276fc729afSOlivier Houchard * 286fc729afSOlivier Houchard * any improvements or extensions that they make and grant Carnegie the 296fc729afSOlivier Houchard * rights to redistribute these changes. 306fc729afSOlivier Houchard */ 31*595f8a59SZbigniew Bodek #include "opt_ddb.h" 326fc729afSOlivier Houchard 336fc729afSOlivier Houchard #include <sys/cdefs.h> 346fc729afSOlivier Houchard __FBSDID("$FreeBSD$"); 356fc729afSOlivier Houchard #include <sys/param.h> 369cdb2bfcSOlivier Houchard #include <sys/systm.h> 376fc729afSOlivier Houchard 386fc729afSOlivier Houchard 396fc729afSOlivier Houchard #include <sys/proc.h> 402f6d0d8fSOlivier Houchard #include <sys/kdb.h> 418d511e2aSJeff Roberson #include <sys/stack.h> 426da235a3SAndrew Turner 436fc729afSOlivier Houchard #include <machine/armreg.h> 446fc729afSOlivier Houchard #include <machine/asm.h> 456fc729afSOlivier Houchard #include <machine/cpufunc.h> 466fc729afSOlivier Houchard #include <machine/db_machdep.h> 47*595f8a59SZbigniew Bodek #include <machine/debug_monitor.h> 486004362eSDavid Schultz #include <machine/pcb.h> 493c90d1eaSRobert Watson #include <machine/stack.h> 506fc729afSOlivier Houchard #include <machine/vmparam.h> 516da235a3SAndrew Turner 526fc729afSOlivier Houchard #include <ddb/ddb.h> 536fc729afSOlivier Houchard #include <ddb/db_access.h> 546fc729afSOlivier Houchard #include <ddb/db_sym.h> 556fc729afSOlivier Houchard #include <ddb/db_output.h> 566fc729afSOlivier Houchard 5729ce0a2aSAndrew Turner static void 5829ce0a2aSAndrew Turner db_stack_trace_cmd(struct unwind_state *state) 5929ce0a2aSAndrew Turner { 6029ce0a2aSAndrew Turner const char *name; 6129ce0a2aSAndrew Turner db_expr_t value; 6229ce0a2aSAndrew Turner db_expr_t offset; 6329ce0a2aSAndrew Turner c_db_sym_t sym; 6429ce0a2aSAndrew Turner u_int reg, i; 6529ce0a2aSAndrew Turner char *sep; 66abf29ad1SIan Lepore uint16_t upd_mask; 67abf29ad1SIan Lepore bool finished; 6829ce0a2aSAndrew Turner 69abf29ad1SIan Lepore finished = false; 70abf29ad1SIan Lepore while (!finished) { 714a8169d9SAndrew Turner finished = unwind_stack_one(state, 1); 7229ce0a2aSAndrew Turner 7329ce0a2aSAndrew Turner /* Print the frame details */ 7429ce0a2aSAndrew Turner sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset); 7529ce0a2aSAndrew Turner if (sym == C_DB_SYM_NULL) { 7629ce0a2aSAndrew Turner value = 0; 7729ce0a2aSAndrew Turner name = "(null)"; 7829ce0a2aSAndrew Turner } else 7929ce0a2aSAndrew Turner db_symbol_values(sym, &name, &value); 8029ce0a2aSAndrew Turner db_printf("%s() at ", name); 8129ce0a2aSAndrew Turner db_printsym(state->start_pc, DB_STGY_PROC); 8229ce0a2aSAndrew Turner db_printf("\n"); 8329ce0a2aSAndrew Turner db_printf("\t pc = 0x%08x lr = 0x%08x (", state->start_pc, 8429ce0a2aSAndrew Turner state->registers[LR]); 8529ce0a2aSAndrew Turner db_printsym(state->registers[LR], DB_STGY_PROC); 8629ce0a2aSAndrew Turner db_printf(")\n"); 8729ce0a2aSAndrew Turner db_printf("\t sp = 0x%08x fp = 0x%08x", 8829ce0a2aSAndrew Turner state->registers[SP], state->registers[FP]); 8929ce0a2aSAndrew Turner 9029ce0a2aSAndrew Turner /* Don't print the registers we have already printed */ 91abf29ad1SIan Lepore upd_mask = state->update_mask & 92abf29ad1SIan Lepore ~((1 << SP) | (1 << FP) | (1 << LR) | (1 << PC)); 9329ce0a2aSAndrew Turner sep = "\n\t"; 94abf29ad1SIan Lepore for (i = 0, reg = 0; upd_mask != 0; upd_mask >>= 1, reg++) { 95abf29ad1SIan Lepore if ((upd_mask & 1) != 0) { 9629ce0a2aSAndrew Turner db_printf("%s%sr%d = 0x%08x", sep, 9729ce0a2aSAndrew Turner (reg < 10) ? " " : "", reg, 9829ce0a2aSAndrew Turner state->registers[reg]); 9929ce0a2aSAndrew Turner i++; 10029ce0a2aSAndrew Turner if (i == 2) { 10129ce0a2aSAndrew Turner sep = "\n\t"; 10229ce0a2aSAndrew Turner i = 0; 10329ce0a2aSAndrew Turner } else 10429ce0a2aSAndrew Turner sep = " "; 10529ce0a2aSAndrew Turner 10629ce0a2aSAndrew Turner } 10729ce0a2aSAndrew Turner } 10829ce0a2aSAndrew Turner db_printf("\n"); 109abf29ad1SIan Lepore 1106da235a3SAndrew Turner if (finished) 1116da235a3SAndrew Turner break; 1126da235a3SAndrew Turner 113d0e8071aSIan Lepore /* 114d0e8071aSIan Lepore * Stop if directed to do so, or if we've unwound back to the 115abf29ad1SIan Lepore * kernel entry point, or if the unwind function didn't change 116abf29ad1SIan Lepore * anything (to avoid getting stuck in this loop forever). 117abf29ad1SIan Lepore * If the latter happens, it's an indication that the unwind 118abf29ad1SIan Lepore * information is incorrect somehow for the function named in 119abf29ad1SIan Lepore * the last frame printed before you see the unwind failure 120abf29ad1SIan Lepore * message (maybe it needs a STOP_UNWINDING). 121abf29ad1SIan Lepore */ 1226da235a3SAndrew Turner if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) { 123abf29ad1SIan Lepore db_printf("Unable to unwind into user mode\n"); 124abf29ad1SIan Lepore finished = true; 125abf29ad1SIan Lepore } else if (state->update_mask == 0) { 126abf29ad1SIan Lepore db_printf("Unwind failure (no registers changed)\n"); 127abf29ad1SIan Lepore finished = true; 128abf29ad1SIan Lepore } 12929ce0a2aSAndrew Turner } 13029ce0a2aSAndrew Turner } 1316fc729afSOlivier Houchard 1326fc729afSOlivier Houchard void 1336fc729afSOlivier Houchard db_md_list_watchpoints() 1346fc729afSOlivier Houchard { 135*595f8a59SZbigniew Bodek 136*595f8a59SZbigniew Bodek dbg_show_watchpoint(); 1376fc729afSOlivier Houchard } 1386fc729afSOlivier Houchard 1396fc729afSOlivier Houchard int 1406fc729afSOlivier Houchard db_md_clr_watchpoint(db_expr_t addr, db_expr_t size) 1416fc729afSOlivier Houchard { 142*595f8a59SZbigniew Bodek 143*595f8a59SZbigniew Bodek return (dbg_remove_watchpoint(addr, size)); 1446fc729afSOlivier Houchard } 1456fc729afSOlivier Houchard 1466fc729afSOlivier Houchard int 1476fc729afSOlivier Houchard db_md_set_watchpoint(db_expr_t addr, db_expr_t size) 1486fc729afSOlivier Houchard { 149*595f8a59SZbigniew Bodek 150*595f8a59SZbigniew Bodek return (dbg_setup_watchpoint(addr, size, HW_WATCHPOINT_RW)); 1516fc729afSOlivier Houchard } 152fd32d93bSMarcel Moolenaar 1532f6d0d8fSOlivier Houchard int 1542f6d0d8fSOlivier Houchard db_trace_thread(struct thread *thr, int count) 1556fc729afSOlivier Houchard { 15629ce0a2aSAndrew Turner struct unwind_state state; 1572ffa4420SMarcel Moolenaar struct pcb *ctx; 1586fc729afSOlivier Houchard 1590cdf4611SGrzegorz Bernacki if (thr != curthread) { 1602ffa4420SMarcel Moolenaar ctx = kdb_thr_ctx(thr); 16129ce0a2aSAndrew Turner 162c4c27bc9SIan Lepore state.registers[FP] = ctx->pcb_regs.sf_r11; 163c4c27bc9SIan Lepore state.registers[SP] = ctx->pcb_regs.sf_sp; 164c4c27bc9SIan Lepore state.registers[LR] = ctx->pcb_regs.sf_lr; 165c4c27bc9SIan Lepore state.registers[PC] = ctx->pcb_regs.sf_pc; 16629ce0a2aSAndrew Turner 16729ce0a2aSAndrew Turner db_stack_trace_cmd(&state); 1680cdf4611SGrzegorz Bernacki } else 1690cdf4611SGrzegorz Bernacki db_trace_self(); 1702f6d0d8fSOlivier Houchard return (0); 1712f6d0d8fSOlivier Houchard } 1722f6d0d8fSOlivier Houchard 1732f6d0d8fSOlivier Houchard void 1742f6d0d8fSOlivier Houchard db_trace_self(void) 1752f6d0d8fSOlivier Houchard { 17629ce0a2aSAndrew Turner struct unwind_state state; 177d80f56e1SAndrew Turner uint32_t sp; 178d80f56e1SAndrew Turner 179d80f56e1SAndrew Turner /* Read the stack pointer */ 180d80f56e1SAndrew Turner __asm __volatile("mov %0, sp" : "=&r" (sp)); 18129ce0a2aSAndrew Turner 18229ce0a2aSAndrew Turner state.registers[FP] = (uint32_t)__builtin_frame_address(0); 183d80f56e1SAndrew Turner state.registers[SP] = sp; 18429ce0a2aSAndrew Turner state.registers[LR] = (uint32_t)__builtin_return_address(0); 18529ce0a2aSAndrew Turner state.registers[PC] = (uint32_t)db_trace_self; 18629ce0a2aSAndrew Turner 18729ce0a2aSAndrew Turner db_stack_trace_cmd(&state); 1886fc729afSOlivier Houchard } 189