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