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