12d690920SAxel Dörfler /* 24535495dSIngo Weinhold * Copyright 2005-2011, 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)); 1044535495dSIngo Weinhold // DR3 is used to hold the current 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 2104535495dSIngo Weinhold 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 2314535495dSIngo Weinhold 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 { 2524535495dSIngo Weinhold 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 2684535495dSIngo Weinhold 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 2924535495dSIngo Weinhold 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 { 3604535495dSIngo Weinhold 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()) { 5724535495dSIngo Weinhold Thread* thread = thread_get_current_thread(); 57334b3b26bSIngo Weinhold 57413b81a3bSIngo Weinhold // set/clear TF in EFLAGS depending on whether single stepping is 57513b81a3bSIngo Weinhold // desired 57634b3b26bSIngo Weinhold if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP) 57734b3b26bSIngo Weinhold frame->flags |= (1 << X86_EFLAGS_TF); 57834b3b26bSIngo Weinhold else 57934b3b26bSIngo Weinhold frame->flags &= ~(1 << X86_EFLAGS_TF); 58034b3b26bSIngo Weinhold } 58134b3b26bSIngo Weinhold } 58234b3b26bSIngo Weinhold 58334b3b26bSIngo Weinhold 58434b3b26bSIngo Weinhold void 5850b11ecb1SIngo Weinhold arch_set_debug_cpu_state(const debug_cpu_state *cpuState) 5862d690920SAxel Dörfler { 5872d690920SAxel Dörfler if (struct iframe *frame = i386_get_user_iframe()) { 5880b11ecb1SIngo Weinhold // For the floating point state to be correct the calling function must 5890b11ecb1SIngo Weinhold // not use these registers (not even indirectly). 5900b11ecb1SIngo Weinhold if (gHasSSE) { 5910b11ecb1SIngo Weinhold // Since fxrstor requires 16-byte alignment and this isn't 5920b11ecb1SIngo Weinhold // guaranteed passed buffer, we use our thread's fpu_state field as 5930b11ecb1SIngo Weinhold // temporary buffer. We need to disable interrupts to make use of 5940b11ecb1SIngo Weinhold // it. 5954535495dSIngo Weinhold Thread* thread = thread_get_current_thread(); 5960b11ecb1SIngo Weinhold InterruptsLocker locker; 5970b11ecb1SIngo Weinhold memcpy(thread->arch_info.fpu_state, &cpuState->extended_registers, 598b2acbcbfSMichael Lotz sizeof(cpuState->extended_registers)); 5990b11ecb1SIngo Weinhold i386_fxrstor(thread->arch_info.fpu_state); 6000b11ecb1SIngo Weinhold } else { 6010b11ecb1SIngo Weinhold // TODO: Implement! We need to convert the format first. 6020b11ecb1SIngo Weinhold // i386_frstor(&cpuState->extended_registers); 6030b11ecb1SIngo Weinhold } 6042d690920SAxel Dörfler 6052d690920SAxel Dörfler // frame->gs = cpuState->gs; 6062d690920SAxel Dörfler // frame->fs = cpuState->fs; 6072d690920SAxel Dörfler // frame->es = cpuState->es; 6082d690920SAxel Dörfler // frame->ds = cpuState->ds; 6092d690920SAxel Dörfler frame->edi = cpuState->edi; 6102d690920SAxel Dörfler frame->esi = cpuState->esi; 6112d690920SAxel Dörfler frame->ebp = cpuState->ebp; 612568ade58SIngo Weinhold // frame->esp = cpuState->esp; 6132d690920SAxel Dörfler frame->ebx = cpuState->ebx; 6142d690920SAxel Dörfler frame->edx = cpuState->edx; 6152d690920SAxel Dörfler frame->ecx = cpuState->ecx; 6162d690920SAxel Dörfler frame->eax = cpuState->eax; 6172d690920SAxel Dörfler // frame->vector = cpuState->vector; 6182d690920SAxel Dörfler // frame->error_code = cpuState->error_code; 6192d690920SAxel Dörfler frame->eip = cpuState->eip; 6202d690920SAxel Dörfler // frame->cs = cpuState->cs; 6212d690920SAxel Dörfler frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS) 6222d690920SAxel Dörfler | (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS); 6232d690920SAxel Dörfler frame->user_esp = cpuState->user_esp; 6242d690920SAxel Dörfler // frame->user_ss = cpuState->user_ss; 6252d690920SAxel Dörfler } 6262d690920SAxel Dörfler } 6272d690920SAxel Dörfler 628667f1eebSIngo Weinhold 6292d690920SAxel Dörfler void 6300b11ecb1SIngo Weinhold arch_get_debug_cpu_state(debug_cpu_state *cpuState) 6312d690920SAxel Dörfler { 6322d690920SAxel Dörfler if (struct iframe *frame = i386_get_user_iframe()) { 6330b11ecb1SIngo Weinhold // For the floating point state to be correct the calling function must 6340b11ecb1SIngo Weinhold // not use these registers (not even indirectly). 6350b11ecb1SIngo Weinhold if (gHasSSE) { 6360b11ecb1SIngo Weinhold // Since fxsave requires 16-byte alignment and this isn't guaranteed 6370b11ecb1SIngo Weinhold // passed buffer, we use our thread's fpu_state field as temporary 6380b11ecb1SIngo Weinhold // buffer. We need to disable interrupts to make use of it. 6394535495dSIngo Weinhold Thread* thread = thread_get_current_thread(); 6400b11ecb1SIngo Weinhold InterruptsLocker locker; 6410b11ecb1SIngo Weinhold i386_fxsave(thread->arch_info.fpu_state); 6420b11ecb1SIngo Weinhold // unlike fnsave, fxsave doesn't reinit the FPU state 6430b11ecb1SIngo Weinhold memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state, 644b2acbcbfSMichael Lotz sizeof(cpuState->extended_registers)); 6450b11ecb1SIngo Weinhold } else { 6460b11ecb1SIngo Weinhold i386_fnsave(&cpuState->extended_registers); 6470b11ecb1SIngo Weinhold i386_frstor(&cpuState->extended_registers); 6480b11ecb1SIngo Weinhold // fnsave reinits the FPU state after saving, so we need to 6490b11ecb1SIngo Weinhold // load it again 6500b11ecb1SIngo Weinhold // TODO: Convert to fxsave format! 6510b11ecb1SIngo Weinhold } 652568ade58SIngo Weinhold get_iframe_registers(frame, cpuState); 6532d690920SAxel Dörfler } 6542d690920SAxel Dörfler } 6552d690920SAxel Dörfler 6562d690920SAxel Dörfler 6572d690920SAxel Dörfler status_t 6582d690920SAxel Dörfler arch_set_breakpoint(void *address) 6592d690920SAxel Dörfler { 6602d690920SAxel Dörfler return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 6612d690920SAxel Dörfler X86_BREAKPOINT_LENGTH_1); 6622d690920SAxel Dörfler } 6632d690920SAxel Dörfler 6642d690920SAxel Dörfler 6652d690920SAxel Dörfler status_t 6662d690920SAxel Dörfler arch_clear_breakpoint(void *address) 6672d690920SAxel Dörfler { 6682d690920SAxel Dörfler return clear_breakpoint(address, false); 6692d690920SAxel Dörfler } 6702d690920SAxel Dörfler 6712d690920SAxel Dörfler 6722d690920SAxel Dörfler status_t 6732d690920SAxel Dörfler arch_set_watchpoint(void *address, uint32 type, int32 length) 6742d690920SAxel Dörfler { 675667f1eebSIngo Weinhold uint32 archType, archLength; 676667f1eebSIngo Weinhold status_t error = check_watch_point_parameters(address, type, length, 677667f1eebSIngo Weinhold archType, archLength); 678667f1eebSIngo Weinhold if (error != B_OK) 679667f1eebSIngo Weinhold return error; 6802d690920SAxel Dörfler 6812d690920SAxel Dörfler return set_breakpoint(address, archType, archLength); 6822d690920SAxel Dörfler } 6832d690920SAxel Dörfler 6842d690920SAxel Dörfler 6852d690920SAxel Dörfler status_t 6862d690920SAxel Dörfler arch_clear_watchpoint(void *address) 6872d690920SAxel Dörfler { 688e40e5ebfSIngo Weinhold return clear_breakpoint(address, true); 6892d690920SAxel Dörfler } 6902d690920SAxel Dörfler 6912d690920SAxel Dörfler 69234b3b26bSIngo Weinhold bool 69334b3b26bSIngo Weinhold arch_has_breakpoints(struct arch_team_debug_info *info) 69434b3b26bSIngo Weinhold { 69534b3b26bSIngo Weinhold // Reading info->dr7 is atomically, so we don't need to lock. The caller 69634b3b26bSIngo Weinhold // has to ensure, that the info doesn't go away. 69734b3b26bSIngo Weinhold return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7); 69834b3b26bSIngo Weinhold } 69934b3b26bSIngo Weinhold 70034b3b26bSIngo Weinhold 701667f1eebSIngo Weinhold #if KERNEL_BREAKPOINTS 7022d690920SAxel Dörfler 703667f1eebSIngo Weinhold status_t 704667f1eebSIngo Weinhold arch_set_kernel_breakpoint(void *address) 705667f1eebSIngo Weinhold { 706667f1eebSIngo Weinhold status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 707667f1eebSIngo Weinhold X86_BREAKPOINT_LENGTH_1); 708667f1eebSIngo Weinhold 709667f1eebSIngo Weinhold if (error != B_OK) { 710667f1eebSIngo Weinhold panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s", 711667f1eebSIngo Weinhold strerror(error)); 7122d690920SAxel Dörfler } 7132d690920SAxel Dörfler 714667f1eebSIngo Weinhold return error; 715667f1eebSIngo Weinhold } 716667f1eebSIngo Weinhold 717667f1eebSIngo Weinhold 718667f1eebSIngo Weinhold status_t 719667f1eebSIngo Weinhold arch_clear_kernel_breakpoint(void *address) 720667f1eebSIngo Weinhold { 721667f1eebSIngo Weinhold status_t error = clear_kernel_breakpoint(address, false); 722667f1eebSIngo Weinhold 723667f1eebSIngo Weinhold if (error != B_OK) { 724667f1eebSIngo Weinhold panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s", 725667f1eebSIngo Weinhold strerror(error)); 726667f1eebSIngo Weinhold } 727667f1eebSIngo Weinhold 728667f1eebSIngo Weinhold return error; 729667f1eebSIngo Weinhold } 730667f1eebSIngo Weinhold 731667f1eebSIngo Weinhold 732667f1eebSIngo Weinhold status_t 733667f1eebSIngo Weinhold arch_set_kernel_watchpoint(void *address, uint32 type, int32 length) 734667f1eebSIngo Weinhold { 735667f1eebSIngo Weinhold uint32 archType, archLength; 736667f1eebSIngo Weinhold status_t error = check_watch_point_parameters(address, type, length, 737667f1eebSIngo Weinhold archType, archLength); 738667f1eebSIngo Weinhold 739667f1eebSIngo Weinhold if (error == B_OK) 740667f1eebSIngo Weinhold error = set_kernel_breakpoint(address, archType, archLength); 741667f1eebSIngo Weinhold 742667f1eebSIngo Weinhold if (error != B_OK) { 743667f1eebSIngo Weinhold panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s", 744667f1eebSIngo Weinhold strerror(error)); 745667f1eebSIngo Weinhold } 746667f1eebSIngo Weinhold 747667f1eebSIngo Weinhold return error; 748667f1eebSIngo Weinhold } 749667f1eebSIngo Weinhold 750667f1eebSIngo Weinhold 751667f1eebSIngo Weinhold status_t 752667f1eebSIngo Weinhold arch_clear_kernel_watchpoint(void *address) 753667f1eebSIngo Weinhold { 754667f1eebSIngo Weinhold status_t error = clear_kernel_breakpoint(address, true); 755667f1eebSIngo Weinhold 756667f1eebSIngo Weinhold if (error != B_OK) { 757667f1eebSIngo Weinhold panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s", 758667f1eebSIngo Weinhold strerror(error)); 759667f1eebSIngo Weinhold } 760667f1eebSIngo Weinhold 761667f1eebSIngo Weinhold return error; 762667f1eebSIngo Weinhold } 763667f1eebSIngo Weinhold 764667f1eebSIngo Weinhold #endif // KERNEL_BREAKPOINTS 765667f1eebSIngo Weinhold 766667f1eebSIngo Weinhold 767667f1eebSIngo Weinhold // #pragma mark - x86 implementation interface 768667f1eebSIngo Weinhold 7692d690920SAxel Dörfler 7702d690920SAxel Dörfler /** 7718ad4a2e9SIngo Weinhold * Interrupts are disabled. \a frame is unused, i.e. can be \c NULL. 7722d690920SAxel Dörfler */ 7732d690920SAxel Dörfler void 77434b3b26bSIngo Weinhold x86_init_user_debug_at_kernel_exit(struct iframe *frame) 7752d690920SAxel Dörfler { 7764535495dSIngo Weinhold Thread *thread = thread_get_current_thread(); 7772d690920SAxel Dörfler 77834b3b26bSIngo Weinhold if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED)) 77934b3b26bSIngo Weinhold return; 780b4476702SIngo Weinhold 781b4476702SIngo Weinhold // disable kernel breakpoints 782b4476702SIngo Weinhold disable_breakpoints(); 78334b3b26bSIngo Weinhold 784*24df6592SIngo Weinhold // install the user breakpoints 7852d690920SAxel Dörfler GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 7862d690920SAxel Dörfler 7872d690920SAxel Dörfler arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info; 7882d690920SAxel Dörfler 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 } 7952d690920SAxel Dörfler 7962d690920SAxel Dörfler 7972d690920SAxel Dörfler /** 79834b3b26bSIngo Weinhold * Interrupts are disabled. 7992d690920SAxel Dörfler */ 8002d690920SAxel Dörfler void 80134b3b26bSIngo Weinhold x86_exit_user_debug_at_kernel_entry() 8022d690920SAxel Dörfler { 8034535495dSIngo Weinhold Thread *thread = thread_get_current_thread(); 8042d690920SAxel Dörfler 805feddedabSIngo Weinhold // We need to save the current values of dr6 and dr7 in the CPU structure, 806feddedabSIngo Weinhold // since in case of a debug exception we might overwrite them before 80713b81a3bSIngo Weinhold // x86_handle_debug_exception() is called. Debug exceptions occur when 80813b81a3bSIngo Weinhold // hitting a hardware break/watchpoint or when single-stepping. 809feddedabSIngo Weinhold asm("movl %%dr6, %0" : "=r"(thread->cpu->arch.dr6)); 810feddedabSIngo Weinhold asm("movl %%dr7, %0" : "=r"(thread->cpu->arch.dr7)); 811feddedabSIngo Weinhold 81213b81a3bSIngo Weinhold // The remainder needs only be done, when user breakpoints are installed. 81313b81a3bSIngo Weinhold if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED)) 81413b81a3bSIngo Weinhold return; 81513b81a3bSIngo Weinhold 816b4476702SIngo Weinhold // disable user breakpoints 817667f1eebSIngo Weinhold disable_breakpoints(); 8182d690920SAxel Dörfler 819b4476702SIngo Weinhold // install kernel breakpoints 8204535495dSIngo Weinhold Team* kernelTeam = team_get_kernel_team(); 821*24df6592SIngo Weinhold 822667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 823*24df6592SIngo Weinhold 824667f1eebSIngo Weinhold install_breakpoints(kernelTeam->debug_info.arch_info); 825667f1eebSIngo Weinhold 82634b3b26bSIngo Weinhold atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED); 82734b3b26bSIngo Weinhold 828*24df6592SIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 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 { 8384535495dSIngo Weinhold Thread* thread = thread_get_current_thread(); 83945538a5eSIngo Weinhold 84045538a5eSIngo Weinhold // Get dr6 and dr7. If the given iframe is a userland frame, the exception 84145538a5eSIngo Weinhold // obviously occurred in userland. In that case 84245538a5eSIngo Weinhold // x86_exit_user_debug_at_kernel_entry() has already been invoked and dr6 84345538a5eSIngo Weinhold // and dr7 are stored in the cpu info. Otherwise we need to fetch the 84445538a5eSIngo Weinhold // current values from the registers. 84545538a5eSIngo Weinhold uint32 dr6; 84645538a5eSIngo Weinhold uint32 dr7; 84745538a5eSIngo Weinhold if (IFRAME_IS_USER(frame)) { 84845538a5eSIngo Weinhold dr6 = thread->cpu->arch.dr6; 84945538a5eSIngo Weinhold dr7 = thread->cpu->arch.dr7; 85045538a5eSIngo Weinhold } else { 85145538a5eSIngo Weinhold asm("movl %%dr6, %0" : "=r"(dr6)); 85245538a5eSIngo Weinhold asm("movl %%dr7, %0" : "=r"(dr7)); 85345538a5eSIngo 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 91313b81a3bSIngo Weinhold // thread that hasn't 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. 927*24df6592SIngo Weinhold InterruptsSpinLocker threadDebugInfoLocker( 928*24df6592SIngo Weinhold thread->debug_info.lock); 9298b3d3d8aSIngo Weinhold 9308b3d3d8aSIngo Weinhold // Check whether the team is still being debugged and set 9318b3d3d8aSIngo Weinhold // the B_THREAD_DEBUG_NOTIFY_SINGLE_STEP and 9328b3d3d8aSIngo Weinhold // B_THREAD_DEBUG_STOP flags, so that the thread will be 9338b3d3d8aSIngo Weinhold // stopped when it is going to leave the kernel and notify the 9348b3d3d8aSIngo Weinhold // debugger about the single-step event. 9358b3d3d8aSIngo Weinhold int32 teamDebugFlags 9368b3d3d8aSIngo Weinhold = atomic_get(&thread->team->debug_info.flags); 9378b3d3d8aSIngo Weinhold if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) { 9388b3d3d8aSIngo Weinhold atomic_or(&thread->debug_info.flags, 9398b3d3d8aSIngo Weinhold B_THREAD_DEBUG_NOTIFY_SINGLE_STEP 9408b3d3d8aSIngo Weinhold | B_THREAD_DEBUG_STOP); 94113b81a3bSIngo Weinhold 94213b81a3bSIngo Weinhold // also set the respective thread flag 94313b81a3bSIngo Weinhold atomic_or(&thread->flags, THREAD_FLAGS_DEBUG_THREAD); 9448b3d3d8aSIngo Weinhold } 9458b3d3d8aSIngo Weinhold } 9468342d4cdSIngo Weinhold } 9472d690920SAxel Dörfler } else if (dr6 & (1 << X86_DR6_BT)) { 9482d690920SAxel Dörfler // task switch 9492d690920SAxel Dörfler // Occurs only, if T in EFLAGS is set (which we don't do). 9508753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 9512d690920SAxel Dörfler dprintf("i386_handle_debug_exception(): ignoring spurious task switch " 9522d690920SAxel Dörfler "exception\n"); 9532d690920SAxel Dörfler 9542d690920SAxel Dörfler enable_interrupts(); 9558753babdSIngo Weinhold } else 9568753babdSIngo Weinhold panic("spurious task switch exception in kernel mode"); 9572d690920SAxel Dörfler } else { 9588753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 95906be24a7SAxel Dörfler TRACE(("i386_handle_debug_exception(): ignoring spurious debug " 96006be24a7SAxel Dörfler "exception (no condition recognized)\n")); 9612d690920SAxel Dörfler 9622d690920SAxel Dörfler enable_interrupts(); 9638753babdSIngo Weinhold } else { 9648753babdSIngo Weinhold panic("spurious debug exception in kernel mode (no condition " 9658753babdSIngo Weinhold "recognized)"); 9668753babdSIngo Weinhold } 9672d690920SAxel Dörfler } 9682d690920SAxel Dörfler } 9692d690920SAxel Dörfler 9702d690920SAxel Dörfler 9712d690920SAxel Dörfler /** 972b4476702SIngo Weinhold * Interrupts are disabled and will possibly be enabled by the function. 9732d690920SAxel Dörfler */ 97434b3b26bSIngo Weinhold void 97534b3b26bSIngo Weinhold x86_handle_breakpoint_exception(struct iframe *frame) 9762d690920SAxel Dörfler { 9772d690920SAxel Dörfler TRACE(("i386_handle_breakpoint_exception()\n")); 9782d690920SAxel Dörfler 979b0f12d64SIngo Weinhold // reset eip to the int3 instruction 980b0f12d64SIngo Weinhold frame->eip--; 981b0f12d64SIngo Weinhold 982bb107c4eSAxel Dörfler if (!IFRAME_IS_USER(frame)) { 983667f1eebSIngo Weinhold panic("breakpoint exception in kernel mode"); 98434b3b26bSIngo Weinhold return; 985667f1eebSIngo Weinhold } 986667f1eebSIngo Weinhold 9872d690920SAxel Dörfler enable_interrupts(); 9882d690920SAxel Dörfler 9892d690920SAxel Dörfler user_debug_breakpoint_hit(true); 9902d690920SAxel Dörfler } 9912d690920SAxel Dörfler 9922d690920SAxel Dörfler 9932d690920SAxel Dörfler void 99434b3b26bSIngo Weinhold x86_init_user_debug() 9952d690920SAxel Dörfler { 9962d690920SAxel Dörfler // get debug settings 9972d690920SAxel Dörfler if (void *handle = load_driver_settings("kernel")) { 9982d690920SAxel Dörfler sQEmuSingleStepHack = get_driver_boolean_parameter(handle, 9992d690920SAxel Dörfler "qemu_single_step_hack", false, false);; 10002d690920SAxel Dörfler 10012d690920SAxel Dörfler unload_driver_settings(handle); 10022d690920SAxel Dörfler } 1003bc5f008aSIngo Weinhold 1004bc5f008aSIngo Weinhold #if KERNEL_BREAKPOINTS 1005bc5f008aSIngo Weinhold // install debugger commands 10068342d4cdSIngo Weinhold add_debugger_command_etc("breakpoints", &debugger_breakpoints, 10078342d4cdSIngo Weinhold "Lists current break-/watchpoints", 10088342d4cdSIngo Weinhold "\n" 10098342d4cdSIngo Weinhold "Lists the current kernel break-/watchpoints.\n", 0); 10108342d4cdSIngo Weinhold add_debugger_command_alias("watchpoints", "breakpoints", NULL); 10118342d4cdSIngo Weinhold add_debugger_command_etc("breakpoint", &debugger_breakpoint, 10128342d4cdSIngo Weinhold "Set/clears a breakpoint", 10138342d4cdSIngo Weinhold "<address> [ clear ]\n" 10148342d4cdSIngo Weinhold "Sets respectively clears the breakpoint at address <address>.\n", 0); 10158342d4cdSIngo Weinhold add_debugger_command_etc("watchpoint", &debugger_watchpoint, 10168342d4cdSIngo Weinhold "Set/clears a watchpoint", 10178342d4cdSIngo Weinhold "<address> <address> ( [ rw ] [ <size> ] | clear )\n" 10188342d4cdSIngo Weinhold "Sets respectively clears the watchpoint at address <address>.\n" 10198342d4cdSIngo Weinhold "If \"rw\" is given the new watchpoint is a read/write watchpoint\n" 10208342d4cdSIngo Weinhold "otherwise a write watchpoint only.\n", 0); 10218342d4cdSIngo Weinhold add_debugger_command_etc("step", &debugger_single_step, 10228342d4cdSIngo Weinhold "Single-steps to the next instruction", 10238342d4cdSIngo Weinhold "\n" 10248342d4cdSIngo Weinhold "Single-steps to the next instruction.\n", 0); 1025bc5f008aSIngo Weinhold #endif 10262d690920SAxel Dörfler } 10272d690920SAxel Dörfler 1028