1 /* 2 * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <arch/user_debugger.h> 8 9 #include <string.h> 10 11 #include <debugger.h> 12 #include <driver_settings.h> 13 #include <int.h> 14 #include <team.h> 15 #include <thread.h> 16 #include <util/AutoLock.h> 17 18 19 //#define TRACE_ARCH_USER_DEBUGGER 20 #ifdef TRACE_ARCH_USER_DEBUGGER 21 # define TRACE(x) dprintf x 22 #else 23 # define TRACE(x) ; 24 #endif 25 26 #define B_NO_MORE_BREAKPOINTS B_BUSY 27 #define B_NO_MORE_WATCHPOINTS B_BUSY 28 #define B_BAD_WATCHPOINT_ALIGNMENT B_BAD_VALUE 29 #define B_WATCHPOINT_TYPE_NOT_SUPPORTED B_NOT_SUPPORTED 30 #define B_WATCHPOINT_LENGTH_NOT_SUPPORTED B_NOT_SUPPORTED 31 #define B_BREAKPOINT_NOT_FOUND B_NAME_NOT_FOUND 32 #define B_WATCHPOINT_NOT_FOUND B_NAME_NOT_FOUND 33 // TODO: Make those real error codes. 34 35 36 extern bool gHasSSE; 37 38 // The software breakpoint instruction (int3). 39 const uint8 kX86SoftwareBreakpoint[1] = { 0xcc }; 40 41 // maps breakpoint slot index to LEN_i LSB number 42 static const size_t sDR7Len[4] = { 43 X86_DR7_LEN0_LSB, X86_DR7_LEN1_LSB, X86_DR7_LEN2_LSB, X86_DR7_LEN3_LSB 44 }; 45 46 // maps breakpoint slot index to R/W_i LSB number 47 static const size_t sDR7RW[4] = { 48 X86_DR7_RW0_LSB, X86_DR7_RW1_LSB, X86_DR7_RW2_LSB, X86_DR7_RW3_LSB 49 }; 50 51 // maps breakpoint slot index to L_i bit number 52 static const size_t sDR7L[4] = { 53 X86_DR7_L0, X86_DR7_L1, X86_DR7_L2, X86_DR7_L3 54 }; 55 56 // maps breakpoint slot index to G_i bit number 57 static const size_t sDR7G[4] = { 58 X86_DR7_G0, X86_DR7_G1, X86_DR7_G2, X86_DR7_G3 59 }; 60 61 // maps breakpoint slot index to B_i bit number 62 static const size_t sDR6B[4] = { 63 X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3 64 }; 65 66 // Enables a hack to make single stepping work under qemu. Set via kernel 67 // driver settings. 68 static bool sQEmuSingleStepHack = false; 69 70 71 #ifdef __x86_64__ 72 73 74 static void 75 get_iframe_registers(const iframe* frame, debug_cpu_state* cpuState) 76 { 77 // Get general purpose registers. 78 cpuState->r15 = frame->r15; 79 cpuState->r14 = frame->r14; 80 cpuState->r13 = frame->r13; 81 cpuState->r12 = frame->r12; 82 cpuState->r11 = frame->r11; 83 cpuState->r10 = frame->r10; 84 cpuState->r9 = frame->r9; 85 cpuState->r8 = frame->r8; 86 cpuState->rbp = frame->bp; 87 cpuState->rsi = frame->si; 88 cpuState->rdi = frame->di; 89 cpuState->rdx = frame->dx; 90 cpuState->rcx = frame->cx; 91 cpuState->rbx = frame->bx; 92 cpuState->rax = frame->ax; 93 cpuState->rip = frame->ip; 94 cpuState->cs = frame->cs; 95 cpuState->rflags = frame->flags; 96 cpuState->rsp = frame->sp; 97 cpuState->ss = frame->ss; 98 99 // Other segment registers are not saved or changed on interrupts, so 100 // get their value here. 101 uint16 seg; 102 __asm__ volatile ("movw %%ds, %0" : "=r" (seg)); 103 cpuState->ds = seg; 104 __asm__ volatile ("movw %%es, %0" : "=r" (seg)); 105 cpuState->es = seg; 106 __asm__ volatile ("movw %%fs, %0" : "=r" (seg)); 107 cpuState->fs = seg; 108 __asm__ volatile ("movw %%gs, %0" : "=r" (seg)); 109 cpuState->gs = seg; 110 } 111 112 113 static void 114 set_iframe_registers(iframe* frame, const debug_cpu_state* cpuState) 115 { 116 frame->r15 = cpuState->r15; 117 frame->r14 = cpuState->r14; 118 frame->r13 = cpuState->r13; 119 frame->r12 = cpuState->r12; 120 frame->r11 = cpuState->r11; 121 frame->r10 = cpuState->r10; 122 frame->r9 = cpuState->r9; 123 frame->r8 = cpuState->r8; 124 frame->bp = cpuState->rbp; 125 frame->si = cpuState->rsi; 126 frame->di = cpuState->rdi; 127 frame->dx = cpuState->rdx; 128 frame->cx = cpuState->rcx; 129 frame->bx = cpuState->rbx; 130 frame->ax = cpuState->rax; 131 frame->ip = cpuState->rip; 132 frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS) 133 | (cpuState->rflags & X86_EFLAGS_USER_SETTABLE_FLAGS); 134 frame->sp = cpuState->rsp; 135 } 136 137 138 #else // __x86_64__ 139 140 141 static void 142 get_iframe_registers(const iframe* frame, debug_cpu_state* cpuState) 143 { 144 cpuState->gs = frame->gs; 145 cpuState->fs = frame->fs; 146 cpuState->es = frame->es; 147 cpuState->ds = frame->ds; 148 cpuState->edi = frame->di; 149 cpuState->esi = frame->si; 150 cpuState->ebp = frame->bp; 151 cpuState->esp = frame->sp; 152 cpuState->ebx = frame->bx; 153 cpuState->edx = frame->orig_edx; 154 cpuState->ecx = frame->cx; 155 cpuState->eax = frame->orig_eax; 156 cpuState->vector = frame->vector; 157 cpuState->error_code = frame->error_code; 158 cpuState->eip = frame->ip; 159 cpuState->cs = frame->cs; 160 cpuState->eflags = frame->flags; 161 cpuState->user_esp = frame->user_sp; 162 cpuState->user_ss = frame->user_ss; 163 } 164 165 166 static void 167 set_iframe_registers(iframe* frame, const debug_cpu_state* cpuState) 168 { 169 // frame->gs = cpuState->gs; 170 // frame->fs = cpuState->fs; 171 // frame->es = cpuState->es; 172 // frame->ds = cpuState->ds; 173 frame->di = cpuState->edi; 174 frame->si = cpuState->esi; 175 frame->bp = cpuState->ebp; 176 // frame->esp = cpuState->esp; 177 frame->bx = cpuState->ebx; 178 frame->dx = cpuState->edx; 179 frame->cx = cpuState->ecx; 180 frame->ax = cpuState->eax; 181 // frame->vector = cpuState->vector; 182 // frame->error_code = cpuState->error_code; 183 frame->ip = cpuState->eip; 184 // frame->cs = cpuState->cs; 185 frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS) 186 | (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS); 187 frame->user_sp = cpuState->user_esp; 188 // frame->user_ss = cpuState->user_ss; 189 } 190 191 192 #endif // __x86_64__ 193 194 195 static inline void 196 install_breakpoints(const arch_team_debug_info& teamInfo) 197 { 198 // set breakpoints 199 asm("mov %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address)); 200 asm("mov %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address)); 201 asm("mov %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address)); 202 #ifdef __x86_64__ 203 asm("mov %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address)); 204 // DR3 is used to hold the current Thread* on 32. 205 #endif 206 207 // enable breakpoints 208 asm("mov %0, %%dr7" : : "r"(teamInfo.dr7)); 209 } 210 211 212 static inline void 213 disable_breakpoints() 214 { 215 asm("mov %0, %%dr7" : : "r"((size_t)X86_BREAKPOINTS_DISABLED_DR7)); 216 } 217 218 219 /*! Sets a break-/watchpoint in the given team info. 220 Interrupts must be disabled and the team debug info lock be held. 221 */ 222 static inline status_t 223 set_breakpoint(arch_team_debug_info& info, void* address, size_t type, 224 size_t length, bool setGlobalFlag) 225 { 226 // check, if there is already a breakpoint at that address 227 bool alreadySet = false; 228 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 229 if (info.breakpoints[i].address == address 230 && info.breakpoints[i].type == type) { 231 alreadySet = true; 232 break; 233 } 234 } 235 236 if (!alreadySet) { 237 // find a free slot 238 int32 slot = -1; 239 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 240 if (!info.breakpoints[i].address) { 241 slot = i; 242 break; 243 } 244 } 245 246 // init the breakpoint 247 if (slot >= 0) { 248 info.breakpoints[slot].address = address; 249 info.breakpoints[slot].type = type; 250 info.breakpoints[slot].length = length; 251 252 info.dr7 |= (length << sDR7Len[slot]) 253 | (type << sDR7RW[slot]) 254 | (1 << sDR7L[slot]); 255 if (setGlobalFlag) 256 info.dr7 |= (1 << sDR7G[slot]); 257 } else { 258 if (type == X86_INSTRUCTION_BREAKPOINT) 259 return B_NO_MORE_BREAKPOINTS; 260 else 261 return B_NO_MORE_WATCHPOINTS; 262 } 263 } 264 265 return B_OK; 266 } 267 268 269 /*! Clears a break-/watchpoint in the given team info. 270 Interrupts must be disabled and the team debug info lock be held. 271 */ 272 static inline status_t 273 clear_breakpoint(arch_team_debug_info& info, void* address, bool watchpoint) 274 { 275 // find the breakpoint 276 int32 slot = -1; 277 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 278 if (info.breakpoints[i].address == address 279 && (watchpoint 280 != (info.breakpoints[i].type == X86_INSTRUCTION_BREAKPOINT))) { 281 slot = i; 282 break; 283 } 284 } 285 286 // clear the breakpoint 287 if (slot >= 0) { 288 info.breakpoints[slot].address = NULL; 289 290 info.dr7 &= ~((0x3 << sDR7Len[slot]) 291 | (0x3 << sDR7RW[slot]) 292 | (1 << sDR7L[slot]) 293 | (1 << sDR7G[slot])); 294 } else { 295 if (watchpoint) 296 return B_WATCHPOINT_NOT_FOUND; 297 else 298 return B_BREAKPOINT_NOT_FOUND; 299 } 300 301 return B_OK; 302 } 303 304 305 static status_t 306 set_breakpoint(void* address, size_t type, size_t length) 307 { 308 if (!address) 309 return B_BAD_VALUE; 310 311 Thread* thread = thread_get_current_thread(); 312 313 cpu_status state = disable_interrupts(); 314 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 315 316 status_t error = set_breakpoint(thread->team->debug_info.arch_info, address, 317 type, length, false); 318 319 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 320 restore_interrupts(state); 321 322 return error; 323 } 324 325 326 static status_t 327 clear_breakpoint(void* address, bool watchpoint) 328 { 329 if (!address) 330 return B_BAD_VALUE; 331 332 Thread* thread = thread_get_current_thread(); 333 334 cpu_status state = disable_interrupts(); 335 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 336 337 status_t error = clear_breakpoint(thread->team->debug_info.arch_info, 338 address, watchpoint); 339 340 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 341 restore_interrupts(state); 342 343 return error; 344 } 345 346 347 #if KERNEL_BREAKPOINTS 348 349 350 static void 351 install_breakpoints_per_cpu(void* /*cookie*/, int cpu) 352 { 353 Team* kernelTeam = team_get_kernel_team(); 354 355 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 356 357 install_breakpoints(kernelTeam->debug_info.arch_info); 358 359 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 360 } 361 362 363 static status_t 364 set_kernel_breakpoint(void* address, size_t type, size_t length) 365 { 366 if (!address) 367 return B_BAD_VALUE; 368 369 Team* kernelTeam = team_get_kernel_team(); 370 371 cpu_status state = disable_interrupts(); 372 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 373 374 status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address, 375 type, length, true); 376 377 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 378 379 call_all_cpus(install_breakpoints_per_cpu, NULL); 380 381 restore_interrupts(state); 382 383 return error; 384 } 385 386 387 static status_t 388 clear_kernel_breakpoint(void* address, bool watchpoint) 389 { 390 if (!address) 391 return B_BAD_VALUE; 392 393 Team* kernelTeam = team_get_kernel_team(); 394 395 cpu_status state = disable_interrupts(); 396 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 397 398 status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info, 399 address, watchpoint); 400 401 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 402 403 call_all_cpus(install_breakpoints_per_cpu, NULL); 404 405 restore_interrupts(state); 406 407 return error; 408 } 409 410 #endif // KERNEL_BREAKPOINTS 411 412 413 static inline status_t 414 check_watch_point_parameters(void* address, uint32 type, int32 length, 415 size_t& archType, size_t& archLength) 416 { 417 // check type 418 switch (type) { 419 case B_DATA_WRITE_WATCHPOINT: 420 archType = X86_DATA_WRITE_BREAKPOINT; 421 break; 422 case B_DATA_READ_WRITE_WATCHPOINT: 423 archType = X86_DATA_READ_WRITE_BREAKPOINT; 424 break; 425 case B_DATA_READ_WATCHPOINT: 426 default: 427 return B_WATCHPOINT_TYPE_NOT_SUPPORTED; 428 break; 429 } 430 431 // check length and alignment 432 switch (length) { 433 case 1: 434 archLength = X86_BREAKPOINT_LENGTH_1; 435 break; 436 case 2: 437 if ((addr_t)address & 0x1) 438 return B_BAD_WATCHPOINT_ALIGNMENT; 439 archLength = X86_BREAKPOINT_LENGTH_2; 440 break; 441 case 4: 442 if ((addr_t)address & 0x3) 443 return B_BAD_WATCHPOINT_ALIGNMENT; 444 archLength = X86_BREAKPOINT_LENGTH_4; 445 break; 446 default: 447 return B_WATCHPOINT_LENGTH_NOT_SUPPORTED; 448 } 449 450 return B_OK; 451 } 452 453 454 // #pragma mark - kernel debugger commands 455 456 457 #if KERNEL_BREAKPOINTS 458 459 static int 460 debugger_breakpoints(int argc, char** argv) 461 { 462 Team* kernelTeam = team_get_kernel_team(); 463 arch_team_debug_info& info = kernelTeam->debug_info.arch_info; 464 465 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 466 kprintf("breakpoint[%" B_PRId32 "] ", i); 467 468 if (info.breakpoints[i].address != NULL) { 469 kprintf("%p ", info.breakpoints[i].address); 470 switch (info.breakpoints[i].type) { 471 case X86_INSTRUCTION_BREAKPOINT: 472 kprintf("instruction"); 473 break; 474 case X86_IO_READ_WRITE_BREAKPOINT: 475 kprintf("io read/write"); 476 break; 477 case X86_DATA_WRITE_BREAKPOINT: 478 kprintf("data write"); 479 break; 480 case X86_DATA_READ_WRITE_BREAKPOINT: 481 kprintf("data read/write"); 482 break; 483 } 484 485 int length = 1; 486 switch (info.breakpoints[i].length) { 487 case X86_BREAKPOINT_LENGTH_1: 488 length = 1; 489 break; 490 case X86_BREAKPOINT_LENGTH_2: 491 length = 2; 492 break; 493 case X86_BREAKPOINT_LENGTH_4: 494 length = 4; 495 break; 496 } 497 498 if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT) 499 kprintf(" %d byte%s", length, (length > 1 ? "s" : "")); 500 } else 501 kprintf("unused"); 502 503 kprintf("\n"); 504 } 505 506 return 0; 507 } 508 509 510 static int 511 debugger_breakpoint(int argc, char** argv) 512 { 513 // get arguments 514 515 if (argc < 2 || argc > 3) 516 return print_debugger_command_usage(argv[0]); 517 518 addr_t address = strtoul(argv[1], NULL, 0); 519 if (address == 0) 520 return print_debugger_command_usage(argv[0]); 521 522 bool clear = false; 523 if (argc == 3) { 524 if (strcmp(argv[2], "clear") == 0) 525 clear = true; 526 else 527 return print_debugger_command_usage(argv[0]); 528 } 529 530 // set/clear breakpoint 531 532 arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; 533 534 status_t error; 535 536 if (clear) { 537 error = clear_breakpoint(info, (void*)address, false); 538 } else { 539 error = set_breakpoint(info, (void*)address, X86_INSTRUCTION_BREAKPOINT, 540 X86_BREAKPOINT_LENGTH_1, true); 541 } 542 543 if (error == B_OK) 544 call_all_cpus_sync(install_breakpoints_per_cpu, NULL); 545 else 546 kprintf("Failed to install breakpoint: %s\n", strerror(error)); 547 548 return 0; 549 } 550 551 552 static int 553 debugger_watchpoint(int argc, char** argv) 554 { 555 // get arguments 556 557 if (argc < 2 || argc > 4) 558 return print_debugger_command_usage(argv[0]); 559 560 addr_t address = strtoul(argv[1], NULL, 0); 561 if (address == 0) 562 return print_debugger_command_usage(argv[0]); 563 564 bool clear = false; 565 bool readWrite = false; 566 int argi = 2; 567 int length = 1; 568 if (argc >= 3) { 569 if (strcmp(argv[argi], "clear") == 0) { 570 clear = true; 571 argi++; 572 } else if (strcmp(argv[argi], "rw") == 0) { 573 readWrite = true; 574 argi++; 575 } 576 577 if (!clear && argi < argc) 578 length = strtoul(argv[argi++], NULL, 0); 579 580 if (length == 0 || argi < argc) 581 return print_debugger_command_usage(argv[0]); 582 } 583 584 // set/clear breakpoint 585 586 arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; 587 588 status_t error; 589 590 if (clear) { 591 error = clear_breakpoint(info, (void*)address, true); 592 } else { 593 uint32 type = readWrite ? B_DATA_READ_WRITE_WATCHPOINT 594 : B_DATA_WRITE_WATCHPOINT; 595 596 size_t archType, archLength; 597 error = check_watch_point_parameters((void*)address, type, length, 598 archType, archLength); 599 600 if (error == B_OK) { 601 error = set_breakpoint(info, (void*)address, archType, archLength, 602 true); 603 } 604 } 605 606 if (error == B_OK) 607 call_all_cpus_sync(install_breakpoints_per_cpu, NULL); 608 else 609 kprintf("Failed to install breakpoint: %s\n", strerror(error)); 610 611 return 0; 612 } 613 614 615 static int 616 debugger_single_step(int argc, char** argv) 617 { 618 // TODO: Since we need an iframe, this doesn't work when KDL wasn't entered 619 // via an exception. 620 621 iframe* frame = x86_get_current_iframe(); 622 if (frame == NULL) { 623 kprintf("Failed to get the current iframe!\n"); 624 return 0; 625 } 626 627 frame->flags |= (1 << X86_EFLAGS_TF); 628 629 return B_KDEBUG_QUIT; 630 } 631 632 633 #endif // KERNEL_BREAKPOINTS 634 635 636 // #pragma mark - in-kernel public interface 637 638 639 void 640 arch_clear_team_debug_info(arch_team_debug_info* info) 641 { 642 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) 643 info->breakpoints[i].address = NULL; 644 645 info->dr7 = X86_BREAKPOINTS_DISABLED_DR7; 646 } 647 648 649 void 650 arch_destroy_team_debug_info(arch_team_debug_info* info) 651 { 652 arch_clear_team_debug_info(info); 653 } 654 655 656 void 657 arch_clear_thread_debug_info(arch_thread_debug_info* info) 658 { 659 info->flags = 0; 660 } 661 662 663 void 664 arch_destroy_thread_debug_info(arch_thread_debug_info* info) 665 { 666 arch_clear_thread_debug_info(info); 667 } 668 669 670 void 671 arch_update_thread_single_step() 672 { 673 if (iframe* frame = x86_get_user_iframe()) { 674 Thread* thread = thread_get_current_thread(); 675 676 // set/clear TF in EFLAGS depending on whether single stepping is 677 // desired 678 if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP) 679 frame->flags |= (1 << X86_EFLAGS_TF); 680 else 681 frame->flags &= ~(1 << X86_EFLAGS_TF); 682 } 683 } 684 685 686 void 687 arch_set_debug_cpu_state(const debug_cpu_state* cpuState) 688 { 689 if (iframe* frame = x86_get_user_iframe()) { 690 // For the floating point state to be correct the calling function must 691 // not use these registers (not even indirectly). 692 if (gHasSSE) { 693 // Since fxrstor requires 16-byte alignment and this isn't 694 // guaranteed passed buffer, we use our thread's fpu_state field as 695 // temporary buffer. We need to disable interrupts to make use of 696 // it. 697 Thread* thread = thread_get_current_thread(); 698 InterruptsLocker locker; 699 memcpy(thread->arch_info.fpu_state, &cpuState->extended_registers, 700 sizeof(cpuState->extended_registers)); 701 x86_fxrstor(thread->arch_info.fpu_state); 702 #ifndef __x86_64__ 703 } else { 704 // TODO: Implement! We need to convert the format first. 705 // x86_frstor(&cpuState->extended_registers); 706 #endif 707 } 708 set_iframe_registers(frame, cpuState); 709 } 710 } 711 712 713 void 714 arch_get_debug_cpu_state(debug_cpu_state* cpuState) 715 { 716 if (iframe* frame = x86_get_user_iframe()) { 717 // For the floating point state to be correct the calling function must 718 // not use these registers (not even indirectly). 719 if (gHasSSE) { 720 // Since fxsave requires 16-byte alignment and this isn't guaranteed 721 // passed buffer, we use our thread's fpu_state field as temporary 722 // buffer. We need to disable interrupts to make use of it. 723 Thread* thread = thread_get_current_thread(); 724 InterruptsLocker locker; 725 x86_fxsave(thread->arch_info.fpu_state); 726 // unlike fnsave, fxsave doesn't reinit the FPU state 727 memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state, 728 sizeof(cpuState->extended_registers)); 729 #ifndef __x86_64__ 730 } else { 731 x86_fnsave(&cpuState->extended_registers); 732 x86_frstor(&cpuState->extended_registers); 733 // fnsave reinits the FPU state after saving, so we need to 734 // load it again 735 // TODO: Convert to fxsave format! 736 #endif 737 } 738 get_iframe_registers(frame, cpuState); 739 } 740 } 741 742 743 status_t 744 arch_set_breakpoint(void* address) 745 { 746 return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 747 X86_BREAKPOINT_LENGTH_1); 748 } 749 750 751 status_t 752 arch_clear_breakpoint(void* address) 753 { 754 return clear_breakpoint(address, false); 755 } 756 757 758 status_t 759 arch_set_watchpoint(void* address, uint32 type, int32 length) 760 { 761 size_t archType, archLength; 762 status_t error = check_watch_point_parameters(address, type, length, 763 archType, archLength); 764 if (error != B_OK) 765 return error; 766 767 return set_breakpoint(address, archType, archLength); 768 } 769 770 771 status_t 772 arch_clear_watchpoint(void* address) 773 { 774 return clear_breakpoint(address, true); 775 } 776 777 778 bool 779 arch_has_breakpoints(arch_team_debug_info* info) 780 { 781 // Reading info->dr7 is atomically, so we don't need to lock. The caller 782 // has to ensure, that the info doesn't go away. 783 return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7); 784 } 785 786 787 #if KERNEL_BREAKPOINTS 788 789 status_t 790 arch_set_kernel_breakpoint(void* address) 791 { 792 status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 793 X86_BREAKPOINT_LENGTH_1); 794 795 if (error != B_OK) { 796 panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s", 797 strerror(error)); 798 } 799 800 return error; 801 } 802 803 804 status_t 805 arch_clear_kernel_breakpoint(void* address) 806 { 807 status_t error = clear_kernel_breakpoint(address, false); 808 809 if (error != B_OK) { 810 panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s", 811 strerror(error)); 812 } 813 814 return error; 815 } 816 817 818 status_t 819 arch_set_kernel_watchpoint(void* address, uint32 type, int32 length) 820 { 821 size_t archType, archLength; 822 status_t error = check_watch_point_parameters(address, type, length, 823 archType, archLength); 824 825 if (error == B_OK) 826 error = set_kernel_breakpoint(address, archType, archLength); 827 828 if (error != B_OK) { 829 panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s", 830 strerror(error)); 831 } 832 833 return error; 834 } 835 836 837 status_t 838 arch_clear_kernel_watchpoint(void* address) 839 { 840 status_t error = clear_kernel_breakpoint(address, true); 841 842 if (error != B_OK) { 843 panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s", 844 strerror(error)); 845 } 846 847 return error; 848 } 849 850 #endif // KERNEL_BREAKPOINTS 851 852 853 // #pragma mark - x86 implementation interface 854 855 856 /** 857 * Interrupts are disabled. \a frame is unused, i.e. can be \c NULL. 858 */ 859 void 860 x86_init_user_debug_at_kernel_exit(iframe* frame) 861 { 862 Thread* thread = thread_get_current_thread(); 863 864 if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED)) 865 return; 866 867 // disable kernel breakpoints 868 disable_breakpoints(); 869 870 // install the user breakpoints 871 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 872 873 arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info; 874 875 install_breakpoints(teamInfo); 876 877 atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED); 878 879 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 880 } 881 882 883 /** 884 * Interrupts are disabled. 885 */ 886 void 887 x86_exit_user_debug_at_kernel_entry() 888 { 889 Thread* thread = thread_get_current_thread(); 890 891 // We need to save the current values of dr6 and dr7 in the CPU structure, 892 // since in case of a debug exception we might overwrite them before 893 // x86_handle_debug_exception() is called. Debug exceptions occur when 894 // hitting a hardware break/watchpoint or when single-stepping. 895 asm("mov %%dr6, %0" : "=r"(thread->cpu->arch.dr6)); 896 asm("mov %%dr7, %0" : "=r"(thread->cpu->arch.dr7)); 897 898 // The remainder needs only be done, when user breakpoints are installed. 899 if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED)) 900 return; 901 902 // disable user breakpoints 903 disable_breakpoints(); 904 905 // install kernel breakpoints 906 Team* kernelTeam = team_get_kernel_team(); 907 908 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 909 910 install_breakpoints(kernelTeam->debug_info.arch_info); 911 912 atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED); 913 914 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 915 } 916 917 918 /** 919 * Interrupts are disabled and will possibly be enabled by the function. 920 */ 921 void 922 x86_handle_debug_exception(iframe* frame) 923 { 924 Thread* thread = thread_get_current_thread(); 925 926 // Get dr6 and dr7. If the given iframe is a userland frame, the exception 927 // obviously occurred in userland. In that case 928 // x86_exit_user_debug_at_kernel_entry() has already been invoked and dr6 929 // and dr7 are stored in the cpu info. Otherwise we need to fetch the 930 // current values from the registers. 931 size_t dr6; 932 size_t dr7; 933 if (IFRAME_IS_USER(frame)) { 934 dr6 = thread->cpu->arch.dr6; 935 dr7 = thread->cpu->arch.dr7; 936 } else { 937 asm("mov %%dr6, %0" : "=r"(dr6)); 938 asm("mov %%dr7, %0" : "=r"(dr7)); 939 } 940 941 TRACE(("x86_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7)); 942 943 // check, which exception condition applies 944 if (dr6 & X86_DR6_BREAKPOINT_MASK) { 945 // breakpoint 946 947 // check which breakpoint was taken 948 bool watchpoint = true; 949 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 950 if (dr6 & (1 << sDR6B[i])) { 951 size_t type = (dr7 >> sDR7RW[i]) & 0x3; 952 if (type == X86_INSTRUCTION_BREAKPOINT) 953 watchpoint = false; 954 } 955 } 956 957 if (IFRAME_IS_USER(frame)) { 958 // enable interrupts and notify the debugger 959 enable_interrupts(); 960 961 if (watchpoint) 962 user_debug_watchpoint_hit(); 963 else 964 user_debug_breakpoint_hit(false); 965 } else { 966 panic("hit kernel %spoint: dr6: 0x%lx, dr7: 0x%lx", 967 watchpoint ? "watch" : "break", dr6, dr7); 968 } 969 } else if (dr6 & (1 << X86_DR6_BD)) { 970 // general detect exception 971 // Occurs only, if GD in DR7 is set (which we don't do) and someone 972 // tries to write to the debug registers. 973 if (IFRAME_IS_USER(frame)) { 974 dprintf("x86_handle_debug_exception(): ignoring spurious general " 975 "detect exception\n"); 976 977 enable_interrupts(); 978 } else 979 panic("spurious general detect exception in kernel mode"); 980 } else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) { 981 // single step 982 983 if (IFRAME_IS_USER(frame)) { 984 // enable interrupts and notify the debugger 985 enable_interrupts(); 986 987 user_debug_single_stepped(); 988 } else { 989 // Disable single-stepping -- the next "step" command will re-enable 990 // it, but we don't want it when continuing otherwise. 991 frame->flags &= ~(1 << X86_EFLAGS_TF); 992 993 // Determine whether the exception occurred at a syscall/trap 994 // kernel entry or whether this is genuine kernel single-stepping. 995 bool inKernel = true; 996 if (thread->team != team_get_kernel_team() 997 && x86_get_user_iframe() == NULL) { 998 // TODO: This is not yet fully correct, since a newly created 999 // thread that hasn't entered userland yet also has this 1000 // property. 1001 inKernel = false; 1002 } 1003 1004 if (inKernel) { 1005 panic("kernel single step"); 1006 } else { 1007 // The thread is a userland thread and it just entered the 1008 // kernel when the single-step exception occurred. This happens 1009 // e.g. when sysenter is called with single-stepping enabled. 1010 // We need to ignore the exception now and send a single-step 1011 // notification later, when the thread wants to return from the 1012 // kernel. 1013 InterruptsSpinLocker threadDebugInfoLocker( 1014 thread->debug_info.lock); 1015 1016 // Check whether the team is still being debugged and set 1017 // the B_THREAD_DEBUG_NOTIFY_SINGLE_STEP and 1018 // B_THREAD_DEBUG_STOP flags, so that the thread will be 1019 // stopped when it is going to leave the kernel and notify the 1020 // debugger about the single-step event. 1021 int32 teamDebugFlags 1022 = atomic_get(&thread->team->debug_info.flags); 1023 if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) { 1024 atomic_or(&thread->debug_info.flags, 1025 B_THREAD_DEBUG_NOTIFY_SINGLE_STEP 1026 | B_THREAD_DEBUG_STOP); 1027 1028 // also set the respective thread flag 1029 atomic_or(&thread->flags, THREAD_FLAGS_DEBUG_THREAD); 1030 } 1031 } 1032 } 1033 } else if (dr6 & (1 << X86_DR6_BT)) { 1034 // task switch 1035 // Occurs only, if T in EFLAGS is set (which we don't do). 1036 if (IFRAME_IS_USER(frame)) { 1037 dprintf("x86_handle_debug_exception(): ignoring spurious task switch " 1038 "exception\n"); 1039 1040 enable_interrupts(); 1041 } else 1042 panic("spurious task switch exception in kernel mode"); 1043 } else { 1044 if (IFRAME_IS_USER(frame)) { 1045 TRACE(("x86_handle_debug_exception(): ignoring spurious debug " 1046 "exception (no condition recognized)\n")); 1047 1048 enable_interrupts(); 1049 } else { 1050 panic("spurious debug exception in kernel mode (no condition " 1051 "recognized)"); 1052 } 1053 } 1054 } 1055 1056 1057 /** 1058 * Interrupts are disabled and will possibly be enabled by the function. 1059 */ 1060 void 1061 x86_handle_breakpoint_exception(iframe* frame) 1062 { 1063 TRACE(("x86_handle_breakpoint_exception()\n")); 1064 1065 // reset eip to the int3 instruction 1066 frame->ip--; 1067 1068 if (!IFRAME_IS_USER(frame)) { 1069 panic("breakpoint exception in kernel mode"); 1070 return; 1071 } 1072 1073 enable_interrupts(); 1074 1075 user_debug_breakpoint_hit(true); 1076 } 1077 1078 1079 void 1080 x86_init_user_debug() 1081 { 1082 // get debug settings 1083 if (void* handle = load_driver_settings("kernel")) { 1084 sQEmuSingleStepHack = get_driver_boolean_parameter(handle, 1085 "qemu_single_step_hack", false, false);; 1086 1087 unload_driver_settings(handle); 1088 } 1089 1090 #if KERNEL_BREAKPOINTS 1091 // install debugger commands 1092 add_debugger_command_etc("breakpoints", &debugger_breakpoints, 1093 "Lists current break-/watchpoints", 1094 "\n" 1095 "Lists the current kernel break-/watchpoints.\n", 0); 1096 add_debugger_command_alias("watchpoints", "breakpoints", NULL); 1097 add_debugger_command_etc("breakpoint", &debugger_breakpoint, 1098 "Set/clears a breakpoint", 1099 "<address> [ clear ]\n" 1100 "Sets respectively clears the breakpoint at address <address>.\n", 0); 1101 add_debugger_command_etc("watchpoint", &debugger_watchpoint, 1102 "Set/clears a watchpoint", 1103 "<address> <address> ( [ rw ] [ <size> ] | clear )\n" 1104 "Sets respectively clears the watchpoint at address <address>.\n" 1105 "If \"rw\" is given the new watchpoint is a read/write watchpoint\n" 1106 "otherwise a write watchpoint only.\n", 0); 1107 add_debugger_command_etc("step", &debugger_single_step, 1108 "Single-steps to the next instruction", 1109 "\n" 1110 "Single-steps to the next instruction.\n", 0); 1111 #endif 1112 } 1113 1114