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