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