1*949c1c4eSmiod /* $OpenBSD: db_trace.c,v 1.21 2024/11/07 16:02:29 miod Exp $ */ 284c41355Smiod /* $NetBSD: db_trace.c,v 1.15 1996/02/22 23:23:41 gwr Exp $ */ 384c41355Smiod 484c41355Smiod /* 584c41355Smiod * Mach Operating System 684c41355Smiod * Copyright (c) 1992 Carnegie Mellon University 784c41355Smiod * All Rights Reserved. 884c41355Smiod * 984c41355Smiod * Permission to use, copy, modify and distribute this software and its 1084c41355Smiod * documentation is hereby granted, provided that both the copyright 1184c41355Smiod * notice and this permission notice appear in all copies of the 1284c41355Smiod * software, derivative works or modified versions, and any portions 1384c41355Smiod * thereof, and that both notices appear in supporting documentation. 1484c41355Smiod * 1584c41355Smiod * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 1684c41355Smiod * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 1784c41355Smiod * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 1884c41355Smiod * 1984c41355Smiod * Carnegie Mellon requests users of this software to return to 2084c41355Smiod * 2184c41355Smiod * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 2284c41355Smiod * School of Computer Science 2384c41355Smiod * Carnegie Mellon University 2484c41355Smiod * Pittsburgh PA 15213-3890 2584c41355Smiod * 2684c41355Smiod * any improvements or extensions that they make and grant Carnegie Mellon 2784c41355Smiod * the rights to redistribute these changes. 2884c41355Smiod */ 2984c41355Smiod 3084c41355Smiod #include <sys/param.h> 3184c41355Smiod #include <sys/systm.h> 3284c41355Smiod #include <sys/proc.h> 33390e38f1Smpi #include <sys/user.h> 342877cd17Smpi #include <sys/stacktrace.h> 35390e38f1Smpi 36390e38f1Smpi #include <uvm/uvm_extern.h> 3784c41355Smiod 3884c41355Smiod #include <machine/db_machdep.h> 3984c41355Smiod #include <machine/signal.h> 4084c41355Smiod #include <machine/pcb.h> 41390e38f1Smpi #include <machine/pmap.h> 4284c41355Smiod 4384c41355Smiod #include <ddb/db_access.h> 4484c41355Smiod #include <ddb/db_sym.h> 4584c41355Smiod #include <ddb/db_variables.h> 4684c41355Smiod #include <ddb/db_interface.h> 4784c41355Smiod #include <ddb/db_output.h> 4884c41355Smiod 498070687fSjason db_regs_t ddb_regs; 508070687fSjason 5184c41355Smiod struct db_variable db_regs[] = { 52f12e1735Smpi { "r0", (long *)&ddb_regs.fixreg[0], FCN_NULL }, 53f12e1735Smpi { "r1", (long *)&ddb_regs.fixreg[1], FCN_NULL }, 54f12e1735Smpi { "r2", (long *)&ddb_regs.fixreg[2], FCN_NULL }, 55f12e1735Smpi { "r3", (long *)&ddb_regs.fixreg[3], FCN_NULL }, 56f12e1735Smpi { "r4", (long *)&ddb_regs.fixreg[4], FCN_NULL }, 57f12e1735Smpi { "r5", (long *)&ddb_regs.fixreg[5], FCN_NULL }, 58f12e1735Smpi { "r6", (long *)&ddb_regs.fixreg[6], FCN_NULL }, 59f12e1735Smpi { "r7", (long *)&ddb_regs.fixreg[7], FCN_NULL }, 60f12e1735Smpi { "r8", (long *)&ddb_regs.fixreg[8], FCN_NULL }, 61f12e1735Smpi { "r9", (long *)&ddb_regs.fixreg[9], FCN_NULL }, 62f12e1735Smpi { "r10", (long *)&ddb_regs.fixreg[10], FCN_NULL }, 63f12e1735Smpi { "r11", (long *)&ddb_regs.fixreg[11], FCN_NULL }, 64f12e1735Smpi { "r12", (long *)&ddb_regs.fixreg[12], FCN_NULL }, 65f12e1735Smpi { "r13", (long *)&ddb_regs.fixreg[13], FCN_NULL }, 662987d5a7Sgkoehler { "r14", (long *)&ddb_regs.fixreg[14], FCN_NULL }, 672987d5a7Sgkoehler { "r15", (long *)&ddb_regs.fixreg[15], FCN_NULL }, 682987d5a7Sgkoehler { "r16", (long *)&ddb_regs.fixreg[16], FCN_NULL }, 69f12e1735Smpi { "r17", (long *)&ddb_regs.fixreg[17], FCN_NULL }, 70f12e1735Smpi { "r18", (long *)&ddb_regs.fixreg[18], FCN_NULL }, 71f12e1735Smpi { "r19", (long *)&ddb_regs.fixreg[19], FCN_NULL }, 72f12e1735Smpi { "r20", (long *)&ddb_regs.fixreg[20], FCN_NULL }, 73f12e1735Smpi { "r21", (long *)&ddb_regs.fixreg[21], FCN_NULL }, 74f12e1735Smpi { "r22", (long *)&ddb_regs.fixreg[22], FCN_NULL }, 75f12e1735Smpi { "r23", (long *)&ddb_regs.fixreg[23], FCN_NULL }, 76f12e1735Smpi { "r24", (long *)&ddb_regs.fixreg[24], FCN_NULL }, 77f12e1735Smpi { "r25", (long *)&ddb_regs.fixreg[25], FCN_NULL }, 78f12e1735Smpi { "r26", (long *)&ddb_regs.fixreg[26], FCN_NULL }, 79f12e1735Smpi { "r27", (long *)&ddb_regs.fixreg[27], FCN_NULL }, 80f12e1735Smpi { "r28", (long *)&ddb_regs.fixreg[28], FCN_NULL }, 81f12e1735Smpi { "r29", (long *)&ddb_regs.fixreg[29], FCN_NULL }, 82f12e1735Smpi { "r30", (long *)&ddb_regs.fixreg[30], FCN_NULL }, 83f12e1735Smpi { "r31", (long *)&ddb_regs.fixreg[31], FCN_NULL }, 84f12e1735Smpi { "lr", (long *)&ddb_regs.lr, FCN_NULL }, 85f12e1735Smpi { "cr", (long *)&ddb_regs.cr, FCN_NULL }, 86f12e1735Smpi { "xer", (long *)&ddb_regs.xer, FCN_NULL }, 87f12e1735Smpi { "ctr", (long *)&ddb_regs.ctr, FCN_NULL }, 88f12e1735Smpi { "iar", (long *)&ddb_regs.srr0, FCN_NULL }, 89f12e1735Smpi { "msr", (long *)&ddb_regs.srr1, FCN_NULL }, 902987d5a7Sgkoehler { "dar", (long *)&ddb_regs.dar, FCN_NULL }, 912987d5a7Sgkoehler { "dsisr", (long *)&ddb_regs.dsisr, FCN_NULL }, 9284c41355Smiod }; 93eaf55909Sdrahn 9485882e82Sjasper struct db_variable *db_eregs = db_regs + nitems(db_regs); 9584c41355Smiod 9684c41355Smiod /* 9784c41355Smiod * this is probably hackery. 9884c41355Smiod */ 9984c41355Smiod void 10084c41355Smiod db_save_regs(struct trapframe *frame) 10184c41355Smiod { 102f12e1735Smpi bcopy(frame, &ddb_regs, sizeof (struct trapframe)); 10384c41355Smiod } 10484c41355Smiod 105390e38f1Smpi /* from locore.S */ 10652de38dfSmpi extern vaddr_t trapexit; 107390e38f1Smpi #define INTSTK (8*1024) /* 8K interrupt stack */ 10884c41355Smiod 109390e38f1Smpi #define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS && \ 110390e38f1Smpi ((vaddr_t)(va)) < VM_MAX_KERNEL_ADDRESS) 11184c41355Smiod 11295573559Sgkoehler #define ININTSTK(va) db_in_interrupt_stack((vaddr_t)(va)) 11395573559Sgkoehler 11495573559Sgkoehler int 11595573559Sgkoehler db_in_interrupt_stack(vaddr_t va) 11695573559Sgkoehler { 11795573559Sgkoehler struct cpu_info *ci; 11895573559Sgkoehler CPU_INFO_ITERATOR cii; 11995573559Sgkoehler vaddr_t stack; 12095573559Sgkoehler 12195573559Sgkoehler CPU_INFO_FOREACH(cii, ci) { 12295573559Sgkoehler stack = (vaddr_t)ci->ci_intstk; 12395573559Sgkoehler if (va >= stack - INTSTK && va < stack) 12495573559Sgkoehler return 1; 12595573559Sgkoehler } 12695573559Sgkoehler return 0; 12795573559Sgkoehler } 128eaf55909Sdrahn 12984c41355Smiod /* 13084c41355Smiod * Frame tracing. 13184c41355Smiod */ 13284c41355Smiod void 133eaf55909Sdrahn db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, 134eaf55909Sdrahn char *modif, int (*pr)(const char *, ...)) 13584c41355Smiod { 13652de38dfSmpi vaddr_t lr, sp, lastsp, *db_fp_args; 137390e38f1Smpi db_expr_t offset; 13862781896Smpi Elf_Sym *sym; 139*949c1c4eSmiod const char *name; 140390e38f1Smpi char c, *cp = modif; 14169993134Sjasper int i, narg, trace_proc = 0; 14284c41355Smiod 143390e38f1Smpi while ((c = *cp++) != 0) { 1447c8c9e97Smpi if (c == 't') 145390e38f1Smpi trace_proc = 1; 14684c41355Smiod } 147390e38f1Smpi 148390e38f1Smpi if (!have_addr) { 149f12e1735Smpi sp = ddb_regs.fixreg[1]; 150f12e1735Smpi lr = ddb_regs.srr0; 151390e38f1Smpi } else { 152390e38f1Smpi if (trace_proc) { 15369e7eddbSmpi struct proc *p = tfind((pid_t)addr); 154390e38f1Smpi if (p == NULL) { 1554c5c9f90Sjasper (*pr) ("not found\n"); 156390e38f1Smpi return; 15784c41355Smiod } 158390e38f1Smpi addr = p->p_addr->u_pcb.pcb_sp; 159390e38f1Smpi } 160390e38f1Smpi sp = addr; 16152de38dfSmpi db_read_bytes(sp + 4, sizeof(vaddr_t), (char *)&lr); 162390e38f1Smpi } 163390e38f1Smpi 164390e38f1Smpi while (count && sp != 0) { 165390e38f1Smpi /* 166390e38f1Smpi * lr contains the return address, so adjust its value 167390e38f1Smpi * to display the offset of the calling address. 168390e38f1Smpi */ 169390e38f1Smpi sym = db_search_symbol(lr - 4, DB_STGY_ANY, &offset); 170390e38f1Smpi db_symbol_values(sym, &name, NULL); 171390e38f1Smpi 172390e38f1Smpi if (name == NULL || strcmp(name, "end") == 0) { 173390e38f1Smpi (*pr)("at 0x%lx", lr - 4); 174390e38f1Smpi } else { 17569993134Sjasper narg = db_ctf_func_numargs(sym); 17669993134Sjasper if (narg < 0 || narg > 8) 17769993134Sjasper narg = 8; 17869993134Sjasper 17969993134Sjasper (*pr)("%s(", name); 18069993134Sjasper 18169993134Sjasper if (narg > 0) { 18252de38dfSmpi db_fp_args = (vaddr_t *)(sp + 8); 18369993134Sjasper 18469993134Sjasper for (i = 0; i < narg; i++) { 18569993134Sjasper (*pr)("%lx", db_fp_args[i]); 18669993134Sjasper if (i != (narg-1)) 18769993134Sjasper (*pr)(","); 18869993134Sjasper } 18969993134Sjasper } 19069993134Sjasper 19169993134Sjasper (*pr)(") at "); 192390e38f1Smpi db_printsym(lr - 4, DB_STGY_PROC, pr); 193390e38f1Smpi } 194390e38f1Smpi (*pr)("\n"); 195390e38f1Smpi 196390e38f1Smpi lastsp = sp; 197390e38f1Smpi 198390e38f1Smpi /* 199390e38f1Smpi * Abuse the fact that the return address of the trap() 200390e38f1Smpi * function is always 'trapexit'. 201390e38f1Smpi */ 20252de38dfSmpi if (lr == (vaddr_t)&trapexit) { 203390e38f1Smpi struct trapframe *tf = (struct trapframe *)(sp + 8); 204390e38f1Smpi uint32_t code = tf->fixreg[0]; 205390e38f1Smpi uint32_t type = tf->exc; 206390e38f1Smpi 207390e38f1Smpi if (tf->srr1 & PSL_PR) 208390e38f1Smpi type |= EXC_USER; 209390e38f1Smpi 210390e38f1Smpi if (type == (EXC_SC|EXC_USER)) 211390e38f1Smpi (*pr)("--- syscall (number %d) ---\n", code); 212390e38f1Smpi else 213390e38f1Smpi (*pr)("--- trap (type 0x%x) ---\n", type); 214390e38f1Smpi } 215390e38f1Smpi 21652de38dfSmpi db_read_bytes(sp, sizeof(vaddr_t), (char *)&sp); 217390e38f1Smpi if (sp == 0) 218390e38f1Smpi break; 219390e38f1Smpi 22052de38dfSmpi db_read_bytes(sp + 4, sizeof(vaddr_t), (char *)&lr); 221390e38f1Smpi 222390e38f1Smpi if (INKERNEL(sp)) { 223390e38f1Smpi if (sp <= lastsp) { 224390e38f1Smpi (*pr)("Bad frame pointer: 0x%lx\n", sp); 225390e38f1Smpi break; 226390e38f1Smpi } 227390e38f1Smpi 228390e38f1Smpi if (ININTSTK(lastsp)) 229390e38f1Smpi (*pr)("--- interrupt ---\n"); 230390e38f1Smpi 231390e38f1Smpi } else { 232390e38f1Smpi if (!ININTSTK(sp)) { 233390e38f1Smpi (*pr)("End of kernel: 0x%lx\n", sp); 234390e38f1Smpi break; 235390e38f1Smpi } 236390e38f1Smpi } 237390e38f1Smpi --count; 238390e38f1Smpi } 239390e38f1Smpi (*pr)("end trace frame: 0x%lx, count: %d\n", sp, count); 24084c41355Smiod } 2412877cd17Smpi 2422877cd17Smpi void 2432877cd17Smpi stacktrace_save_at(struct stacktrace *st, unsigned int skip) 2442877cd17Smpi { 2452877cd17Smpi vaddr_t lr, sp, lastsp; 2462877cd17Smpi 2472877cd17Smpi sp = (vaddr_t)__builtin_frame_address(0); 2482877cd17Smpi if (!INKERNEL(sp) && !ININTSTK(sp)) 2492877cd17Smpi return; 2502877cd17Smpi 2512877cd17Smpi st->st_count = 0; 2522877cd17Smpi while (st->st_count < STACKTRACE_MAX) { 2532877cd17Smpi lr = *(vaddr_t *)(sp + 4) - 4; 2542877cd17Smpi if (lr & 3) 2552877cd17Smpi break; 2562877cd17Smpi 2572877cd17Smpi if (skip == 0) 2582877cd17Smpi st->st_pc[st->st_count++] = lr; 2592877cd17Smpi else 2602877cd17Smpi skip--; 2612877cd17Smpi 2622877cd17Smpi lastsp = sp; 2632877cd17Smpi sp = *(vaddr_t *)sp; 2642877cd17Smpi 2652877cd17Smpi if ((sp == 0) || (sp & 3) || (sp <= lastsp)) 2662877cd17Smpi break; 2672877cd17Smpi if (!INKERNEL(sp) && !ININTSTK(sp)) 2682877cd17Smpi break; 2692877cd17Smpi } 2702877cd17Smpi } 271a28bb56fSclaudio 272a28bb56fSclaudio void 273a28bb56fSclaudio stacktrace_save_utrace(struct stacktrace *st) 274a28bb56fSclaudio { 275a28bb56fSclaudio st->st_count = 0; 276a28bb56fSclaudio } 277