1 /* $OpenBSD: db_trace.c,v 1.10 2024/11/07 16:02:29 miod Exp $ */ 2 /* $NetBSD: db_trace.c,v 1.15 1996/02/22 23:23:41 gwr Exp $ */ 3 4 /* 5 * Mach Operating System 6 * Copyright (c) 1992 Carnegie Mellon University 7 * All Rights Reserved. 8 * 9 * Permission to use, copy, modify and distribute this software and its 10 * documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 17 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie Mellon 27 * the rights to redistribute these changes. 28 */ 29 30 #include <sys/param.h> 31 #include <sys/proc.h> 32 #include <sys/stacktrace.h> 33 #include <sys/systm.h> 34 #include <sys/user.h> 35 36 #include <machine/db_machdep.h> 37 38 #include <ddb/db_access.h> 39 #include <ddb/db_interface.h> 40 #include <ddb/db_sym.h> 41 #include <ddb/db_variables.h> 42 43 db_regs_t ddb_regs; 44 45 struct db_variable db_regs[] = { 46 { "r0", (long *)&ddb_regs.fixreg[0], FCN_NULL }, 47 { "r1", (long *)&ddb_regs.fixreg[1], FCN_NULL }, 48 { "r2", (long *)&ddb_regs.fixreg[2], FCN_NULL }, 49 { "r3", (long *)&ddb_regs.fixreg[3], FCN_NULL }, 50 { "r4", (long *)&ddb_regs.fixreg[4], FCN_NULL }, 51 { "r5", (long *)&ddb_regs.fixreg[5], FCN_NULL }, 52 { "r6", (long *)&ddb_regs.fixreg[6], FCN_NULL }, 53 { "r7", (long *)&ddb_regs.fixreg[7], FCN_NULL }, 54 { "r8", (long *)&ddb_regs.fixreg[8], FCN_NULL }, 55 { "r9", (long *)&ddb_regs.fixreg[9], FCN_NULL }, 56 { "r10", (long *)&ddb_regs.fixreg[10], FCN_NULL }, 57 { "r11", (long *)&ddb_regs.fixreg[11], FCN_NULL }, 58 { "r12", (long *)&ddb_regs.fixreg[12], FCN_NULL }, 59 { "r13", (long *)&ddb_regs.fixreg[13], FCN_NULL }, 60 { "r14", (long *)&ddb_regs.fixreg[14], FCN_NULL }, 61 { "r15", (long *)&ddb_regs.fixreg[15], FCN_NULL }, 62 { "r16", (long *)&ddb_regs.fixreg[16], FCN_NULL }, 63 { "r17", (long *)&ddb_regs.fixreg[17], FCN_NULL }, 64 { "r18", (long *)&ddb_regs.fixreg[18], FCN_NULL }, 65 { "r19", (long *)&ddb_regs.fixreg[19], FCN_NULL }, 66 { "r20", (long *)&ddb_regs.fixreg[20], FCN_NULL }, 67 { "r21", (long *)&ddb_regs.fixreg[21], FCN_NULL }, 68 { "r22", (long *)&ddb_regs.fixreg[22], FCN_NULL }, 69 { "r23", (long *)&ddb_regs.fixreg[23], FCN_NULL }, 70 { "r24", (long *)&ddb_regs.fixreg[24], FCN_NULL }, 71 { "r25", (long *)&ddb_regs.fixreg[25], FCN_NULL }, 72 { "r26", (long *)&ddb_regs.fixreg[26], FCN_NULL }, 73 { "r27", (long *)&ddb_regs.fixreg[27], FCN_NULL }, 74 { "r28", (long *)&ddb_regs.fixreg[28], FCN_NULL }, 75 { "r29", (long *)&ddb_regs.fixreg[29], FCN_NULL }, 76 { "r30", (long *)&ddb_regs.fixreg[30], FCN_NULL }, 77 { "r31", (long *)&ddb_regs.fixreg[31], FCN_NULL }, 78 { "lr", (long *)&ddb_regs.lr, FCN_NULL }, 79 { "cr", (long *)&ddb_regs.cr, FCN_NULL }, 80 { "xer", (long *)&ddb_regs.xer, FCN_NULL }, 81 { "ctr", (long *)&ddb_regs.ctr, FCN_NULL }, 82 { "iar", (long *)&ddb_regs.srr0, FCN_NULL }, 83 { "msr", (long *)&ddb_regs.srr1, FCN_NULL }, 84 { "dar", (long *)&ddb_regs.dar, FCN_NULL }, 85 { "dsisr", (long *)&ddb_regs.dsisr, FCN_NULL }, 86 }; 87 88 struct db_variable *db_eregs = db_regs + nitems(db_regs); 89 90 extern vaddr_t trapexit; 91 92 /* stdu r1,_(r1) */ 93 #define inst_establish_frame(ins) ((ins & 0xffff0003) == 0xf8210001) 94 95 void 96 db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, 97 char *modif, int (*pr)(const char *, ...)) 98 { 99 vaddr_t callpc, lr, sp, lastsp; 100 db_expr_t offset; 101 const char *name; 102 char c, *cp = modif; 103 Elf_Sym *sym; 104 int has_frame, trace_proc = 0; 105 int end_trace = 0; 106 107 while ((c = *cp++) != 0) { 108 if (c == 't') 109 trace_proc = 1; 110 } 111 112 if (!have_addr) { 113 sp = ddb_regs.fixreg[1]; 114 callpc = ddb_regs.srr0; 115 has_frame = 0; 116 } else { 117 if (trace_proc) { 118 (*pr)("trace/t not yet implemented!\n"); 119 return; 120 } else 121 sp = addr; 122 /* The 1st return address is in the 2nd frame. */ 123 db_read_bytes(sp, sizeof(vaddr_t), (char *)&sp); 124 db_read_bytes(sp + 16, sizeof(vaddr_t), (char *)&lr); 125 callpc = lr - 4; 126 has_frame = 1; 127 } 128 129 while (count && sp != 0) { 130 sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); 131 db_symbol_values(sym, &name, NULL); 132 133 /* Guess whether this function has a stack frame. */ 134 if (!has_frame && sym) { 135 vaddr_t iaddr, limit; 136 uint32_t ins; 137 138 iaddr = sym->st_value; 139 limit = MIN(iaddr + 0x100, callpc); 140 for (; iaddr < limit; iaddr += 4) { 141 db_read_bytes(iaddr, sizeof(ins), 142 (char *)&ins); 143 if (inst_establish_frame(ins)) { 144 has_frame = 1; 145 break; 146 } 147 } 148 } 149 150 if (name == NULL || strcmp(name, "end") == 0) { 151 (*pr)("at 0x%lx", callpc); 152 } else { 153 db_printsym(callpc, DB_STGY_PROC, pr); 154 } 155 (*pr)("\n"); 156 157 /* Go to the next frame. */ 158 lastsp = sp; 159 160 if (lr == (vaddr_t)&trapexit) { 161 struct trapframe *frame = 162 (struct trapframe *)(sp + 32); 163 164 if ((frame->srr1 & PSL_PR) && frame->exc == EXC_SC) { 165 (*pr)("--- syscall (number %ld) ---\n", 166 frame->fixreg[0]); 167 } else { 168 (*pr)("--- trap (type 0x%x) ---\n", 169 frame->exc); 170 } 171 172 if (frame->srr1 & PSL_PR) 173 end_trace = 1; 174 175 sp = frame->fixreg[1]; 176 lr = frame->srr0 + 4; 177 } else if (!has_frame) { 178 lr = ddb_regs.lr; 179 has_frame = 1; 180 } else { 181 db_read_bytes(sp, sizeof(vaddr_t), (char *)&sp); 182 if (sp == 0) 183 break; 184 if (sp <= lastsp) { 185 (*pr)("Bad frame pointer: 0x%lx\n", sp); 186 break; 187 } 188 db_read_bytes(sp + 16, sizeof(vaddr_t), (char *)&lr); 189 } 190 callpc = lr - 4; 191 192 if (end_trace) { 193 (*pr)("End of kernel: 0x%lx lr 0x%lx\n", sp, callpc); 194 break; 195 } 196 197 --count; 198 } 199 } 200 201 extern char _start[], _etext[]; 202 203 void 204 stacktrace_save_at(struct stacktrace *st, unsigned int skip) 205 { 206 struct callframe *frame, *lastframe, *limit; 207 struct proc *p = curproc; 208 209 st->st_count = 0; 210 211 if (p == NULL) 212 return; 213 214 frame = __builtin_frame_address(0); 215 limit = (struct callframe *)(p->p_addr + USPACE - FRAMELEN); 216 217 while (st->st_count < STACKTRACE_MAX) { 218 if (skip == 0) 219 st->st_pc[st->st_count++] = frame->cf_lr; 220 else 221 skip--; 222 223 lastframe = frame; 224 frame = (struct callframe *)frame->cf_sp; 225 226 if (frame <= lastframe) 227 break; 228 if (frame >= limit) 229 break; 230 if (frame->cf_lr < (vaddr_t)_start || 231 frame->cf_lr >= (vaddr_t)_etext) 232 break; 233 } 234 } 235 236 void 237 stacktrace_save_utrace(struct stacktrace *st) 238 { 239 st->st_count = 0; 240 } 241