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