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/smp.h> 35 #include <sys/stack.h> 36 #include <sys/sysent.h> 37 38 #include <machine/cpu.h> 39 #include <machine/md_var.h> 40 #include <machine/pcb.h> 41 #include <machine/reg.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 #define TRAP_INTERRUPT 5 127 128 static void db_nextframe(struct amd64_frame **, db_addr_t *, struct thread *); 129 static void db_print_stack_entry(const char *, db_addr_t, void *); 130 static void decode_syscall(int, struct thread *); 131 132 static const char * watchtype_str(int type); 133 int amd64_set_watch(int watchnum, unsigned long watchaddr, int size, 134 int access, struct dbreg *d); 135 int amd64_clr_watch(int watchnum, struct dbreg *d); 136 137 static void 138 db_print_stack_entry(const char *name, db_addr_t callpc, void *frame) 139 { 140 141 db_printf("%s() at ", name != NULL ? name : "??"); 142 db_printsym(callpc, DB_STGY_PROC); 143 if (frame != NULL) 144 db_printf("/frame 0x%lx", (register_t)frame); 145 db_printf("\n"); 146 } 147 148 static void 149 decode_syscall(int number, struct thread *td) 150 { 151 struct proc *p; 152 c_db_sym_t sym; 153 db_expr_t diff; 154 sy_call_t *f; 155 const char *symname; 156 157 db_printf(" (%d", number); 158 p = (td != NULL) ? td->td_proc : NULL; 159 if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) { 160 f = p->p_sysent->sv_table[number].sy_call; 161 sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff); 162 if (sym != DB_SYM_NULL && diff == 0) { 163 db_symbol_values(sym, &symname, NULL); 164 db_printf(", %s, %s", p->p_sysent->sv_name, symname); 165 } 166 } 167 db_printf(")"); 168 } 169 170 /* 171 * Figure out the next frame up in the call stack. 172 */ 173 static void 174 db_nextframe(struct amd64_frame **fp, db_addr_t *ip, struct thread *td) 175 { 176 struct trapframe *tf; 177 int frame_type; 178 long rip, rsp, rbp; 179 db_expr_t offset; 180 c_db_sym_t sym; 181 const char *name; 182 183 rip = db_get_value((long) &(*fp)->f_retaddr, 8, FALSE); 184 rbp = db_get_value((long) &(*fp)->f_frame, 8, FALSE); 185 186 /* 187 * Figure out frame type. We look at the address just before 188 * the saved instruction pointer as the saved EIP is after the 189 * call function, and if the function being called is marked as 190 * dead (such as panic() at the end of dblfault_handler()), then 191 * the instruction at the saved EIP will be part of a different 192 * function (syscall() in this example) rather than the one that 193 * actually made the call. 194 */ 195 frame_type = NORMAL; 196 sym = db_search_symbol(rip - 1, DB_STGY_ANY, &offset); 197 db_symbol_values(sym, &name, NULL); 198 if (name != NULL) { 199 if (strcmp(name, "calltrap") == 0 || 200 strcmp(name, "fork_trampoline") == 0 || 201 strcmp(name, "mchk_calltrap") == 0 || 202 strcmp(name, "nmi_calltrap") == 0 || 203 strcmp(name, "Xdblfault") == 0) 204 frame_type = TRAP; 205 else if (strncmp(name, "Xatpic_intr", 11) == 0 || 206 strncmp(name, "Xapic_isr", 9) == 0 || 207 strcmp(name, "Xtimerint") == 0 || 208 strcmp(name, "Xipi_intr_bitmap_handler") == 0 || 209 strcmp(name, "Xcpustop") == 0 || 210 strcmp(name, "Xcpususpend") == 0 || 211 strcmp(name, "Xrendezvous") == 0) 212 frame_type = INTERRUPT; 213 else if (strcmp(name, "Xfast_syscall") == 0 || 214 strcmp(name, "Xfast_syscall_pti") == 0 || 215 strcmp(name, "fast_syscall_common") == 0) 216 frame_type = SYSCALL; 217 #ifdef COMPAT_FREEBSD32 218 else if (strcmp(name, "Xint0x80_syscall") == 0) 219 frame_type = SYSCALL; 220 #endif 221 /* XXX: These are interrupts with trap frames. */ 222 else if (strcmp(name, "Xtimerint") == 0 || 223 strcmp(name, "Xcpustop") == 0 || 224 strcmp(name, "Xcpususpend") == 0 || 225 strcmp(name, "Xrendezvous") == 0 || 226 strcmp(name, "Xipi_intr_bitmap_handler") == 0) 227 frame_type = TRAP_INTERRUPT; 228 } 229 230 /* 231 * Normal frames need no special processing. 232 */ 233 if (frame_type == NORMAL) { 234 *ip = (db_addr_t) rip; 235 *fp = (struct amd64_frame *) rbp; 236 return; 237 } 238 239 db_print_stack_entry(name, rip, &(*fp)->f_frame); 240 241 /* 242 * Point to base of trapframe which is just above the 243 * current frame. 244 */ 245 tf = (struct trapframe *)((long)*fp + 16); 246 247 if (INKERNEL((long) tf)) { 248 rsp = tf->tf_rsp; 249 rip = tf->tf_rip; 250 rbp = tf->tf_rbp; 251 switch (frame_type) { 252 case TRAP: 253 db_printf("--- trap %#r", tf->tf_trapno); 254 break; 255 case SYSCALL: 256 db_printf("--- syscall"); 257 decode_syscall(tf->tf_rax, td); 258 break; 259 case TRAP_INTERRUPT: 260 case INTERRUPT: 261 db_printf("--- interrupt"); 262 break; 263 default: 264 panic("The moon has moved again."); 265 } 266 db_printf(", rip = %#lr, rsp = %#lr, rbp = %#lr ---\n", rip, 267 rsp, rbp); 268 } 269 270 *ip = (db_addr_t) rip; 271 *fp = (struct amd64_frame *) rbp; 272 } 273 274 static int 275 db_backtrace(struct thread *td, struct trapframe *tf, struct amd64_frame *frame, 276 db_addr_t pc, register_t sp, int count) 277 { 278 struct amd64_frame *actframe; 279 const char *name; 280 db_expr_t offset; 281 c_db_sym_t sym; 282 boolean_t first; 283 284 if (count == -1) 285 count = 1024; 286 287 first = TRUE; 288 while (count-- && !db_pager_quit) { 289 sym = db_search_symbol(pc, DB_STGY_ANY, &offset); 290 db_symbol_values(sym, &name, NULL); 291 292 /* 293 * Attempt to determine a (possibly fake) frame that gives 294 * the caller's pc. It may differ from `frame' if the 295 * current function never sets up a standard frame or hasn't 296 * set one up yet or has just discarded one. The last two 297 * cases can be guessed fairly reliably for code generated 298 * by gcc. The first case is too much trouble to handle in 299 * general because the amount of junk on the stack depends 300 * on the pc (the special handling of "calltrap", etc. in 301 * db_nextframe() works because the `next' pc is special). 302 */ 303 actframe = frame; 304 if (first) { 305 first = FALSE; 306 if (sym == C_DB_SYM_NULL && sp != 0) { 307 /* 308 * If a symbol couldn't be found, we've probably 309 * jumped to a bogus location, so try and use 310 * the return address to find our caller. 311 */ 312 db_print_stack_entry(name, pc, NULL); 313 pc = db_get_value(sp, 8, FALSE); 314 if (db_search_symbol(pc, DB_STGY_PROC, 315 &offset) == C_DB_SYM_NULL) 316 break; 317 continue; 318 } else if (tf != NULL) { 319 int instr; 320 321 instr = db_get_value(pc, 4, FALSE); 322 if ((instr & 0xffffffff) == 0xe5894855) { 323 /* pushq %rbp; movq %rsp, %rbp */ 324 actframe = (void *)(tf->tf_rsp - 8); 325 } else if ((instr & 0xffffff) == 0xe58948) { 326 /* movq %rsp, %rbp */ 327 actframe = (void *)tf->tf_rsp; 328 if (tf->tf_rbp == 0) { 329 /* Fake frame better. */ 330 frame = actframe; 331 } 332 } else if ((instr & 0xff) == 0xc3) { 333 /* ret */ 334 actframe = (void *)(tf->tf_rsp - 8); 335 } else if (offset == 0) { 336 /* Probably an assembler symbol. */ 337 actframe = (void *)(tf->tf_rsp - 8); 338 } 339 } else if (name != NULL && 340 strcmp(name, "fork_trampoline") == 0) { 341 /* 342 * Don't try to walk back on a stack for a 343 * process that hasn't actually been run yet. 344 */ 345 db_print_stack_entry(name, pc, actframe); 346 break; 347 } 348 } 349 350 db_print_stack_entry(name, pc, actframe); 351 352 if (actframe != frame) { 353 /* `frame' belongs to caller. */ 354 pc = (db_addr_t) 355 db_get_value((long)&actframe->f_retaddr, 8, FALSE); 356 continue; 357 } 358 359 db_nextframe(&frame, &pc, td); 360 361 if (INKERNEL((long)pc) && !INKERNEL((long)frame)) { 362 sym = db_search_symbol(pc, DB_STGY_ANY, &offset); 363 db_symbol_values(sym, &name, NULL); 364 db_print_stack_entry(name, pc, frame); 365 break; 366 } 367 if (!INKERNEL((long) frame)) { 368 break; 369 } 370 } 371 372 return (0); 373 } 374 375 void 376 db_trace_self(void) 377 { 378 struct amd64_frame *frame; 379 db_addr_t callpc; 380 register_t rbp; 381 382 __asm __volatile("movq %%rbp,%0" : "=r" (rbp)); 383 frame = (struct amd64_frame *)rbp; 384 callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE); 385 frame = frame->f_frame; 386 db_backtrace(curthread, NULL, frame, callpc, 0, -1); 387 } 388 389 int 390 db_trace_thread(struct thread *thr, int count) 391 { 392 struct pcb *ctx; 393 struct trapframe *tf; 394 395 ctx = kdb_thr_ctx(thr); 396 tf = thr == kdb_thread ? kdb_frame : NULL; 397 return (db_backtrace(thr, tf, (struct amd64_frame *)ctx->pcb_rbp, 398 ctx->pcb_rip, ctx->pcb_rsp, count)); 399 } 400 401 int 402 amd64_set_watch(watchnum, watchaddr, size, access, d) 403 int watchnum; 404 unsigned long watchaddr; 405 int size; 406 int access; 407 struct dbreg *d; 408 { 409 int i, len; 410 411 if (watchnum == -1) { 412 for (i = 0; i < 4; i++) 413 if (!DBREG_DR7_ENABLED(d->dr[7], i)) 414 break; 415 if (i < 4) 416 watchnum = i; 417 else 418 return (-1); 419 } 420 421 switch (access) { 422 case DBREG_DR7_EXEC: 423 size = 1; /* size must be 1 for an execution breakpoint */ 424 /* fall through */ 425 case DBREG_DR7_WRONLY: 426 case DBREG_DR7_RDWR: 427 break; 428 default: 429 return (-1); 430 } 431 432 /* 433 * we can watch a 1, 2, 4, or 8 byte sized location 434 */ 435 switch (size) { 436 case 1: 437 len = DBREG_DR7_LEN_1; 438 break; 439 case 2: 440 len = DBREG_DR7_LEN_2; 441 break; 442 case 4: 443 len = DBREG_DR7_LEN_4; 444 break; 445 case 8: 446 len = DBREG_DR7_LEN_8; 447 break; 448 default: 449 return (-1); 450 } 451 452 /* clear the bits we are about to affect */ 453 d->dr[7] &= ~DBREG_DR7_MASK(watchnum); 454 455 /* set drN register to the address, N=watchnum */ 456 DBREG_DRX(d, watchnum) = watchaddr; 457 458 /* enable the watchpoint */ 459 d->dr[7] |= DBREG_DR7_SET(watchnum, len, access, 460 DBREG_DR7_GLOBAL_ENABLE); 461 462 return (watchnum); 463 } 464 465 466 int 467 amd64_clr_watch(watchnum, d) 468 int watchnum; 469 struct dbreg *d; 470 { 471 472 if (watchnum < 0 || watchnum >= 4) 473 return (-1); 474 475 d->dr[7] &= ~DBREG_DR7_MASK(watchnum); 476 DBREG_DRX(d, watchnum) = 0; 477 478 return (0); 479 } 480 481 482 int 483 db_md_set_watchpoint(addr, size) 484 db_expr_t addr; 485 db_expr_t size; 486 { 487 struct dbreg *d; 488 struct pcpu *pc; 489 int avail, c, cpu, i, wsize; 490 491 d = (struct dbreg *)PCPU_PTR(dbreg); 492 cpu = PCPU_GET(cpuid); 493 fill_dbregs(NULL, d); 494 495 avail = 0; 496 for (i = 0; i < 4; i++) { 497 if (!DBREG_DR7_ENABLED(d->dr[7], i)) 498 avail++; 499 } 500 501 if (avail * 8 < size) 502 return (-1); 503 504 for (i = 0; i < 4 && size > 0; i++) { 505 if (!DBREG_DR7_ENABLED(d->dr[7], i)) { 506 if (size >= 8 || (avail == 1 && size > 4)) 507 wsize = 8; 508 else if (size > 2) 509 wsize = 4; 510 else 511 wsize = size; 512 amd64_set_watch(i, addr, wsize, DBREG_DR7_WRONLY, d); 513 addr += wsize; 514 size -= wsize; 515 avail--; 516 } 517 } 518 519 set_dbregs(NULL, d); 520 CPU_FOREACH(c) { 521 if (c == cpu) 522 continue; 523 pc = pcpu_find(c); 524 memcpy(pc->pc_dbreg, d, sizeof(*d)); 525 pc->pc_dbreg_cmd = PC_DBREG_CMD_LOAD; 526 } 527 528 return (0); 529 } 530 531 int 532 db_md_clr_watchpoint(addr, size) 533 db_expr_t addr; 534 db_expr_t size; 535 { 536 struct dbreg *d; 537 struct pcpu *pc; 538 int i, c, cpu; 539 540 d = (struct dbreg *)PCPU_PTR(dbreg); 541 cpu = PCPU_GET(cpuid); 542 fill_dbregs(NULL, d); 543 544 for (i = 0; i < 4; i++) { 545 if (DBREG_DR7_ENABLED(d->dr[7], i)) { 546 if (DBREG_DRX((d), i) >= addr && 547 DBREG_DRX((d), i) < addr + size) 548 amd64_clr_watch(i, d); 549 550 } 551 } 552 553 set_dbregs(NULL, d); 554 CPU_FOREACH(c) { 555 if (c == cpu) 556 continue; 557 pc = pcpu_find(c); 558 memcpy(pc->pc_dbreg, d, sizeof(*d)); 559 pc->pc_dbreg_cmd = PC_DBREG_CMD_LOAD; 560 } 561 562 return (0); 563 } 564 565 566 static const char * 567 watchtype_str(type) 568 int type; 569 { 570 switch (type) { 571 case DBREG_DR7_EXEC : return "execute"; break; 572 case DBREG_DR7_RDWR : return "read/write"; break; 573 case DBREG_DR7_WRONLY : return "write"; break; 574 default : return "invalid"; break; 575 } 576 } 577 578 579 void 580 db_md_list_watchpoints(void) 581 { 582 struct dbreg d; 583 int i, len, type; 584 585 fill_dbregs(NULL, &d); 586 587 db_printf("\nhardware watchpoints:\n"); 588 db_printf(" watch status type len address\n"); 589 db_printf(" ----- -------- ---------- --- ------------------\n"); 590 for (i = 0; i < 4; i++) { 591 if (DBREG_DR7_ENABLED(d.dr[7], i)) { 592 type = DBREG_DR7_ACCESS(d.dr[7], i); 593 len = DBREG_DR7_LEN(d.dr[7], i); 594 if (len == DBREG_DR7_LEN_8) 595 len = 8; 596 else 597 len++; 598 db_printf(" %-5d %-8s %10s %3d ", 599 i, "enabled", watchtype_str(type), len); 600 db_printsym((db_addr_t)DBREG_DRX(&d, i), DB_STGY_ANY); 601 db_printf("\n"); 602 } else { 603 db_printf(" %-5d disabled\n", i); 604 } 605 } 606 607 db_printf("\ndebug register values:\n"); 608 for (i = 0; i < 8; i++) 609 if (i != 4 && i != 5) 610 db_printf(" dr%d 0x%016lx\n", i, DBREG_DRX(&d, i)); 611 db_printf("\n"); 612 } 613 614 void 615 amd64_db_resume_dbreg(void) 616 { 617 struct dbreg *d; 618 619 switch (PCPU_GET(dbreg_cmd)) { 620 case PC_DBREG_CMD_LOAD: 621 d = (struct dbreg *)PCPU_PTR(dbreg); 622 set_dbregs(NULL, d); 623 PCPU_SET(dbreg_cmd, PC_DBREG_CMD_NONE); 624 break; 625 } 626 } 627