1 /* $NetBSD: db_trace.c,v 1.50 2021/02/10 07:19:54 simonb Exp $ */ 2 3 /* 4 * Mach Operating System 5 * Copyright (c) 1993-1987 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie Mellon 26 * the rights to redistribute these changes. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.50 2021/02/10 07:19:54 simonb Exp $"); 31 32 #ifdef _KERNEL_OPT 33 #include "opt_ddb.h" 34 #endif 35 36 #include <sys/types.h> 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/proc.h> 40 #include <sys/cpu.h> 41 42 #include <mips/mips_opcode.h> 43 #include <mips/stacktrace.h> 44 45 #include <machine/db_machdep.h> 46 #include <machine/locore.h> 47 48 #include <ddb/db_access.h> 49 #include <ddb/db_interface.h> 50 #include <ddb/db_output.h> 51 #include <ddb/db_variables.h> 52 #include <ddb/db_sym.h> 53 54 int __start(void); /* lowest kernel code address */ 55 vaddr_t getreg_val(db_expr_t regno); 56 57 #define REG_ARG(i) (4+i) 58 #define SAVES_RA(x) isa_spill((x),31) 59 60 #define KERN_SAVE_REG_IDX(vp) ( \ 61 ((vp)->valuep >= (int *)(&((struct mips_saved_state *)0)->s0) && \ 62 (vp)->valuep <= (int *)(&((struct mips_saved_state *)0)->s7))? \ 63 vp->valuep - (int *)(&((struct mips_saved_state *)0)->s0): \ 64 ((vp)->valuep >= (int *)(&((struct mips_saved_state *)0)->sp) && \ 65 (vp)->valuep <= (int *)(&((struct mips_saved_state *)0)->ra))? \ 66 ((vp)->valuep-(int *)(&((struct mips_saved_state *)0)->sp)) + \ 67 ((int *)(&((struct mips_kernel_state *)0)->sp) - (int *)0): \ 68 -1) 69 70 db_sym_t localsym(db_sym_t sym, bool isreg, int *lex_level); 71 72 /* 73 * Machine register set. 74 */ 75 struct mips_saved_state *db_cur_exc_frame = 0; 76 77 int db_mips_variable_func(const struct db_variable *, db_expr_t *, int); 78 79 #define DB_SETF_REGS db_mips_variable_func 80 81 const struct db_variable db_regs[] = { 82 { "at", (long *)&ddb_regs.r_regs[_R_AST], DB_SETF_REGS, NULL }, 83 { "v0", (long *)&ddb_regs.r_regs[_R_V0], DB_SETF_REGS, NULL }, 84 { "v1", (long *)&ddb_regs.r_regs[_R_V1], DB_SETF_REGS, NULL }, 85 { "a0", (long *)&ddb_regs.r_regs[_R_A0], DB_SETF_REGS, NULL }, 86 { "a1", (long *)&ddb_regs.r_regs[_R_A1], DB_SETF_REGS, NULL }, 87 { "a2", (long *)&ddb_regs.r_regs[_R_A2], DB_SETF_REGS, NULL }, 88 { "a3", (long *)&ddb_regs.r_regs[_R_A3], DB_SETF_REGS, NULL }, 89 #if defined(__mips_n32) || defined(__mips_n64) 90 { "a4", (long *)&ddb_regs.r_regs[_R_A4], DB_SETF_REGS, NULL }, 91 { "a5", (long *)&ddb_regs.r_regs[_R_A5], DB_SETF_REGS, NULL }, 92 { "a6", (long *)&ddb_regs.r_regs[_R_A6], DB_SETF_REGS, NULL }, 93 { "a7", (long *)&ddb_regs.r_regs[_R_A7], DB_SETF_REGS, NULL }, 94 { "t0", (long *)&ddb_regs.r_regs[_R_T0], DB_SETF_REGS, NULL }, 95 { "t1", (long *)&ddb_regs.r_regs[_R_T1], DB_SETF_REGS, NULL }, 96 { "t2", (long *)&ddb_regs.r_regs[_R_T2], DB_SETF_REGS, NULL }, 97 { "t3", (long *)&ddb_regs.r_regs[_R_T3], DB_SETF_REGS, NULL }, 98 #else 99 { "t0", (long *)&ddb_regs.r_regs[_R_T0], DB_SETF_REGS, NULL }, 100 { "t1", (long *)&ddb_regs.r_regs[_R_T1], DB_SETF_REGS, NULL }, 101 { "t2", (long *)&ddb_regs.r_regs[_R_T2], DB_SETF_REGS, NULL }, 102 { "t3", (long *)&ddb_regs.r_regs[_R_T3], DB_SETF_REGS, NULL }, 103 { "t4", (long *)&ddb_regs.r_regs[_R_T4], DB_SETF_REGS, NULL }, 104 { "t5", (long *)&ddb_regs.r_regs[_R_T5], DB_SETF_REGS, NULL }, 105 { "t6", (long *)&ddb_regs.r_regs[_R_T6], DB_SETF_REGS, NULL }, 106 { "t7", (long *)&ddb_regs.r_regs[_R_T7], DB_SETF_REGS, NULL }, 107 #endif /* __mips_n32 || __mips_n64 */ 108 { "s0", (long *)&ddb_regs.r_regs[_R_S0], DB_SETF_REGS, NULL }, 109 { "s1", (long *)&ddb_regs.r_regs[_R_S1], DB_SETF_REGS, NULL }, 110 { "s2", (long *)&ddb_regs.r_regs[_R_S2], DB_SETF_REGS, NULL }, 111 { "s3", (long *)&ddb_regs.r_regs[_R_S3], DB_SETF_REGS, NULL }, 112 { "s4", (long *)&ddb_regs.r_regs[_R_S4], DB_SETF_REGS, NULL }, 113 { "s5", (long *)&ddb_regs.r_regs[_R_S5], DB_SETF_REGS, NULL }, 114 { "s6", (long *)&ddb_regs.r_regs[_R_S6], DB_SETF_REGS, NULL }, 115 { "s7", (long *)&ddb_regs.r_regs[_R_S7], DB_SETF_REGS, NULL }, 116 { "t8", (long *)&ddb_regs.r_regs[_R_T8], DB_SETF_REGS, NULL }, 117 { "t9", (long *)&ddb_regs.r_regs[_R_T9], DB_SETF_REGS, NULL }, 118 { "k0", (long *)&ddb_regs.r_regs[_R_K0], DB_SETF_REGS, NULL }, 119 { "k1", (long *)&ddb_regs.r_regs[_R_K1], DB_SETF_REGS, NULL }, 120 { "gp", (long *)&ddb_regs.r_regs[_R_GP], DB_SETF_REGS, NULL }, 121 { "sp", (long *)&ddb_regs.r_regs[_R_SP], DB_SETF_REGS, NULL }, 122 { "fp", (long *)&ddb_regs.r_regs[_R_S8], DB_SETF_REGS, NULL },/* frame ptr */ 123 { "ra", (long *)&ddb_regs.r_regs[_R_RA], DB_SETF_REGS, NULL }, 124 { "sr", (long *)&ddb_regs.r_regs[_R_SR], DB_SETF_REGS, NULL }, 125 { "mdlo",(long *)&ddb_regs.r_regs[_R_MULLO], DB_SETF_REGS, NULL }, 126 { "mdhi",(long *)&ddb_regs.r_regs[_R_MULHI], DB_SETF_REGS, NULL }, 127 { "bad", (long *)&ddb_regs.r_regs[_R_BADVADDR], DB_SETF_REGS, NULL }, 128 { "cs", (long *)&ddb_regs.r_regs[_R_CAUSE], DB_SETF_REGS, NULL }, 129 { "pc", (long *)&ddb_regs.r_regs[_R_PC], DB_SETF_REGS, NULL }, 130 }; 131 const struct db_variable * const db_eregs = db_regs + __arraycount(db_regs); 132 133 void 134 db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, 135 const char *modif, void (*pr)(const char *, ...)) 136 { 137 #ifndef DDB_TRACE 138 struct pcb *pcb; 139 const char *cp = modif; 140 char c; 141 bool lwpaddr = false; 142 vaddr_t pc, sp, s8, ra; 143 #ifndef _KERNEL 144 mips_label_t label; 145 #endif 146 147 if (!have_addr) { 148 struct reg * regs = &ddb_regs; 149 stacktrace_subr(regs->r_regs[_R_A0], 150 regs->r_regs[_R_A1], 151 regs->r_regs[_R_A2], 152 regs->r_regs[_R_A3], 153 regs->r_regs[_R_PC], 154 regs->r_regs[_R_SP], 155 /* non-virtual frame pointer */ 156 regs->r_regs[_R_S8], 157 regs->r_regs[_R_RA], 158 pr); 159 return; 160 } 161 162 while ((c = *cp++) != 0) { 163 if (c == 'a') { 164 lwpaddr = true; 165 } 166 } 167 168 if (lwpaddr) { 169 #ifdef _KERNEL 170 struct lwp *l; 171 172 l = (struct lwp *)(intptr_t)addr; 173 (*pr)("pid %d.%d ", l->l_proc->p_pid, l->l_lid); 174 pcb = lwp_getpcb(l); 175 #else 176 struct proc pstore; 177 struct lwp lstore; 178 179 db_read_bytes(addr, sizeof(lstore), (char *)&lstore); 180 db_read_bytes((db_addr_t)lstore.l_proc, sizeof(pstore), 181 (char *)&pstore); 182 (*pr)("pid %d.%d ", pstore.p_pid, lstore.l_lid); 183 pcb = lwp_getpcb(&lstore); 184 #endif 185 } else { 186 /* "trace/t" */ 187 188 (*pr)("pid %d ", (int)addr); 189 #ifdef _KERNEL 190 struct lwp *l; 191 struct proc *p = proc_find_raw(addr); 192 193 if (p == NULL) { 194 (*pr)("not found\n"); 195 return; 196 } 197 l = LIST_FIRST(&p->p_lwps); /* XXX NJWLWP */ 198 pcb = lwp_getpcb(l); 199 #else 200 (*pr)("no proc_find_raw() in crash\n"); 201 return; 202 #endif 203 } 204 205 (*pr)("at %p\n", pcb); 206 207 #ifdef _KERNEL 208 pc = (vaddr_t)cpu_switchto; 209 sp = pcb->pcb_context.val[_L_SP]; 210 s8 = pcb->pcb_context.val[_L_S8]; 211 ra = pcb->pcb_context.val[_L_RA]; 212 #else 213 pc = db_mach_addr_cpuswitch(); 214 db_read_bytes((db_addr_t)&pcb->pcb_context, sizeof(label), (char *)&label); 215 sp = label.val[_L_SP]; 216 s8 = label.val[_L_S8]; 217 ra = label.val[_L_RA]; 218 #endif 219 stacktrace_subr(0,0,0,0, /* no args known */ 220 pc, sp, s8, ra, 221 pr); 222 #else 223 /* 224 * Incomplete but practically useful stack backtrace. 225 */ 226 #define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */ 227 #define MIPS_JR_K0 0x03400008 /* instruction code for jr k0 */ 228 #define MIPS_ERET 0x42000018 /* instruction code for eret */ 229 register_t va, pc, ra, sp, func; 230 int insn; 231 InstFmt i; 232 int stacksize; 233 db_addr_t offset; 234 const char *name; 235 extern char verylocore[]; 236 237 pc = ddb_regs.r_regs[_R_PC]; 238 sp = ddb_regs.r_regs[_R_SP]; 239 ra = ddb_regs.r_regs[_R_RA]; 240 do { 241 va = pc; 242 do { 243 va -= sizeof(int); 244 insn = *(int *)(intptr_t)va; 245 if (insn == MIPS_ERET) 246 goto mips3_eret; 247 } while (insn != MIPS_JR_RA && insn != MIPS_JR_K0); 248 va += sizeof(int); 249 mips3_eret: 250 va += sizeof(int); 251 while (*(int *)(intptr_t)va == 0x00000000) 252 va += sizeof(int); 253 func = va; 254 stacksize = 0; 255 do { 256 i.word = *(int *)(intptr_t)va; 257 if (((i.IType.op == OP_SW) || (i.IType.op == OP_SD)) 258 && i.IType.rs == _R_SP 259 && i.IType.rt == _R_RA) 260 ra = *(int *)(intptr_t)(sp + (short)i.IType.imm); 261 if (((i.IType.op == OP_ADDIU) || (i.IType.op == OP_DADDIU)) 262 && i.IType.rs == _R_SP 263 && i.IType.rt == _R_SP) 264 stacksize = -(short)i.IType.imm; 265 va += sizeof(int); 266 } while (va < pc); 267 268 db_find_sym_and_offset(func, &name, &offset); 269 if (name == 0) 270 name = "?"; 271 (*pr)("%s()+0x%x, called by %p, stack size %d\n", 272 name, pc - func, (void *)(intptr_t)ra, stacksize); 273 274 if (ra == pc) { 275 (*pr)("-- loop? --\n"); 276 return; 277 } 278 sp += stacksize; 279 pc = ra; 280 } while (pc > (intptr_t)verylocore); 281 if (pc < 0x80000000) 282 (*pr)("-- user process --\n"); 283 else 284 (*pr)("-- kernel entry --\n"); 285 #endif 286 } 287 288 /* 289 * Helper function for db_stacktrace() and friends, used to get the 290 * pc via the return address. 291 */ 292 void 293 db_mips_stack_trace(void *ra, void *fp, void (*pr)(const char *, ...)) 294 { 295 vaddr_t pc; 296 297 /* 298 * The jal instruction for our caller is two insns before the 299 * return address. 300 */ 301 pc = (vaddr_t)__builtin_return_address(0) - sizeof(uint32_t) * 2; 302 303 stacktrace_subr(0, 0, 0, 0, /* no args known */ 304 pc, (intptr_t)fp, (intptr_t)fp, (intptr_t)ra, 305 pr); 306 } 307 308 int 309 db_mips_variable_func(const struct db_variable *vp, db_expr_t *valuep, 310 int db_var_fcn) 311 { 312 313 switch (db_var_fcn) { 314 case DB_VAR_GET: 315 *valuep = *(mips_reg_t *) vp->valuep; 316 break; 317 case DB_VAR_SET: 318 *(mips_reg_t *) vp->valuep = *valuep; 319 break; 320 } 321 return 0; 322 } 323