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