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