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 */ 316fc729afSOlivier Houchard 326fc729afSOlivier Houchard #include <sys/cdefs.h> 336fc729afSOlivier Houchard __FBSDID("$FreeBSD$"); 346fc729afSOlivier Houchard #include <sys/param.h> 359cdb2bfcSOlivier Houchard #include <sys/systm.h> 366fc729afSOlivier Houchard 376fc729afSOlivier Houchard 386fc729afSOlivier Houchard #include <sys/proc.h> 392f6d0d8fSOlivier Houchard #include <sys/kdb.h> 408d511e2aSJeff Roberson #include <sys/stack.h> 416da235a3SAndrew Turner 426fc729afSOlivier Houchard #include <machine/armreg.h> 436fc729afSOlivier Houchard #include <machine/asm.h> 446fc729afSOlivier Houchard #include <machine/cpufunc.h> 456fc729afSOlivier Houchard #include <machine/db_machdep.h> 466004362eSDavid Schultz #include <machine/pcb.h> 473c90d1eaSRobert Watson #include <machine/stack.h> 486fc729afSOlivier Houchard #include <machine/vmparam.h> 496da235a3SAndrew Turner 506fc729afSOlivier Houchard #include <ddb/ddb.h> 516fc729afSOlivier Houchard #include <ddb/db_access.h> 526fc729afSOlivier Houchard #include <ddb/db_sym.h> 536fc729afSOlivier Houchard #include <ddb/db_output.h> 546fc729afSOlivier Houchard 5529ce0a2aSAndrew Turner static void 5629ce0a2aSAndrew Turner db_stack_trace_cmd(struct unwind_state *state) 5729ce0a2aSAndrew Turner { 5829ce0a2aSAndrew Turner const char *name; 5929ce0a2aSAndrew Turner db_expr_t value; 6029ce0a2aSAndrew Turner db_expr_t offset; 6129ce0a2aSAndrew Turner c_db_sym_t sym; 6229ce0a2aSAndrew Turner u_int reg, i; 6329ce0a2aSAndrew Turner char *sep; 64abf29ad1SIan Lepore uint16_t upd_mask; 65abf29ad1SIan Lepore bool finished; 6629ce0a2aSAndrew Turner 67abf29ad1SIan Lepore finished = false; 68abf29ad1SIan Lepore while (!finished) { 69*4a8169d9SAndrew Turner finished = unwind_stack_one(state, 1); 7029ce0a2aSAndrew Turner 7129ce0a2aSAndrew Turner /* Print the frame details */ 7229ce0a2aSAndrew Turner sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset); 7329ce0a2aSAndrew Turner if (sym == C_DB_SYM_NULL) { 7429ce0a2aSAndrew Turner value = 0; 7529ce0a2aSAndrew Turner name = "(null)"; 7629ce0a2aSAndrew Turner } else 7729ce0a2aSAndrew Turner db_symbol_values(sym, &name, &value); 7829ce0a2aSAndrew Turner db_printf("%s() at ", name); 7929ce0a2aSAndrew Turner db_printsym(state->start_pc, DB_STGY_PROC); 8029ce0a2aSAndrew Turner db_printf("\n"); 8129ce0a2aSAndrew Turner db_printf("\t pc = 0x%08x lr = 0x%08x (", state->start_pc, 8229ce0a2aSAndrew Turner state->registers[LR]); 8329ce0a2aSAndrew Turner db_printsym(state->registers[LR], DB_STGY_PROC); 8429ce0a2aSAndrew Turner db_printf(")\n"); 8529ce0a2aSAndrew Turner db_printf("\t sp = 0x%08x fp = 0x%08x", 8629ce0a2aSAndrew Turner state->registers[SP], state->registers[FP]); 8729ce0a2aSAndrew Turner 8829ce0a2aSAndrew Turner /* Don't print the registers we have already printed */ 89abf29ad1SIan Lepore upd_mask = state->update_mask & 90abf29ad1SIan Lepore ~((1 << SP) | (1 << FP) | (1 << LR) | (1 << PC)); 9129ce0a2aSAndrew Turner sep = "\n\t"; 92abf29ad1SIan Lepore for (i = 0, reg = 0; upd_mask != 0; upd_mask >>= 1, reg++) { 93abf29ad1SIan Lepore if ((upd_mask & 1) != 0) { 9429ce0a2aSAndrew Turner db_printf("%s%sr%d = 0x%08x", sep, 9529ce0a2aSAndrew Turner (reg < 10) ? " " : "", reg, 9629ce0a2aSAndrew Turner state->registers[reg]); 9729ce0a2aSAndrew Turner i++; 9829ce0a2aSAndrew Turner if (i == 2) { 9929ce0a2aSAndrew Turner sep = "\n\t"; 10029ce0a2aSAndrew Turner i = 0; 10129ce0a2aSAndrew Turner } else 10229ce0a2aSAndrew Turner sep = " "; 10329ce0a2aSAndrew Turner 10429ce0a2aSAndrew Turner } 10529ce0a2aSAndrew Turner } 10629ce0a2aSAndrew Turner db_printf("\n"); 107abf29ad1SIan Lepore 1086da235a3SAndrew Turner if (finished) 1096da235a3SAndrew Turner break; 1106da235a3SAndrew Turner 111d0e8071aSIan Lepore /* 112d0e8071aSIan Lepore * Stop if directed to do so, or if we've unwound back to the 113abf29ad1SIan Lepore * kernel entry point, or if the unwind function didn't change 114abf29ad1SIan Lepore * anything (to avoid getting stuck in this loop forever). 115abf29ad1SIan Lepore * If the latter happens, it's an indication that the unwind 116abf29ad1SIan Lepore * information is incorrect somehow for the function named in 117abf29ad1SIan Lepore * the last frame printed before you see the unwind failure 118abf29ad1SIan Lepore * message (maybe it needs a STOP_UNWINDING). 119abf29ad1SIan Lepore */ 1206da235a3SAndrew Turner if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) { 121abf29ad1SIan Lepore db_printf("Unable to unwind into user mode\n"); 122abf29ad1SIan Lepore finished = true; 123abf29ad1SIan Lepore } else if (state->update_mask == 0) { 124abf29ad1SIan Lepore db_printf("Unwind failure (no registers changed)\n"); 125abf29ad1SIan Lepore finished = true; 126abf29ad1SIan Lepore } 12729ce0a2aSAndrew Turner } 12829ce0a2aSAndrew Turner } 1296fc729afSOlivier Houchard 1306fc729afSOlivier Houchard /* XXX stubs */ 1316fc729afSOlivier Houchard void 1326fc729afSOlivier Houchard db_md_list_watchpoints() 1336fc729afSOlivier Houchard { 1346fc729afSOlivier Houchard } 1356fc729afSOlivier Houchard 1366fc729afSOlivier Houchard int 1376fc729afSOlivier Houchard db_md_clr_watchpoint(db_expr_t addr, db_expr_t size) 1386fc729afSOlivier Houchard { 1396fc729afSOlivier Houchard return (0); 1406fc729afSOlivier Houchard } 1416fc729afSOlivier Houchard 1426fc729afSOlivier Houchard int 1436fc729afSOlivier Houchard db_md_set_watchpoint(db_expr_t addr, db_expr_t size) 1446fc729afSOlivier Houchard { 1456fc729afSOlivier Houchard return (0); 1466fc729afSOlivier Houchard } 147fd32d93bSMarcel Moolenaar 1482f6d0d8fSOlivier Houchard int 1492f6d0d8fSOlivier Houchard db_trace_thread(struct thread *thr, int count) 1506fc729afSOlivier Houchard { 15129ce0a2aSAndrew Turner struct unwind_state state; 1522ffa4420SMarcel Moolenaar struct pcb *ctx; 1536fc729afSOlivier Houchard 1540cdf4611SGrzegorz Bernacki if (thr != curthread) { 1552ffa4420SMarcel Moolenaar ctx = kdb_thr_ctx(thr); 15629ce0a2aSAndrew Turner 157c4c27bc9SIan Lepore state.registers[FP] = ctx->pcb_regs.sf_r11; 158c4c27bc9SIan Lepore state.registers[SP] = ctx->pcb_regs.sf_sp; 159c4c27bc9SIan Lepore state.registers[LR] = ctx->pcb_regs.sf_lr; 160c4c27bc9SIan Lepore state.registers[PC] = ctx->pcb_regs.sf_pc; 16129ce0a2aSAndrew Turner 16229ce0a2aSAndrew Turner db_stack_trace_cmd(&state); 1630cdf4611SGrzegorz Bernacki } else 1640cdf4611SGrzegorz Bernacki db_trace_self(); 1652f6d0d8fSOlivier Houchard return (0); 1662f6d0d8fSOlivier Houchard } 1672f6d0d8fSOlivier Houchard 1682f6d0d8fSOlivier Houchard void 1692f6d0d8fSOlivier Houchard db_trace_self(void) 1702f6d0d8fSOlivier Houchard { 17129ce0a2aSAndrew Turner struct unwind_state state; 172d80f56e1SAndrew Turner uint32_t sp; 173d80f56e1SAndrew Turner 174d80f56e1SAndrew Turner /* Read the stack pointer */ 175d80f56e1SAndrew Turner __asm __volatile("mov %0, sp" : "=&r" (sp)); 17629ce0a2aSAndrew Turner 17729ce0a2aSAndrew Turner state.registers[FP] = (uint32_t)__builtin_frame_address(0); 178d80f56e1SAndrew Turner state.registers[SP] = sp; 17929ce0a2aSAndrew Turner state.registers[LR] = (uint32_t)__builtin_return_address(0); 18029ce0a2aSAndrew Turner state.registers[PC] = (uint32_t)db_trace_self; 18129ce0a2aSAndrew Turner 18229ce0a2aSAndrew Turner db_stack_trace_cmd(&state); 1836fc729afSOlivier Houchard } 184