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 i386_frstor(cpuState->extended_regs); 534 // For this to be correct the calling function must not use these 535 // registers (not even indirectly). 536 537 // frame->gs = cpuState->gs; 538 // frame->fs = cpuState->fs; 539 // frame->es = cpuState->es; 540 // frame->ds = cpuState->ds; 541 frame->edi = cpuState->edi; 542 frame->esi = cpuState->esi; 543 frame->ebp = cpuState->ebp; 544 frame->esp = cpuState->esp; 545 frame->ebx = cpuState->ebx; 546 frame->edx = cpuState->edx; 547 frame->ecx = cpuState->ecx; 548 frame->eax = cpuState->eax; 549 // frame->vector = cpuState->vector; 550 // frame->error_code = cpuState->error_code; 551 frame->eip = cpuState->eip; 552 // frame->cs = cpuState->cs; 553 frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS) 554 | (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS); 555 frame->user_esp = cpuState->user_esp; 556 // frame->user_ss = cpuState->user_ss; 557 } 558 } 559 560 561 void 562 arch_get_debug_cpu_state(struct debug_cpu_state *cpuState) 563 { 564 if (struct iframe *frame = i386_get_user_iframe()) { 565 i386_fnsave(cpuState->extended_regs); 566 // For this to be correct the calling function must not use these 567 // registers (not even indirectly). 568 569 cpuState->gs = frame->gs; 570 cpuState->fs = frame->fs; 571 cpuState->es = frame->es; 572 cpuState->ds = frame->ds; 573 cpuState->edi = frame->edi; 574 cpuState->esi = frame->esi; 575 cpuState->ebp = frame->ebp; 576 cpuState->esp = frame->esp; 577 cpuState->ebx = frame->ebx; 578 cpuState->edx = frame->orig_edx; 579 cpuState->ecx = frame->ecx; 580 cpuState->eax = frame->orig_eax; 581 cpuState->vector = frame->vector; 582 cpuState->error_code = frame->error_code; 583 cpuState->eip = frame->eip; 584 cpuState->cs = frame->cs; 585 cpuState->eflags = frame->flags; 586 cpuState->user_esp = frame->user_esp; 587 cpuState->user_ss = frame->user_ss; 588 } 589 } 590 591 592 status_t 593 arch_set_breakpoint(void *address) 594 { 595 return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 596 X86_BREAKPOINT_LENGTH_1); 597 } 598 599 600 status_t 601 arch_clear_breakpoint(void *address) 602 { 603 return clear_breakpoint(address, false); 604 } 605 606 607 status_t 608 arch_set_watchpoint(void *address, uint32 type, int32 length) 609 { 610 uint32 archType, archLength; 611 status_t error = check_watch_point_parameters(address, type, length, 612 archType, archLength); 613 if (error != B_OK) 614 return error; 615 616 return set_breakpoint(address, archType, archLength); 617 } 618 619 620 status_t 621 arch_clear_watchpoint(void *address) 622 { 623 return clear_breakpoint(address, false); 624 } 625 626 627 bool 628 arch_has_breakpoints(struct arch_team_debug_info *info) 629 { 630 // Reading info->dr7 is atomically, so we don't need to lock. The caller 631 // has to ensure, that the info doesn't go away. 632 return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7); 633 } 634 635 636 #if KERNEL_BREAKPOINTS 637 638 status_t 639 arch_set_kernel_breakpoint(void *address) 640 { 641 status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 642 X86_BREAKPOINT_LENGTH_1); 643 644 if (error != B_OK) { 645 panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s", 646 strerror(error)); 647 } 648 649 return error; 650 } 651 652 653 status_t 654 arch_clear_kernel_breakpoint(void *address) 655 { 656 status_t error = clear_kernel_breakpoint(address, false); 657 658 if (error != B_OK) { 659 panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s", 660 strerror(error)); 661 } 662 663 return error; 664 } 665 666 667 status_t 668 arch_set_kernel_watchpoint(void *address, uint32 type, int32 length) 669 { 670 uint32 archType, archLength; 671 status_t error = check_watch_point_parameters(address, type, length, 672 archType, archLength); 673 674 if (error == B_OK) 675 error = set_kernel_breakpoint(address, archType, archLength); 676 677 if (error != B_OK) { 678 panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s", 679 strerror(error)); 680 } 681 682 return error; 683 } 684 685 686 status_t 687 arch_clear_kernel_watchpoint(void *address) 688 { 689 status_t error = clear_kernel_breakpoint(address, true); 690 691 if (error != B_OK) { 692 panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s", 693 strerror(error)); 694 } 695 696 return error; 697 } 698 699 #endif // KERNEL_BREAKPOINTS 700 701 702 // #pragma mark - x86 implementation interface 703 704 705 /** 706 * Interrupts are disabled. 707 */ 708 void 709 x86_init_user_debug_at_kernel_exit(struct iframe *frame) 710 { 711 struct thread *thread = thread_get_current_thread(); 712 713 #if !KERNEL_BREAKPOINTS 714 if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED)) 715 return; 716 #endif 717 718 GRAB_THREAD_LOCK(); 719 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 720 721 arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info; 722 723 // install the breakpoints 724 install_breakpoints(teamInfo); 725 726 atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED); 727 728 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 729 RELEASE_THREAD_LOCK(); 730 } 731 732 733 /** 734 * Interrupts are disabled. 735 */ 736 void 737 x86_exit_user_debug_at_kernel_entry() 738 { 739 struct thread *thread = thread_get_current_thread(); 740 741 #if !KERNEL_BREAKPOINTS 742 if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED)) 743 return; 744 #endif 745 746 GRAB_THREAD_LOCK(); 747 748 // disable breakpoints 749 disable_breakpoints(); 750 751 #if KERNEL_BREAKPOINTS 752 struct team* kernelTeam = team_get_kernel_team(); 753 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 754 install_breakpoints(kernelTeam->debug_info.arch_info); 755 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 756 #endif 757 758 atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED); 759 760 RELEASE_THREAD_LOCK(); 761 } 762 763 764 /** 765 * Interrupts are disabled and will be enabled by the function. 766 */ 767 void 768 x86_handle_debug_exception(struct iframe *frame) 769 { 770 // get debug status and control registers 771 uint32 dr6, dr7; 772 asm("movl %%dr6, %0" : "=r"(dr6)); 773 asm("movl %%dr7, %0" : "=r"(dr7)); 774 775 TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7)); 776 777 if (!IFRAME_IS_USER(frame)) { 778 panic("debug exception in kernel mode: dr6: 0x%lx, dr7: 0x%lx", dr6, 779 dr7); 780 return; 781 } 782 783 // check, which exception condition applies 784 if (dr6 & X86_DR6_BREAKPOINT_MASK) { 785 // breakpoint 786 787 // check which breakpoint was taken 788 bool watchpoint = true; 789 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 790 if (dr6 & (1 << sDR6B[i])) { 791 // If it is an instruction breakpoint, we need to set RF in 792 // EFLAGS to prevent triggering the same exception 793 // again (breakpoint instructions are triggered *before* 794 // executing the instruction). 795 uint32 type = (dr7 >> sDR7RW[i]) & 0x3; 796 if (type == X86_INSTRUCTION_BREAKPOINT) { 797 frame->flags |= (1 << X86_EFLAGS_RF); 798 watchpoint = false; 799 } 800 } 801 } 802 803 // enable interrupts and notify the debugger 804 enable_interrupts(); 805 806 if (watchpoint) 807 user_debug_watchpoint_hit(); 808 else 809 user_debug_breakpoint_hit(false); 810 } else if (dr6 & (1 << X86_DR6_BD)) { 811 // general detect exception 812 // Occurs only, if GD in DR7 is set (which we don't do) and someone 813 // tries to write to the debug registers. 814 dprintf("i386_handle_debug_exception(): ignoring spurious general " 815 "detect exception\n"); 816 817 enable_interrupts(); 818 } else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) { 819 // single step 820 821 // enable interrupts and notify the debugger 822 enable_interrupts(); 823 824 user_debug_single_stepped(); 825 } else if (dr6 & (1 << X86_DR6_BT)) { 826 // task switch 827 // Occurs only, if T in EFLAGS is set (which we don't do). 828 dprintf("i386_handle_debug_exception(): ignoring spurious task switch " 829 "exception\n"); 830 831 enable_interrupts(); 832 } else { 833 TRACE(("i386_handle_debug_exception(): ignoring spurious debug " 834 "exception (no condition recognized)\n")); 835 836 enable_interrupts(); 837 } 838 } 839 840 841 /** 842 * Interrupts are disabled and will be enabled by the function. 843 */ 844 void 845 x86_handle_breakpoint_exception(struct iframe *frame) 846 { 847 TRACE(("i386_handle_breakpoint_exception()\n")); 848 849 if (!IFRAME_IS_USER(frame)) { 850 panic("breakpoint exception in kernel mode"); 851 return; 852 } 853 854 enable_interrupts(); 855 856 user_debug_breakpoint_hit(true); 857 } 858 859 860 void 861 x86_init_user_debug() 862 { 863 // get debug settings 864 if (void *handle = load_driver_settings("kernel")) { 865 sQEmuSingleStepHack = get_driver_boolean_parameter(handle, 866 "qemu_single_step_hack", false, false);; 867 868 unload_driver_settings(handle); 869 } 870 871 #if KERNEL_BREAKPOINTS 872 // install debugger commands 873 add_debugger_command("breakpoints", &debugger_breakpoints, 874 "lists current break-/watchpoints"); 875 add_debugger_command("breakpoint", &debugger_breakpoint, 876 "set/clear a breakpoint"); 877 add_debugger_command("watchpoints", &debugger_breakpoints, 878 "lists current break-/watchpoints"); 879 add_debugger_command("watchpoint", &debugger_watchpoint, 880 "set/clear a watchpoint"); 881 #endif 882 } 883 884