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 6667f1eebSIngo Weinhold #include <arch/user_debugger.h> 7667f1eebSIngo Weinhold 82d690920SAxel Dörfler #include <string.h> 92d690920SAxel Dörfler 102d690920SAxel Dörfler #include <debugger.h> 112d690920SAxel Dörfler #include <driver_settings.h> 122d690920SAxel Dörfler #include <int.h> 13667f1eebSIngo Weinhold #include <team.h> 142d690920SAxel Dörfler #include <thread.h> 15667f1eebSIngo Weinhold 162d690920SAxel Dörfler 172d690920SAxel Dörfler //#define TRACE_ARCH_USER_DEBUGGER 182d690920SAxel Dörfler #ifdef TRACE_ARCH_USER_DEBUGGER 192d690920SAxel Dörfler # define TRACE(x) dprintf x 202d690920SAxel Dörfler #else 212d690920SAxel Dörfler # define TRACE(x) ; 222d690920SAxel Dörfler #endif 232d690920SAxel Dörfler 24667f1eebSIngo Weinhold #define B_NO_MORE_BREAKPOINTS B_BUSY 25667f1eebSIngo Weinhold #define B_NO_MORE_WATCHPOINTS B_BUSY 26667f1eebSIngo Weinhold #define B_BAD_WATCHPOINT_ALIGNMENT B_BAD_VALUE 27667f1eebSIngo Weinhold #define B_WATCHPOINT_TYPE_NOT_SUPPORTED B_NOT_SUPPORTED 28667f1eebSIngo Weinhold #define B_WATCHPOINT_LENGTH_NOT_SUPPORTED B_NOT_SUPPORTED 29667f1eebSIngo Weinhold #define B_BREAKPOINT_NOT_FOUND B_NAME_NOT_FOUND 30667f1eebSIngo Weinhold #define B_WATCHPOINT_NOT_FOUND B_NAME_NOT_FOUND 312d690920SAxel Dörfler // ToDo: Make those real error codes. 322d690920SAxel Dörfler 33*b0f12d64SIngo Weinhold // The software breakpoint instruction (int3). 34*b0f12d64SIngo Weinhold const uint8 kX86SoftwareBreakpoint[1] = { 0xcc }; 35*b0f12d64SIngo Weinhold 362d690920SAxel Dörfler // maps breakpoint slot index to LEN_i LSB number 372d690920SAxel Dörfler static const uint32 sDR7Len[4] = { 382d690920SAxel Dörfler X86_DR7_LEN0_LSB, X86_DR7_LEN1_LSB, X86_DR7_LEN2_LSB, X86_DR7_LEN3_LSB 392d690920SAxel Dörfler }; 402d690920SAxel Dörfler 412d690920SAxel Dörfler // maps breakpoint slot index to R/W_i LSB number 422d690920SAxel Dörfler static const uint32 sDR7RW[4] = { 432d690920SAxel Dörfler X86_DR7_RW0_LSB, X86_DR7_RW1_LSB, X86_DR7_RW2_LSB, X86_DR7_RW3_LSB 442d690920SAxel Dörfler }; 452d690920SAxel Dörfler 462d690920SAxel Dörfler // maps breakpoint slot index to L_i bit number 472d690920SAxel Dörfler static const uint32 sDR7L[4] = { 482d690920SAxel Dörfler X86_DR7_L0, X86_DR7_L1, X86_DR7_L2, X86_DR7_L3 492d690920SAxel Dörfler }; 502d690920SAxel Dörfler 51667f1eebSIngo Weinhold // maps breakpoint slot index to G_i bit number 52667f1eebSIngo Weinhold static const uint32 sDR7G[4] = { 53667f1eebSIngo Weinhold X86_DR7_G0, X86_DR7_G1, X86_DR7_G2, X86_DR7_G3 54667f1eebSIngo Weinhold }; 55667f1eebSIngo Weinhold 562d690920SAxel Dörfler // maps breakpoint slot index to B_i bit number 572d690920SAxel Dörfler static const uint32 sDR6B[4] = { 582d690920SAxel Dörfler X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3 592d690920SAxel Dörfler }; 602d690920SAxel Dörfler 612d690920SAxel Dörfler // Enables a hack to make single stepping work under qemu. Set via kernel 622d690920SAxel Dörfler // driver settings. 632d690920SAxel Dörfler static bool sQEmuSingleStepHack = false; 642d690920SAxel Dörfler 652d690920SAxel Dörfler 66568ade58SIngo Weinhold static void 67568ade58SIngo Weinhold get_iframe_registers(struct iframe *frame, struct debug_cpu_state *cpuState) 68568ade58SIngo Weinhold { 69568ade58SIngo Weinhold cpuState->gs = frame->gs; 70568ade58SIngo Weinhold cpuState->fs = frame->fs; 71568ade58SIngo Weinhold cpuState->es = frame->es; 72568ade58SIngo Weinhold cpuState->ds = frame->ds; 73568ade58SIngo Weinhold cpuState->edi = frame->edi; 74568ade58SIngo Weinhold cpuState->esi = frame->esi; 75568ade58SIngo Weinhold cpuState->ebp = frame->ebp; 76568ade58SIngo Weinhold cpuState->esp = frame->esp; 77568ade58SIngo Weinhold cpuState->ebx = frame->ebx; 78568ade58SIngo Weinhold cpuState->edx = frame->orig_edx; 79568ade58SIngo Weinhold cpuState->ecx = frame->ecx; 80568ade58SIngo Weinhold cpuState->eax = frame->orig_eax; 81568ade58SIngo Weinhold cpuState->vector = frame->vector; 82568ade58SIngo Weinhold cpuState->error_code = frame->error_code; 83568ade58SIngo Weinhold cpuState->eip = frame->eip; 84568ade58SIngo Weinhold cpuState->cs = frame->cs; 85568ade58SIngo Weinhold cpuState->eflags = frame->flags; 86568ade58SIngo Weinhold cpuState->user_esp = frame->user_esp; 87568ade58SIngo Weinhold cpuState->user_ss = frame->user_ss; 88568ade58SIngo Weinhold } 89568ade58SIngo Weinhold 90568ade58SIngo Weinhold 91667f1eebSIngo Weinhold static inline void 92667f1eebSIngo Weinhold install_breakpoints(const arch_team_debug_info &teamInfo) 93667f1eebSIngo Weinhold { 94667f1eebSIngo Weinhold // set breakpoints 95667f1eebSIngo Weinhold asm("movl %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address)); 96667f1eebSIngo Weinhold asm("movl %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address)); 97667f1eebSIngo Weinhold asm("movl %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address)); 98667f1eebSIngo Weinhold // asm("movl %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address)); 99667f1eebSIngo Weinhold // DR3 is used to hold the current struct thread*. 100667f1eebSIngo Weinhold 101667f1eebSIngo Weinhold // enable breakpoints 102667f1eebSIngo Weinhold asm("movl %0, %%dr7" : : "r"(teamInfo.dr7)); 103667f1eebSIngo Weinhold } 104667f1eebSIngo Weinhold 105667f1eebSIngo Weinhold 106667f1eebSIngo Weinhold static inline void 107667f1eebSIngo Weinhold disable_breakpoints() 108667f1eebSIngo Weinhold { 109667f1eebSIngo Weinhold asm("movl %0, %%dr7" : : "r"(X86_BREAKPOINTS_DISABLED_DR7)); 110667f1eebSIngo Weinhold } 111667f1eebSIngo Weinhold 112667f1eebSIngo Weinhold 113667f1eebSIngo Weinhold /*! Sets a break-/watchpoint in the given team info. 114667f1eebSIngo Weinhold Interrupts must be disabled and the team debug info lock be held. 115667f1eebSIngo Weinhold */ 116667f1eebSIngo Weinhold static inline status_t 117667f1eebSIngo Weinhold set_breakpoint(arch_team_debug_info &info, void *address, uint32 type, 118667f1eebSIngo Weinhold uint32 length, bool setGlobalFlag) 119667f1eebSIngo Weinhold { 120667f1eebSIngo Weinhold // check, if there is already a breakpoint at that address 121667f1eebSIngo Weinhold bool alreadySet = false; 122667f1eebSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 123667f1eebSIngo Weinhold if (info.breakpoints[i].address == address 124667f1eebSIngo Weinhold && info.breakpoints[i].type == type) { 125667f1eebSIngo Weinhold alreadySet = true; 126667f1eebSIngo Weinhold break; 127667f1eebSIngo Weinhold } 128667f1eebSIngo Weinhold } 129667f1eebSIngo Weinhold 130667f1eebSIngo Weinhold if (!alreadySet) { 131667f1eebSIngo Weinhold // find a free slot 132667f1eebSIngo Weinhold int32 slot = -1; 133667f1eebSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 134667f1eebSIngo Weinhold if (!info.breakpoints[i].address) { 135667f1eebSIngo Weinhold slot = i; 136667f1eebSIngo Weinhold break; 137667f1eebSIngo Weinhold } 138667f1eebSIngo Weinhold } 139667f1eebSIngo Weinhold 140667f1eebSIngo Weinhold // init the breakpoint 141667f1eebSIngo Weinhold if (slot >= 0) { 142667f1eebSIngo Weinhold info.breakpoints[slot].address = address; 143667f1eebSIngo Weinhold info.breakpoints[slot].type = type; 144667f1eebSIngo Weinhold info.breakpoints[slot].length = length; 145667f1eebSIngo Weinhold 146667f1eebSIngo Weinhold info.dr7 |= (length << sDR7Len[slot]) 147667f1eebSIngo Weinhold | (type << sDR7RW[slot]) 148667f1eebSIngo Weinhold | (1 << sDR7L[slot]); 149667f1eebSIngo Weinhold if (setGlobalFlag) 150667f1eebSIngo Weinhold info.dr7 |= (1 << sDR7G[slot]); 151667f1eebSIngo Weinhold } else { 152667f1eebSIngo Weinhold if (type == X86_INSTRUCTION_BREAKPOINT) 153667f1eebSIngo Weinhold return B_NO_MORE_BREAKPOINTS; 154667f1eebSIngo Weinhold else 155667f1eebSIngo Weinhold return B_NO_MORE_WATCHPOINTS; 156667f1eebSIngo Weinhold } 157667f1eebSIngo Weinhold } 158667f1eebSIngo Weinhold 159667f1eebSIngo Weinhold return B_OK; 160667f1eebSIngo Weinhold } 161667f1eebSIngo Weinhold 162667f1eebSIngo Weinhold 163667f1eebSIngo Weinhold /*! Clears a break-/watchpoint in the given team info. 164667f1eebSIngo Weinhold Interrupts must be disabled and the team debug info lock be held. 165667f1eebSIngo Weinhold */ 166667f1eebSIngo Weinhold static inline status_t 167667f1eebSIngo Weinhold clear_breakpoint(arch_team_debug_info &info, void *address, bool watchpoint) 168667f1eebSIngo Weinhold { 169667f1eebSIngo Weinhold // find the breakpoint 170667f1eebSIngo Weinhold int32 slot = -1; 171667f1eebSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 172667f1eebSIngo Weinhold if (info.breakpoints[i].address == address 173667f1eebSIngo Weinhold && (watchpoint 174667f1eebSIngo Weinhold != (info.breakpoints[i].type == X86_INSTRUCTION_BREAKPOINT))) { 175667f1eebSIngo Weinhold slot = i; 176667f1eebSIngo Weinhold break; 177667f1eebSIngo Weinhold } 178667f1eebSIngo Weinhold } 179667f1eebSIngo Weinhold 180667f1eebSIngo Weinhold // clear the breakpoint 181667f1eebSIngo Weinhold if (slot >= 0) { 182667f1eebSIngo Weinhold info.breakpoints[slot].address = NULL; 183667f1eebSIngo Weinhold 184667f1eebSIngo Weinhold info.dr7 &= ~((0x3 << sDR7Len[slot]) 185667f1eebSIngo Weinhold | (0x3 << sDR7RW[slot]) 186667f1eebSIngo Weinhold | (1 << sDR7L[slot]) 187667f1eebSIngo Weinhold | (1 << sDR7G[slot])); 188667f1eebSIngo Weinhold } else { 189667f1eebSIngo Weinhold if (watchpoint) 190667f1eebSIngo Weinhold return B_WATCHPOINT_NOT_FOUND; 191667f1eebSIngo Weinhold else 192667f1eebSIngo Weinhold return B_BREAKPOINT_NOT_FOUND; 193667f1eebSIngo Weinhold } 194667f1eebSIngo Weinhold 195667f1eebSIngo Weinhold return B_OK; 196667f1eebSIngo Weinhold } 197667f1eebSIngo Weinhold 198667f1eebSIngo Weinhold 199667f1eebSIngo Weinhold static status_t 200667f1eebSIngo Weinhold set_breakpoint(void *address, uint32 type, uint32 length) 201667f1eebSIngo Weinhold { 202667f1eebSIngo Weinhold if (!address) 203667f1eebSIngo Weinhold return B_BAD_VALUE; 204667f1eebSIngo Weinhold 205667f1eebSIngo Weinhold struct thread *thread = thread_get_current_thread(); 206667f1eebSIngo Weinhold 207667f1eebSIngo Weinhold cpu_status state = disable_interrupts(); 208667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 209667f1eebSIngo Weinhold 210667f1eebSIngo Weinhold status_t error = set_breakpoint(thread->team->debug_info.arch_info, address, 211667f1eebSIngo Weinhold type, length, false); 212667f1eebSIngo Weinhold 213667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 214667f1eebSIngo Weinhold restore_interrupts(state); 215667f1eebSIngo Weinhold 216667f1eebSIngo Weinhold return error; 217667f1eebSIngo Weinhold } 218667f1eebSIngo Weinhold 219667f1eebSIngo Weinhold 220667f1eebSIngo Weinhold static status_t 221667f1eebSIngo Weinhold clear_breakpoint(void *address, bool watchpoint) 222667f1eebSIngo Weinhold { 223667f1eebSIngo Weinhold if (!address) 224667f1eebSIngo Weinhold return B_BAD_VALUE; 225667f1eebSIngo Weinhold 226667f1eebSIngo Weinhold struct thread *thread = thread_get_current_thread(); 227667f1eebSIngo Weinhold 228667f1eebSIngo Weinhold cpu_status state = disable_interrupts(); 229667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 230667f1eebSIngo Weinhold 231667f1eebSIngo Weinhold status_t error = clear_breakpoint(thread->team->debug_info.arch_info, 232667f1eebSIngo Weinhold address, watchpoint); 233667f1eebSIngo Weinhold 234667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 235667f1eebSIngo Weinhold restore_interrupts(state); 236667f1eebSIngo Weinhold 237667f1eebSIngo Weinhold return error; 238667f1eebSIngo Weinhold } 239667f1eebSIngo Weinhold 240667f1eebSIngo Weinhold 241667f1eebSIngo Weinhold #if KERNEL_BREAKPOINTS 242667f1eebSIngo Weinhold 24331d9352fSIngo Weinhold 24431d9352fSIngo Weinhold static void 24531d9352fSIngo Weinhold install_breakpoints_per_cpu(void* /*cookie*/, int cpu) 24631d9352fSIngo Weinhold { 24731d9352fSIngo Weinhold struct team* kernelTeam = team_get_kernel_team(); 24831d9352fSIngo Weinhold 24931d9352fSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 25031d9352fSIngo Weinhold 25131d9352fSIngo Weinhold install_breakpoints(kernelTeam->debug_info.arch_info); 25231d9352fSIngo Weinhold 25331d9352fSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 25431d9352fSIngo Weinhold } 25531d9352fSIngo Weinhold 25631d9352fSIngo Weinhold 257667f1eebSIngo Weinhold static status_t 258667f1eebSIngo Weinhold set_kernel_breakpoint(void *address, uint32 type, uint32 length) 259667f1eebSIngo Weinhold { 260667f1eebSIngo Weinhold if (!address) 261667f1eebSIngo Weinhold return B_BAD_VALUE; 262667f1eebSIngo Weinhold 263667f1eebSIngo Weinhold struct team* kernelTeam = team_get_kernel_team(); 264667f1eebSIngo Weinhold 265667f1eebSIngo Weinhold cpu_status state = disable_interrupts(); 266667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 267667f1eebSIngo Weinhold 268667f1eebSIngo Weinhold status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address, 269667f1eebSIngo Weinhold type, length, true); 270667f1eebSIngo Weinhold 271667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 27231d9352fSIngo Weinhold 27331d9352fSIngo Weinhold call_all_cpus(install_breakpoints_per_cpu, NULL); 27431d9352fSIngo Weinhold 275667f1eebSIngo Weinhold restore_interrupts(state); 276667f1eebSIngo Weinhold 277667f1eebSIngo Weinhold return error; 278667f1eebSIngo Weinhold } 279667f1eebSIngo Weinhold 280667f1eebSIngo Weinhold 281667f1eebSIngo Weinhold static status_t 282667f1eebSIngo Weinhold clear_kernel_breakpoint(void *address, bool watchpoint) 283667f1eebSIngo Weinhold { 284667f1eebSIngo Weinhold if (!address) 285667f1eebSIngo Weinhold return B_BAD_VALUE; 286667f1eebSIngo Weinhold 287667f1eebSIngo Weinhold struct team* kernelTeam = team_get_kernel_team(); 288667f1eebSIngo Weinhold 289667f1eebSIngo Weinhold cpu_status state = disable_interrupts(); 290667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 291667f1eebSIngo Weinhold 292667f1eebSIngo Weinhold status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info, 293667f1eebSIngo Weinhold address, watchpoint); 294667f1eebSIngo Weinhold 295667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 29631d9352fSIngo Weinhold 29731d9352fSIngo Weinhold call_all_cpus(install_breakpoints_per_cpu, NULL); 29831d9352fSIngo Weinhold 299667f1eebSIngo Weinhold restore_interrupts(state); 300667f1eebSIngo Weinhold 301667f1eebSIngo Weinhold return error; 302667f1eebSIngo Weinhold } 303667f1eebSIngo Weinhold 304667f1eebSIngo Weinhold #endif // KERNEL_BREAKPOINTS 305667f1eebSIngo Weinhold 306667f1eebSIngo Weinhold 307667f1eebSIngo Weinhold static inline status_t 308667f1eebSIngo Weinhold check_watch_point_parameters(void* address, uint32 type, int32 length, 309667f1eebSIngo Weinhold uint32& archType, uint32& archLength) 310667f1eebSIngo Weinhold { 311667f1eebSIngo Weinhold // check type 312667f1eebSIngo Weinhold switch (type) { 313667f1eebSIngo Weinhold case B_DATA_WRITE_WATCHPOINT: 314667f1eebSIngo Weinhold archType = X86_DATA_WRITE_BREAKPOINT; 315667f1eebSIngo Weinhold break; 316667f1eebSIngo Weinhold case B_DATA_READ_WRITE_WATCHPOINT: 317667f1eebSIngo Weinhold archType = X86_DATA_READ_WRITE_BREAKPOINT; 318667f1eebSIngo Weinhold break; 319667f1eebSIngo Weinhold case B_DATA_READ_WATCHPOINT: 320667f1eebSIngo Weinhold default: 321667f1eebSIngo Weinhold return B_WATCHPOINT_TYPE_NOT_SUPPORTED; 322667f1eebSIngo Weinhold break; 323667f1eebSIngo Weinhold } 324667f1eebSIngo Weinhold 325667f1eebSIngo Weinhold // check length and alignment 326667f1eebSIngo Weinhold switch (length) { 327667f1eebSIngo Weinhold case 1: 328667f1eebSIngo Weinhold archLength = X86_BREAKPOINT_LENGTH_1; 329667f1eebSIngo Weinhold break; 330667f1eebSIngo Weinhold case 2: 331667f1eebSIngo Weinhold if ((uint32)address & 0x1) 332667f1eebSIngo Weinhold return B_BAD_WATCHPOINT_ALIGNMENT; 333667f1eebSIngo Weinhold archLength = X86_BREAKPOINT_LENGTH_2; 334667f1eebSIngo Weinhold break; 335667f1eebSIngo Weinhold case 4: 336667f1eebSIngo Weinhold if ((uint32)address & 0x3) 337667f1eebSIngo Weinhold return B_BAD_WATCHPOINT_ALIGNMENT; 338667f1eebSIngo Weinhold archLength = X86_BREAKPOINT_LENGTH_4; 339667f1eebSIngo Weinhold break; 340667f1eebSIngo Weinhold default: 341667f1eebSIngo Weinhold return B_WATCHPOINT_LENGTH_NOT_SUPPORTED; 342667f1eebSIngo Weinhold } 343667f1eebSIngo Weinhold 344667f1eebSIngo Weinhold return B_OK; 345667f1eebSIngo Weinhold } 346667f1eebSIngo Weinhold 347667f1eebSIngo Weinhold 348bc5f008aSIngo Weinhold // #pragma mark - kernel debugger commands 349bc5f008aSIngo Weinhold 350bc5f008aSIngo Weinhold #if KERNEL_BREAKPOINTS 351bc5f008aSIngo Weinhold 352bc5f008aSIngo Weinhold static int 353bc5f008aSIngo Weinhold debugger_breakpoints(int argc, char** argv) 354bc5f008aSIngo Weinhold { 355bc5f008aSIngo Weinhold struct team* kernelTeam = team_get_kernel_team(); 356bc5f008aSIngo Weinhold arch_team_debug_info& info = kernelTeam->debug_info.arch_info; 357bc5f008aSIngo Weinhold 358bc5f008aSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 359bc5f008aSIngo Weinhold kprintf("breakpoint[%ld] ", i); 360bc5f008aSIngo Weinhold 361bc5f008aSIngo Weinhold if (info.breakpoints[i].address != NULL) { 362bc5f008aSIngo Weinhold kprintf("%p ", info.breakpoints[i].address); 363bc5f008aSIngo Weinhold switch (info.breakpoints[i].type) { 364bc5f008aSIngo Weinhold case X86_INSTRUCTION_BREAKPOINT: 365bc5f008aSIngo Weinhold kprintf("instruction"); 366bc5f008aSIngo Weinhold break; 367bc5f008aSIngo Weinhold case X86_IO_READ_WRITE_BREAKPOINT: 368bc5f008aSIngo Weinhold kprintf("io read/write"); 369bc5f008aSIngo Weinhold break; 370bc5f008aSIngo Weinhold case X86_DATA_WRITE_BREAKPOINT: 371bc5f008aSIngo Weinhold kprintf("data write"); 372bc5f008aSIngo Weinhold break; 373bc5f008aSIngo Weinhold case X86_DATA_READ_WRITE_BREAKPOINT: 374bc5f008aSIngo Weinhold kprintf("data read/write"); 375bc5f008aSIngo Weinhold break; 376bc5f008aSIngo Weinhold } 377bc5f008aSIngo Weinhold 378bc5f008aSIngo Weinhold int length = 1; 379bc5f008aSIngo Weinhold switch (info.breakpoints[i].length) { 380bc5f008aSIngo Weinhold case X86_BREAKPOINT_LENGTH_1: 381bc5f008aSIngo Weinhold length = 1; 382bc5f008aSIngo Weinhold break; 383bc5f008aSIngo Weinhold case X86_BREAKPOINT_LENGTH_2: 384bc5f008aSIngo Weinhold length = 2; 385bc5f008aSIngo Weinhold break; 386bc5f008aSIngo Weinhold case X86_BREAKPOINT_LENGTH_4: 387bc5f008aSIngo Weinhold length = 4; 388bc5f008aSIngo Weinhold break; 389bc5f008aSIngo Weinhold } 390bc5f008aSIngo Weinhold 391bc5f008aSIngo Weinhold if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT) 392bc5f008aSIngo Weinhold kprintf(" %d byte%s", length, (length > 1 ? "s" : "")); 393bc5f008aSIngo Weinhold } else 394bc5f008aSIngo Weinhold kprintf("unused"); 395bc5f008aSIngo Weinhold 396bc5f008aSIngo Weinhold kprintf("\n"); 397bc5f008aSIngo Weinhold } 398bc5f008aSIngo Weinhold 399bc5f008aSIngo Weinhold return 0; 400bc5f008aSIngo Weinhold } 401bc5f008aSIngo Weinhold 402bc5f008aSIngo Weinhold 403bc5f008aSIngo Weinhold static int 404bc5f008aSIngo Weinhold debugger_breakpoint(int argc, char** argv) 405bc5f008aSIngo Weinhold { 406bc5f008aSIngo Weinhold // get arguments 407bc5f008aSIngo Weinhold 408bc5f008aSIngo Weinhold if (argc < 2 || argc > 3) 4098342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 410bc5f008aSIngo Weinhold 411bc5f008aSIngo Weinhold addr_t address = strtoul(argv[1], NULL, 0); 412bc5f008aSIngo Weinhold if (address == 0) 4138342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 414bc5f008aSIngo Weinhold 415bc5f008aSIngo Weinhold bool clear = false; 416bc5f008aSIngo Weinhold if (argc == 3) { 417bc5f008aSIngo Weinhold if (strcmp(argv[2], "clear") == 0) 418bc5f008aSIngo Weinhold clear = true; 419bc5f008aSIngo Weinhold else 4208342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 421bc5f008aSIngo Weinhold } 422bc5f008aSIngo Weinhold 423bc5f008aSIngo Weinhold // set/clear breakpoint 424bc5f008aSIngo Weinhold 425bc5f008aSIngo Weinhold arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; 426bc5f008aSIngo Weinhold 427bc5f008aSIngo Weinhold status_t error; 428bc5f008aSIngo Weinhold 429bc5f008aSIngo Weinhold if (clear) { 430bc5f008aSIngo Weinhold error = clear_breakpoint(info, (void*)address, false); 431bc5f008aSIngo Weinhold } else { 432bc5f008aSIngo Weinhold error = set_breakpoint(info, (void*)address, X86_INSTRUCTION_BREAKPOINT, 433bc5f008aSIngo Weinhold X86_BREAKPOINT_LENGTH_1, true); 434bc5f008aSIngo Weinhold } 435bc5f008aSIngo Weinhold 436bc5f008aSIngo Weinhold if (error == B_OK) 43731d9352fSIngo Weinhold call_all_cpus_sync(install_breakpoints_per_cpu, NULL); 438bc5f008aSIngo Weinhold else 439bc5f008aSIngo Weinhold kprintf("Failed to install breakpoint: %s\n", strerror(error)); 440bc5f008aSIngo Weinhold 441bc5f008aSIngo Weinhold return 0; 442bc5f008aSIngo Weinhold } 443bc5f008aSIngo Weinhold 444bc5f008aSIngo Weinhold 445bc5f008aSIngo Weinhold static int 446bc5f008aSIngo Weinhold debugger_watchpoint(int argc, char** argv) 447bc5f008aSIngo Weinhold { 448bc5f008aSIngo Weinhold // get arguments 449bc5f008aSIngo Weinhold 450bc5f008aSIngo Weinhold if (argc < 2 || argc > 4) 4518342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 452bc5f008aSIngo Weinhold 453bc5f008aSIngo Weinhold addr_t address = strtoul(argv[1], NULL, 0); 454bc5f008aSIngo Weinhold if (address == 0) 4558342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 456bc5f008aSIngo Weinhold 457bc5f008aSIngo Weinhold bool clear = false; 458bc5f008aSIngo Weinhold bool readWrite = false; 459bc5f008aSIngo Weinhold int argi = 2; 460bc5f008aSIngo Weinhold int length = 1; 461bc5f008aSIngo Weinhold if (argc >= 3) { 462bc5f008aSIngo Weinhold if (strcmp(argv[argi], "clear") == 0) { 463bc5f008aSIngo Weinhold clear = true; 464bc5f008aSIngo Weinhold argi++; 465bc5f008aSIngo Weinhold } else if (strcmp(argv[argi], "rw") == 0) { 466bc5f008aSIngo Weinhold readWrite = true; 467bc5f008aSIngo Weinhold argi++; 468bc5f008aSIngo Weinhold } 469bc5f008aSIngo Weinhold 470bc5f008aSIngo Weinhold if (!clear && argi < argc) 471bc5f008aSIngo Weinhold length = strtoul(argv[argi++], NULL, 0); 472bc5f008aSIngo Weinhold 473bc5f008aSIngo Weinhold if (length == 0 || argi < argc) 4748342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]); 475bc5f008aSIngo Weinhold } 476bc5f008aSIngo Weinhold 477bc5f008aSIngo Weinhold // set/clear breakpoint 478bc5f008aSIngo Weinhold 479bc5f008aSIngo Weinhold arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info; 480bc5f008aSIngo Weinhold 481bc5f008aSIngo Weinhold status_t error; 482bc5f008aSIngo Weinhold 483bc5f008aSIngo Weinhold if (clear) { 484bc5f008aSIngo Weinhold error = clear_breakpoint(info, (void*)address, true); 485bc5f008aSIngo Weinhold } else { 486bc5f008aSIngo Weinhold uint32 type = readWrite ? B_DATA_READ_WRITE_WATCHPOINT 487bc5f008aSIngo Weinhold : B_DATA_WRITE_WATCHPOINT; 488bc5f008aSIngo Weinhold 489bc5f008aSIngo Weinhold uint32 archType, archLength; 490bc5f008aSIngo Weinhold error = check_watch_point_parameters((void*)address, type, length, 491bc5f008aSIngo Weinhold archType, archLength); 492bc5f008aSIngo Weinhold 493bc5f008aSIngo Weinhold if (error == B_OK) { 494bc5f008aSIngo Weinhold error = set_breakpoint(info, (void*)address, archType, archLength, 495bc5f008aSIngo Weinhold true); 496bc5f008aSIngo Weinhold } 497bc5f008aSIngo Weinhold } 498bc5f008aSIngo Weinhold 499bc5f008aSIngo Weinhold if (error == B_OK) 50031d9352fSIngo Weinhold call_all_cpus_sync(install_breakpoints_per_cpu, NULL); 501bc5f008aSIngo Weinhold else 502bc5f008aSIngo Weinhold kprintf("Failed to install breakpoint: %s\n", strerror(error)); 503bc5f008aSIngo Weinhold 504bc5f008aSIngo Weinhold return 0; 505bc5f008aSIngo Weinhold } 506bc5f008aSIngo Weinhold 5078342d4cdSIngo Weinhold 5088342d4cdSIngo Weinhold static int 5098342d4cdSIngo Weinhold debugger_single_step(int argc, char** argv) 5108342d4cdSIngo Weinhold { 5118342d4cdSIngo Weinhold // TODO: Since we need an iframe, this doesn't work when KDL wasn't entered 5128342d4cdSIngo Weinhold // via an exception. 5138342d4cdSIngo Weinhold 5148342d4cdSIngo Weinhold struct iframe* frame = i386_get_current_iframe(); 5158342d4cdSIngo Weinhold if (frame == NULL) { 5168342d4cdSIngo Weinhold kprintf("Failed to get the current iframe!\n"); 5178342d4cdSIngo Weinhold return 0; 5188342d4cdSIngo Weinhold } 5198342d4cdSIngo Weinhold 5208342d4cdSIngo Weinhold frame->flags |= (1 << X86_EFLAGS_TF); 5218342d4cdSIngo Weinhold 5228342d4cdSIngo Weinhold return B_KDEBUG_QUIT; 5238342d4cdSIngo Weinhold } 5248342d4cdSIngo Weinhold 5258342d4cdSIngo Weinhold 526bc5f008aSIngo Weinhold #endif // KERNEL_BREAKPOINTS 527bc5f008aSIngo Weinhold 528bc5f008aSIngo Weinhold 529667f1eebSIngo Weinhold // #pragma mark - in-kernel public interface 530667f1eebSIngo Weinhold 531667f1eebSIngo Weinhold 5322d690920SAxel Dörfler void 5332d690920SAxel Dörfler arch_clear_team_debug_info(struct arch_team_debug_info *info) 5342d690920SAxel Dörfler { 5352d690920SAxel Dörfler for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) 5362d690920SAxel Dörfler info->breakpoints[i].address = NULL; 5372d690920SAxel Dörfler 5382d690920SAxel Dörfler info->dr7 = X86_BREAKPOINTS_DISABLED_DR7; 5392d690920SAxel Dörfler } 5402d690920SAxel Dörfler 5412d690920SAxel Dörfler 5422d690920SAxel Dörfler void 5432d690920SAxel Dörfler arch_destroy_team_debug_info(struct arch_team_debug_info *info) 5442d690920SAxel Dörfler { 5452d690920SAxel Dörfler arch_clear_team_debug_info(info); 5462d690920SAxel Dörfler } 5472d690920SAxel Dörfler 5482d690920SAxel Dörfler 5492d690920SAxel Dörfler void 5502d690920SAxel Dörfler arch_clear_thread_debug_info(struct arch_thread_debug_info *info) 5512d690920SAxel Dörfler { 5522d690920SAxel Dörfler info->flags = 0; 5532d690920SAxel Dörfler } 5542d690920SAxel Dörfler 5552d690920SAxel Dörfler 5562d690920SAxel Dörfler void 5572d690920SAxel Dörfler arch_destroy_thread_debug_info(struct arch_thread_debug_info *info) 5582d690920SAxel Dörfler { 5592d690920SAxel Dörfler arch_clear_thread_debug_info(info); 5602d690920SAxel Dörfler } 5612d690920SAxel Dörfler 5622d690920SAxel Dörfler 5632d690920SAxel Dörfler void 56434b3b26bSIngo Weinhold arch_update_thread_single_step() 56534b3b26bSIngo Weinhold { 56634b3b26bSIngo Weinhold if (struct iframe* frame = i386_get_user_iframe()) { 56734b3b26bSIngo Weinhold struct thread* thread = thread_get_current_thread(); 56834b3b26bSIngo Weinhold 56934b3b26bSIngo Weinhold // set/clear TF in EFLAGS depending on if single stepping is desired 57034b3b26bSIngo Weinhold if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP) 57134b3b26bSIngo Weinhold frame->flags |= (1 << X86_EFLAGS_TF); 57234b3b26bSIngo Weinhold else 57334b3b26bSIngo Weinhold frame->flags &= ~(1 << X86_EFLAGS_TF); 57434b3b26bSIngo Weinhold } 57534b3b26bSIngo Weinhold } 57634b3b26bSIngo Weinhold 57734b3b26bSIngo Weinhold 57834b3b26bSIngo Weinhold void 5792d690920SAxel Dörfler arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState) 5802d690920SAxel Dörfler { 5812d690920SAxel Dörfler if (struct iframe *frame = i386_get_user_iframe()) { 5822d690920SAxel Dörfler i386_frstor(cpuState->extended_regs); 5832d690920SAxel Dörfler // For this to be correct the calling function must not use these 5842d690920SAxel Dörfler // registers (not even indirectly). 5852d690920SAxel Dörfler 5862d690920SAxel Dörfler // frame->gs = cpuState->gs; 5872d690920SAxel Dörfler // frame->fs = cpuState->fs; 5882d690920SAxel Dörfler // frame->es = cpuState->es; 5892d690920SAxel Dörfler // frame->ds = cpuState->ds; 5902d690920SAxel Dörfler frame->edi = cpuState->edi; 5912d690920SAxel Dörfler frame->esi = cpuState->esi; 5922d690920SAxel Dörfler frame->ebp = cpuState->ebp; 593568ade58SIngo Weinhold // frame->esp = cpuState->esp; 5942d690920SAxel Dörfler frame->ebx = cpuState->ebx; 5952d690920SAxel Dörfler frame->edx = cpuState->edx; 5962d690920SAxel Dörfler frame->ecx = cpuState->ecx; 5972d690920SAxel Dörfler frame->eax = cpuState->eax; 5982d690920SAxel Dörfler // frame->vector = cpuState->vector; 5992d690920SAxel Dörfler // frame->error_code = cpuState->error_code; 6002d690920SAxel Dörfler frame->eip = cpuState->eip; 6012d690920SAxel Dörfler // frame->cs = cpuState->cs; 6022d690920SAxel Dörfler frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS) 6032d690920SAxel Dörfler | (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS); 6042d690920SAxel Dörfler frame->user_esp = cpuState->user_esp; 6052d690920SAxel Dörfler // frame->user_ss = cpuState->user_ss; 6062d690920SAxel Dörfler } 6072d690920SAxel Dörfler } 6082d690920SAxel Dörfler 609667f1eebSIngo Weinhold 6102d690920SAxel Dörfler void 6112d690920SAxel Dörfler arch_get_debug_cpu_state(struct debug_cpu_state *cpuState) 6122d690920SAxel Dörfler { 6132d690920SAxel Dörfler if (struct iframe *frame = i386_get_user_iframe()) { 6147eee76e6SMichael Lotz i386_fnsave(cpuState->extended_regs); 6152d690920SAxel Dörfler // For this to be correct the calling function must not use these 6162d690920SAxel Dörfler // registers (not even indirectly). 617568ade58SIngo Weinhold get_iframe_registers(frame, cpuState); 6182d690920SAxel Dörfler } 6192d690920SAxel Dörfler } 6202d690920SAxel Dörfler 6212d690920SAxel Dörfler 622568ade58SIngo Weinhold /*! \brief Returns the CPU state for the given thread. 623568ade58SIngo Weinhold The thread must not be running and the threads spinlock must be held. 624568ade58SIngo Weinhold */ 625568ade58SIngo Weinhold status_t 626568ade58SIngo Weinhold arch_get_thread_debug_cpu_state(struct thread *thread, 627568ade58SIngo Weinhold struct debug_cpu_state *cpuState) 628568ade58SIngo Weinhold { 629568ade58SIngo Weinhold struct iframe *frame = i386_get_thread_user_iframe(thread); 630568ade58SIngo Weinhold if (frame == NULL) 631568ade58SIngo Weinhold return B_BAD_VALUE; 632568ade58SIngo Weinhold 633568ade58SIngo Weinhold get_iframe_registers(frame, cpuState); 634568ade58SIngo Weinhold memcpy(cpuState->extended_regs, thread->arch_info.fpu_state, 635568ade58SIngo Weinhold sizeof(cpuState->extended_regs)); 636568ade58SIngo Weinhold 637568ade58SIngo Weinhold return B_OK; 638568ade58SIngo Weinhold } 639568ade58SIngo Weinhold 640568ade58SIngo Weinhold 6412d690920SAxel Dörfler status_t 6422d690920SAxel Dörfler arch_set_breakpoint(void *address) 6432d690920SAxel Dörfler { 6442d690920SAxel Dörfler return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 6452d690920SAxel Dörfler X86_BREAKPOINT_LENGTH_1); 6462d690920SAxel Dörfler } 6472d690920SAxel Dörfler 6482d690920SAxel Dörfler 6492d690920SAxel Dörfler status_t 6502d690920SAxel Dörfler arch_clear_breakpoint(void *address) 6512d690920SAxel Dörfler { 6522d690920SAxel Dörfler return clear_breakpoint(address, false); 6532d690920SAxel Dörfler } 6542d690920SAxel Dörfler 6552d690920SAxel Dörfler 6562d690920SAxel Dörfler status_t 6572d690920SAxel Dörfler arch_set_watchpoint(void *address, uint32 type, int32 length) 6582d690920SAxel Dörfler { 659667f1eebSIngo Weinhold uint32 archType, archLength; 660667f1eebSIngo Weinhold status_t error = check_watch_point_parameters(address, type, length, 661667f1eebSIngo Weinhold archType, archLength); 662667f1eebSIngo Weinhold if (error != B_OK) 663667f1eebSIngo Weinhold return error; 6642d690920SAxel Dörfler 6652d690920SAxel Dörfler return set_breakpoint(address, archType, archLength); 6662d690920SAxel Dörfler } 6672d690920SAxel Dörfler 6682d690920SAxel Dörfler 6692d690920SAxel Dörfler status_t 6702d690920SAxel Dörfler arch_clear_watchpoint(void *address) 6712d690920SAxel Dörfler { 6722d690920SAxel Dörfler return clear_breakpoint(address, false); 6732d690920SAxel Dörfler } 6742d690920SAxel Dörfler 6752d690920SAxel Dörfler 67634b3b26bSIngo Weinhold bool 67734b3b26bSIngo Weinhold arch_has_breakpoints(struct arch_team_debug_info *info) 67834b3b26bSIngo Weinhold { 67934b3b26bSIngo Weinhold // Reading info->dr7 is atomically, so we don't need to lock. The caller 68034b3b26bSIngo Weinhold // has to ensure, that the info doesn't go away. 68134b3b26bSIngo Weinhold return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7); 68234b3b26bSIngo Weinhold } 68334b3b26bSIngo Weinhold 68434b3b26bSIngo Weinhold 685667f1eebSIngo Weinhold #if KERNEL_BREAKPOINTS 6862d690920SAxel Dörfler 687667f1eebSIngo Weinhold status_t 688667f1eebSIngo Weinhold arch_set_kernel_breakpoint(void *address) 689667f1eebSIngo Weinhold { 690667f1eebSIngo Weinhold status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 691667f1eebSIngo Weinhold X86_BREAKPOINT_LENGTH_1); 692667f1eebSIngo Weinhold 693667f1eebSIngo Weinhold if (error != B_OK) { 694667f1eebSIngo Weinhold panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s", 695667f1eebSIngo Weinhold strerror(error)); 6962d690920SAxel Dörfler } 6972d690920SAxel Dörfler 698667f1eebSIngo Weinhold return error; 699667f1eebSIngo Weinhold } 700667f1eebSIngo Weinhold 701667f1eebSIngo Weinhold 702667f1eebSIngo Weinhold status_t 703667f1eebSIngo Weinhold arch_clear_kernel_breakpoint(void *address) 704667f1eebSIngo Weinhold { 705667f1eebSIngo Weinhold status_t error = clear_kernel_breakpoint(address, false); 706667f1eebSIngo Weinhold 707667f1eebSIngo Weinhold if (error != B_OK) { 708667f1eebSIngo Weinhold panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s", 709667f1eebSIngo Weinhold strerror(error)); 710667f1eebSIngo Weinhold } 711667f1eebSIngo Weinhold 712667f1eebSIngo Weinhold return error; 713667f1eebSIngo Weinhold } 714667f1eebSIngo Weinhold 715667f1eebSIngo Weinhold 716667f1eebSIngo Weinhold status_t 717667f1eebSIngo Weinhold arch_set_kernel_watchpoint(void *address, uint32 type, int32 length) 718667f1eebSIngo Weinhold { 719667f1eebSIngo Weinhold uint32 archType, archLength; 720667f1eebSIngo Weinhold status_t error = check_watch_point_parameters(address, type, length, 721667f1eebSIngo Weinhold archType, archLength); 722667f1eebSIngo Weinhold 723667f1eebSIngo Weinhold if (error == B_OK) 724667f1eebSIngo Weinhold error = set_kernel_breakpoint(address, archType, archLength); 725667f1eebSIngo Weinhold 726667f1eebSIngo Weinhold if (error != B_OK) { 727667f1eebSIngo Weinhold panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s", 728667f1eebSIngo Weinhold strerror(error)); 729667f1eebSIngo Weinhold } 730667f1eebSIngo Weinhold 731667f1eebSIngo Weinhold return error; 732667f1eebSIngo Weinhold } 733667f1eebSIngo Weinhold 734667f1eebSIngo Weinhold 735667f1eebSIngo Weinhold status_t 736667f1eebSIngo Weinhold arch_clear_kernel_watchpoint(void *address) 737667f1eebSIngo Weinhold { 738667f1eebSIngo Weinhold status_t error = clear_kernel_breakpoint(address, true); 739667f1eebSIngo Weinhold 740667f1eebSIngo Weinhold if (error != B_OK) { 741667f1eebSIngo Weinhold panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s", 742667f1eebSIngo Weinhold strerror(error)); 743667f1eebSIngo Weinhold } 744667f1eebSIngo Weinhold 745667f1eebSIngo Weinhold return error; 746667f1eebSIngo Weinhold } 747667f1eebSIngo Weinhold 748667f1eebSIngo Weinhold #endif // KERNEL_BREAKPOINTS 749667f1eebSIngo Weinhold 750667f1eebSIngo Weinhold 751667f1eebSIngo Weinhold // #pragma mark - x86 implementation interface 752667f1eebSIngo Weinhold 7532d690920SAxel Dörfler 7542d690920SAxel Dörfler /** 75534b3b26bSIngo Weinhold * Interrupts are disabled. 7562d690920SAxel Dörfler */ 7572d690920SAxel Dörfler void 75834b3b26bSIngo Weinhold x86_init_user_debug_at_kernel_exit(struct iframe *frame) 7592d690920SAxel Dörfler { 7602d690920SAxel Dörfler struct thread *thread = thread_get_current_thread(); 7612d690920SAxel Dörfler 76234b3b26bSIngo Weinhold if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED)) 76334b3b26bSIngo Weinhold return; 764b4476702SIngo Weinhold 765b4476702SIngo Weinhold // disable kernel breakpoints 766b4476702SIngo Weinhold disable_breakpoints(); 76734b3b26bSIngo Weinhold 7682d690920SAxel Dörfler GRAB_THREAD_LOCK(); 7692d690920SAxel Dörfler GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 7702d690920SAxel Dörfler 7712d690920SAxel Dörfler arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info; 7722d690920SAxel Dörfler 773b4476702SIngo Weinhold // install the user breakpoints 7742d690920SAxel Dörfler install_breakpoints(teamInfo); 7752d690920SAxel Dörfler 77634b3b26bSIngo Weinhold atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED); 7772d690920SAxel Dörfler 7782d690920SAxel Dörfler RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 7792d690920SAxel Dörfler RELEASE_THREAD_LOCK(); 7802d690920SAxel Dörfler } 7812d690920SAxel Dörfler 7822d690920SAxel Dörfler 7832d690920SAxel Dörfler /** 78434b3b26bSIngo Weinhold * Interrupts are disabled. 7852d690920SAxel Dörfler */ 7862d690920SAxel Dörfler void 78734b3b26bSIngo Weinhold x86_exit_user_debug_at_kernel_entry() 7882d690920SAxel Dörfler { 7892d690920SAxel Dörfler struct thread *thread = thread_get_current_thread(); 7902d690920SAxel Dörfler 79134b3b26bSIngo Weinhold if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED)) 79234b3b26bSIngo Weinhold return; 79334b3b26bSIngo Weinhold 7942d690920SAxel Dörfler GRAB_THREAD_LOCK(); 7952d690920SAxel Dörfler 796b4476702SIngo Weinhold // disable user breakpoints 797667f1eebSIngo Weinhold disable_breakpoints(); 7982d690920SAxel Dörfler 799b4476702SIngo Weinhold // install kernel breakpoints 800667f1eebSIngo Weinhold struct team* kernelTeam = team_get_kernel_team(); 801667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 802667f1eebSIngo Weinhold install_breakpoints(kernelTeam->debug_info.arch_info); 803667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); 804667f1eebSIngo Weinhold 80534b3b26bSIngo Weinhold atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED); 80634b3b26bSIngo Weinhold 8072d690920SAxel Dörfler RELEASE_THREAD_LOCK(); 8082d690920SAxel Dörfler } 8092d690920SAxel Dörfler 8102d690920SAxel Dörfler 8112d690920SAxel Dörfler /** 812b4476702SIngo Weinhold * Interrupts are disabled and will possibly be enabled by the function. 8132d690920SAxel Dörfler */ 81434b3b26bSIngo Weinhold void 81534b3b26bSIngo Weinhold x86_handle_debug_exception(struct iframe *frame) 8162d690920SAxel Dörfler { 8172d690920SAxel Dörfler // get debug status and control registers 8182d690920SAxel Dörfler uint32 dr6, dr7; 8192d690920SAxel Dörfler asm("movl %%dr6, %0" : "=r"(dr6)); 8202d690920SAxel Dörfler asm("movl %%dr7, %0" : "=r"(dr7)); 8212d690920SAxel Dörfler 8222d690920SAxel Dörfler TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7)); 8232d690920SAxel Dörfler 8242d690920SAxel Dörfler // check, which exception condition applies 8252d690920SAxel Dörfler if (dr6 & X86_DR6_BREAKPOINT_MASK) { 8262d690920SAxel Dörfler // breakpoint 8272d690920SAxel Dörfler 8282d690920SAxel Dörfler // check which breakpoint was taken 8292d690920SAxel Dörfler bool watchpoint = true; 8302d690920SAxel Dörfler for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 8312d690920SAxel Dörfler if (dr6 & (1 << sDR6B[i])) { 8322d690920SAxel Dörfler uint32 type = (dr7 >> sDR7RW[i]) & 0x3; 833568ade58SIngo Weinhold if (type == X86_INSTRUCTION_BREAKPOINT) 8342d690920SAxel Dörfler watchpoint = false; 8352d690920SAxel Dörfler } 8362d690920SAxel Dörfler } 8372d690920SAxel Dörfler 8388753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 8392d690920SAxel Dörfler // enable interrupts and notify the debugger 8402d690920SAxel Dörfler enable_interrupts(); 8412d690920SAxel Dörfler 8422d690920SAxel Dörfler if (watchpoint) 8432d690920SAxel Dörfler user_debug_watchpoint_hit(); 8442d690920SAxel Dörfler else 8452d690920SAxel Dörfler user_debug_breakpoint_hit(false); 8468753babdSIngo Weinhold } else { 8478753babdSIngo Weinhold panic("hit kernel %spoint: dr6: 0x%lx, dr7: 0x%lx", 8488753babdSIngo Weinhold watchpoint ? "watch" : "break", dr6, dr7); 8498753babdSIngo Weinhold } 8502d690920SAxel Dörfler } else if (dr6 & (1 << X86_DR6_BD)) { 8512d690920SAxel Dörfler // general detect exception 8522d690920SAxel Dörfler // Occurs only, if GD in DR7 is set (which we don't do) and someone 8532d690920SAxel Dörfler // tries to write to the debug registers. 8548753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 8552d690920SAxel Dörfler dprintf("i386_handle_debug_exception(): ignoring spurious general " 8562d690920SAxel Dörfler "detect exception\n"); 8572d690920SAxel Dörfler 8582d690920SAxel Dörfler enable_interrupts(); 8598753babdSIngo Weinhold } else 8608753babdSIngo Weinhold panic("spurious general detect exception in kernel mode"); 8612d690920SAxel Dörfler } else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) { 8622d690920SAxel Dörfler // single step 8632d690920SAxel Dörfler 8648753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 8652d690920SAxel Dörfler // enable interrupts and notify the debugger 8662d690920SAxel Dörfler enable_interrupts(); 8672d690920SAxel Dörfler 8682d690920SAxel Dörfler user_debug_single_stepped(); 8698342d4cdSIngo Weinhold } else { 8708342d4cdSIngo Weinhold // Disable single-stepping -- the next "step" command will re-enable 8718342d4cdSIngo Weinhold // it, but we don't want it when continuing otherwise. 8728342d4cdSIngo Weinhold frame->flags &= ~(1 << X86_EFLAGS_TF); 8738342d4cdSIngo Weinhold 8748753babdSIngo Weinhold panic("kernel single step"); 8758342d4cdSIngo Weinhold } 8762d690920SAxel Dörfler } else if (dr6 & (1 << X86_DR6_BT)) { 8772d690920SAxel Dörfler // task switch 8782d690920SAxel Dörfler // Occurs only, if T in EFLAGS is set (which we don't do). 8798753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 8802d690920SAxel Dörfler dprintf("i386_handle_debug_exception(): ignoring spurious task switch " 8812d690920SAxel Dörfler "exception\n"); 8822d690920SAxel Dörfler 8832d690920SAxel Dörfler enable_interrupts(); 8848753babdSIngo Weinhold } else 8858753babdSIngo Weinhold panic("spurious task switch exception in kernel mode"); 8862d690920SAxel Dörfler } else { 8878753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) { 88806be24a7SAxel Dörfler TRACE(("i386_handle_debug_exception(): ignoring spurious debug " 88906be24a7SAxel Dörfler "exception (no condition recognized)\n")); 8902d690920SAxel Dörfler 8912d690920SAxel Dörfler enable_interrupts(); 8928753babdSIngo Weinhold } else { 8938753babdSIngo Weinhold panic("spurious debug exception in kernel mode (no condition " 8948753babdSIngo Weinhold "recognized)"); 8958753babdSIngo Weinhold } 8962d690920SAxel Dörfler } 8972d690920SAxel Dörfler } 8982d690920SAxel Dörfler 8992d690920SAxel Dörfler 9002d690920SAxel Dörfler /** 901b4476702SIngo Weinhold * Interrupts are disabled and will possibly be enabled by the function. 9022d690920SAxel Dörfler */ 90334b3b26bSIngo Weinhold void 90434b3b26bSIngo Weinhold x86_handle_breakpoint_exception(struct iframe *frame) 9052d690920SAxel Dörfler { 9062d690920SAxel Dörfler TRACE(("i386_handle_breakpoint_exception()\n")); 9072d690920SAxel Dörfler 908*b0f12d64SIngo Weinhold // reset eip to the int3 instruction 909*b0f12d64SIngo Weinhold frame->eip--; 910*b0f12d64SIngo Weinhold 911bb107c4eSAxel Dörfler if (!IFRAME_IS_USER(frame)) { 912667f1eebSIngo Weinhold panic("breakpoint exception in kernel mode"); 91334b3b26bSIngo Weinhold return; 914667f1eebSIngo Weinhold } 915667f1eebSIngo Weinhold 9162d690920SAxel Dörfler enable_interrupts(); 9172d690920SAxel Dörfler 9182d690920SAxel Dörfler user_debug_breakpoint_hit(true); 9192d690920SAxel Dörfler } 9202d690920SAxel Dörfler 9212d690920SAxel Dörfler 9222d690920SAxel Dörfler void 92334b3b26bSIngo Weinhold x86_init_user_debug() 9242d690920SAxel Dörfler { 9252d690920SAxel Dörfler // get debug settings 9262d690920SAxel Dörfler if (void *handle = load_driver_settings("kernel")) { 9272d690920SAxel Dörfler sQEmuSingleStepHack = get_driver_boolean_parameter(handle, 9282d690920SAxel Dörfler "qemu_single_step_hack", false, false);; 9292d690920SAxel Dörfler 9302d690920SAxel Dörfler unload_driver_settings(handle); 9312d690920SAxel Dörfler } 932bc5f008aSIngo Weinhold 933bc5f008aSIngo Weinhold #if KERNEL_BREAKPOINTS 934bc5f008aSIngo Weinhold // install debugger commands 9358342d4cdSIngo Weinhold add_debugger_command_etc("breakpoints", &debugger_breakpoints, 9368342d4cdSIngo Weinhold "Lists current break-/watchpoints", 9378342d4cdSIngo Weinhold "\n" 9388342d4cdSIngo Weinhold "Lists the current kernel break-/watchpoints.\n", 0); 9398342d4cdSIngo Weinhold add_debugger_command_alias("watchpoints", "breakpoints", NULL); 9408342d4cdSIngo Weinhold add_debugger_command_etc("breakpoint", &debugger_breakpoint, 9418342d4cdSIngo Weinhold "Set/clears a breakpoint", 9428342d4cdSIngo Weinhold "<address> [ clear ]\n" 9438342d4cdSIngo Weinhold "Sets respectively clears the breakpoint at address <address>.\n", 0); 9448342d4cdSIngo Weinhold add_debugger_command_etc("watchpoint", &debugger_watchpoint, 9458342d4cdSIngo Weinhold "Set/clears a watchpoint", 9468342d4cdSIngo Weinhold "<address> <address> ( [ rw ] [ <size> ] | clear )\n" 9478342d4cdSIngo Weinhold "Sets respectively clears the watchpoint at address <address>.\n" 9488342d4cdSIngo Weinhold "If \"rw\" is given the new watchpoint is a read/write watchpoint\n" 9498342d4cdSIngo Weinhold "otherwise a write watchpoint only.\n", 0); 9508342d4cdSIngo Weinhold add_debugger_command_etc("step", &debugger_single_step, 9518342d4cdSIngo Weinhold "Single-steps to the next instruction", 9528342d4cdSIngo Weinhold "\n" 9538342d4cdSIngo Weinhold "Single-steps to the next instruction.\n", 0); 954bc5f008aSIngo Weinhold #endif 9552d690920SAxel Dörfler } 9562d690920SAxel Dörfler 957