12d690920SAxel Dörfler /* 2568ade58SIngo Weinhold * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 32d690920SAxel Dörfler * Distributed under the terms of the MIT License. 42d690920SAxel Dörfler */ 52d690920SAxel Dörfler 60b11ecb1SIngo Weinhold 7667f1eebSIngo Weinhold #include <arch/user_debugger.h> 8667f1eebSIngo Weinhold 92d690920SAxel Dörfler #include <string.h> 102d690920SAxel Dörfler 112d690920SAxel Dörfler #include <debugger.h> 122d690920SAxel Dörfler #include <driver_settings.h> 132d690920SAxel Dörfler #include <int.h> 14667f1eebSIngo Weinhold #include <team.h> 152d690920SAxel Dörfler #include <thread.h> 160b11ecb1SIngo Weinhold #include <util/AutoLock.h> 17667f1eebSIngo Weinhold 182d690920SAxel Dörfler 192d690920SAxel Dörfler //#define TRACE_ARCH_USER_DEBUGGER 202d690920SAxel Dörfler #ifdef TRACE_ARCH_USER_DEBUGGER 212d690920SAxel Dörfler # define TRACE(x) dprintf x 222d690920SAxel Dörfler #else 232d690920SAxel Dörfler # define TRACE(x) ; 242d690920SAxel Dörfler #endif 252d690920SAxel Dörfler 26667f1eebSIngo Weinhold #define B_NO_MORE_BREAKPOINTS B_BUSY 27667f1eebSIngo Weinhold #define B_NO_MORE_WATCHPOINTS B_BUSY 28667f1eebSIngo Weinhold #define B_BAD_WATCHPOINT_ALIGNMENT B_BAD_VALUE 29667f1eebSIngo Weinhold #define B_WATCHPOINT_TYPE_NOT_SUPPORTED B_NOT_SUPPORTED 30667f1eebSIngo Weinhold #define B_WATCHPOINT_LENGTH_NOT_SUPPORTED B_NOT_SUPPORTED 31667f1eebSIngo Weinhold #define B_BREAKPOINT_NOT_FOUND B_NAME_NOT_FOUND 32667f1eebSIngo Weinhold #define B_WATCHPOINT_NOT_FOUND B_NAME_NOT_FOUND 330b11ecb1SIngo Weinhold // TODO: Make those real error codes. 340b11ecb1SIngo Weinhold 350b11ecb1SIngo Weinhold 360b11ecb1SIngo Weinhold extern bool gHasSSE; 372d690920SAxel Dörfler 38b0f12d64SIngo Weinhold // The software breakpoint instruction (int3). 39b0f12d64SIngo Weinhold const uint8 kX86SoftwareBreakpoint[1] = { 0xcc }; 40b0f12d64SIngo Weinhold 412d690920SAxel Dörfler // maps breakpoint slot index to LEN_i LSB number 422d690920SAxel Dörfler static const uint32 sDR7Len[4] = { 432d690920SAxel Dörfler X86_DR7_LEN0_LSB, X86_DR7_LEN1_LSB, X86_DR7_LEN2_LSB, X86_DR7_LEN3_LSB 442d690920SAxel Dörfler }; 452d690920SAxel Dörfler 462d690920SAxel Dörfler // maps breakpoint slot index to R/W_i LSB number 472d690920SAxel Dörfler static const uint32 sDR7RW[4] = { 482d690920SAxel Dörfler X86_DR7_RW0_LSB, X86_DR7_RW1_LSB, X86_DR7_RW2_LSB, X86_DR7_RW3_LSB 492d690920SAxel Dörfler }; 502d690920SAxel Dörfler 512d690920SAxel Dörfler // maps breakpoint slot index to L_i bit number 522d690920SAxel Dörfler static const uint32 sDR7L[4] = { 532d690920SAxel Dörfler X86_DR7_L0, X86_DR7_L1, X86_DR7_L2, X86_DR7_L3 542d690920SAxel Dörfler }; 552d690920SAxel Dörfler 56667f1eebSIngo Weinhold // maps breakpoint slot index to G_i bit number 57667f1eebSIngo Weinhold static const uint32 sDR7G[4] = { 58667f1eebSIngo Weinhold X86_DR7_G0, X86_DR7_G1, X86_DR7_G2, X86_DR7_G3 59667f1eebSIngo Weinhold }; 60667f1eebSIngo Weinhold 612d690920SAxel Dörfler // maps breakpoint slot index to B_i bit number 622d690920SAxel Dörfler static const uint32 sDR6B[4] = { 632d690920SAxel Dörfler X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3 642d690920SAxel Dörfler }; 652d690920SAxel Dörfler 662d690920SAxel Dörfler // Enables a hack to make single stepping work under qemu. Set via kernel 672d690920SAxel Dörfler // driver settings. 682d690920SAxel Dörfler static bool sQEmuSingleStepHack = false; 692d690920SAxel Dörfler 702d690920SAxel Dörfler 71568ade58SIngo Weinhold static void 720b11ecb1SIngo Weinhold get_iframe_registers(struct iframe *frame, debug_cpu_state *cpuState) 73568ade58SIngo Weinhold { 74568ade58SIngo Weinhold cpuState->gs = frame->gs; 75568ade58SIngo Weinhold cpuState->fs = frame->fs; 76568ade58SIngo Weinhold cpuState->es = frame->es; 77568ade58SIngo Weinhold cpuState->ds = frame->ds; 78568ade58SIngo Weinhold cpuState->edi = frame->edi; 79568ade58SIngo Weinhold cpuState->esi = frame->esi; 80568ade58SIngo Weinhold cpuState->ebp = frame->ebp; 81568ade58SIngo Weinhold cpuState->esp = frame->esp; 82568ade58SIngo Weinhold cpuState->ebx = frame->ebx; 83568ade58SIngo Weinhold cpuState->edx = frame->orig_edx; 84568ade58SIngo Weinhold cpuState->ecx = frame->ecx; 85568ade58SIngo Weinhold cpuState->eax = frame->orig_eax; 86568ade58SIngo Weinhold cpuState->vector = frame->vector; 87568ade58SIngo Weinhold cpuState->error_code = frame->error_code; 88568ade58SIngo Weinhold cpuState->eip = frame->eip; 89568ade58SIngo Weinhold cpuState->cs = frame->cs; 90568ade58SIngo Weinhold cpuState->eflags = frame->flags; 91568ade58SIngo Weinhold cpuState->user_esp = frame->user_esp; 92568ade58SIngo Weinhold cpuState->user_ss = frame->user_ss; 93568ade58SIngo Weinhold } 94568ade58SIngo Weinhold 95568ade58SIngo Weinhold 96667f1eebSIngo Weinhold static inline void 97667f1eebSIngo Weinhold install_breakpoints(const arch_team_debug_info &teamInfo) 98667f1eebSIngo Weinhold { 99667f1eebSIngo Weinhold // set breakpoints 100667f1eebSIngo Weinhold asm("movl %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address)); 101667f1eebSIngo Weinhold asm("movl %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address)); 102667f1eebSIngo Weinhold asm("movl %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address)); 103667f1eebSIngo Weinhold // asm("movl %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address)); 104667f1eebSIngo Weinhold // DR3 is used to hold the current struct thread*. 105667f1eebSIngo Weinhold 106667f1eebSIngo Weinhold // enable breakpoints 107667f1eebSIngo Weinhold asm("movl %0, %%dr7" : : "r"(teamInfo.dr7)); 108667f1eebSIngo Weinhold } 109667f1eebSIngo Weinhold 110667f1eebSIngo Weinhold 111667f1eebSIngo Weinhold static inline void 112667f1eebSIngo Weinhold disable_breakpoints() 113667f1eebSIngo Weinhold { 114667f1eebSIngo Weinhold asm("movl %0, %%dr7" : : "r"(X86_BREAKPOINTS_DISABLED_DR7)); 115667f1eebSIngo Weinhold } 116667f1eebSIngo Weinhold 117667f1eebSIngo Weinhold 118667f1eebSIngo Weinhold /*! Sets a break-/watchpoint in the given team info. 119667f1eebSIngo Weinhold Interrupts must be disabled and the team debug info lock be held. 120667f1eebSIngo Weinhold */ 121667f1eebSIngo Weinhold static inline status_t 122667f1eebSIngo Weinhold set_breakpoint(arch_team_debug_info &info, void *address, uint32 type, 123667f1eebSIngo Weinhold uint32 length, bool setGlobalFlag) 124667f1eebSIngo Weinhold { 125667f1eebSIngo Weinhold // check, if there is already a breakpoint at that address 126667f1eebSIngo Weinhold bool alreadySet = false; 127667f1eebSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 128667f1eebSIngo Weinhold if (info.breakpoints[i].address == address 129667f1eebSIngo Weinhold && info.breakpoints[i].type == type) { 130667f1eebSIngo Weinhold alreadySet = true; 131667f1eebSIngo Weinhold break; 132667f1eebSIngo Weinhold } 133667f1eebSIngo Weinhold } 134667f1eebSIngo Weinhold 135667f1eebSIngo Weinhold if (!alreadySet) { 136667f1eebSIngo Weinhold // find a free slot 137667f1eebSIngo Weinhold int32 slot = -1; 138667f1eebSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 139667f1eebSIngo Weinhold if (!info.breakpoints[i].address) { 140667f1eebSIngo Weinhold slot = i; 141667f1eebSIngo Weinhold break; 142667f1eebSIngo Weinhold } 143667f1eebSIngo Weinhold } 144667f1eebSIngo Weinhold 145667f1eebSIngo Weinhold // init the breakpoint 146667f1eebSIngo Weinhold if (slot >= 0) { 147667f1eebSIngo Weinhold info.breakpoints[slot].address = address; 148667f1eebSIngo Weinhold info.breakpoints[slot].type = type; 149667f1eebSIngo Weinhold info.breakpoints[slot].length = length; 150667f1eebSIngo Weinhold 151667f1eebSIngo Weinhold info.dr7 |= (length << sDR7Len[slot]) 152667f1eebSIngo Weinhold | (type << sDR7RW[slot]) 153667f1eebSIngo Weinhold | (1 << sDR7L[slot]); 154667f1eebSIngo Weinhold if (setGlobalFlag) 155667f1eebSIngo Weinhold info.dr7 |= (1 << sDR7G[slot]); 156667f1eebSIngo Weinhold } else { 157667f1eebSIngo Weinhold if (type == X86_INSTRUCTION_BREAKPOINT) 158667f1eebSIngo Weinhold return B_NO_MORE_BREAKPOINTS; 159667f1eebSIngo Weinhold else 160667f1eebSIngo Weinhold return B_NO_MORE_WATCHPOINTS; 161667f1eebSIngo Weinhold } 162667f1eebSIngo Weinhold } 163667f1eebSIngo Weinhold 164667f1eebSIngo Weinhold return B_OK; 165667f1eebSIngo Weinhold } 166667f1eebSIngo Weinhold 167667f1eebSIngo Weinhold 168667f1eebSIngo Weinhold /*! Clears a break-/watchpoint in the given team info. 169667f1eebSIngo Weinhold Interrupts must be disabled and the team debug info lock be held. 170667f1eebSIngo Weinhold */ 171667f1eebSIngo Weinhold static inline status_t 172667f1eebSIngo Weinhold clear_breakpoint(arch_team_debug_info &info, void *address, bool watchpoint) 173667f1eebSIngo Weinhold { 174667f1eebSIngo Weinhold // find the breakpoint 175667f1eebSIngo Weinhold int32 slot = -1; 176667f1eebSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 177667f1eebSIngo Weinhold if (info.breakpoints[i].address == address 178667f1eebSIngo Weinhold && (watchpoint 179667f1eebSIngo Weinhold != (info.breakpoints[i].type == X86_INSTRUCTION_BREAKPOINT))) { 180667f1eebSIngo Weinhold slot = i; 181667f1eebSIngo Weinhold break; 182667f1eebSIngo Weinhold } 183667f1eebSIngo Weinhold } 184667f1eebSIngo Weinhold 185667f1eebSIngo Weinhold // clear the breakpoint 186667f1eebSIngo Weinhold if (slot >= 0) { 187667f1eebSIngo Weinhold info.breakpoints[slot].address = NULL; 188667f1eebSIngo Weinhold 189667f1eebSIngo Weinhold info.dr7 &= ~((0x3 << sDR7Len[slot]) 190667f1eebSIngo Weinhold | (0x3 << sDR7RW[slot]) 191667f1eebSIngo Weinhold | (1 << sDR7L[slot]) 192667f1eebSIngo Weinhold | (1 << sDR7G[slot])); 193667f1eebSIngo Weinhold } else { 194667f1eebSIngo Weinhold if (watchpoint) 195667f1eebSIngo Weinhold return B_WATCHPOINT_NOT_FOUND; 196667f1eebSIngo Weinhold else 197667f1eebSIngo Weinhold return B_BREAKPOINT_NOT_FOUND; 198667f1eebSIngo Weinhold } 199667f1eebSIngo Weinhold 200667f1eebSIngo Weinhold return B_OK; 201667f1eebSIngo Weinhold } 202667f1eebSIngo Weinhold 203667f1eebSIngo Weinhold 204667f1eebSIngo Weinhold static status_t 205667f1eebSIngo Weinhold set_breakpoint(void *address, uint32 type, uint32 length) 206667f1eebSIngo Weinhold { 207667f1eebSIngo Weinhold if (!address) 208667f1eebSIngo Weinhold return B_BAD_VALUE; 209667f1eebSIngo Weinhold 210667f1eebSIngo Weinhold struct thread *thread = thread_get_current_thread(); 211667f1eebSIngo Weinhold 212667f1eebSIngo Weinhold cpu_status state = disable_interrupts(); 213667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 214667f1eebSIngo Weinhold 215667f1eebSIngo Weinhold status_t error = set_breakpoint(thread->team->debug_info.arch_info, address, 216667f1eebSIngo Weinhold type, length, false); 217667f1eebSIngo Weinhold 218667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 219667f1eebSIngo Weinhold restore_interrupts(state); 220667f1eebSIngo Weinhold 221667f1eebSIngo Weinhold return error; 222667f1eebSIngo Weinhold } 223667f1eebSIngo Weinhold 224667f1eebSIngo Weinhold 225667f1eebSIngo Weinhold static status_t 226667f1eebSIngo Weinhold clear_breakpoint(void *address, bool watchpoint) 227667f1eebSIngo Weinhold { 228667f1eebSIngo Weinhold if (!address) 229667f1eebSIngo Weinhold return B_BAD_VALUE; 230667f1eebSIngo Weinhold 231667f1eebSIngo Weinhold struct thread *thread = thread_get_current_thread(); 232667f1eebSIngo Weinhold 233667f1eebSIngo Weinhold cpu_status state = disable_interrupts(); 234667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 235667f1eebSIngo Weinhold 236667f1eebSIngo Weinhold status_t error = clear_breakpoint(thread->team->debug_info.arch_info, 237667f1eebSIngo Weinhold address, watchpoint); 238667f1eebSIngo Weinhold 239667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 240667f1eebSIngo Weinhold restore_interrupts(state); 241667f1eebSIngo Weinhold 242667f1eebSIngo Weinhold return error; 243667f1eebSIngo Weinhold } 244667f1eebSIngo Weinhold 245667f1eebSIngo Weinhold 246667f1eebSIngo Weinhold #if KERNEL_BREAKPOINTS 247667f1eebSIngo Weinhold 24831d9352fSIngo Weinhold 24931d9352fSIngo Weinhold static void 25031d9352fSIngo Weinhold install_breakpoints_per_cpu(void* /*cookie*/, int cpu) 25131d9352fSIngo Weinhold { 25231d9352fSIngo Weinhold struct team* kernelTeam = team_get_kernel_team(); 25331d9352fSIngo Weinhold 25431d9352fSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 25531d9352fSIngo Weinhold 25631d9352fSIngo Weinhold install_breakpoints(kernelTeam->debug_info.arch_info); 25731d9352fSIngo Weinhold 25831d9352fSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 25931d9352fSIngo Weinhold } 26031d9352fSIngo Weinhold 26131d9352fSIngo Weinhold 262667f1eebSIngo Weinhold static status_t 263667f1eebSIngo Weinhold set_kernel_breakpoint(void *address, uint32 type, uint32 length) 264667f1eebSIngo Weinhold { 265667f1eebSIngo Weinhold if (!address) 266667f1eebSIngo Weinhold return B_BAD_VALUE; 267667f1eebSIngo Weinhold 268667f1eebSIngo Weinhold struct team* kernelTeam = team_get_kernel_team(); 269667f1eebSIngo Weinhold 270667f1eebSIngo Weinhold cpu_status state = disable_interrupts(); 271667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 272667f1eebSIngo Weinhold 273667f1eebSIngo Weinhold status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address, 274667f1eebSIngo Weinhold type, length, true); 275667f1eebSIngo Weinhold 276667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 27731d9352fSIngo Weinhold 27831d9352fSIngo Weinhold call_all_cpus(install_breakpoints_per_cpu, NULL); 27931d9352fSIngo Weinhold 280667f1eebSIngo Weinhold restore_interrupts(state); 281667f1eebSIngo Weinhold 282667f1eebSIngo Weinhold return error; 283667f1eebSIngo Weinhold } 284667f1eebSIngo Weinhold 285667f1eebSIngo Weinhold 286667f1eebSIngo Weinhold static status_t 287667f1eebSIngo Weinhold clear_kernel_breakpoint(void *address, bool watchpoint) 288667f1eebSIngo Weinhold { 289667f1eebSIngo Weinhold if (!address) 290667f1eebSIngo Weinhold return B_BAD_VALUE; 291667f1eebSIngo Weinhold 292667f1eebSIngo Weinhold struct team* kernelTeam = team_get_kernel_team(); 293667f1eebSIngo Weinhold 294667f1eebSIngo Weinhold cpu_status state = disable_interrupts(); 295667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 296667f1eebSIngo Weinhold 297667f1eebSIngo Weinhold status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info, 298667f1eebSIngo Weinhold address, watchpoint); 299667f1eebSIngo Weinhold 300667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 30131d9352fSIngo Weinhold 30231d9352fSIngo Weinhold call_all_cpus(install_breakpoints_per_cpu, NULL); 30331d9352fSIngo Weinhold 304667f1eebSIngo Weinhold restore_interrupts(state); 305667f1eebSIngo Weinhold 306667f1eebSIngo Weinhold return error; 307667f1eebSIngo Weinhold } 308667f1eebSIngo Weinhold 309667f1eebSIngo Weinhold #endif // KERNEL_BREAKPOINTS 310667f1eebSIngo Weinhold 311667f1eebSIngo Weinhold 312667f1eebSIngo Weinhold static inline status_t 313667f1eebSIngo Weinhold check_watch_point_parameters(void* address, uint32 type, int32 length, 314667f1eebSIngo Weinhold uint32& archType, uint32& archLength) 315667f1eebSIngo Weinhold { 316667f1eebSIngo Weinhold // check type 317667f1eebSIngo Weinhold switch (type) { 318667f1eebSIngo Weinhold case B_DATA_WRITE_WATCHPOINT: 319667f1eebSIngo Weinhold archType = X86_DATA_WRITE_BREAKPOINT; 320667f1eebSIngo Weinhold break; 321667f1eebSIngo Weinhold case B_DATA_READ_WRITE_WATCHPOINT: 322667f1eebSIngo Weinhold archType = X86_DATA_READ_WRITE_BREAKPOINT; 323667f1eebSIngo Weinhold break; 324667f1eebSIngo Weinhold case B_DATA_READ_WATCHPOINT: 325667f1eebSIngo Weinhold default: 326667f1eebSIngo Weinhold return B_WATCHPOINT_TYPE_NOT_SUPPORTED; 327667f1eebSIngo Weinhold break; 328667f1eebSIngo Weinhold } 329667f1eebSIngo Weinhold 330667f1eebSIngo Weinhold // check length and alignment 331667f1eebSIngo Weinhold switch (length) { 332667f1eebSIngo Weinhold case 1: 333667f1eebSIngo Weinhold archLength = X86_BREAKPOINT_LENGTH_1; 334667f1eebSIngo Weinhold break; 335667f1eebSIngo Weinhold case 2: 336667f1eebSIngo Weinhold if ((uint32)address & 0x1) 337667f1eebSIngo Weinhold return B_BAD_WATCHPOINT_ALIGNMENT; 338667f1eebSIngo Weinhold archLength = X86_BREAKPOINT_LENGTH_2; 339667f1eebSIngo Weinhold break; 340667f1eebSIngo Weinhold case 4: 341667f1eebSIngo Weinhold if ((uint32)address & 0x3) 342667f1eebSIngo Weinhold return B_BAD_WATCHPOINT_ALIGNMENT; 343667f1eebSIngo Weinhold archLength = X86_BREAKPOINT_LENGTH_4; 344667f1eebSIngo Weinhold break; 345667f1eebSIngo Weinhold default: 346667f1eebSIngo Weinhold return B_WATCHPOINT_LENGTH_NOT_SUPPORTED; 347667f1eebSIngo Weinhold } 348667f1eebSIngo Weinhold 349667f1eebSIngo Weinhold return B_OK; 350667f1eebSIngo Weinhold } 351667f1eebSIngo Weinhold 352667f1eebSIngo Weinhold 353bc5f008aSIngo Weinhold // #pragma mark - kernel debugger commands 354bc5f008aSIngo Weinhold 355bc5f008aSIngo Weinhold #if KERNEL_BREAKPOINTS 356bc5f008aSIngo Weinhold 357bc5f008aSIngo Weinhold static int 358bc5f008aSIngo Weinhold debugger_breakpoints(int argc, char** argv) 359bc5f008aSIngo Weinhold { 360bc5f008aSIngo Weinhold struct team* kernelTeam = team_get_kernel_team(); 361bc5f008aSIngo Weinhold arch_team_debug_info& info = kernelTeam->debug_info.arch_info; 362bc5f008aSIngo Weinhold 363bc5f008aSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 364bc5f008aSIngo Weinhold kprintf("breakpoint[%ld] ", i); 365bc5f008aSIngo Weinhold 366bc5f008aSIngo Weinhold if (info.breakpoints[i].address != NULL) { 367bc5f008aSIngo Weinhold kprintf("%p ", info.breakpoints[i].address); 368bc5f008aSIngo Weinhold switch (info.breakpoints[i].type) { 369bc5f008aSIngo Weinhold case X86_INSTRUCTION_BREAKPOINT: 370bc5f008aSIngo Weinhold kprintf("instruction"); 371bc5f008aSIngo Weinhold break; 372bc5f008aSIngo Weinhold case X86_IO_READ_WRITE_BREAKPOINT: 373bc5f008aSIngo Weinhold kprintf("io read/write"); 374bc5f008aSIngo Weinhold break; 375bc5f008aSIngo Weinhold case X86_DATA_WRITE_BREAKPOINT: 376bc5f008aSIngo Weinhold kprintf("data write"); 377bc5f008aSIngo Weinhold break; 378bc5f008aSIngo Weinhold case X86_DATA_READ_WRITE_BREAKPOINT: 379bc5f008aSIngo Weinhold kprintf("data read/write"); 380bc5f008aSIngo Weinhold break; 381bc5f008aSIngo Weinhold } 382bc5f008aSIngo Weinhold 383bc5f008aSIngo Weinhold int length = 1; 384bc5f008aSIngo Weinhold switch (info.breakpoints[i].length) { 385bc5f008aSIngo Weinhold case X86_BREAKPOINT_LENGTH_1: 386bc5f008aSIngo Weinhold length = 1; 387bc5f008aSIngo Weinhold break; 388bc5f008aSIngo Weinhold case X86_BREAKPOINT_LENGTH_2: 389bc5f008aSIngo Weinhold length = 2; 390bc5f008aSIngo Weinhold break; 391bc5f008aSIngo Weinhold case X86_BREAKPOINT_LENGTH_4: 392bc5f008aSIngo Weinhold length = 4; 393bc5f008aSIngo Weinhold break; 394bc5f008aSIngo Weinhold } 395bc5f008aSIngo Weinhold 396bc5f008aSIngo Weinhold if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT) 397bc5f008aSIngo Weinhold kprintf(" %d byte%s", length, (length > 1 ? "s" : "")); 398bc5f008aSIngo Weinhold } else 399bc5f008aSIngo Weinhold kprintf("unused"); 400bc5f008aSIngo Weinhold 401bc5f008aSIngo Weinhold kprintf("\n"); 402bc5f008aSIngo Weinhold } 403bc5f008aSIngo Weinhold 404bc5f008aSIngo Weinhold return 0; 405bc5f008aSIngo Weinhold } 406bc5f008aSIngo Weinhold 407bc5f008aSIngo Weinhold 408bc5f008aSIngo Weinhold static int 409bc5f008aSIngo Weinhold debugger_breakpoint(int argc, char** argv) 410bc5f008aSIngo Weinhold { 411bc5f008aSIngo Weinhold // get arguments 412bc5f008aSIngo Weinhold 413bc5f008aSIngo Weinhold if (argc < 2 || argc > 3) 4148342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 415bc5f008aSIngo Weinhold 416bc5f008aSIngo Weinhold addr_t address = strtoul(argv[1], NULL, 0); 417bc5f008aSIngo Weinhold if (address == 0) 4188342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 419bc5f008aSIngo Weinhold 420bc5f008aSIngo Weinhold bool clear = false; 421bc5f008aSIngo Weinhold if (argc == 3) { 422bc5f008aSIngo Weinhold if (strcmp(argv[2], "clear") == 0) 423bc5f008aSIngo Weinhold clear = true; 424bc5f008aSIngo Weinhold else 4258342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 426bc5f008aSIngo Weinhold } 427bc5f008aSIngo Weinhold 428bc5f008aSIngo Weinhold // set/clear breakpoint 429bc5f008aSIngo Weinhold 430bc5f008aSIngo Weinhold arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; 431bc5f008aSIngo Weinhold 432bc5f008aSIngo Weinhold status_t error; 433bc5f008aSIngo Weinhold 434bc5f008aSIngo Weinhold if (clear) { 435bc5f008aSIngo Weinhold error = clear_breakpoint(info, (void*)address, false); 436bc5f008aSIngo Weinhold } else { 437bc5f008aSIngo Weinhold error = set_breakpoint(info, (void*)address, X86_INSTRUCTION_BREAKPOINT, 438bc5f008aSIngo Weinhold X86_BREAKPOINT_LENGTH_1, true); 439bc5f008aSIngo Weinhold } 440bc5f008aSIngo Weinhold 441bc5f008aSIngo Weinhold if (error == B_OK) 44231d9352fSIngo Weinhold call_all_cpus_sync(install_breakpoints_per_cpu, NULL); 443bc5f008aSIngo Weinhold else 444bc5f008aSIngo Weinhold kprintf("Failed to install breakpoint: %s\n", strerror(error)); 445bc5f008aSIngo Weinhold 446bc5f008aSIngo Weinhold return 0; 447bc5f008aSIngo Weinhold } 448bc5f008aSIngo Weinhold 449bc5f008aSIngo Weinhold 450bc5f008aSIngo Weinhold static int 451bc5f008aSIngo Weinhold debugger_watchpoint(int argc, char** argv) 452bc5f008aSIngo Weinhold { 453bc5f008aSIngo Weinhold // get arguments 454bc5f008aSIngo Weinhold 455bc5f008aSIngo Weinhold if (argc < 2 || argc > 4) 4568342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 457bc5f008aSIngo Weinhold 458bc5f008aSIngo Weinhold addr_t address = strtoul(argv[1], NULL, 0); 459bc5f008aSIngo Weinhold if (address == 0) 4608342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 461bc5f008aSIngo Weinhold 462bc5f008aSIngo Weinhold bool clear = false; 463bc5f008aSIngo Weinhold bool readWrite = false; 464bc5f008aSIngo Weinhold int argi = 2; 465bc5f008aSIngo Weinhold int length = 1; 466bc5f008aSIngo Weinhold if (argc >= 3) { 467bc5f008aSIngo Weinhold if (strcmp(argv[argi], "clear") == 0) { 468bc5f008aSIngo Weinhold clear = true; 469bc5f008aSIngo Weinhold argi++; 470bc5f008aSIngo Weinhold } else if (strcmp(argv[argi], "rw") == 0) { 471bc5f008aSIngo Weinhold readWrite = true; 472bc5f008aSIngo Weinhold argi++; 473bc5f008aSIngo Weinhold } 474bc5f008aSIngo Weinhold 475bc5f008aSIngo Weinhold if (!clear && argi < argc) 476bc5f008aSIngo Weinhold length = strtoul(argv[argi++], NULL, 0); 477bc5f008aSIngo Weinhold 478bc5f008aSIngo Weinhold if (length == 0 || argi < argc) 4798342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 480bc5f008aSIngo Weinhold } 481bc5f008aSIngo Weinhold 482bc5f008aSIngo Weinhold // set/clear breakpoint 483bc5f008aSIngo Weinhold 484bc5f008aSIngo Weinhold arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; 485bc5f008aSIngo Weinhold 486bc5f008aSIngo Weinhold status_t error; 487bc5f008aSIngo Weinhold 488bc5f008aSIngo Weinhold if (clear) { 489bc5f008aSIngo Weinhold error = clear_breakpoint(info, (void*)address, true); 490bc5f008aSIngo Weinhold } else { 491bc5f008aSIngo Weinhold uint32 type = readWrite ? B_DATA_READ_WRITE_WATCHPOINT 492bc5f008aSIngo Weinhold : B_DATA_WRITE_WATCHPOINT; 493bc5f008aSIngo Weinhold 494bc5f008aSIngo Weinhold uint32 archType, archLength; 495bc5f008aSIngo Weinhold error = check_watch_point_parameters((void*)address, type, length, 496bc5f008aSIngo Weinhold archType, archLength); 497bc5f008aSIngo Weinhold 498bc5f008aSIngo Weinhold if (error == B_OK) { 499bc5f008aSIngo Weinhold error = set_breakpoint(info, (void*)address, archType, archLength, 500bc5f008aSIngo Weinhold true); 501bc5f008aSIngo Weinhold } 502bc5f008aSIngo Weinhold } 503bc5f008aSIngo Weinhold 504bc5f008aSIngo Weinhold if (error == B_OK) 50531d9352fSIngo Weinhold call_all_cpus_sync(install_breakpoints_per_cpu, NULL); 506bc5f008aSIngo Weinhold else 507bc5f008aSIngo Weinhold kprintf("Failed to install breakpoint: %s\n", strerror(error)); 508bc5f008aSIngo Weinhold 509bc5f008aSIngo Weinhold return 0; 510bc5f008aSIngo Weinhold } 511bc5f008aSIngo Weinhold 5128342d4cdSIngo Weinhold 5138342d4cdSIngo Weinhold static int 5148342d4cdSIngo Weinhold debugger_single_step(int argc, char** argv) 5158342d4cdSIngo Weinhold { 5168342d4cdSIngo Weinhold // TODO: Since we need an iframe, this doesn't work when KDL wasn't entered 5178342d4cdSIngo Weinhold // via an exception. 5188342d4cdSIngo Weinhold 5198342d4cdSIngo Weinhold struct iframe* frame = i386_get_current_iframe(); 5208342d4cdSIngo Weinhold if (frame == NULL) { 5218342d4cdSIngo Weinhold kprintf("Failed to get the current iframe!\n"); 5228342d4cdSIngo Weinhold return 0; 5238342d4cdSIngo Weinhold } 5248342d4cdSIngo Weinhold 5258342d4cdSIngo Weinhold frame->flags |= (1 << X86_EFLAGS_TF); 5268342d4cdSIngo Weinhold 5278342d4cdSIngo Weinhold return B_KDEBUG_QUIT; 5288342d4cdSIngo Weinhold } 5298342d4cdSIngo Weinhold 5308342d4cdSIngo Weinhold 531bc5f008aSIngo Weinhold #endif // KERNEL_BREAKPOINTS 532bc5f008aSIngo Weinhold 533bc5f008aSIngo Weinhold 534667f1eebSIngo Weinhold // #pragma mark - in-kernel public interface 535667f1eebSIngo Weinhold 536667f1eebSIngo Weinhold 5372d690920SAxel Dörfler void 5382d690920SAxel Dörfler arch_clear_team_debug_info(struct arch_team_debug_info *info) 5392d690920SAxel Dörfler { 5402d690920SAxel Dörfler for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) 5412d690920SAxel Dörfler info->breakpoints[i].address = NULL; 5422d690920SAxel Dörfler 5432d690920SAxel Dörfler info->dr7 = X86_BREAKPOINTS_DISABLED_DR7; 5442d690920SAxel Dörfler } 5452d690920SAxel Dörfler 5462d690920SAxel Dörfler 5472d690920SAxel Dörfler void 5482d690920SAxel Dörfler arch_destroy_team_debug_info(struct arch_team_debug_info *info) 5492d690920SAxel Dörfler { 5502d690920SAxel Dörfler arch_clear_team_debug_info(info); 5512d690920SAxel Dörfler } 5522d690920SAxel Dörfler 5532d690920SAxel Dörfler 5542d690920SAxel Dörfler void 5552d690920SAxel Dörfler arch_clear_thread_debug_info(struct arch_thread_debug_info *info) 5562d690920SAxel Dörfler { 5572d690920SAxel Dörfler info->flags = 0; 5582d690920SAxel Dörfler } 5592d690920SAxel Dörfler 5602d690920SAxel Dörfler 5612d690920SAxel Dörfler void 5622d690920SAxel Dörfler arch_destroy_thread_debug_info(struct arch_thread_debug_info *info) 5632d690920SAxel Dörfler { 5642d690920SAxel Dörfler arch_clear_thread_debug_info(info); 5652d690920SAxel Dörfler } 5662d690920SAxel Dörfler 5672d690920SAxel Dörfler 5682d690920SAxel Dörfler void 56934b3b26bSIngo Weinhold arch_update_thread_single_step() 57034b3b26bSIngo Weinhold { 57134b3b26bSIngo Weinhold if (struct iframe* frame = i386_get_user_iframe()) { 57234b3b26bSIngo Weinhold struct thread* thread = thread_get_current_thread(); 57334b3b26bSIngo Weinhold 57434b3b26bSIngo Weinhold // set/clear TF in EFLAGS depending on if single stepping is desired 57534b3b26bSIngo Weinhold if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP) 57634b3b26bSIngo Weinhold frame->flags |= (1 << X86_EFLAGS_TF); 57734b3b26bSIngo Weinhold else 57834b3b26bSIngo Weinhold frame->flags &= ~(1 << X86_EFLAGS_TF); 57934b3b26bSIngo Weinhold } 58034b3b26bSIngo Weinhold } 58134b3b26bSIngo Weinhold 58234b3b26bSIngo Weinhold 58334b3b26bSIngo Weinhold void 5840b11ecb1SIngo Weinhold arch_set_debug_cpu_state(const debug_cpu_state *cpuState) 5852d690920SAxel Dörfler { 5862d690920SAxel Dörfler if (struct iframe *frame = i386_get_user_iframe()) { 5870b11ecb1SIngo Weinhold // For the floating point state to be correct the calling function must 5880b11ecb1SIngo Weinhold // not use these registers (not even indirectly). 5890b11ecb1SIngo Weinhold if (gHasSSE) { 5900b11ecb1SIngo Weinhold // Since fxrstor requires 16-byte alignment and this isn't 5910b11ecb1SIngo Weinhold // guaranteed passed buffer, we use our thread's fpu_state field as 5920b11ecb1SIngo Weinhold // temporary buffer. We need to disable interrupts to make use of 5930b11ecb1SIngo Weinhold // it. 5940b11ecb1SIngo Weinhold struct thread* thread = thread_get_current_thread(); 5950b11ecb1SIngo Weinhold InterruptsLocker locker; 5960b11ecb1SIngo Weinhold memcpy(thread->arch_info.fpu_state, &cpuState->extended_registers, 5970b11ecb1SIngo Weinhold sizeof(&cpuState->extended_registers)); 5980b11ecb1SIngo Weinhold i386_fxrstor(thread->arch_info.fpu_state); 5990b11ecb1SIngo Weinhold } else { 6000b11ecb1SIngo Weinhold // TODO: Implement! We need to convert the format first. 6010b11ecb1SIngo Weinhold // i386_frstor(&cpuState->extended_registers); 6020b11ecb1SIngo Weinhold } 6032d690920SAxel Dörfler 6042d690920SAxel Dörfler // frame->gs = cpuState->gs; 6052d690920SAxel Dörfler // frame->fs = cpuState->fs; 6062d690920SAxel Dörfler // frame->es = cpuState->es; 6072d690920SAxel Dörfler // frame->ds = cpuState->ds; 6082d690920SAxel Dörfler frame->edi = cpuState->edi; 6092d690920SAxel Dörfler frame->esi = cpuState->esi; 6102d690920SAxel Dörfler frame->ebp = cpuState->ebp; 611568ade58SIngo Weinhold // frame->esp = cpuState->esp; 6122d690920SAxel Dörfler frame->ebx = cpuState->ebx; 6132d690920SAxel Dörfler frame->edx = cpuState->edx; 6142d690920SAxel Dörfler frame->ecx = cpuState->ecx; 6152d690920SAxel Dörfler frame->eax = cpuState->eax; 6162d690920SAxel Dörfler // frame->vector = cpuState->vector; 6172d690920SAxel Dörfler // frame->error_code = cpuState->error_code; 6182d690920SAxel Dörfler frame->eip = cpuState->eip; 6192d690920SAxel Dörfler // frame->cs = cpuState->cs; 6202d690920SAxel Dörfler frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS) 6212d690920SAxel Dörfler | (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS); 6222d690920SAxel Dörfler frame->user_esp = cpuState->user_esp; 6232d690920SAxel Dörfler // frame->user_ss = cpuState->user_ss; 6242d690920SAxel Dörfler } 6252d690920SAxel Dörfler } 6262d690920SAxel Dörfler 627667f1eebSIngo Weinhold 6282d690920SAxel Dörfler void 6290b11ecb1SIngo Weinhold arch_get_debug_cpu_state(debug_cpu_state *cpuState) 6302d690920SAxel Dörfler { 6312d690920SAxel Dörfler if (struct iframe *frame = i386_get_user_iframe()) { 6320b11ecb1SIngo Weinhold // For the floating point state to be correct the calling function must 6330b11ecb1SIngo Weinhold // not use these registers (not even indirectly). 6340b11ecb1SIngo Weinhold if (gHasSSE) { 6350b11ecb1SIngo Weinhold // Since fxsave requires 16-byte alignment and this isn't guaranteed 6360b11ecb1SIngo Weinhold // passed buffer, we use our thread's fpu_state field as temporary 6370b11ecb1SIngo Weinhold // buffer. We need to disable interrupts to make use of it. 6380b11ecb1SIngo Weinhold struct thread* thread = thread_get_current_thread(); 6390b11ecb1SIngo Weinhold InterruptsLocker locker; 6400b11ecb1SIngo Weinhold i386_fxsave(thread->arch_info.fpu_state); 6410b11ecb1SIngo Weinhold // unlike fnsave, fxsave doesn't reinit the FPU state 6420b11ecb1SIngo Weinhold memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state, 6430b11ecb1SIngo Weinhold sizeof(&cpuState->extended_registers)); 6440b11ecb1SIngo Weinhold } else { 6450b11ecb1SIngo Weinhold i386_fnsave(&cpuState->extended_registers); 6460b11ecb1SIngo Weinhold i386_frstor(&cpuState->extended_registers); 6470b11ecb1SIngo Weinhold // fnsave reinits the FPU state after saving, so we need to 6480b11ecb1SIngo Weinhold // load it again 6490b11ecb1SIngo Weinhold // TODO: Convert to fxsave format! 6500b11ecb1SIngo Weinhold } 651568ade58SIngo Weinhold get_iframe_registers(frame, cpuState); 6522d690920SAxel Dörfler } 6532d690920SAxel Dörfler } 6542d690920SAxel Dörfler 6552d690920SAxel Dörfler 6562d690920SAxel Dörfler status_t 6572d690920SAxel Dörfler arch_set_breakpoint(void *address) 6582d690920SAxel Dörfler { 6592d690920SAxel Dörfler return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 6602d690920SAxel Dörfler X86_BREAKPOINT_LENGTH_1); 6612d690920SAxel Dörfler } 6622d690920SAxel Dörfler 6632d690920SAxel Dörfler 6642d690920SAxel Dörfler status_t 6652d690920SAxel Dörfler arch_clear_breakpoint(void *address) 6662d690920SAxel Dörfler { 6672d690920SAxel Dörfler return clear_breakpoint(address, false); 6682d690920SAxel Dörfler } 6692d690920SAxel Dörfler 6702d690920SAxel Dörfler 6712d690920SAxel Dörfler status_t 6722d690920SAxel Dörfler arch_set_watchpoint(void *address, uint32 type, int32 length) 6732d690920SAxel Dörfler { 674667f1eebSIngo Weinhold uint32 archType, archLength; 675667f1eebSIngo Weinhold status_t error = check_watch_point_parameters(address, type, length, 676667f1eebSIngo Weinhold archType, archLength); 677667f1eebSIngo Weinhold if (error != B_OK) 678667f1eebSIngo Weinhold return error; 6792d690920SAxel Dörfler 6802d690920SAxel Dörfler return set_breakpoint(address, archType, archLength); 6812d690920SAxel Dörfler } 6822d690920SAxel Dörfler 6832d690920SAxel Dörfler 6842d690920SAxel Dörfler status_t 6852d690920SAxel Dörfler arch_clear_watchpoint(void *address) 6862d690920SAxel Dörfler { 6872d690920SAxel Dörfler return clear_breakpoint(address, false); 6882d690920SAxel Dörfler } 6892d690920SAxel Dörfler 6902d690920SAxel Dörfler 69134b3b26bSIngo Weinhold bool 69234b3b26bSIngo Weinhold arch_has_breakpoints(struct arch_team_debug_info *info) 69334b3b26bSIngo Weinhold { 69434b3b26bSIngo Weinhold // Reading info->dr7 is atomically, so we don't need to lock. The caller 69534b3b26bSIngo Weinhold // has to ensure, that the info doesn't go away. 69634b3b26bSIngo Weinhold return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7); 69734b3b26bSIngo Weinhold } 69834b3b26bSIngo Weinhold 69934b3b26bSIngo Weinhold 700667f1eebSIngo Weinhold #if KERNEL_BREAKPOINTS 7012d690920SAxel Dörfler 702667f1eebSIngo Weinhold status_t 703667f1eebSIngo Weinhold arch_set_kernel_breakpoint(void *address) 704667f1eebSIngo Weinhold { 705667f1eebSIngo Weinhold status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 706667f1eebSIngo Weinhold X86_BREAKPOINT_LENGTH_1); 707667f1eebSIngo Weinhold 708667f1eebSIngo Weinhold if (error != B_OK) { 709667f1eebSIngo Weinhold panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s", 710667f1eebSIngo Weinhold strerror(error)); 7112d690920SAxel Dörfler } 7122d690920SAxel Dörfler 713667f1eebSIngo Weinhold return error; 714667f1eebSIngo Weinhold } 715667f1eebSIngo Weinhold 716667f1eebSIngo Weinhold 717667f1eebSIngo Weinhold status_t 718667f1eebSIngo Weinhold arch_clear_kernel_breakpoint(void *address) 719667f1eebSIngo Weinhold { 720667f1eebSIngo Weinhold status_t error = clear_kernel_breakpoint(address, false); 721667f1eebSIngo Weinhold 722667f1eebSIngo Weinhold if (error != B_OK) { 723667f1eebSIngo Weinhold panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s", 724667f1eebSIngo Weinhold strerror(error)); 725667f1eebSIngo Weinhold } 726667f1eebSIngo Weinhold 727667f1eebSIngo Weinhold return error; 728667f1eebSIngo Weinhold } 729667f1eebSIngo Weinhold 730667f1eebSIngo Weinhold 731667f1eebSIngo Weinhold status_t 732667f1eebSIngo Weinhold arch_set_kernel_watchpoint(void *address, uint32 type, int32 length) 733667f1eebSIngo Weinhold { 734667f1eebSIngo Weinhold uint32 archType, archLength; 735667f1eebSIngo Weinhold status_t error = check_watch_point_parameters(address, type, length, 736667f1eebSIngo Weinhold archType, archLength); 737667f1eebSIngo Weinhold 738667f1eebSIngo Weinhold if (error == B_OK) 739667f1eebSIngo Weinhold error = set_kernel_breakpoint(address, archType, archLength); 740667f1eebSIngo Weinhold 741667f1eebSIngo Weinhold if (error != B_OK) { 742667f1eebSIngo Weinhold panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s", 743667f1eebSIngo Weinhold strerror(error)); 744667f1eebSIngo Weinhold } 745667f1eebSIngo Weinhold 746667f1eebSIngo Weinhold return error; 747667f1eebSIngo Weinhold } 748667f1eebSIngo Weinhold 749667f1eebSIngo Weinhold 750667f1eebSIngo Weinhold status_t 751667f1eebSIngo Weinhold arch_clear_kernel_watchpoint(void *address) 752667f1eebSIngo Weinhold { 753667f1eebSIngo Weinhold status_t error = clear_kernel_breakpoint(address, true); 754667f1eebSIngo Weinhold 755667f1eebSIngo Weinhold if (error != B_OK) { 756667f1eebSIngo Weinhold panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s", 757667f1eebSIngo Weinhold strerror(error)); 758667f1eebSIngo Weinhold } 759667f1eebSIngo Weinhold 760667f1eebSIngo Weinhold return error; 761667f1eebSIngo Weinhold } 762667f1eebSIngo Weinhold 763667f1eebSIngo Weinhold #endif // KERNEL_BREAKPOINTS 764667f1eebSIngo Weinhold 765667f1eebSIngo Weinhold 766667f1eebSIngo Weinhold // #pragma mark - x86 implementation interface 767667f1eebSIngo Weinhold 7682d690920SAxel Dörfler 7692d690920SAxel Dörfler /** 7708ad4a2e9SIngo Weinhold * Interrupts are disabled. \a frame is unused, i.e. can be \c NULL. 7712d690920SAxel Dörfler */ 7722d690920SAxel Dörfler void 77334b3b26bSIngo Weinhold x86_init_user_debug_at_kernel_exit(struct iframe *frame) 7742d690920SAxel Dörfler { 7752d690920SAxel Dörfler struct thread *thread = thread_get_current_thread(); 7762d690920SAxel Dörfler 77734b3b26bSIngo Weinhold if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED)) 77834b3b26bSIngo Weinhold return; 779b4476702SIngo Weinhold 780b4476702SIngo Weinhold // disable kernel breakpoints 781b4476702SIngo Weinhold disable_breakpoints(); 78234b3b26bSIngo Weinhold 7832d690920SAxel Dörfler GRAB_THREAD_LOCK(); 7842d690920SAxel Dörfler GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 7852d690920SAxel Dörfler 7862d690920SAxel Dörfler arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info; 7872d690920SAxel Dörfler 788b4476702SIngo Weinhold // install the user breakpoints 7892d690920SAxel Dörfler install_breakpoints(teamInfo); 7902d690920SAxel Dörfler 79134b3b26bSIngo Weinhold atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED); 7922d690920SAxel Dörfler 7932d690920SAxel Dörfler RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 7942d690920SAxel Dörfler RELEASE_THREAD_LOCK(); 7952d690920SAxel Dörfler } 7962d690920SAxel Dörfler 7972d690920SAxel Dörfler 7982d690920SAxel Dörfler /** 79934b3b26bSIngo Weinhold * Interrupts are disabled. 8002d690920SAxel Dörfler */ 8012d690920SAxel Dörfler void 80234b3b26bSIngo Weinhold x86_exit_user_debug_at_kernel_entry() 8032d690920SAxel Dörfler { 8042d690920SAxel Dörfler struct thread *thread = thread_get_current_thread(); 8052d690920SAxel Dörfler 80634b3b26bSIngo Weinhold if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED)) 80734b3b26bSIngo Weinhold return; 80834b3b26bSIngo Weinhold 809feddedabSIngo Weinhold // We need to save the current values of dr6 and dr7 in the CPU structure, 810feddedabSIngo Weinhold // since in case of a debug exception we might overwrite them before 811feddedabSIngo Weinhold // x86_handle_debug_exception() is called. 812feddedabSIngo Weinhold asm("movl %%dr6, %0" : "=r"(thread->cpu->arch.dr6)); 813feddedabSIngo Weinhold asm("movl %%dr7, %0" : "=r"(thread->cpu->arch.dr7)); 814feddedabSIngo Weinhold 8152d690920SAxel Dörfler GRAB_THREAD_LOCK(); 8162d690920SAxel Dörfler 817b4476702SIngo Weinhold // disable user breakpoints 818667f1eebSIngo Weinhold disable_breakpoints(); 8192d690920SAxel Dörfler 820b4476702SIngo Weinhold // install kernel breakpoints 821667f1eebSIngo Weinhold struct team* kernelTeam = team_get_kernel_team(); 822667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 823667f1eebSIngo Weinhold install_breakpoints(kernelTeam->debug_info.arch_info); 824667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 825667f1eebSIngo Weinhold 82634b3b26bSIngo Weinhold atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED); 82734b3b26bSIngo Weinhold 8282d690920SAxel Dörfler RELEASE_THREAD_LOCK(); 8292d690920SAxel Dörfler } 8302d690920SAxel Dörfler 8312d690920SAxel Dörfler 8322d690920SAxel Dörfler /** 833b4476702SIngo Weinhold * Interrupts are disabled and will possibly be enabled by the function. 8342d690920SAxel Dörfler */ 83534b3b26bSIngo Weinhold void 83634b3b26bSIngo Weinhold x86_handle_debug_exception(struct iframe *frame) 8372d690920SAxel Dörfler { 838feddedabSIngo Weinhold struct thread* thread = thread_get_current_thread(); 839*45538a5eSIngo Weinhold 840*45538a5eSIngo Weinhold // Get dr6 and dr7. If the given iframe is a userland frame, the exception 841*45538a5eSIngo Weinhold // obviously occurred in userland. In that case 842*45538a5eSIngo Weinhold // x86_exit_user_debug_at_kernel_entry() has already been invoked and dr6 843*45538a5eSIngo Weinhold // and dr7 are stored in the cpu info. Otherwise we need to fetch the 844*45538a5eSIngo Weinhold // current values from the registers. 845*45538a5eSIngo Weinhold uint32 dr6; 846*45538a5eSIngo Weinhold uint32 dr7; 847*45538a5eSIngo Weinhold if (IFRAME_IS_USER(frame)) { 848*45538a5eSIngo Weinhold dr6 = thread->cpu->arch.dr6; 849*45538a5eSIngo Weinhold dr7 = thread->cpu->arch.dr7; 850*45538a5eSIngo Weinhold } else { 851*45538a5eSIngo Weinhold asm("movl %%dr6, %0" : "=r"(dr6)); 852*45538a5eSIngo Weinhold asm("movl %%dr7, %0" : "=r"(dr7)); 853*45538a5eSIngo Weinhold } 8542d690920SAxel Dörfler 8552d690920SAxel Dörfler TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7)); 8562d690920SAxel Dörfler 8572d690920SAxel Dörfler // check, which exception condition applies 8582d690920SAxel Dörfler if (dr6 & X86_DR6_BREAKPOINT_MASK) { 8592d690920SAxel Dörfler // breakpoint 8602d690920SAxel Dörfler 8612d690920SAxel Dörfler // check which breakpoint was taken 8622d690920SAxel Dörfler bool watchpoint = true; 8632d690920SAxel Dörfler for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 8642d690920SAxel Dörfler if (dr6 & (1 << sDR6B[i])) { 8652d690920SAxel Dörfler uint32 type = (dr7 >> sDR7RW[i]) & 0x3; 866568ade58SIngo Weinhold if (type == X86_INSTRUCTION_BREAKPOINT) 8672d690920SAxel Dörfler watchpoint = false; 8682d690920SAxel Dörfler } 8692d690920SAxel Dörfler } 8702d690920SAxel Dörfler 8718753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 8722d690920SAxel Dörfler // enable interrupts and notify the debugger 8732d690920SAxel Dörfler enable_interrupts(); 8742d690920SAxel Dörfler 8752d690920SAxel Dörfler if (watchpoint) 8762d690920SAxel Dörfler user_debug_watchpoint_hit(); 8772d690920SAxel Dörfler else 8782d690920SAxel Dörfler user_debug_breakpoint_hit(false); 8798753babdSIngo Weinhold } else { 8808753babdSIngo Weinhold panic("hit kernel %spoint: dr6: 0x%lx, dr7: 0x%lx", 8818753babdSIngo Weinhold watchpoint ? "watch" : "break", dr6, dr7); 8828753babdSIngo Weinhold } 8832d690920SAxel Dörfler } else if (dr6 & (1 << X86_DR6_BD)) { 8842d690920SAxel Dörfler // general detect exception 8852d690920SAxel Dörfler // Occurs only, if GD in DR7 is set (which we don't do) and someone 8862d690920SAxel Dörfler // tries to write to the debug registers. 8878753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 8882d690920SAxel Dörfler dprintf("i386_handle_debug_exception(): ignoring spurious general " 8892d690920SAxel Dörfler "detect exception\n"); 8902d690920SAxel Dörfler 8912d690920SAxel Dörfler enable_interrupts(); 8928753babdSIngo Weinhold } else 8938753babdSIngo Weinhold panic("spurious general detect exception in kernel mode"); 8942d690920SAxel Dörfler } else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) { 8952d690920SAxel Dörfler // single step 8962d690920SAxel Dörfler 8978753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 8982d690920SAxel Dörfler // enable interrupts and notify the debugger 8992d690920SAxel Dörfler enable_interrupts(); 9002d690920SAxel Dörfler 9012d690920SAxel Dörfler user_debug_single_stepped(); 9028342d4cdSIngo Weinhold } else { 9038342d4cdSIngo Weinhold // Disable single-stepping -- the next "step" command will re-enable 9048342d4cdSIngo Weinhold // it, but we don't want it when continuing otherwise. 9058342d4cdSIngo Weinhold frame->flags &= ~(1 << X86_EFLAGS_TF); 9068342d4cdSIngo Weinhold 9078b3d3d8aSIngo Weinhold // Determine whether the exception occurred at a syscall/trap 9088b3d3d8aSIngo Weinhold // kernel entry or whether this is genuine kernel single-stepping. 9098b3d3d8aSIngo Weinhold bool inKernel = true; 9108b3d3d8aSIngo Weinhold if (thread->team != team_get_kernel_team() 9118b3d3d8aSIngo Weinhold && i386_get_user_iframe() == NULL) { 9128b3d3d8aSIngo Weinhold // TODO: This is not yet fully correct, since a newly created 9138b3d3d8aSIngo Weinhold // thread that doesn't have entered userland yet also has this 9148b3d3d8aSIngo Weinhold // property. 9158b3d3d8aSIngo Weinhold inKernel = false; 9168b3d3d8aSIngo Weinhold } 9178b3d3d8aSIngo Weinhold 9188b3d3d8aSIngo Weinhold if (inKernel) { 9198753babdSIngo Weinhold panic("kernel single step"); 9208b3d3d8aSIngo Weinhold } else { 9218b3d3d8aSIngo Weinhold // The thread is a userland thread and it just entered the 9228b3d3d8aSIngo Weinhold // kernel when the single-step exception occurred. This happens 9238b3d3d8aSIngo Weinhold // e.g. when sysenter is called with single-stepping enabled. 9248b3d3d8aSIngo Weinhold // We need to ignore the exception now and send a single-step 9258b3d3d8aSIngo Weinhold // notification later, when the thread wants to return from the 9268b3d3d8aSIngo Weinhold // kernel. 9278b3d3d8aSIngo Weinhold InterruptsSpinLocker threadLocker(gThreadSpinlock); 9288b3d3d8aSIngo Weinhold 9298b3d3d8aSIngo Weinhold // Check whether the team is still being debugged and set 9308b3d3d8aSIngo Weinhold // the B_THREAD_DEBUG_NOTIFY_SINGLE_STEP and 9318b3d3d8aSIngo Weinhold // B_THREAD_DEBUG_STOP flags, so that the thread will be 9328b3d3d8aSIngo Weinhold // stopped when it is going to leave the kernel and notify the 9338b3d3d8aSIngo Weinhold // debugger about the single-step event. 9348b3d3d8aSIngo Weinhold int32 teamDebugFlags 9358b3d3d8aSIngo Weinhold = atomic_get(&thread->team->debug_info.flags); 9368b3d3d8aSIngo Weinhold if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) { 9378b3d3d8aSIngo Weinhold atomic_or(&thread->debug_info.flags, 9388b3d3d8aSIngo Weinhold B_THREAD_DEBUG_NOTIFY_SINGLE_STEP 9398b3d3d8aSIngo Weinhold | B_THREAD_DEBUG_STOP); 9408b3d3d8aSIngo Weinhold } 9418b3d3d8aSIngo Weinhold } 9428342d4cdSIngo Weinhold } 9432d690920SAxel Dörfler } else if (dr6 & (1 << X86_DR6_BT)) { 9442d690920SAxel Dörfler // task switch 9452d690920SAxel Dörfler // Occurs only, if T in EFLAGS is set (which we don't do). 9468753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 9472d690920SAxel Dörfler dprintf("i386_handle_debug_exception(): ignoring spurious task switch " 9482d690920SAxel Dörfler "exception\n"); 9492d690920SAxel Dörfler 9502d690920SAxel Dörfler enable_interrupts(); 9518753babdSIngo Weinhold } else 9528753babdSIngo Weinhold panic("spurious task switch exception in kernel mode"); 9532d690920SAxel Dörfler } else { 9548753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 95506be24a7SAxel Dörfler TRACE(("i386_handle_debug_exception(): ignoring spurious debug " 95606be24a7SAxel Dörfler "exception (no condition recognized)\n")); 9572d690920SAxel Dörfler 9582d690920SAxel Dörfler enable_interrupts(); 9598753babdSIngo Weinhold } else { 9608753babdSIngo Weinhold panic("spurious debug exception in kernel mode (no condition " 9618753babdSIngo Weinhold "recognized)"); 9628753babdSIngo Weinhold } 9632d690920SAxel Dörfler } 9642d690920SAxel Dörfler } 9652d690920SAxel Dörfler 9662d690920SAxel Dörfler 9672d690920SAxel Dörfler /** 968b4476702SIngo Weinhold * Interrupts are disabled and will possibly be enabled by the function. 9692d690920SAxel Dörfler */ 97034b3b26bSIngo Weinhold void 97134b3b26bSIngo Weinhold x86_handle_breakpoint_exception(struct iframe *frame) 9722d690920SAxel Dörfler { 9732d690920SAxel Dörfler TRACE(("i386_handle_breakpoint_exception()\n")); 9742d690920SAxel Dörfler 975b0f12d64SIngo Weinhold // reset eip to the int3 instruction 976b0f12d64SIngo Weinhold frame->eip--; 977b0f12d64SIngo Weinhold 978bb107c4eSAxel Dörfler if (!IFRAME_IS_USER(frame)) { 979667f1eebSIngo Weinhold panic("breakpoint exception in kernel mode"); 98034b3b26bSIngo Weinhold return; 981667f1eebSIngo Weinhold } 982667f1eebSIngo Weinhold 9832d690920SAxel Dörfler enable_interrupts(); 9842d690920SAxel Dörfler 9852d690920SAxel Dörfler user_debug_breakpoint_hit(true); 9862d690920SAxel Dörfler } 9872d690920SAxel Dörfler 9882d690920SAxel Dörfler 9892d690920SAxel Dörfler void 99034b3b26bSIngo Weinhold x86_init_user_debug() 9912d690920SAxel Dörfler { 9922d690920SAxel Dörfler // get debug settings 9932d690920SAxel Dörfler if (void *handle = load_driver_settings("kernel")) { 9942d690920SAxel Dörfler sQEmuSingleStepHack = get_driver_boolean_parameter(handle, 9952d690920SAxel Dörfler "qemu_single_step_hack", false, false);; 9962d690920SAxel Dörfler 9972d690920SAxel Dörfler unload_driver_settings(handle); 9982d690920SAxel Dörfler } 999bc5f008aSIngo Weinhold 1000bc5f008aSIngo Weinhold #if KERNEL_BREAKPOINTS 1001bc5f008aSIngo Weinhold // install debugger commands 10028342d4cdSIngo Weinhold add_debugger_command_etc("breakpoints", &debugger_breakpoints, 10038342d4cdSIngo Weinhold "Lists current break-/watchpoints", 10048342d4cdSIngo Weinhold "\n" 10058342d4cdSIngo Weinhold "Lists the current kernel break-/watchpoints.\n", 0); 10068342d4cdSIngo Weinhold add_debugger_command_alias("watchpoints", "breakpoints", NULL); 10078342d4cdSIngo Weinhold add_debugger_command_etc("breakpoint", &debugger_breakpoint, 10088342d4cdSIngo Weinhold "Set/clears a breakpoint", 10098342d4cdSIngo Weinhold "<address> [ clear ]\n" 10108342d4cdSIngo Weinhold "Sets respectively clears the breakpoint at address <address>.\n", 0); 10118342d4cdSIngo Weinhold add_debugger_command_etc("watchpoint", &debugger_watchpoint, 10128342d4cdSIngo Weinhold "Set/clears a watchpoint", 10138342d4cdSIngo Weinhold "<address> <address> ( [ rw ] [ <size> ] | clear )\n" 10148342d4cdSIngo Weinhold "Sets respectively clears the watchpoint at address <address>.\n" 10158342d4cdSIngo Weinhold "If \"rw\" is given the new watchpoint is a read/write watchpoint\n" 10168342d4cdSIngo Weinhold "otherwise a write watchpoint only.\n", 0); 10178342d4cdSIngo Weinhold add_debugger_command_etc("step", &debugger_single_step, 10188342d4cdSIngo Weinhold "Single-steps to the next instruction", 10198342d4cdSIngo Weinhold "\n" 10208342d4cdSIngo Weinhold "Single-steps to the next instruction.\n", 0); 1021bc5f008aSIngo Weinhold #endif 10222d690920SAxel Dörfler } 10232d690920SAxel Dörfler 1024