1 /* 2 * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <arch/user_debugger.h> 7 8 #include <string.h> 9 10 #include <debugger.h> 11 #include <driver_settings.h> 12 #include <int.h> 13 #include <team.h> 14 #include <thread.h> 15 16 17 //#define TRACE_ARCH_USER_DEBUGGER 18 #ifdef TRACE_ARCH_USER_DEBUGGER 19 # define TRACE(x) dprintf x 20 #else 21 # define TRACE(x) ; 22 #endif 23 24 #define B_NO_MORE_BREAKPOINTS B_BUSY 25 #define B_NO_MORE_WATCHPOINTS B_BUSY 26 #define B_BAD_WATCHPOINT_ALIGNMENT B_BAD_VALUE 27 #define B_WATCHPOINT_TYPE_NOT_SUPPORTED B_NOT_SUPPORTED 28 #define B_WATCHPOINT_LENGTH_NOT_SUPPORTED B_NOT_SUPPORTED 29 #define B_BREAKPOINT_NOT_FOUND B_NAME_NOT_FOUND 30 #define B_WATCHPOINT_NOT_FOUND B_NAME_NOT_FOUND 31 // ToDo: Make those real error codes. 32 33 // maps breakpoint slot index to LEN_i LSB number 34 static const uint32 sDR7Len[4] = { 35 X86_DR7_LEN0_LSB, X86_DR7_LEN1_LSB, X86_DR7_LEN2_LSB, X86_DR7_LEN3_LSB 36 }; 37 38 // maps breakpoint slot index to R/W_i LSB number 39 static const uint32 sDR7RW[4] = { 40 X86_DR7_RW0_LSB, X86_DR7_RW1_LSB, X86_DR7_RW2_LSB, X86_DR7_RW3_LSB 41 }; 42 43 // maps breakpoint slot index to L_i bit number 44 static const uint32 sDR7L[4] = { 45 X86_DR7_L0, X86_DR7_L1, X86_DR7_L2, X86_DR7_L3 46 }; 47 48 // maps breakpoint slot index to G_i bit number 49 static const uint32 sDR7G[4] = { 50 X86_DR7_G0, X86_DR7_G1, X86_DR7_G2, X86_DR7_G3 51 }; 52 53 // maps breakpoint slot index to B_i bit number 54 static const uint32 sDR6B[4] = { 55 X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3 56 }; 57 58 // Enables a hack to make single stepping work under qemu. Set via kernel 59 // driver settings. 60 static bool sQEmuSingleStepHack = false; 61 62 63 static inline void 64 install_breakpoints(const arch_team_debug_info &teamInfo) 65 { 66 // set breakpoints 67 asm("movl %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address)); 68 asm("movl %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address)); 69 asm("movl %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address)); 70 // asm("movl %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address)); 71 // DR3 is used to hold the current struct thread*. 72 73 // enable breakpoints 74 asm("movl %0, %%dr7" : : "r"(teamInfo.dr7)); 75 } 76 77 78 static inline void 79 disable_breakpoints() 80 { 81 asm("movl %0, %%dr7" : : "r"(X86_BREAKPOINTS_DISABLED_DR7)); 82 } 83 84 85 /*! Sets a break-/watchpoint in the given team info. 86 Interrupts must be disabled and the team debug info lock be held. 87 */ 88 static inline status_t 89 set_breakpoint(arch_team_debug_info &info, void *address, uint32 type, 90 uint32 length, bool setGlobalFlag) 91 { 92 // check, if there is already a breakpoint at that address 93 bool alreadySet = false; 94 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 95 if (info.breakpoints[i].address == address 96 && info.breakpoints[i].type == type) { 97 alreadySet = true; 98 break; 99 } 100 } 101 102 if (!alreadySet) { 103 // find a free slot 104 int32 slot = -1; 105 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 106 if (!info.breakpoints[i].address) { 107 slot = i; 108 break; 109 } 110 } 111 112 // init the breakpoint 113 if (slot >= 0) { 114 info.breakpoints[slot].address = address; 115 info.breakpoints[slot].type = type; 116 info.breakpoints[slot].length = length; 117 118 info.dr7 |= (length << sDR7Len[slot]) 119 | (type << sDR7RW[slot]) 120 | (1 << sDR7L[slot]); 121 if (setGlobalFlag) 122 info.dr7 |= (1 << sDR7G[slot]); 123 } else { 124 if (type == X86_INSTRUCTION_BREAKPOINT) 125 return B_NO_MORE_BREAKPOINTS; 126 else 127 return B_NO_MORE_WATCHPOINTS; 128 } 129 } 130 131 return B_OK; 132 } 133 134 135 /*! Clears a break-/watchpoint in the given team info. 136 Interrupts must be disabled and the team debug info lock be held. 137 */ 138 static inline status_t 139 clear_breakpoint(arch_team_debug_info &info, void *address, bool watchpoint) 140 { 141 // find the breakpoint 142 int32 slot = -1; 143 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 144 if (info.breakpoints[i].address == address 145 && (watchpoint 146 != (info.breakpoints[i].type == X86_INSTRUCTION_BREAKPOINT))) { 147 slot = i; 148 break; 149 } 150 } 151 152 // clear the breakpoint 153 if (slot >= 0) { 154 info.breakpoints[slot].address = NULL; 155 156 info.dr7 &= ~((0x3 << sDR7Len[slot]) 157 | (0x3 << sDR7RW[slot]) 158 | (1 << sDR7L[slot]) 159 | (1 << sDR7G[slot])); 160 } else { 161 if (watchpoint) 162 return B_WATCHPOINT_NOT_FOUND; 163 else 164 return B_BREAKPOINT_NOT_FOUND; 165 } 166 167 return B_OK; 168 } 169 170 171 static status_t 172 set_breakpoint(void *address, uint32 type, uint32 length) 173 { 174 if (!address) 175 return B_BAD_VALUE; 176 177 struct thread *thread = thread_get_current_thread(); 178 179 cpu_status state = disable_interrupts(); 180 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 181 182 status_t error = set_breakpoint(thread->team->debug_info.arch_info, address, 183 type, length, false); 184 185 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 186 restore_interrupts(state); 187 188 return error; 189 } 190 191 192 static status_t 193 clear_breakpoint(void *address, bool watchpoint) 194 { 195 if (!address) 196 return B_BAD_VALUE; 197 198 struct thread *thread = thread_get_current_thread(); 199 200 cpu_status state = disable_interrupts(); 201 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 202 203 status_t error = clear_breakpoint(thread->team->debug_info.arch_info, 204 address, watchpoint); 205 206 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 207 restore_interrupts(state); 208 209 return error; 210 } 211 212 213 #if KERNEL_BREAKPOINTS 214 215 216 static void 217 install_breakpoints_per_cpu(void* /*cookie*/, int cpu) 218 { 219 struct team* kernelTeam = team_get_kernel_team(); 220 221 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 222 223 install_breakpoints(kernelTeam->debug_info.arch_info); 224 225 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 226 } 227 228 229 static status_t 230 set_kernel_breakpoint(void *address, uint32 type, uint32 length) 231 { 232 if (!address) 233 return B_BAD_VALUE; 234 235 struct team* kernelTeam = team_get_kernel_team(); 236 237 cpu_status state = disable_interrupts(); 238 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 239 240 status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address, 241 type, length, true); 242 243 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 244 245 call_all_cpus(install_breakpoints_per_cpu, NULL); 246 247 restore_interrupts(state); 248 249 return error; 250 } 251 252 253 static status_t 254 clear_kernel_breakpoint(void *address, bool watchpoint) 255 { 256 if (!address) 257 return B_BAD_VALUE; 258 259 struct team* kernelTeam = team_get_kernel_team(); 260 261 cpu_status state = disable_interrupts(); 262 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 263 264 status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info, 265 address, watchpoint); 266 267 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 268 269 call_all_cpus(install_breakpoints_per_cpu, NULL); 270 271 restore_interrupts(state); 272 273 return error; 274 } 275 276 #endif // KERNEL_BREAKPOINTS 277 278 279 static inline status_t 280 check_watch_point_parameters(void* address, uint32 type, int32 length, 281 uint32& archType, uint32& archLength) 282 { 283 // check type 284 switch (type) { 285 case B_DATA_WRITE_WATCHPOINT: 286 archType = X86_DATA_WRITE_BREAKPOINT; 287 break; 288 case B_DATA_READ_WRITE_WATCHPOINT: 289 archType = X86_DATA_READ_WRITE_BREAKPOINT; 290 break; 291 case B_DATA_READ_WATCHPOINT: 292 default: 293 return B_WATCHPOINT_TYPE_NOT_SUPPORTED; 294 break; 295 } 296 297 // check length and alignment 298 switch (length) { 299 case 1: 300 archLength = X86_BREAKPOINT_LENGTH_1; 301 break; 302 case 2: 303 if ((uint32)address & 0x1) 304 return B_BAD_WATCHPOINT_ALIGNMENT; 305 archLength = X86_BREAKPOINT_LENGTH_2; 306 break; 307 case 4: 308 if ((uint32)address & 0x3) 309 return B_BAD_WATCHPOINT_ALIGNMENT; 310 archLength = X86_BREAKPOINT_LENGTH_4; 311 break; 312 default: 313 return B_WATCHPOINT_LENGTH_NOT_SUPPORTED; 314 } 315 316 return B_OK; 317 } 318 319 320 // #pragma mark - kernel debugger commands 321 322 #if KERNEL_BREAKPOINTS 323 324 static int 325 debugger_breakpoints(int argc, char** argv) 326 { 327 struct team* kernelTeam = team_get_kernel_team(); 328 arch_team_debug_info& info = kernelTeam->debug_info.arch_info; 329 330 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 331 kprintf("breakpoint[%ld] ", i); 332 333 if (info.breakpoints[i].address != NULL) { 334 kprintf("%p ", info.breakpoints[i].address); 335 switch (info.breakpoints[i].type) { 336 case X86_INSTRUCTION_BREAKPOINT: 337 kprintf("instruction"); 338 break; 339 case X86_IO_READ_WRITE_BREAKPOINT: 340 kprintf("io read/write"); 341 break; 342 case X86_DATA_WRITE_BREAKPOINT: 343 kprintf("data write"); 344 break; 345 case X86_DATA_READ_WRITE_BREAKPOINT: 346 kprintf("data read/write"); 347 break; 348 } 349 350 int length = 1; 351 switch (info.breakpoints[i].length) { 352 case X86_BREAKPOINT_LENGTH_1: 353 length = 1; 354 break; 355 case X86_BREAKPOINT_LENGTH_2: 356 length = 2; 357 break; 358 case X86_BREAKPOINT_LENGTH_4: 359 length = 4; 360 break; 361 } 362 363 if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT) 364 kprintf(" %d byte%s", length, (length > 1 ? "s" : "")); 365 } else 366 kprintf("unused"); 367 368 kprintf("\n"); 369 } 370 371 return 0; 372 } 373 374 375 static int 376 debugger_breakpoint(int argc, char** argv) 377 { 378 // get arguments 379 380 if (argc < 2 || argc > 3) 381 return print_debugger_command_usage(argv[0]); 382 383 addr_t address = strtoul(argv[1], NULL, 0); 384 if (address == 0) 385 return print_debugger_command_usage(argv[0]); 386 387 bool clear = false; 388 if (argc == 3) { 389 if (strcmp(argv[2], "clear") == 0) 390 clear = true; 391 else 392 return print_debugger_command_usage(argv[0]); 393 } 394 395 // set/clear breakpoint 396 397 arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; 398 399 status_t error; 400 401 if (clear) { 402 error = clear_breakpoint(info, (void*)address, false); 403 } else { 404 error = set_breakpoint(info, (void*)address, X86_INSTRUCTION_BREAKPOINT, 405 X86_BREAKPOINT_LENGTH_1, true); 406 } 407 408 if (error == B_OK) 409 call_all_cpus_sync(install_breakpoints_per_cpu, NULL); 410 else 411 kprintf("Failed to install breakpoint: %s\n", strerror(error)); 412 413 return 0; 414 } 415 416 417 static int 418 debugger_watchpoint(int argc, char** argv) 419 { 420 // get arguments 421 422 if (argc < 2 || argc > 4) 423 return print_debugger_command_usage(argv[0]); 424 425 addr_t address = strtoul(argv[1], NULL, 0); 426 if (address == 0) 427 return print_debugger_command_usage(argv[0]); 428 429 bool clear = false; 430 bool readWrite = false; 431 int argi = 2; 432 int length = 1; 433 if (argc >= 3) { 434 if (strcmp(argv[argi], "clear") == 0) { 435 clear = true; 436 argi++; 437 } else if (strcmp(argv[argi], "rw") == 0) { 438 readWrite = true; 439 argi++; 440 } 441 442 if (!clear && argi < argc) 443 length = strtoul(argv[argi++], NULL, 0); 444 445 if (length == 0 || argi < argc) 446 return print_debugger_command_usage(argv[0]); 447 } 448 449 // set/clear breakpoint 450 451 arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; 452 453 status_t error; 454 455 if (clear) { 456 error = clear_breakpoint(info, (void*)address, true); 457 } else { 458 uint32 type = readWrite ? B_DATA_READ_WRITE_WATCHPOINT 459 : B_DATA_WRITE_WATCHPOINT; 460 461 uint32 archType, archLength; 462 error = check_watch_point_parameters((void*)address, type, length, 463 archType, archLength); 464 465 if (error == B_OK) { 466 error = set_breakpoint(info, (void*)address, archType, archLength, 467 true); 468 } 469 } 470 471 if (error == B_OK) 472 call_all_cpus_sync(install_breakpoints_per_cpu, NULL); 473 else 474 kprintf("Failed to install breakpoint: %s\n", strerror(error)); 475 476 return 0; 477 } 478 479 480 static int 481 debugger_single_step(int argc, char** argv) 482 { 483 // TODO: Since we need an iframe, this doesn't work when KDL wasn't entered 484 // via an exception. 485 486 struct iframe* frame = i386_get_current_iframe(); 487 if (frame == NULL) { 488 kprintf("Failed to get the current iframe!\n"); 489 return 0; 490 } 491 492 frame->flags |= (1 << X86_EFLAGS_TF); 493 494 return B_KDEBUG_QUIT; 495 } 496 497 498 #endif // KERNEL_BREAKPOINTS 499 500 501 // #pragma mark - in-kernel public interface 502 503 504 void 505 arch_clear_team_debug_info(struct arch_team_debug_info *info) 506 { 507 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) 508 info->breakpoints[i].address = NULL; 509 510 info->dr7 = X86_BREAKPOINTS_DISABLED_DR7; 511 } 512 513 514 void 515 arch_destroy_team_debug_info(struct arch_team_debug_info *info) 516 { 517 arch_clear_team_debug_info(info); 518 } 519 520 521 void 522 arch_clear_thread_debug_info(struct arch_thread_debug_info *info) 523 { 524 info->flags = 0; 525 } 526 527 528 void 529 arch_destroy_thread_debug_info(struct arch_thread_debug_info *info) 530 { 531 arch_clear_thread_debug_info(info); 532 } 533 534 535 void 536 arch_update_thread_single_step() 537 { 538 if (struct iframe* frame = i386_get_user_iframe()) { 539 struct thread* thread = thread_get_current_thread(); 540 541 // set/clear TF in EFLAGS depending on if single stepping is desired 542 if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP) 543 frame->flags |= (1 << X86_EFLAGS_TF); 544 else 545 frame->flags &= ~(1 << X86_EFLAGS_TF); 546 } 547 } 548 549 550 void 551 arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState) 552 { 553 if (struct iframe *frame = i386_get_user_iframe()) { 554 i386_frstor(cpuState->extended_regs); 555 // For this to be correct the calling function must not use these 556 // registers (not even indirectly). 557 558 // frame->gs = cpuState->gs; 559 // frame->fs = cpuState->fs; 560 // frame->es = cpuState->es; 561 // frame->ds = cpuState->ds; 562 frame->edi = cpuState->edi; 563 frame->esi = cpuState->esi; 564 frame->ebp = cpuState->ebp; 565 frame->esp = cpuState->esp; 566 frame->ebx = cpuState->ebx; 567 frame->edx = cpuState->edx; 568 frame->ecx = cpuState->ecx; 569 frame->eax = cpuState->eax; 570 // frame->vector = cpuState->vector; 571 // frame->error_code = cpuState->error_code; 572 frame->eip = cpuState->eip; 573 // frame->cs = cpuState->cs; 574 frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS) 575 | (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS); 576 frame->user_esp = cpuState->user_esp; 577 // frame->user_ss = cpuState->user_ss; 578 } 579 } 580 581 582 void 583 arch_get_debug_cpu_state(struct debug_cpu_state *cpuState) 584 { 585 if (struct iframe *frame = i386_get_user_iframe()) { 586 i386_fnsave(cpuState->extended_regs); 587 // For this to be correct the calling function must not use these 588 // registers (not even indirectly). 589 590 cpuState->gs = frame->gs; 591 cpuState->fs = frame->fs; 592 cpuState->es = frame->es; 593 cpuState->ds = frame->ds; 594 cpuState->edi = frame->edi; 595 cpuState->esi = frame->esi; 596 cpuState->ebp = frame->ebp; 597 cpuState->esp = frame->esp; 598 cpuState->ebx = frame->ebx; 599 cpuState->edx = frame->orig_edx; 600 cpuState->ecx = frame->ecx; 601 cpuState->eax = frame->orig_eax; 602 cpuState->vector = frame->vector; 603 cpuState->error_code = frame->error_code; 604 cpuState->eip = frame->eip; 605 cpuState->cs = frame->cs; 606 cpuState->eflags = frame->flags; 607 cpuState->user_esp = frame->user_esp; 608 cpuState->user_ss = frame->user_ss; 609 } 610 } 611 612 613 status_t 614 arch_set_breakpoint(void *address) 615 { 616 return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 617 X86_BREAKPOINT_LENGTH_1); 618 } 619 620 621 status_t 622 arch_clear_breakpoint(void *address) 623 { 624 return clear_breakpoint(address, false); 625 } 626 627 628 status_t 629 arch_set_watchpoint(void *address, uint32 type, int32 length) 630 { 631 uint32 archType, archLength; 632 status_t error = check_watch_point_parameters(address, type, length, 633 archType, archLength); 634 if (error != B_OK) 635 return error; 636 637 return set_breakpoint(address, archType, archLength); 638 } 639 640 641 status_t 642 arch_clear_watchpoint(void *address) 643 { 644 return clear_breakpoint(address, false); 645 } 646 647 648 bool 649 arch_has_breakpoints(struct arch_team_debug_info *info) 650 { 651 // Reading info->dr7 is atomically, so we don't need to lock. The caller 652 // has to ensure, that the info doesn't go away. 653 return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7); 654 } 655 656 657 #if KERNEL_BREAKPOINTS 658 659 status_t 660 arch_set_kernel_breakpoint(void *address) 661 { 662 status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 663 X86_BREAKPOINT_LENGTH_1); 664 665 if (error != B_OK) { 666 panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s", 667 strerror(error)); 668 } 669 670 return error; 671 } 672 673 674 status_t 675 arch_clear_kernel_breakpoint(void *address) 676 { 677 status_t error = clear_kernel_breakpoint(address, false); 678 679 if (error != B_OK) { 680 panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s", 681 strerror(error)); 682 } 683 684 return error; 685 } 686 687 688 status_t 689 arch_set_kernel_watchpoint(void *address, uint32 type, int32 length) 690 { 691 uint32 archType, archLength; 692 status_t error = check_watch_point_parameters(address, type, length, 693 archType, archLength); 694 695 if (error == B_OK) 696 error = set_kernel_breakpoint(address, archType, archLength); 697 698 if (error != B_OK) { 699 panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s", 700 strerror(error)); 701 } 702 703 return error; 704 } 705 706 707 status_t 708 arch_clear_kernel_watchpoint(void *address) 709 { 710 status_t error = clear_kernel_breakpoint(address, true); 711 712 if (error != B_OK) { 713 panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s", 714 strerror(error)); 715 } 716 717 return error; 718 } 719 720 #endif // KERNEL_BREAKPOINTS 721 722 723 // #pragma mark - x86 implementation interface 724 725 726 /** 727 * Interrupts are disabled. 728 */ 729 void 730 x86_init_user_debug_at_kernel_exit(struct iframe *frame) 731 { 732 struct thread *thread = thread_get_current_thread(); 733 734 if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED)) 735 return; 736 737 // disable kernel breakpoints 738 disable_breakpoints(); 739 740 GRAB_THREAD_LOCK(); 741 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 742 743 arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info; 744 745 // install the user breakpoints 746 install_breakpoints(teamInfo); 747 748 atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED); 749 750 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 751 RELEASE_THREAD_LOCK(); 752 } 753 754 755 /** 756 * Interrupts are disabled. 757 */ 758 void 759 x86_exit_user_debug_at_kernel_entry() 760 { 761 struct thread *thread = thread_get_current_thread(); 762 763 if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED)) 764 return; 765 766 GRAB_THREAD_LOCK(); 767 768 // disable user breakpoints 769 disable_breakpoints(); 770 771 // install kernel breakpoints 772 struct team* kernelTeam = team_get_kernel_team(); 773 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 774 install_breakpoints(kernelTeam->debug_info.arch_info); 775 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 776 777 atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED); 778 779 RELEASE_THREAD_LOCK(); 780 } 781 782 783 /** 784 * Interrupts are disabled and will possibly be enabled by the function. 785 */ 786 void 787 x86_handle_debug_exception(struct iframe *frame) 788 { 789 // get debug status and control registers 790 uint32 dr6, dr7; 791 asm("movl %%dr6, %0" : "=r"(dr6)); 792 asm("movl %%dr7, %0" : "=r"(dr7)); 793 794 TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7)); 795 796 // check, which exception condition applies 797 if (dr6 & X86_DR6_BREAKPOINT_MASK) { 798 // breakpoint 799 800 // check which breakpoint was taken 801 bool watchpoint = true; 802 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 803 if (dr6 & (1 << sDR6B[i])) { 804 // If it is an instruction breakpoint, we need to set RF in 805 // EFLAGS to prevent triggering the same exception 806 // again (breakpoint instructions are triggered *before* 807 // executing the instruction). 808 uint32 type = (dr7 >> sDR7RW[i]) & 0x3; 809 if (type == X86_INSTRUCTION_BREAKPOINT) { 810 frame->flags |= (1 << X86_EFLAGS_RF); 811 watchpoint = false; 812 } 813 } 814 } 815 816 if (IFRAME_IS_USER(frame)) { 817 // enable interrupts and notify the debugger 818 enable_interrupts(); 819 820 if (watchpoint) 821 user_debug_watchpoint_hit(); 822 else 823 user_debug_breakpoint_hit(false); 824 } else { 825 panic("hit kernel %spoint: dr6: 0x%lx, dr7: 0x%lx", 826 watchpoint ? "watch" : "break", dr6, dr7); 827 } 828 } else if (dr6 & (1 << X86_DR6_BD)) { 829 // general detect exception 830 // Occurs only, if GD in DR7 is set (which we don't do) and someone 831 // tries to write to the debug registers. 832 if (IFRAME_IS_USER(frame)) { 833 dprintf("i386_handle_debug_exception(): ignoring spurious general " 834 "detect exception\n"); 835 836 enable_interrupts(); 837 } else 838 panic("spurious general detect exception in kernel mode"); 839 } else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) { 840 // single step 841 842 if (IFRAME_IS_USER(frame)) { 843 // enable interrupts and notify the debugger 844 enable_interrupts(); 845 846 user_debug_single_stepped(); 847 } else { 848 // Disable single-stepping -- the next "step" command will re-enable 849 // it, but we don't want it when continuing otherwise. 850 frame->flags &= ~(1 << X86_EFLAGS_TF); 851 852 panic("kernel single step"); 853 } 854 } else if (dr6 & (1 << X86_DR6_BT)) { 855 // task switch 856 // Occurs only, if T in EFLAGS is set (which we don't do). 857 if (IFRAME_IS_USER(frame)) { 858 dprintf("i386_handle_debug_exception(): ignoring spurious task switch " 859 "exception\n"); 860 861 enable_interrupts(); 862 } else 863 panic("spurious task switch exception in kernel mode"); 864 } else { 865 if (IFRAME_IS_USER(frame)) { 866 TRACE(("i386_handle_debug_exception(): ignoring spurious debug " 867 "exception (no condition recognized)\n")); 868 869 enable_interrupts(); 870 } else { 871 panic("spurious debug exception in kernel mode (no condition " 872 "recognized)"); 873 } 874 } 875 } 876 877 878 /** 879 * Interrupts are disabled and will possibly be enabled by the function. 880 */ 881 void 882 x86_handle_breakpoint_exception(struct iframe *frame) 883 { 884 TRACE(("i386_handle_breakpoint_exception()\n")); 885 886 if (!IFRAME_IS_USER(frame)) { 887 panic("breakpoint exception in kernel mode"); 888 return; 889 } 890 891 enable_interrupts(); 892 893 user_debug_breakpoint_hit(true); 894 } 895 896 897 void 898 x86_init_user_debug() 899 { 900 // get debug settings 901 if (void *handle = load_driver_settings("kernel")) { 902 sQEmuSingleStepHack = get_driver_boolean_parameter(handle, 903 "qemu_single_step_hack", false, false);; 904 905 unload_driver_settings(handle); 906 } 907 908 #if KERNEL_BREAKPOINTS 909 // install debugger commands 910 add_debugger_command_etc("breakpoints", &debugger_breakpoints, 911 "Lists current break-/watchpoints", 912 "\n" 913 "Lists the current kernel break-/watchpoints.\n", 0); 914 add_debugger_command_alias("watchpoints", "breakpoints", NULL); 915 add_debugger_command_etc("breakpoint", &debugger_breakpoint, 916 "Set/clears a breakpoint", 917 "<address> [ clear ]\n" 918 "Sets respectively clears the breakpoint at address <address>.\n", 0); 919 add_debugger_command_etc("watchpoint", &debugger_watchpoint, 920 "Set/clears a watchpoint", 921 "<address> <address> ( [ rw ] [ <size> ] | clear )\n" 922 "Sets respectively clears the watchpoint at address <address>.\n" 923 "If \"rw\" is given the new watchpoint is a read/write watchpoint\n" 924 "otherwise a write watchpoint only.\n", 0); 925 add_debugger_command_etc("step", &debugger_single_step, 926 "Single-steps to the next instruction", 927 "\n" 928 "Single-steps to the next instruction.\n", 0); 929 #endif 930 } 931 932