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 static status_t 216 set_kernel_breakpoint(void *address, uint32 type, uint32 length) 217 { 218 if (!address) 219 return B_BAD_VALUE; 220 221 struct team* kernelTeam = team_get_kernel_team(); 222 223 cpu_status state = disable_interrupts(); 224 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 225 226 status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address, 227 type, length, true); 228 229 install_breakpoints(kernelTeam->debug_info.arch_info); 230 231 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 232 restore_interrupts(state); 233 234 return error; 235 } 236 237 238 static status_t 239 clear_kernel_breakpoint(void *address, bool watchpoint) 240 { 241 if (!address) 242 return B_BAD_VALUE; 243 244 struct team* kernelTeam = team_get_kernel_team(); 245 246 cpu_status state = disable_interrupts(); 247 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 248 249 status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info, 250 address, watchpoint); 251 252 install_breakpoints(kernelTeam->debug_info.arch_info); 253 254 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 255 restore_interrupts(state); 256 257 return error; 258 } 259 260 #endif // KERNEL_BREAKPOINTS 261 262 263 static inline status_t 264 check_watch_point_parameters(void* address, uint32 type, int32 length, 265 uint32& archType, uint32& archLength) 266 { 267 // check type 268 switch (type) { 269 case B_DATA_WRITE_WATCHPOINT: 270 archType = X86_DATA_WRITE_BREAKPOINT; 271 break; 272 case B_DATA_READ_WRITE_WATCHPOINT: 273 archType = X86_DATA_READ_WRITE_BREAKPOINT; 274 break; 275 case B_DATA_READ_WATCHPOINT: 276 default: 277 return B_WATCHPOINT_TYPE_NOT_SUPPORTED; 278 break; 279 } 280 281 // check length and alignment 282 switch (length) { 283 case 1: 284 archLength = X86_BREAKPOINT_LENGTH_1; 285 break; 286 case 2: 287 if ((uint32)address & 0x1) 288 return B_BAD_WATCHPOINT_ALIGNMENT; 289 archLength = X86_BREAKPOINT_LENGTH_2; 290 break; 291 case 4: 292 if ((uint32)address & 0x3) 293 return B_BAD_WATCHPOINT_ALIGNMENT; 294 archLength = X86_BREAKPOINT_LENGTH_4; 295 break; 296 default: 297 return B_WATCHPOINT_LENGTH_NOT_SUPPORTED; 298 } 299 300 return B_OK; 301 } 302 303 304 // #pragma mark - kernel debugger commands 305 306 #if KERNEL_BREAKPOINTS 307 308 static int 309 debugger_breakpoints(int argc, char** argv) 310 { 311 struct team* kernelTeam = team_get_kernel_team(); 312 arch_team_debug_info& info = kernelTeam->debug_info.arch_info; 313 314 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 315 kprintf("breakpoint[%ld] ", i); 316 317 if (info.breakpoints[i].address != NULL) { 318 kprintf("%p ", info.breakpoints[i].address); 319 switch (info.breakpoints[i].type) { 320 case X86_INSTRUCTION_BREAKPOINT: 321 kprintf("instruction"); 322 break; 323 case X86_IO_READ_WRITE_BREAKPOINT: 324 kprintf("io read/write"); 325 break; 326 case X86_DATA_WRITE_BREAKPOINT: 327 kprintf("data write"); 328 break; 329 case X86_DATA_READ_WRITE_BREAKPOINT: 330 kprintf("data read/write"); 331 break; 332 } 333 334 int length = 1; 335 switch (info.breakpoints[i].length) { 336 case X86_BREAKPOINT_LENGTH_1: 337 length = 1; 338 break; 339 case X86_BREAKPOINT_LENGTH_2: 340 length = 2; 341 break; 342 case X86_BREAKPOINT_LENGTH_4: 343 length = 4; 344 break; 345 } 346 347 if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT) 348 kprintf(" %d byte%s", length, (length > 1 ? "s" : "")); 349 } else 350 kprintf("unused"); 351 352 kprintf("\n"); 353 } 354 355 return 0; 356 } 357 358 359 static int 360 debugger_breakpoint_usage(const char* command) 361 { 362 if (command[0] == 'b') { 363 kprintf("Usage: breakpoint <address>\n"); 364 kprintf(" breakpoint <address> clear\n"); 365 } else { 366 kprintf("Usage: watchpoint <address> [ rw ] [ <size> ]\n"); 367 kprintf(" watchpoint <address> clear\n"); 368 } 369 return 0; 370 } 371 372 373 static int 374 debugger_breakpoint(int argc, char** argv) 375 { 376 // get arguments 377 378 if (argc < 2 || argc > 3) 379 return debugger_breakpoint_usage(argv[0]); 380 381 addr_t address = strtoul(argv[1], NULL, 0); 382 if (address == 0) 383 return debugger_breakpoint_usage(argv[0]); 384 385 bool clear = false; 386 if (argc == 3) { 387 if (strcmp(argv[2], "clear") == 0) 388 clear = true; 389 else 390 return debugger_breakpoint_usage(argv[0]); 391 } 392 393 // set/clear breakpoint 394 395 arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; 396 397 status_t error; 398 399 if (clear) { 400 error = clear_breakpoint(info, (void*)address, false); 401 } else { 402 error = set_breakpoint(info, (void*)address, X86_INSTRUCTION_BREAKPOINT, 403 X86_BREAKPOINT_LENGTH_1, true); 404 } 405 406 if (error == B_OK) 407 install_breakpoints(info); 408 else 409 kprintf("Failed to install breakpoint: %s\n", strerror(error)); 410 411 return 0; 412 } 413 414 415 static int 416 debugger_watchpoint(int argc, char** argv) 417 { 418 // get arguments 419 420 if (argc < 2 || argc > 4) 421 return debugger_breakpoint_usage(argv[0]); 422 423 addr_t address = strtoul(argv[1], NULL, 0); 424 if (address == 0) 425 return debugger_breakpoint_usage(argv[0]); 426 427 bool clear = false; 428 bool readWrite = false; 429 int argi = 2; 430 int length = 1; 431 if (argc >= 3) { 432 if (strcmp(argv[argi], "clear") == 0) { 433 clear = true; 434 argi++; 435 } else if (strcmp(argv[argi], "rw") == 0) { 436 readWrite = true; 437 argi++; 438 } 439 440 if (!clear && argi < argc) 441 length = strtoul(argv[argi++], NULL, 0); 442 443 if (length == 0 || argi < argc) 444 return debugger_breakpoint_usage(argv[0]); 445 } 446 447 // set/clear breakpoint 448 449 arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; 450 451 status_t error; 452 453 if (clear) { 454 error = clear_breakpoint(info, (void*)address, true); 455 } else { 456 uint32 type = readWrite ? B_DATA_READ_WRITE_WATCHPOINT 457 : B_DATA_WRITE_WATCHPOINT; 458 459 uint32 archType, archLength; 460 error = check_watch_point_parameters((void*)address, type, length, 461 archType, archLength); 462 463 if (error == B_OK) { 464 error = set_breakpoint(info, (void*)address, archType, archLength, 465 true); 466 } 467 } 468 469 if (error == B_OK) 470 install_breakpoints(info); 471 else 472 kprintf("Failed to install breakpoint: %s\n", strerror(error)); 473 474 return 0; 475 } 476 477 #endif // KERNEL_BREAKPOINTS 478 479 480 // #pragma mark - in-kernel public interface 481 482 483 void 484 arch_clear_team_debug_info(struct arch_team_debug_info *info) 485 { 486 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) 487 info->breakpoints[i].address = NULL; 488 489 info->dr7 = X86_BREAKPOINTS_DISABLED_DR7; 490 } 491 492 493 void 494 arch_destroy_team_debug_info(struct arch_team_debug_info *info) 495 { 496 arch_clear_team_debug_info(info); 497 } 498 499 500 void 501 arch_clear_thread_debug_info(struct arch_thread_debug_info *info) 502 { 503 info->flags = 0; 504 } 505 506 507 void 508 arch_destroy_thread_debug_info(struct arch_thread_debug_info *info) 509 { 510 arch_clear_thread_debug_info(info); 511 } 512 513 514 void 515 arch_update_thread_single_step() 516 { 517 if (struct iframe* frame = i386_get_user_iframe()) { 518 struct thread* thread = thread_get_current_thread(); 519 520 // set/clear TF in EFLAGS depending on if single stepping is desired 521 if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP) 522 frame->flags |= (1 << X86_EFLAGS_TF); 523 else 524 frame->flags &= ~(1 << X86_EFLAGS_TF); 525 } 526 } 527 528 529 void 530 arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState) 531 { 532 if (struct iframe *frame = i386_get_user_iframe()) { 533 struct thread *thread = thread_get_current_thread(); 534 535 i386_frstor(cpuState->extended_regs); 536 // For this to be correct the calling function must not use these 537 // registers (not even indirectly). 538 539 // frame->gs = cpuState->gs; 540 // frame->fs = cpuState->fs; 541 // frame->es = cpuState->es; 542 // frame->ds = cpuState->ds; 543 frame->edi = cpuState->edi; 544 frame->esi = cpuState->esi; 545 frame->ebp = cpuState->ebp; 546 frame->esp = cpuState->esp; 547 frame->ebx = cpuState->ebx; 548 frame->edx = cpuState->edx; 549 frame->ecx = cpuState->ecx; 550 frame->eax = cpuState->eax; 551 // frame->vector = cpuState->vector; 552 // frame->error_code = cpuState->error_code; 553 frame->eip = cpuState->eip; 554 // frame->cs = cpuState->cs; 555 frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS) 556 | (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS); 557 frame->user_esp = cpuState->user_esp; 558 // frame->user_ss = cpuState->user_ss; 559 } 560 } 561 562 563 void 564 arch_get_debug_cpu_state(struct debug_cpu_state *cpuState) 565 { 566 if (struct iframe *frame = i386_get_user_iframe()) { 567 struct thread *thread = thread_get_current_thread(); 568 569 i386_fnsave(cpuState->extended_regs); 570 // For this to be correct the calling function must not use these 571 // registers (not even indirectly). 572 573 cpuState->gs = frame->gs; 574 cpuState->fs = frame->fs; 575 cpuState->es = frame->es; 576 cpuState->ds = frame->ds; 577 cpuState->edi = frame->edi; 578 cpuState->esi = frame->esi; 579 cpuState->ebp = frame->ebp; 580 cpuState->esp = frame->esp; 581 cpuState->ebx = frame->ebx; 582 cpuState->edx = frame->orig_edx; 583 cpuState->ecx = frame->ecx; 584 cpuState->eax = frame->orig_eax; 585 cpuState->vector = frame->vector; 586 cpuState->error_code = frame->error_code; 587 cpuState->eip = frame->eip; 588 cpuState->cs = frame->cs; 589 cpuState->eflags = frame->flags; 590 cpuState->user_esp = frame->user_esp; 591 cpuState->user_ss = frame->user_ss; 592 } 593 } 594 595 596 status_t 597 arch_set_breakpoint(void *address) 598 { 599 return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 600 X86_BREAKPOINT_LENGTH_1); 601 } 602 603 604 status_t 605 arch_clear_breakpoint(void *address) 606 { 607 return clear_breakpoint(address, false); 608 } 609 610 611 status_t 612 arch_set_watchpoint(void *address, uint32 type, int32 length) 613 { 614 uint32 archType, archLength; 615 status_t error = check_watch_point_parameters(address, type, length, 616 archType, archLength); 617 if (error != B_OK) 618 return error; 619 620 return set_breakpoint(address, archType, archLength); 621 } 622 623 624 status_t 625 arch_clear_watchpoint(void *address) 626 { 627 return clear_breakpoint(address, false); 628 } 629 630 631 bool 632 arch_has_breakpoints(struct arch_team_debug_info *info) 633 { 634 // Reading info->dr7 is atomically, so we don't need to lock. The caller 635 // has to ensure, that the info doesn't go away. 636 return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7); 637 } 638 639 640 #if KERNEL_BREAKPOINTS 641 642 status_t 643 arch_set_kernel_breakpoint(void *address) 644 { 645 status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 646 X86_BREAKPOINT_LENGTH_1); 647 648 if (error != B_OK) { 649 panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s", 650 strerror(error)); 651 } 652 653 return error; 654 } 655 656 657 status_t 658 arch_clear_kernel_breakpoint(void *address) 659 { 660 status_t error = clear_kernel_breakpoint(address, false); 661 662 if (error != B_OK) { 663 panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s", 664 strerror(error)); 665 } 666 667 return error; 668 } 669 670 671 status_t 672 arch_set_kernel_watchpoint(void *address, uint32 type, int32 length) 673 { 674 uint32 archType, archLength; 675 status_t error = check_watch_point_parameters(address, type, length, 676 archType, archLength); 677 678 if (error == B_OK) 679 error = set_kernel_breakpoint(address, archType, archLength); 680 681 if (error != B_OK) { 682 panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s", 683 strerror(error)); 684 } 685 686 return error; 687 } 688 689 690 status_t 691 arch_clear_kernel_watchpoint(void *address) 692 { 693 status_t error = clear_kernel_breakpoint(address, true); 694 695 if (error != B_OK) { 696 panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s", 697 strerror(error)); 698 } 699 700 return error; 701 } 702 703 #endif // KERNEL_BREAKPOINTS 704 705 706 // #pragma mark - x86 implementation interface 707 708 709 /** 710 * Interrupts are disabled. 711 */ 712 void 713 x86_init_user_debug_at_kernel_exit(struct iframe *frame) 714 { 715 struct thread *thread = thread_get_current_thread(); 716 717 #if !KERNEL_BREAKPOINTS 718 if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED)) 719 return; 720 #endif 721 722 GRAB_THREAD_LOCK(); 723 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 724 725 arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info; 726 727 // install the breakpoints 728 install_breakpoints(teamInfo); 729 730 atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED); 731 732 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 733 RELEASE_THREAD_LOCK(); 734 } 735 736 737 /** 738 * Interrupts are disabled. 739 */ 740 void 741 x86_exit_user_debug_at_kernel_entry() 742 { 743 struct thread *thread = thread_get_current_thread(); 744 745 #if !KERNEL_BREAKPOINTS 746 if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED)) 747 return; 748 #endif 749 750 GRAB_THREAD_LOCK(); 751 752 // disable breakpoints 753 disable_breakpoints(); 754 755 #if KERNEL_BREAKPOINTS 756 struct team* kernelTeam = team_get_kernel_team(); 757 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 758 install_breakpoints(kernelTeam->debug_info.arch_info); 759 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 760 #endif 761 762 atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED); 763 764 RELEASE_THREAD_LOCK(); 765 } 766 767 768 /** 769 * Interrupts are disabled and will be enabled by the function. 770 */ 771 void 772 x86_handle_debug_exception(struct iframe *frame) 773 { 774 // get debug status and control registers 775 uint32 dr6, dr7; 776 asm("movl %%dr6, %0" : "=r"(dr6)); 777 asm("movl %%dr7, %0" : "=r"(dr7)); 778 779 TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7)); 780 781 if (frame->cs != USER_CODE_SEG) { 782 panic("debug exception in kernel mode: dr6: 0x%lx, dr7: 0x%lx", dr6, 783 dr7); 784 return; 785 } 786 787 // check, which exception condition applies 788 if (dr6 & X86_DR6_BREAKPOINT_MASK) { 789 // breakpoint 790 791 // check which breakpoint was taken 792 bool watchpoint = true; 793 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 794 if (dr6 & (1 << sDR6B[i])) { 795 // If it is an instruction breakpoint, we need to set RF in 796 // EFLAGS to prevent triggering the same exception 797 // again (breakpoint instructions are triggered *before* 798 // executing the instruction). 799 uint32 type = (dr7 >> sDR7RW[i]) & 0x3; 800 if (type == X86_INSTRUCTION_BREAKPOINT) { 801 frame->flags |= (1 << X86_EFLAGS_RF); 802 watchpoint = false; 803 } 804 } 805 } 806 807 // enable interrupts and notify the debugger 808 enable_interrupts(); 809 810 if (watchpoint) 811 user_debug_watchpoint_hit(); 812 else 813 user_debug_breakpoint_hit(false); 814 } else if (dr6 & (1 << X86_DR6_BD)) { 815 // general detect exception 816 // Occurs only, if GD in DR7 is set (which we don't do) and someone 817 // tries to write to the debug registers. 818 dprintf("i386_handle_debug_exception(): ignoring spurious general " 819 "detect exception\n"); 820 821 enable_interrupts(); 822 } else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) { 823 // single step 824 825 // enable interrupts and notify the debugger 826 enable_interrupts(); 827 828 user_debug_single_stepped(); 829 } else if (dr6 & (1 << X86_DR6_BT)) { 830 // task switch 831 // Occurs only, if T in EFLAGS is set (which we don't do). 832 dprintf("i386_handle_debug_exception(): ignoring spurious task switch " 833 "exception\n"); 834 835 enable_interrupts(); 836 } else { 837 TRACE(("i386_handle_debug_exception(): ignoring spurious debug " 838 "exception (no condition recognized)\n")); 839 840 enable_interrupts(); 841 } 842 } 843 844 845 /** 846 * Interrupts are disabled and will be enabled by the function. 847 */ 848 void 849 x86_handle_breakpoint_exception(struct iframe *frame) 850 { 851 TRACE(("i386_handle_breakpoint_exception()\n")); 852 853 if (frame->cs != USER_CODE_SEG) { 854 panic("breakpoint exception in kernel mode"); 855 return; 856 } 857 858 enable_interrupts(); 859 860 user_debug_breakpoint_hit(true); 861 } 862 863 864 void 865 x86_init_user_debug() 866 { 867 // get debug settings 868 if (void *handle = load_driver_settings("kernel")) { 869 sQEmuSingleStepHack = get_driver_boolean_parameter(handle, 870 "qemu_single_step_hack", false, false);; 871 872 unload_driver_settings(handle); 873 } 874 875 #if KERNEL_BREAKPOINTS 876 // install debugger commands 877 add_debugger_command("breakpoints", &debugger_breakpoints, 878 "lists current break-/watchpoints"); 879 add_debugger_command("breakpoint", &debugger_breakpoint, 880 "set/clear a breakpoint"); 881 add_debugger_command("watchpoints", &debugger_breakpoints, 882 "lists current break-/watchpoints"); 883 add_debugger_command("watchpoint", &debugger_watchpoint, 884 "set/clear a watchpoint"); 885 #endif 886 } 887 888