1 /*- 2 * Mach Operating System 3 * Copyright (c) 1991,1990 Carnegie Mellon University 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify and distribute this software and its 7 * documentation is hereby granted, provided that both the copyright 8 * notice and this permission notice appear in all copies of the 9 * software, derivative works or modified versions, and any portions 10 * thereof, and that both notices appear in supporting documentation. 11 * 12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15 * 16 * Carnegie Mellon requests users of this software to return to 17 * 18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19 * School of Computer Science 20 * Carnegie Mellon University 21 * Pittsburgh PA 15213-3890 22 * 23 * any improvements or extensions that they make and grant Carnegie the 24 * rights to redistribute these changes. 25 */ 26 27 #include <sys/cdefs.h> 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/kdb.h> 31 #include <sys/proc.h> 32 #include <sys/reg.h> 33 #include <sys/smp.h> 34 #include <sys/stack.h> 35 36 #include <machine/cpu.h> 37 #include <machine/md_var.h> 38 #include <machine/pcb.h> 39 #include <machine/stack.h> 40 41 #include <vm/vm.h> 42 #include <vm/vm_param.h> 43 #include <vm/pmap.h> 44 45 #include <ddb/ddb.h> 46 #include <ddb/db_access.h> 47 #include <ddb/db_sym.h> 48 #include <ddb/db_variables.h> 49 50 static db_varfcn_t db_frame; 51 static db_varfcn_t db_frame_seg; 52 53 CTASSERT(sizeof(struct dbreg) == sizeof(((struct pcpu *)NULL)->pc_dbreg)); 54 55 /* 56 * Machine register set. 57 */ 58 #define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) 59 struct db_variable db_regs[] = { 60 { "cs", DB_OFFSET(tf_cs), db_frame_seg }, 61 { "ds", DB_OFFSET(tf_ds), db_frame_seg }, 62 { "es", DB_OFFSET(tf_es), db_frame_seg }, 63 { "fs", DB_OFFSET(tf_fs), db_frame_seg }, 64 { "gs", DB_OFFSET(tf_gs), db_frame_seg }, 65 { "ss", DB_OFFSET(tf_ss), db_frame_seg }, 66 { "rax", DB_OFFSET(tf_rax), db_frame }, 67 { "rcx", DB_OFFSET(tf_rcx), db_frame }, 68 { "rdx", DB_OFFSET(tf_rdx), db_frame }, 69 { "rbx", DB_OFFSET(tf_rbx), db_frame }, 70 { "rsp", DB_OFFSET(tf_rsp), db_frame }, 71 { "rbp", DB_OFFSET(tf_rbp), db_frame }, 72 { "rsi", DB_OFFSET(tf_rsi), db_frame }, 73 { "rdi", DB_OFFSET(tf_rdi), db_frame }, 74 { "r8", DB_OFFSET(tf_r8), db_frame }, 75 { "r9", DB_OFFSET(tf_r9), db_frame }, 76 { "r10", DB_OFFSET(tf_r10), db_frame }, 77 { "r11", DB_OFFSET(tf_r11), db_frame }, 78 { "r12", DB_OFFSET(tf_r12), db_frame }, 79 { "r13", DB_OFFSET(tf_r13), db_frame }, 80 { "r14", DB_OFFSET(tf_r14), db_frame }, 81 { "r15", DB_OFFSET(tf_r15), db_frame }, 82 { "rip", DB_OFFSET(tf_rip), db_frame }, 83 { "rflags", DB_OFFSET(tf_rflags), db_frame }, 84 }; 85 struct db_variable *db_eregs = db_regs + nitems(db_regs); 86 87 static int 88 db_frame_seg(struct db_variable *vp, db_expr_t *valuep, int op) 89 { 90 uint16_t *reg; 91 92 if (kdb_frame == NULL) 93 return (0); 94 95 reg = (uint16_t *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep); 96 if (op == DB_VAR_GET) 97 *valuep = *reg; 98 else 99 *reg = *valuep; 100 return (1); 101 } 102 103 static int 104 db_frame(struct db_variable *vp, db_expr_t *valuep, int op) 105 { 106 long *reg; 107 108 if (kdb_frame == NULL) 109 return (0); 110 111 reg = (long *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep); 112 if (op == DB_VAR_GET) 113 *valuep = *reg; 114 else 115 *reg = *valuep; 116 return (1); 117 } 118 119 #define NORMAL 0 120 #define TRAP 1 121 #define INTERRUPT 2 122 #define SYSCALL 3 123 124 static void 125 db_print_stack_entry(const char *name, db_addr_t callpc, db_addr_t frame) 126 { 127 128 db_printf("%s() at ", name != NULL ? name : "??"); 129 db_printsym(callpc, DB_STGY_PROC); 130 if (frame != 0) 131 db_printf("/frame %#lx", frame); 132 db_printf("\n"); 133 } 134 135 /* 136 * Figure out the next frame up in the call stack. 137 */ 138 static void 139 db_nextframe(db_addr_t *fp, db_addr_t *ip, struct thread *td) 140 { 141 struct trapframe *tf; 142 db_addr_t tf_addr; 143 int frame_type; 144 long rip, rsp, rbp; 145 db_expr_t offset; 146 c_db_sym_t sym; 147 const char *name; 148 149 rip = db_get_value(*fp + offsetof(struct amd64_frame, f_retaddr), 8, 150 FALSE); 151 rbp = db_get_value(*fp + offsetof(struct amd64_frame, f_frame), 8, 152 FALSE); 153 154 /* 155 * Figure out frame type. We look at the address just before 156 * the saved instruction pointer as the saved EIP is after the 157 * call function, and if the function being called is marked as 158 * dead (such as panic() at the end of dblfault_handler()), then 159 * the instruction at the saved EIP will be part of a different 160 * function (syscall() in this example) rather than the one that 161 * actually made the call. 162 */ 163 frame_type = NORMAL; 164 sym = db_search_symbol(rip - 1, DB_STGY_ANY, &offset); 165 db_symbol_values(sym, &name, NULL); 166 if (name != NULL) { 167 if (strcmp(name, "calltrap") == 0 || 168 strcmp(name, "fork_trampoline") == 0 || 169 strcmp(name, "mchk_calltrap") == 0 || 170 strcmp(name, "nmi_calltrap") == 0 || 171 strcmp(name, "Xdblfault") == 0) 172 frame_type = TRAP; 173 else if (strncmp(name, "Xatpic_intr", 11) == 0 || 174 strncmp(name, "Xapic_isr", 9) == 0 || 175 strcmp(name, "Xxen_intr_upcall") == 0 || 176 strcmp(name, "Xtimerint") == 0 || 177 strcmp(name, "Xipi_intr_bitmap_handler") == 0 || 178 strcmp(name, "Xcpustop") == 0 || 179 strcmp(name, "Xcpususpend") == 0 || 180 strcmp(name, "Xrendezvous") == 0) 181 frame_type = INTERRUPT; 182 else if (strcmp(name, "Xfast_syscall") == 0 || 183 strcmp(name, "Xfast_syscall_pti") == 0 || 184 strcmp(name, "fast_syscall_common") == 0) 185 frame_type = SYSCALL; 186 #ifdef COMPAT_FREEBSD32 187 else if (strcmp(name, "Xint0x80_syscall") == 0) 188 frame_type = SYSCALL; 189 #endif 190 } 191 192 /* 193 * Normal frames need no special processing. 194 */ 195 if (frame_type == NORMAL) { 196 *ip = rip; 197 *fp = rbp; 198 return; 199 } 200 201 db_print_stack_entry(name, rip, *fp); 202 203 /* 204 * Point to base of trapframe which is just above the 205 * current frame. 206 */ 207 tf_addr = *fp + 16; 208 209 if (!__is_aligned(tf_addr, _Alignof(*tf)) || !INKERNEL(tf_addr)) { 210 db_printf("--- invalid trapframe %p\n", (void *)tf_addr); 211 *ip = 0; 212 *fp = 0; 213 return; 214 } 215 tf = (struct trapframe *)tf_addr; 216 217 rsp = tf->tf_rsp; 218 rip = tf->tf_rip; 219 rbp = tf->tf_rbp; 220 switch (frame_type) { 221 case TRAP: 222 db_printf("--- trap %#r", tf->tf_trapno); 223 break; 224 case SYSCALL: 225 db_printf("--- syscall"); 226 db_decode_syscall(td, tf->tf_rax); 227 break; 228 case INTERRUPT: 229 db_printf("--- interrupt"); 230 break; 231 default: 232 __assert_unreachable(); 233 } 234 db_printf(", rip = %#lr, rsp = %#lr, rbp = %#lr ---\n", rip, rsp, rbp); 235 236 *ip = rip; 237 *fp = rbp; 238 } 239 240 static int __nosanitizeaddress __nosanitizememory 241 db_backtrace(struct thread *td, struct trapframe *tf, db_addr_t frame, 242 db_addr_t pc, register_t sp, int count) 243 { 244 db_addr_t actframe; 245 const char *name; 246 db_expr_t offset; 247 c_db_sym_t sym; 248 boolean_t first; 249 250 if (count == -1) 251 count = 1024; 252 253 first = TRUE; 254 while (count-- && !db_pager_quit) { 255 sym = db_search_symbol(pc, DB_STGY_ANY, &offset); 256 db_symbol_values(sym, &name, NULL); 257 258 /* 259 * Attempt to determine a (possibly fake) frame that gives 260 * the caller's pc. It may differ from `frame' if the 261 * current function never sets up a standard frame or hasn't 262 * set one up yet or has just discarded one. The last two 263 * cases can be guessed fairly reliably for code generated 264 * by gcc. The first case is too much trouble to handle in 265 * general because the amount of junk on the stack depends 266 * on the pc (the special handling of "calltrap", etc. in 267 * db_nextframe() works because the `next' pc is special). 268 */ 269 actframe = frame; 270 if (first) { 271 first = FALSE; 272 if (sym == C_DB_SYM_NULL && sp != 0) { 273 /* 274 * If a symbol couldn't be found, we've probably 275 * jumped to a bogus location, so try and use 276 * the return address to find our caller. 277 */ 278 db_print_stack_entry(name, pc, 0); 279 pc = db_get_value(sp, 8, FALSE); 280 if (db_search_symbol(pc, DB_STGY_PROC, 281 &offset) == C_DB_SYM_NULL) 282 break; 283 continue; 284 } else if (tf != NULL) { 285 int instr; 286 287 instr = db_get_value(pc, 4, FALSE); 288 if ((instr & 0xffffffff) == 0xe5894855) { 289 /* pushq %rbp; movq %rsp, %rbp */ 290 actframe = tf->tf_rsp - 8; 291 } else if ((instr & 0xffffff) == 0xe58948) { 292 /* movq %rsp, %rbp */ 293 actframe = tf->tf_rsp; 294 if (tf->tf_rbp == 0) { 295 /* Fake frame better. */ 296 frame = actframe; 297 } 298 } else if ((instr & 0xff) == 0xc3) { 299 /* ret */ 300 actframe = tf->tf_rsp - 8; 301 } else if (offset == 0) { 302 /* Probably an assembler symbol. */ 303 actframe = tf->tf_rsp - 8; 304 } 305 } else if (name != NULL && 306 strcmp(name, "fork_trampoline") == 0) { 307 /* 308 * Don't try to walk back on a stack for a 309 * process that hasn't actually been run yet. 310 */ 311 db_print_stack_entry(name, pc, actframe); 312 break; 313 } 314 } 315 316 db_print_stack_entry(name, pc, actframe); 317 318 if (actframe != frame) { 319 /* `frame' belongs to caller. */ 320 pc = db_get_value(actframe + 321 offsetof(struct amd64_frame, f_retaddr), 8, FALSE); 322 continue; 323 } 324 325 db_nextframe(&frame, &pc, td); 326 if (frame == 0) 327 break; 328 329 if (!__is_aligned(frame, _Alignof(struct amd64_frame)) || 330 !INKERNEL(frame)) { 331 if (INKERNEL(pc)) { 332 sym = db_search_symbol(pc, DB_STGY_ANY, 333 &offset); 334 db_symbol_values(sym, &name, NULL); 335 db_print_stack_entry(name, pc, frame); 336 break; 337 } 338 break; 339 } 340 } 341 342 return (0); 343 } 344 345 void 346 db_trace_self(void) 347 { 348 db_addr_t callpc, frame; 349 register_t rbp; 350 351 __asm __volatile("movq %%rbp,%0" : "=r" (rbp)); 352 callpc = db_get_value(rbp + offsetof(struct amd64_frame, f_retaddr), 8, 353 FALSE); 354 frame = db_get_value(rbp + offsetof(struct amd64_frame, f_frame), 8, 355 FALSE); 356 db_backtrace(curthread, NULL, frame, callpc, 0, -1); 357 } 358 359 int 360 db_trace_thread(struct thread *thr, int count) 361 { 362 struct pcb *ctx; 363 struct trapframe *tf; 364 365 ctx = kdb_thr_ctx(thr); 366 tf = thr == kdb_thread ? kdb_frame : NULL; 367 return (db_backtrace(thr, tf, ctx->pcb_rbp, ctx->pcb_rip, ctx->pcb_rsp, 368 count)); 369 } 370 371 void 372 db_md_list_watchpoints(void) 373 { 374 375 dbreg_list_watchpoints(); 376 } 377