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