12d690920SAxel Dörfler /*
299f00556SIngo Weinhold * Copyright 2005-2016, 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
36*6f3a5c9aSAdrien Destugues #ifdef __x86_64__
37*6f3a5c9aSAdrien Destugues extern bool gHasXsave;
38*6f3a5c9aSAdrien Destugues #else
390b11ecb1SIngo Weinhold extern bool gHasSSE;
40396b7422SPaweł Dziepak #endif
412d690920SAxel Dörfler
42b0f12d64SIngo Weinhold // The software breakpoint instruction (int3).
43b0f12d64SIngo Weinhold const uint8 kX86SoftwareBreakpoint[1] = { 0xcc };
44b0f12d64SIngo Weinhold
452d690920SAxel Dörfler // maps breakpoint slot index to LEN_i LSB number
468a190335SAlex Smith static const size_t sDR7Len[4] = {
472d690920SAxel Dörfler X86_DR7_LEN0_LSB, X86_DR7_LEN1_LSB, X86_DR7_LEN2_LSB, X86_DR7_LEN3_LSB
482d690920SAxel Dörfler };
492d690920SAxel Dörfler
502d690920SAxel Dörfler // maps breakpoint slot index to R/W_i LSB number
518a190335SAlex Smith static const size_t sDR7RW[4] = {
522d690920SAxel Dörfler X86_DR7_RW0_LSB, X86_DR7_RW1_LSB, X86_DR7_RW2_LSB, X86_DR7_RW3_LSB
532d690920SAxel Dörfler };
542d690920SAxel Dörfler
552d690920SAxel Dörfler // maps breakpoint slot index to L_i bit number
568a190335SAlex Smith static const size_t sDR7L[4] = {
572d690920SAxel Dörfler X86_DR7_L0, X86_DR7_L1, X86_DR7_L2, X86_DR7_L3
582d690920SAxel Dörfler };
592d690920SAxel Dörfler
60667f1eebSIngo Weinhold // maps breakpoint slot index to G_i bit number
618a190335SAlex Smith static const size_t sDR7G[4] = {
62667f1eebSIngo Weinhold X86_DR7_G0, X86_DR7_G1, X86_DR7_G2, X86_DR7_G3
63667f1eebSIngo Weinhold };
64667f1eebSIngo Weinhold
652d690920SAxel Dörfler // maps breakpoint slot index to B_i bit number
668a190335SAlex Smith static const size_t sDR6B[4] = {
672d690920SAxel Dörfler X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3
682d690920SAxel Dörfler };
692d690920SAxel Dörfler
702d690920SAxel Dörfler // Enables a hack to make single stepping work under qemu. Set via kernel
712d690920SAxel Dörfler // driver settings.
722d690920SAxel Dörfler static bool sQEmuSingleStepHack = false;
732d690920SAxel Dörfler
742d690920SAxel Dörfler
758a190335SAlex Smith #ifdef __x86_64__
768a190335SAlex Smith
778a190335SAlex Smith
78568ade58SIngo Weinhold static void
get_iframe_registers(const iframe * frame,debug_cpu_state * cpuState)798a190335SAlex Smith get_iframe_registers(const iframe* frame, debug_cpu_state* cpuState)
808a190335SAlex Smith {
818a190335SAlex Smith // Get general purpose registers.
828a190335SAlex Smith cpuState->r15 = frame->r15;
838a190335SAlex Smith cpuState->r14 = frame->r14;
848a190335SAlex Smith cpuState->r13 = frame->r13;
858a190335SAlex Smith cpuState->r12 = frame->r12;
868a190335SAlex Smith cpuState->r11 = frame->r11;
878a190335SAlex Smith cpuState->r10 = frame->r10;
888a190335SAlex Smith cpuState->r9 = frame->r9;
898a190335SAlex Smith cpuState->r8 = frame->r8;
908a190335SAlex Smith cpuState->rbp = frame->bp;
918a190335SAlex Smith cpuState->rsi = frame->si;
928a190335SAlex Smith cpuState->rdi = frame->di;
938a190335SAlex Smith cpuState->rdx = frame->dx;
948a190335SAlex Smith cpuState->rcx = frame->cx;
958a190335SAlex Smith cpuState->rbx = frame->bx;
968a190335SAlex Smith cpuState->rax = frame->ax;
97271b27d5SAlex Smith cpuState->vector = frame->vector;
98271b27d5SAlex Smith cpuState->error_code = frame->error_code;
998a190335SAlex Smith cpuState->rip = frame->ip;
1008a190335SAlex Smith cpuState->cs = frame->cs;
1018a190335SAlex Smith cpuState->rflags = frame->flags;
1028a190335SAlex Smith cpuState->rsp = frame->sp;
1038a190335SAlex Smith cpuState->ss = frame->ss;
1048a190335SAlex Smith
1058a190335SAlex Smith // Other segment registers are not saved or changed on interrupts, so
1068a190335SAlex Smith // get their value here.
1078a190335SAlex Smith uint16 seg;
1088a190335SAlex Smith __asm__ volatile ("movw %%ds, %0" : "=r" (seg));
1098a190335SAlex Smith cpuState->ds = seg;
1108a190335SAlex Smith __asm__ volatile ("movw %%es, %0" : "=r" (seg));
1118a190335SAlex Smith cpuState->es = seg;
1128a190335SAlex Smith __asm__ volatile ("movw %%fs, %0" : "=r" (seg));
1138a190335SAlex Smith cpuState->fs = seg;
1148a190335SAlex Smith __asm__ volatile ("movw %%gs, %0" : "=r" (seg));
1158a190335SAlex Smith cpuState->gs = seg;
1168a190335SAlex Smith }
1178a190335SAlex Smith
1188a190335SAlex Smith
1198a190335SAlex Smith static void
set_iframe_registers(iframe * frame,const debug_cpu_state * cpuState)1208a190335SAlex Smith set_iframe_registers(iframe* frame, const debug_cpu_state* cpuState)
1218a190335SAlex Smith {
1228a190335SAlex Smith frame->r15 = cpuState->r15;
1238a190335SAlex Smith frame->r14 = cpuState->r14;
1248a190335SAlex Smith frame->r13 = cpuState->r13;
1258a190335SAlex Smith frame->r12 = cpuState->r12;
1268a190335SAlex Smith frame->r11 = cpuState->r11;
1278a190335SAlex Smith frame->r10 = cpuState->r10;
1288a190335SAlex Smith frame->r9 = cpuState->r9;
1298a190335SAlex Smith frame->r8 = cpuState->r8;
1308a190335SAlex Smith frame->bp = cpuState->rbp;
1318a190335SAlex Smith frame->si = cpuState->rsi;
1328a190335SAlex Smith frame->di = cpuState->rdi;
1338a190335SAlex Smith frame->dx = cpuState->rdx;
1348a190335SAlex Smith frame->cx = cpuState->rcx;
1358a190335SAlex Smith frame->bx = cpuState->rbx;
1368a190335SAlex Smith frame->ax = cpuState->rax;
1378a190335SAlex Smith frame->ip = cpuState->rip;
1388a190335SAlex Smith frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS)
1398a190335SAlex Smith | (cpuState->rflags & X86_EFLAGS_USER_SETTABLE_FLAGS);
1408a190335SAlex Smith frame->sp = cpuState->rsp;
1418a190335SAlex Smith }
1428a190335SAlex Smith
1438a190335SAlex Smith
1448a190335SAlex Smith #else // __x86_64__
1458a190335SAlex Smith
1468a190335SAlex Smith
1478a190335SAlex Smith static void
get_iframe_registers(const iframe * frame,debug_cpu_state * cpuState)1488a190335SAlex Smith get_iframe_registers(const iframe* frame, debug_cpu_state* cpuState)
149568ade58SIngo Weinhold {
150568ade58SIngo Weinhold cpuState->gs = frame->gs;
151568ade58SIngo Weinhold cpuState->fs = frame->fs;
152568ade58SIngo Weinhold cpuState->es = frame->es;
153568ade58SIngo Weinhold cpuState->ds = frame->ds;
154b5c9d24aSAlex Smith cpuState->edi = frame->di;
155b5c9d24aSAlex Smith cpuState->esi = frame->si;
156b5c9d24aSAlex Smith cpuState->ebp = frame->bp;
157b5c9d24aSAlex Smith cpuState->esp = frame->sp;
158b5c9d24aSAlex Smith cpuState->ebx = frame->bx;
159568ade58SIngo Weinhold cpuState->edx = frame->orig_edx;
160b5c9d24aSAlex Smith cpuState->ecx = frame->cx;
161568ade58SIngo Weinhold cpuState->eax = frame->orig_eax;
162568ade58SIngo Weinhold cpuState->vector = frame->vector;
163568ade58SIngo Weinhold cpuState->error_code = frame->error_code;
164b5c9d24aSAlex Smith cpuState->eip = frame->ip;
165568ade58SIngo Weinhold cpuState->cs = frame->cs;
166568ade58SIngo Weinhold cpuState->eflags = frame->flags;
167b5c9d24aSAlex Smith cpuState->user_esp = frame->user_sp;
168568ade58SIngo Weinhold cpuState->user_ss = frame->user_ss;
169568ade58SIngo Weinhold }
170568ade58SIngo Weinhold
171568ade58SIngo Weinhold
1728a190335SAlex Smith static void
set_iframe_registers(iframe * frame,const debug_cpu_state * cpuState)1738a190335SAlex Smith set_iframe_registers(iframe* frame, const debug_cpu_state* cpuState)
1748a190335SAlex Smith {
1758a190335SAlex Smith // frame->gs = cpuState->gs;
1768a190335SAlex Smith // frame->fs = cpuState->fs;
1778a190335SAlex Smith // frame->es = cpuState->es;
1788a190335SAlex Smith // frame->ds = cpuState->ds;
1798a190335SAlex Smith frame->di = cpuState->edi;
1808a190335SAlex Smith frame->si = cpuState->esi;
1818a190335SAlex Smith frame->bp = cpuState->ebp;
1828a190335SAlex Smith // frame->esp = cpuState->esp;
1838a190335SAlex Smith frame->bx = cpuState->ebx;
1848a190335SAlex Smith frame->dx = cpuState->edx;
1858a190335SAlex Smith frame->cx = cpuState->ecx;
1868a190335SAlex Smith frame->ax = cpuState->eax;
1878a190335SAlex Smith // frame->vector = cpuState->vector;
1888a190335SAlex Smith // frame->error_code = cpuState->error_code;
1898a190335SAlex Smith frame->ip = cpuState->eip;
1908a190335SAlex Smith // frame->cs = cpuState->cs;
1918a190335SAlex Smith frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS)
1928a190335SAlex Smith | (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS);
1938a190335SAlex Smith frame->user_sp = cpuState->user_esp;
1948a190335SAlex Smith // frame->user_ss = cpuState->user_ss;
1958a190335SAlex Smith }
1968a190335SAlex Smith
1978a190335SAlex Smith
1988a190335SAlex Smith #endif // __x86_64__
1998a190335SAlex Smith
2008a190335SAlex Smith
20199f00556SIngo Weinhold static void
get_cpu_state(Thread * thread,iframe * frame,debug_cpu_state * cpuState)20299f00556SIngo Weinhold get_cpu_state(Thread* thread, iframe* frame, debug_cpu_state* cpuState)
20399f00556SIngo Weinhold {
20499f00556SIngo Weinhold // For the floating point state to be correct the calling function must
20599f00556SIngo Weinhold // not use these registers (not even indirectly).
20699f00556SIngo Weinhold #ifdef __x86_64__
207*6f3a5c9aSAdrien Destugues memset(&cpuState->extended_registers, 0,
208*6f3a5c9aSAdrien Destugues sizeof(cpuState->extended_registers));
209*6f3a5c9aSAdrien Destugues
21099f00556SIngo Weinhold if (frame->fpu != nullptr) {
211*6f3a5c9aSAdrien Destugues if (gHasXsave) {
212*6f3a5c9aSAdrien Destugues // TODO check the xsave header to know the actual size of the
213*6f3a5c9aSAdrien Destugues // register context depending on what is saved. For now we assume
214*6f3a5c9aSAdrien Destugues // there is only the YMM AVX registers
21599f00556SIngo Weinhold memcpy(&cpuState->extended_registers, frame->fpu,
21699f00556SIngo Weinhold sizeof(cpuState->extended_registers));
21799f00556SIngo Weinhold } else {
218*6f3a5c9aSAdrien Destugues // Only the "legacy area" saved by fxsave is available
219*6f3a5c9aSAdrien Destugues memcpy(&cpuState->extended_registers, frame->fpu,
220*6f3a5c9aSAdrien Destugues sizeof(cpuState->extended_registers.fp_fxsave));
221*6f3a5c9aSAdrien Destugues }
22299f00556SIngo Weinhold }
22399f00556SIngo Weinhold #else
22499f00556SIngo Weinhold Thread* thisThread = thread_get_current_thread();
22599f00556SIngo Weinhold if (gHasSSE) {
22699f00556SIngo Weinhold if (thread == thisThread) {
22799f00556SIngo Weinhold // Since fxsave requires 16-byte alignment and this isn't guaranteed
22899f00556SIngo Weinhold // for the passed buffer, we use our thread's fpu_state field as
22999f00556SIngo Weinhold // temporary buffer. We need to disable interrupts to make use of
23099f00556SIngo Weinhold // it.
23199f00556SIngo Weinhold Thread* thread = thread_get_current_thread();
23299f00556SIngo Weinhold InterruptsLocker locker;
23399f00556SIngo Weinhold x86_fxsave(thread->arch_info.fpu_state);
23499f00556SIngo Weinhold // unlike fnsave, fxsave doesn't reinit the FPU state
23599f00556SIngo Weinhold }
23699f00556SIngo Weinhold memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state,
23799f00556SIngo Weinhold sizeof(cpuState->extended_registers));
23899f00556SIngo Weinhold } else {
23999f00556SIngo Weinhold if (thread == thisThread) {
24099f00556SIngo Weinhold x86_fnsave(&cpuState->extended_registers);
24199f00556SIngo Weinhold // fnsave reinits the FPU state after saving, so we need to
24299f00556SIngo Weinhold // load it again
24399f00556SIngo Weinhold x86_frstor(&cpuState->extended_registers);
24499f00556SIngo Weinhold } else {
24599f00556SIngo Weinhold memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state,
24699f00556SIngo Weinhold sizeof(cpuState->extended_registers));
24799f00556SIngo Weinhold }
24899f00556SIngo Weinhold // TODO: Convert to fxsave format!
24999f00556SIngo Weinhold }
25099f00556SIngo Weinhold #endif
25199f00556SIngo Weinhold get_iframe_registers(frame, cpuState);
25299f00556SIngo Weinhold }
25399f00556SIngo Weinhold
25499f00556SIngo Weinhold
255667f1eebSIngo Weinhold static inline void
install_breakpoints(const arch_team_debug_info & teamInfo)256667f1eebSIngo Weinhold install_breakpoints(const arch_team_debug_info& teamInfo)
257667f1eebSIngo Weinhold {
258667f1eebSIngo Weinhold // set breakpoints
2598a190335SAlex Smith asm("mov %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address));
2608a190335SAlex Smith asm("mov %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address));
2618a190335SAlex Smith asm("mov %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address));
2628a190335SAlex Smith asm("mov %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address));
263667f1eebSIngo Weinhold
264667f1eebSIngo Weinhold // enable breakpoints
2658a190335SAlex Smith asm("mov %0, %%dr7" : : "r"(teamInfo.dr7));
266667f1eebSIngo Weinhold }
267667f1eebSIngo Weinhold
268667f1eebSIngo Weinhold
269667f1eebSIngo Weinhold static inline void
disable_breakpoints()270667f1eebSIngo Weinhold disable_breakpoints()
271667f1eebSIngo Weinhold {
2728a190335SAlex Smith asm("mov %0, %%dr7" : : "r"((size_t)X86_BREAKPOINTS_DISABLED_DR7));
273667f1eebSIngo Weinhold }
274667f1eebSIngo Weinhold
275667f1eebSIngo Weinhold
276667f1eebSIngo Weinhold /*! Sets a break-/watchpoint in the given team info.
277667f1eebSIngo Weinhold Interrupts must be disabled and the team debug info lock be held.
278667f1eebSIngo Weinhold */
279667f1eebSIngo Weinhold static inline status_t
set_breakpoint(arch_team_debug_info & info,void * address,size_t type,size_t length,bool setGlobalFlag)2808a190335SAlex Smith set_breakpoint(arch_team_debug_info& info, void* address, size_t type,
2818a190335SAlex Smith size_t length, bool setGlobalFlag)
282667f1eebSIngo Weinhold {
283667f1eebSIngo Weinhold // check, if there is already a breakpoint at that address
284667f1eebSIngo Weinhold bool alreadySet = false;
285667f1eebSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
286667f1eebSIngo Weinhold if (info.breakpoints[i].address == address
287667f1eebSIngo Weinhold && info.breakpoints[i].type == type) {
288667f1eebSIngo Weinhold alreadySet = true;
289667f1eebSIngo Weinhold break;
290667f1eebSIngo Weinhold }
291667f1eebSIngo Weinhold }
292667f1eebSIngo Weinhold
293667f1eebSIngo Weinhold if (!alreadySet) {
294667f1eebSIngo Weinhold // find a free slot
295667f1eebSIngo Weinhold int32 slot = -1;
296667f1eebSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
297667f1eebSIngo Weinhold if (!info.breakpoints[i].address) {
298667f1eebSIngo Weinhold slot = i;
299667f1eebSIngo Weinhold break;
300667f1eebSIngo Weinhold }
301667f1eebSIngo Weinhold }
302667f1eebSIngo Weinhold
303667f1eebSIngo Weinhold // init the breakpoint
304667f1eebSIngo Weinhold if (slot >= 0) {
305667f1eebSIngo Weinhold info.breakpoints[slot].address = address;
306667f1eebSIngo Weinhold info.breakpoints[slot].type = type;
307667f1eebSIngo Weinhold info.breakpoints[slot].length = length;
308667f1eebSIngo Weinhold
309667f1eebSIngo Weinhold info.dr7 |= (length << sDR7Len[slot])
310667f1eebSIngo Weinhold | (type << sDR7RW[slot])
311667f1eebSIngo Weinhold | (1 << sDR7L[slot]);
312667f1eebSIngo Weinhold if (setGlobalFlag)
313667f1eebSIngo Weinhold info.dr7 |= (1 << sDR7G[slot]);
314667f1eebSIngo Weinhold } else {
315667f1eebSIngo Weinhold if (type == X86_INSTRUCTION_BREAKPOINT)
316667f1eebSIngo Weinhold return B_NO_MORE_BREAKPOINTS;
317667f1eebSIngo Weinhold else
318667f1eebSIngo Weinhold return B_NO_MORE_WATCHPOINTS;
319667f1eebSIngo Weinhold }
320667f1eebSIngo Weinhold }
321667f1eebSIngo Weinhold
322667f1eebSIngo Weinhold return B_OK;
323667f1eebSIngo Weinhold }
324667f1eebSIngo Weinhold
325667f1eebSIngo Weinhold
326667f1eebSIngo Weinhold /*! Clears a break-/watchpoint in the given team info.
327667f1eebSIngo Weinhold Interrupts must be disabled and the team debug info lock be held.
328667f1eebSIngo Weinhold */
329667f1eebSIngo Weinhold static inline status_t
clear_breakpoint(arch_team_debug_info & info,void * address,bool watchpoint)330667f1eebSIngo Weinhold clear_breakpoint(arch_team_debug_info& info, void* address, bool watchpoint)
331667f1eebSIngo Weinhold {
332667f1eebSIngo Weinhold // find the breakpoint
333667f1eebSIngo Weinhold int32 slot = -1;
334667f1eebSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
335667f1eebSIngo Weinhold if (info.breakpoints[i].address == address
336667f1eebSIngo Weinhold && (watchpoint
337667f1eebSIngo Weinhold != (info.breakpoints[i].type == X86_INSTRUCTION_BREAKPOINT))) {
338667f1eebSIngo Weinhold slot = i;
339667f1eebSIngo Weinhold break;
340667f1eebSIngo Weinhold }
341667f1eebSIngo Weinhold }
342667f1eebSIngo Weinhold
343667f1eebSIngo Weinhold // clear the breakpoint
344667f1eebSIngo Weinhold if (slot >= 0) {
345667f1eebSIngo Weinhold info.breakpoints[slot].address = NULL;
346667f1eebSIngo Weinhold
347667f1eebSIngo Weinhold info.dr7 &= ~((0x3 << sDR7Len[slot])
348667f1eebSIngo Weinhold | (0x3 << sDR7RW[slot])
349667f1eebSIngo Weinhold | (1 << sDR7L[slot])
350667f1eebSIngo Weinhold | (1 << sDR7G[slot]));
351667f1eebSIngo Weinhold } else {
352667f1eebSIngo Weinhold if (watchpoint)
353667f1eebSIngo Weinhold return B_WATCHPOINT_NOT_FOUND;
354667f1eebSIngo Weinhold else
355667f1eebSIngo Weinhold return B_BREAKPOINT_NOT_FOUND;
356667f1eebSIngo Weinhold }
357667f1eebSIngo Weinhold
358667f1eebSIngo Weinhold return B_OK;
359667f1eebSIngo Weinhold }
360667f1eebSIngo Weinhold
361667f1eebSIngo Weinhold
362667f1eebSIngo Weinhold static status_t
set_breakpoint(void * address,size_t type,size_t length)3638a190335SAlex Smith set_breakpoint(void* address, size_t type, size_t length)
364667f1eebSIngo Weinhold {
365667f1eebSIngo Weinhold if (!address)
366667f1eebSIngo Weinhold return B_BAD_VALUE;
367667f1eebSIngo Weinhold
3684535495dSIngo Weinhold Thread* thread = thread_get_current_thread();
369667f1eebSIngo Weinhold
370667f1eebSIngo Weinhold cpu_status state = disable_interrupts();
371667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
372667f1eebSIngo Weinhold
373667f1eebSIngo Weinhold status_t error = set_breakpoint(thread->team->debug_info.arch_info, address,
374667f1eebSIngo Weinhold type, length, false);
375667f1eebSIngo Weinhold
376667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
377667f1eebSIngo Weinhold restore_interrupts(state);
378667f1eebSIngo Weinhold
379667f1eebSIngo Weinhold return error;
380667f1eebSIngo Weinhold }
381667f1eebSIngo Weinhold
382667f1eebSIngo Weinhold
383667f1eebSIngo Weinhold static status_t
clear_breakpoint(void * address,bool watchpoint)384667f1eebSIngo Weinhold clear_breakpoint(void* address, bool watchpoint)
385667f1eebSIngo Weinhold {
386667f1eebSIngo Weinhold if (!address)
387667f1eebSIngo Weinhold return B_BAD_VALUE;
388667f1eebSIngo Weinhold
3894535495dSIngo Weinhold Thread* thread = thread_get_current_thread();
390667f1eebSIngo Weinhold
391667f1eebSIngo Weinhold cpu_status state = disable_interrupts();
392667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
393667f1eebSIngo Weinhold
394667f1eebSIngo Weinhold status_t error = clear_breakpoint(thread->team->debug_info.arch_info,
395667f1eebSIngo Weinhold address, watchpoint);
396667f1eebSIngo Weinhold
397667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
398667f1eebSIngo Weinhold restore_interrupts(state);
399667f1eebSIngo Weinhold
400667f1eebSIngo Weinhold return error;
401667f1eebSIngo Weinhold }
402667f1eebSIngo Weinhold
403667f1eebSIngo Weinhold
404667f1eebSIngo Weinhold #if KERNEL_BREAKPOINTS
405667f1eebSIngo Weinhold
40631d9352fSIngo Weinhold
40731d9352fSIngo Weinhold static void
install_breakpoints_per_cpu(void *,int cpu)40831d9352fSIngo Weinhold install_breakpoints_per_cpu(void* /*cookie*/, int cpu)
40931d9352fSIngo Weinhold {
4104535495dSIngo Weinhold Team* kernelTeam = team_get_kernel_team();
41131d9352fSIngo Weinhold
41231d9352fSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
41331d9352fSIngo Weinhold
41431d9352fSIngo Weinhold install_breakpoints(kernelTeam->debug_info.arch_info);
41531d9352fSIngo Weinhold
41631d9352fSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
41731d9352fSIngo Weinhold }
41831d9352fSIngo Weinhold
41931d9352fSIngo Weinhold
420667f1eebSIngo Weinhold static status_t
set_kernel_breakpoint(void * address,size_t type,size_t length)4218a190335SAlex Smith set_kernel_breakpoint(void* address, size_t type, size_t length)
422667f1eebSIngo Weinhold {
423667f1eebSIngo Weinhold if (!address)
424667f1eebSIngo Weinhold return B_BAD_VALUE;
425667f1eebSIngo Weinhold
4264535495dSIngo Weinhold Team* kernelTeam = team_get_kernel_team();
427667f1eebSIngo Weinhold
428667f1eebSIngo Weinhold cpu_status state = disable_interrupts();
429667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
430667f1eebSIngo Weinhold
431667f1eebSIngo Weinhold status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address,
432667f1eebSIngo Weinhold type, length, true);
433667f1eebSIngo Weinhold
434667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
43531d9352fSIngo Weinhold
43631d9352fSIngo Weinhold call_all_cpus(install_breakpoints_per_cpu, NULL);
43731d9352fSIngo Weinhold
438667f1eebSIngo Weinhold restore_interrupts(state);
439667f1eebSIngo Weinhold
440667f1eebSIngo Weinhold return error;
441667f1eebSIngo Weinhold }
442667f1eebSIngo Weinhold
443667f1eebSIngo Weinhold
444667f1eebSIngo Weinhold static status_t
clear_kernel_breakpoint(void * address,bool watchpoint)445667f1eebSIngo Weinhold clear_kernel_breakpoint(void* address, bool watchpoint)
446667f1eebSIngo Weinhold {
447667f1eebSIngo Weinhold if (!address)
448667f1eebSIngo Weinhold return B_BAD_VALUE;
449667f1eebSIngo Weinhold
4504535495dSIngo Weinhold Team* kernelTeam = team_get_kernel_team();
451667f1eebSIngo Weinhold
452667f1eebSIngo Weinhold cpu_status state = disable_interrupts();
453667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
454667f1eebSIngo Weinhold
455667f1eebSIngo Weinhold status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info,
456667f1eebSIngo Weinhold address, watchpoint);
457667f1eebSIngo Weinhold
458667f1eebSIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
45931d9352fSIngo Weinhold
46031d9352fSIngo Weinhold call_all_cpus(install_breakpoints_per_cpu, NULL);
46131d9352fSIngo Weinhold
462667f1eebSIngo Weinhold restore_interrupts(state);
463667f1eebSIngo Weinhold
464667f1eebSIngo Weinhold return error;
465667f1eebSIngo Weinhold }
466667f1eebSIngo Weinhold
467667f1eebSIngo Weinhold #endif // KERNEL_BREAKPOINTS
468667f1eebSIngo Weinhold
469667f1eebSIngo Weinhold
470667f1eebSIngo Weinhold static inline status_t
check_watch_point_parameters(void * address,uint32 type,int32 length,size_t & archType,size_t & archLength)471667f1eebSIngo Weinhold check_watch_point_parameters(void* address, uint32 type, int32 length,
4728a190335SAlex Smith size_t& archType, size_t& archLength)
473667f1eebSIngo Weinhold {
474667f1eebSIngo Weinhold // check type
475667f1eebSIngo Weinhold switch (type) {
476667f1eebSIngo Weinhold case B_DATA_WRITE_WATCHPOINT:
477667f1eebSIngo Weinhold archType = X86_DATA_WRITE_BREAKPOINT;
478667f1eebSIngo Weinhold break;
479667f1eebSIngo Weinhold case B_DATA_READ_WRITE_WATCHPOINT:
480667f1eebSIngo Weinhold archType = X86_DATA_READ_WRITE_BREAKPOINT;
481667f1eebSIngo Weinhold break;
482667f1eebSIngo Weinhold case B_DATA_READ_WATCHPOINT:
483667f1eebSIngo Weinhold default:
484667f1eebSIngo Weinhold return B_WATCHPOINT_TYPE_NOT_SUPPORTED;
485667f1eebSIngo Weinhold break;
486667f1eebSIngo Weinhold }
487667f1eebSIngo Weinhold
488667f1eebSIngo Weinhold // check length and alignment
489667f1eebSIngo Weinhold switch (length) {
490667f1eebSIngo Weinhold case 1:
491667f1eebSIngo Weinhold archLength = X86_BREAKPOINT_LENGTH_1;
492667f1eebSIngo Weinhold break;
493667f1eebSIngo Weinhold case 2:
4948a190335SAlex Smith if ((addr_t)address & 0x1)
495667f1eebSIngo Weinhold return B_BAD_WATCHPOINT_ALIGNMENT;
496667f1eebSIngo Weinhold archLength = X86_BREAKPOINT_LENGTH_2;
497667f1eebSIngo Weinhold break;
498667f1eebSIngo Weinhold case 4:
4998a190335SAlex Smith if ((addr_t)address & 0x3)
500667f1eebSIngo Weinhold return B_BAD_WATCHPOINT_ALIGNMENT;
501667f1eebSIngo Weinhold archLength = X86_BREAKPOINT_LENGTH_4;
502667f1eebSIngo Weinhold break;
503667f1eebSIngo Weinhold default:
504667f1eebSIngo Weinhold return B_WATCHPOINT_LENGTH_NOT_SUPPORTED;
505667f1eebSIngo Weinhold }
506667f1eebSIngo Weinhold
507667f1eebSIngo Weinhold return B_OK;
508667f1eebSIngo Weinhold }
509667f1eebSIngo Weinhold
510667f1eebSIngo Weinhold
511bc5f008aSIngo Weinhold // #pragma mark - kernel debugger commands
512bc5f008aSIngo Weinhold
5138a190335SAlex Smith
514bc5f008aSIngo Weinhold #if KERNEL_BREAKPOINTS
515bc5f008aSIngo Weinhold
516bc5f008aSIngo Weinhold static int
debugger_breakpoints(int argc,char ** argv)517bc5f008aSIngo Weinhold debugger_breakpoints(int argc, char** argv)
518bc5f008aSIngo Weinhold {
5194535495dSIngo Weinhold Team* kernelTeam = team_get_kernel_team();
520bc5f008aSIngo Weinhold arch_team_debug_info& info = kernelTeam->debug_info.arch_info;
521bc5f008aSIngo Weinhold
522bc5f008aSIngo Weinhold for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
5238a190335SAlex Smith kprintf("breakpoint[%" B_PRId32 "] ", i);
524bc5f008aSIngo Weinhold
525bc5f008aSIngo Weinhold if (info.breakpoints[i].address != NULL) {
526bc5f008aSIngo Weinhold kprintf("%p ", info.breakpoints[i].address);
527bc5f008aSIngo Weinhold switch (info.breakpoints[i].type) {
528bc5f008aSIngo Weinhold case X86_INSTRUCTION_BREAKPOINT:
529bc5f008aSIngo Weinhold kprintf("instruction");
530bc5f008aSIngo Weinhold break;
531bc5f008aSIngo Weinhold case X86_IO_READ_WRITE_BREAKPOINT:
532bc5f008aSIngo Weinhold kprintf("io read/write");
533bc5f008aSIngo Weinhold break;
534bc5f008aSIngo Weinhold case X86_DATA_WRITE_BREAKPOINT:
535bc5f008aSIngo Weinhold kprintf("data write");
536bc5f008aSIngo Weinhold break;
537bc5f008aSIngo Weinhold case X86_DATA_READ_WRITE_BREAKPOINT:
538bc5f008aSIngo Weinhold kprintf("data read/write");
539bc5f008aSIngo Weinhold break;
540bc5f008aSIngo Weinhold }
541bc5f008aSIngo Weinhold
542bc5f008aSIngo Weinhold int length = 1;
543bc5f008aSIngo Weinhold switch (info.breakpoints[i].length) {
544bc5f008aSIngo Weinhold case X86_BREAKPOINT_LENGTH_1:
545bc5f008aSIngo Weinhold length = 1;
546bc5f008aSIngo Weinhold break;
547bc5f008aSIngo Weinhold case X86_BREAKPOINT_LENGTH_2:
548bc5f008aSIngo Weinhold length = 2;
549bc5f008aSIngo Weinhold break;
550bc5f008aSIngo Weinhold case X86_BREAKPOINT_LENGTH_4:
551bc5f008aSIngo Weinhold length = 4;
552bc5f008aSIngo Weinhold break;
553bc5f008aSIngo Weinhold }
554bc5f008aSIngo Weinhold
555bc5f008aSIngo Weinhold if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT)
556bc5f008aSIngo Weinhold kprintf(" %d byte%s", length, (length > 1 ? "s" : ""));
557bc5f008aSIngo Weinhold } else
558bc5f008aSIngo Weinhold kprintf("unused");
559bc5f008aSIngo Weinhold
560bc5f008aSIngo Weinhold kprintf("\n");
561bc5f008aSIngo Weinhold }
562bc5f008aSIngo Weinhold
563bc5f008aSIngo Weinhold return 0;
564bc5f008aSIngo Weinhold }
565bc5f008aSIngo Weinhold
566bc5f008aSIngo Weinhold
567bc5f008aSIngo Weinhold static int
debugger_breakpoint(int argc,char ** argv)568bc5f008aSIngo Weinhold debugger_breakpoint(int argc, char** argv)
569bc5f008aSIngo Weinhold {
570bc5f008aSIngo Weinhold // get arguments
571bc5f008aSIngo Weinhold
572bc5f008aSIngo Weinhold if (argc < 2 || argc > 3)
5738342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]);
574bc5f008aSIngo Weinhold
575bc5f008aSIngo Weinhold addr_t address = strtoul(argv[1], NULL, 0);
576bc5f008aSIngo Weinhold if (address == 0)
5778342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]);
578bc5f008aSIngo Weinhold
579bc5f008aSIngo Weinhold bool clear = false;
580bc5f008aSIngo Weinhold if (argc == 3) {
581bc5f008aSIngo Weinhold if (strcmp(argv[2], "clear") == 0)
582bc5f008aSIngo Weinhold clear = true;
583bc5f008aSIngo Weinhold else
5848342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]);
585bc5f008aSIngo Weinhold }
586bc5f008aSIngo Weinhold
587bc5f008aSIngo Weinhold // set/clear breakpoint
588bc5f008aSIngo Weinhold
589bc5f008aSIngo Weinhold arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
590bc5f008aSIngo Weinhold
591bc5f008aSIngo Weinhold status_t error;
592bc5f008aSIngo Weinhold
593bc5f008aSIngo Weinhold if (clear) {
594bc5f008aSIngo Weinhold error = clear_breakpoint(info, (void*)address, false);
595bc5f008aSIngo Weinhold } else {
596bc5f008aSIngo Weinhold error = set_breakpoint(info, (void*)address, X86_INSTRUCTION_BREAKPOINT,
597bc5f008aSIngo Weinhold X86_BREAKPOINT_LENGTH_1, true);
598bc5f008aSIngo Weinhold }
599bc5f008aSIngo Weinhold
600bc5f008aSIngo Weinhold if (error == B_OK)
60131d9352fSIngo Weinhold call_all_cpus_sync(install_breakpoints_per_cpu, NULL);
602bc5f008aSIngo Weinhold else
603bc5f008aSIngo Weinhold kprintf("Failed to install breakpoint: %s\n", strerror(error));
604bc5f008aSIngo Weinhold
605bc5f008aSIngo Weinhold return 0;
606bc5f008aSIngo Weinhold }
607bc5f008aSIngo Weinhold
608bc5f008aSIngo Weinhold
609bc5f008aSIngo Weinhold static int
debugger_watchpoint(int argc,char ** argv)610bc5f008aSIngo Weinhold debugger_watchpoint(int argc, char** argv)
611bc5f008aSIngo Weinhold {
612bc5f008aSIngo Weinhold // get arguments
613bc5f008aSIngo Weinhold
614bc5f008aSIngo Weinhold if (argc < 2 || argc > 4)
6158342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]);
616bc5f008aSIngo Weinhold
617bc5f008aSIngo Weinhold addr_t address = strtoul(argv[1], NULL, 0);
618bc5f008aSIngo Weinhold if (address == 0)
6198342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]);
620bc5f008aSIngo Weinhold
621bc5f008aSIngo Weinhold bool clear = false;
622bc5f008aSIngo Weinhold bool readWrite = false;
623bc5f008aSIngo Weinhold int argi = 2;
624bc5f008aSIngo Weinhold int length = 1;
625bc5f008aSIngo Weinhold if (argc >= 3) {
626bc5f008aSIngo Weinhold if (strcmp(argv[argi], "clear") == 0) {
627bc5f008aSIngo Weinhold clear = true;
628bc5f008aSIngo Weinhold argi++;
629bc5f008aSIngo Weinhold } else if (strcmp(argv[argi], "rw") == 0) {
630bc5f008aSIngo Weinhold readWrite = true;
631bc5f008aSIngo Weinhold argi++;
632bc5f008aSIngo Weinhold }
633bc5f008aSIngo Weinhold
634bc5f008aSIngo Weinhold if (!clear && argi < argc)
635bc5f008aSIngo Weinhold length = strtoul(argv[argi++], NULL, 0);
636bc5f008aSIngo Weinhold
637bc5f008aSIngo Weinhold if (length == 0 || argi < argc)
6388342d4cdSIngo Weinhold return print_debugger_command_usage(argv[0]);
639bc5f008aSIngo Weinhold }
640bc5f008aSIngo Weinhold
641bc5f008aSIngo Weinhold // set/clear breakpoint
642bc5f008aSIngo Weinhold
643bc5f008aSIngo Weinhold arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
644bc5f008aSIngo Weinhold
645bc5f008aSIngo Weinhold status_t error;
646bc5f008aSIngo Weinhold
647bc5f008aSIngo Weinhold if (clear) {
648bc5f008aSIngo Weinhold error = clear_breakpoint(info, (void*)address, true);
649bc5f008aSIngo Weinhold } else {
650bc5f008aSIngo Weinhold uint32 type = readWrite ? B_DATA_READ_WRITE_WATCHPOINT
651bc5f008aSIngo Weinhold : B_DATA_WRITE_WATCHPOINT;
652bc5f008aSIngo Weinhold
6538a190335SAlex Smith size_t archType, archLength;
654bc5f008aSIngo Weinhold error = check_watch_point_parameters((void*)address, type, length,
655bc5f008aSIngo Weinhold archType, archLength);
656bc5f008aSIngo Weinhold
657bc5f008aSIngo Weinhold if (error == B_OK) {
658bc5f008aSIngo Weinhold error = set_breakpoint(info, (void*)address, archType, archLength,
659bc5f008aSIngo Weinhold true);
660bc5f008aSIngo Weinhold }
661bc5f008aSIngo Weinhold }
662bc5f008aSIngo Weinhold
663bc5f008aSIngo Weinhold if (error == B_OK)
66431d9352fSIngo Weinhold call_all_cpus_sync(install_breakpoints_per_cpu, NULL);
665bc5f008aSIngo Weinhold else
666bc5f008aSIngo Weinhold kprintf("Failed to install breakpoint: %s\n", strerror(error));
667bc5f008aSIngo Weinhold
668bc5f008aSIngo Weinhold return 0;
669bc5f008aSIngo Weinhold }
670bc5f008aSIngo Weinhold
6718342d4cdSIngo Weinhold
6728342d4cdSIngo Weinhold static int
debugger_single_step(int argc,char ** argv)6738342d4cdSIngo Weinhold debugger_single_step(int argc, char** argv)
6748342d4cdSIngo Weinhold {
6758342d4cdSIngo Weinhold // TODO: Since we need an iframe, this doesn't work when KDL wasn't entered
6768342d4cdSIngo Weinhold // via an exception.
6778342d4cdSIngo Weinhold
6788a190335SAlex Smith iframe* frame = x86_get_current_iframe();
6798342d4cdSIngo Weinhold if (frame == NULL) {
6808342d4cdSIngo Weinhold kprintf("Failed to get the current iframe!\n");
6818342d4cdSIngo Weinhold return 0;
6828342d4cdSIngo Weinhold }
6838342d4cdSIngo Weinhold
6848342d4cdSIngo Weinhold frame->flags |= (1 << X86_EFLAGS_TF);
6858342d4cdSIngo Weinhold
6868342d4cdSIngo Weinhold return B_KDEBUG_QUIT;
6878342d4cdSIngo Weinhold }
6888342d4cdSIngo Weinhold
6898342d4cdSIngo Weinhold
690bc5f008aSIngo Weinhold #endif // KERNEL_BREAKPOINTS
691bc5f008aSIngo Weinhold
692bc5f008aSIngo Weinhold
693667f1eebSIngo Weinhold // #pragma mark - in-kernel public interface
694667f1eebSIngo Weinhold
695667f1eebSIngo Weinhold
6962d690920SAxel Dörfler void
arch_clear_team_debug_info(arch_team_debug_info * info)6978a190335SAlex Smith arch_clear_team_debug_info(arch_team_debug_info* info)
6982d690920SAxel Dörfler {
6992d690920SAxel Dörfler for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++)
7002d690920SAxel Dörfler info->breakpoints[i].address = NULL;
7012d690920SAxel Dörfler
7022d690920SAxel Dörfler info->dr7 = X86_BREAKPOINTS_DISABLED_DR7;
7032d690920SAxel Dörfler }
7042d690920SAxel Dörfler
7052d690920SAxel Dörfler
7062d690920SAxel Dörfler void
arch_destroy_team_debug_info(arch_team_debug_info * info)7078a190335SAlex Smith arch_destroy_team_debug_info(arch_team_debug_info* info)
7082d690920SAxel Dörfler {
7092d690920SAxel Dörfler arch_clear_team_debug_info(info);
7102d690920SAxel Dörfler }
7112d690920SAxel Dörfler
7122d690920SAxel Dörfler
7132d690920SAxel Dörfler void
arch_clear_thread_debug_info(arch_thread_debug_info * info)7148a190335SAlex Smith arch_clear_thread_debug_info(arch_thread_debug_info* info)
7152d690920SAxel Dörfler {
7162d690920SAxel Dörfler info->flags = 0;
7172d690920SAxel Dörfler }
7182d690920SAxel Dörfler
7192d690920SAxel Dörfler
7202d690920SAxel Dörfler void
arch_destroy_thread_debug_info(arch_thread_debug_info * info)7218a190335SAlex Smith arch_destroy_thread_debug_info(arch_thread_debug_info* info)
7222d690920SAxel Dörfler {
7232d690920SAxel Dörfler arch_clear_thread_debug_info(info);
7242d690920SAxel Dörfler }
7252d690920SAxel Dörfler
7262d690920SAxel Dörfler
7272d690920SAxel Dörfler void
arch_update_thread_single_step()72834b3b26bSIngo Weinhold arch_update_thread_single_step()
72934b3b26bSIngo Weinhold {
7308a190335SAlex Smith if (iframe* frame = x86_get_user_iframe()) {
7314535495dSIngo Weinhold Thread* thread = thread_get_current_thread();
73234b3b26bSIngo Weinhold
73313b81a3bSIngo Weinhold // set/clear TF in EFLAGS depending on whether single stepping is
73413b81a3bSIngo Weinhold // desired
73534b3b26bSIngo Weinhold if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP)
73634b3b26bSIngo Weinhold frame->flags |= (1 << X86_EFLAGS_TF);
73734b3b26bSIngo Weinhold else
73834b3b26bSIngo Weinhold frame->flags &= ~(1 << X86_EFLAGS_TF);
73934b3b26bSIngo Weinhold }
74034b3b26bSIngo Weinhold }
74134b3b26bSIngo Weinhold
74234b3b26bSIngo Weinhold
74334b3b26bSIngo Weinhold void
arch_set_debug_cpu_state(const debug_cpu_state * cpuState)7440b11ecb1SIngo Weinhold arch_set_debug_cpu_state(const debug_cpu_state* cpuState)
7452d690920SAxel Dörfler {
7468a190335SAlex Smith if (iframe* frame = x86_get_user_iframe()) {
7470b11ecb1SIngo Weinhold // For the floating point state to be correct the calling function must
7480b11ecb1SIngo Weinhold // not use these registers (not even indirectly).
749396b7422SPaweł Dziepak #ifdef __x86_64__
750396b7422SPaweł Dziepak Thread* thread = thread_get_current_thread();
751396b7422SPaweł Dziepak memcpy(thread->arch_info.fpu_state, &cpuState->extended_registers,
752396b7422SPaweł Dziepak sizeof(cpuState->extended_registers));
753396b7422SPaweł Dziepak frame->fpu = &thread->arch_info.fpu_state;
754396b7422SPaweł Dziepak #else
7550b11ecb1SIngo Weinhold if (gHasSSE) {
7560b11ecb1SIngo Weinhold // Since fxrstor requires 16-byte alignment and this isn't
7570b11ecb1SIngo Weinhold // guaranteed passed buffer, we use our thread's fpu_state field as
7580b11ecb1SIngo Weinhold // temporary buffer. We need to disable interrupts to make use of
7590b11ecb1SIngo Weinhold // it.
7604535495dSIngo Weinhold Thread* thread = thread_get_current_thread();
7610b11ecb1SIngo Weinhold InterruptsLocker locker;
7620b11ecb1SIngo Weinhold memcpy(thread->arch_info.fpu_state, &cpuState->extended_registers,
763b2acbcbfSMichael Lotz sizeof(cpuState->extended_registers));
7644304bb98SAlex Smith x86_fxrstor(thread->arch_info.fpu_state);
7650b11ecb1SIngo Weinhold } else {
7660b11ecb1SIngo Weinhold // TODO: Implement! We need to convert the format first.
7674304bb98SAlex Smith // x86_frstor(&cpuState->extended_registers);
7680b11ecb1SIngo Weinhold }
769396b7422SPaweł Dziepak #endif
7708a190335SAlex Smith set_iframe_registers(frame, cpuState);
7712d690920SAxel Dörfler }
7722d690920SAxel Dörfler }
7732d690920SAxel Dörfler
774667f1eebSIngo Weinhold
7752d690920SAxel Dörfler void
arch_get_debug_cpu_state(debug_cpu_state * cpuState)7760b11ecb1SIngo Weinhold arch_get_debug_cpu_state(debug_cpu_state* cpuState)
7772d690920SAxel Dörfler {
77899f00556SIngo Weinhold if (iframe* frame = x86_get_user_iframe())
77999f00556SIngo Weinhold get_cpu_state(thread_get_current_thread(), frame, cpuState);
780396b7422SPaweł Dziepak }
78199f00556SIngo Weinhold
78299f00556SIngo Weinhold
78399f00556SIngo Weinhold /*! \brief Retrieves the CPU state for the given thread.
78499f00556SIngo Weinhold The thread must not be running and the thread's scheduler spinlock must be
78599f00556SIngo Weinhold held.
78699f00556SIngo Weinhold \param thread The thread whose CPU state to retrieve.
78799f00556SIngo Weinhold \param cpuState Pointer to pre-allocated storage for the CPU state.
78899f00556SIngo Weinhold \return \c B_OK, if everything goes fine, another error code, if the CPU
78999f00556SIngo Weinhold state could not be retrieved.
79099f00556SIngo Weinhold */
79199f00556SIngo Weinhold status_t
arch_get_thread_debug_cpu_state(Thread * thread,debug_cpu_state * cpuState)79299f00556SIngo Weinhold arch_get_thread_debug_cpu_state(Thread* thread, debug_cpu_state* cpuState)
79399f00556SIngo Weinhold {
79499f00556SIngo Weinhold iframe* frame = x86_get_thread_user_iframe(thread);
79599f00556SIngo Weinhold if (frame == NULL)
79699f00556SIngo Weinhold return B_BAD_VALUE;
79799f00556SIngo Weinhold
79899f00556SIngo Weinhold get_cpu_state(thread, frame, cpuState);
79999f00556SIngo Weinhold return B_OK;
8002d690920SAxel Dörfler }
8012d690920SAxel Dörfler
8022d690920SAxel Dörfler
8032d690920SAxel Dörfler status_t
arch_set_breakpoint(void * address)8042d690920SAxel Dörfler arch_set_breakpoint(void* address)
8052d690920SAxel Dörfler {
8062d690920SAxel Dörfler return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
8072d690920SAxel Dörfler X86_BREAKPOINT_LENGTH_1);
8082d690920SAxel Dörfler }
8092d690920SAxel Dörfler
8102d690920SAxel Dörfler
8112d690920SAxel Dörfler status_t
arch_clear_breakpoint(void * address)8122d690920SAxel Dörfler arch_clear_breakpoint(void* address)
8132d690920SAxel Dörfler {
8142d690920SAxel Dörfler return clear_breakpoint(address, false);
8152d690920SAxel Dörfler }
8162d690920SAxel Dörfler
8172d690920SAxel Dörfler
8182d690920SAxel Dörfler status_t
arch_set_watchpoint(void * address,uint32 type,int32 length)8192d690920SAxel Dörfler arch_set_watchpoint(void* address, uint32 type, int32 length)
8202d690920SAxel Dörfler {
8218a190335SAlex Smith size_t archType, archLength;
822667f1eebSIngo Weinhold status_t error = check_watch_point_parameters(address, type, length,
823667f1eebSIngo Weinhold archType, archLength);
824667f1eebSIngo Weinhold if (error != B_OK)
825667f1eebSIngo Weinhold return error;
8262d690920SAxel Dörfler
8272d690920SAxel Dörfler return set_breakpoint(address, archType, archLength);
8282d690920SAxel Dörfler }
8292d690920SAxel Dörfler
8302d690920SAxel Dörfler
8312d690920SAxel Dörfler status_t
arch_clear_watchpoint(void * address)8322d690920SAxel Dörfler arch_clear_watchpoint(void* address)
8332d690920SAxel Dörfler {
834e40e5ebfSIngo Weinhold return clear_breakpoint(address, true);
8352d690920SAxel Dörfler }
8362d690920SAxel Dörfler
8372d690920SAxel Dörfler
83834b3b26bSIngo Weinhold bool
arch_has_breakpoints(arch_team_debug_info * info)8398a190335SAlex Smith arch_has_breakpoints(arch_team_debug_info* info)
84034b3b26bSIngo Weinhold {
84134b3b26bSIngo Weinhold // Reading info->dr7 is atomically, so we don't need to lock. The caller
84234b3b26bSIngo Weinhold // has to ensure, that the info doesn't go away.
84334b3b26bSIngo Weinhold return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7);
84434b3b26bSIngo Weinhold }
84534b3b26bSIngo Weinhold
84634b3b26bSIngo Weinhold
847667f1eebSIngo Weinhold #if KERNEL_BREAKPOINTS
8482d690920SAxel Dörfler
849667f1eebSIngo Weinhold status_t
arch_set_kernel_breakpoint(void * address)850667f1eebSIngo Weinhold arch_set_kernel_breakpoint(void* address)
851667f1eebSIngo Weinhold {
852667f1eebSIngo Weinhold status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
853667f1eebSIngo Weinhold X86_BREAKPOINT_LENGTH_1);
854667f1eebSIngo Weinhold
855667f1eebSIngo Weinhold if (error != B_OK) {
856667f1eebSIngo Weinhold panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s",
857667f1eebSIngo Weinhold strerror(error));
8582d690920SAxel Dörfler }
8592d690920SAxel Dörfler
860667f1eebSIngo Weinhold return error;
861667f1eebSIngo Weinhold }
862667f1eebSIngo Weinhold
863667f1eebSIngo Weinhold
864667f1eebSIngo Weinhold status_t
arch_clear_kernel_breakpoint(void * address)865667f1eebSIngo Weinhold arch_clear_kernel_breakpoint(void* address)
866667f1eebSIngo Weinhold {
867667f1eebSIngo Weinhold status_t error = clear_kernel_breakpoint(address, false);
868667f1eebSIngo Weinhold
869667f1eebSIngo Weinhold if (error != B_OK) {
870667f1eebSIngo Weinhold panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s",
871667f1eebSIngo Weinhold strerror(error));
872667f1eebSIngo Weinhold }
873667f1eebSIngo Weinhold
874667f1eebSIngo Weinhold return error;
875667f1eebSIngo Weinhold }
876667f1eebSIngo Weinhold
877667f1eebSIngo Weinhold
878667f1eebSIngo Weinhold status_t
arch_set_kernel_watchpoint(void * address,uint32 type,int32 length)879667f1eebSIngo Weinhold arch_set_kernel_watchpoint(void* address, uint32 type, int32 length)
880667f1eebSIngo Weinhold {
8818a190335SAlex Smith size_t archType, archLength;
882667f1eebSIngo Weinhold status_t error = check_watch_point_parameters(address, type, length,
883667f1eebSIngo Weinhold archType, archLength);
884667f1eebSIngo Weinhold
885667f1eebSIngo Weinhold if (error == B_OK)
886667f1eebSIngo Weinhold error = set_kernel_breakpoint(address, archType, archLength);
887667f1eebSIngo Weinhold
888667f1eebSIngo Weinhold if (error != B_OK) {
889667f1eebSIngo Weinhold panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s",
890667f1eebSIngo Weinhold strerror(error));
891667f1eebSIngo Weinhold }
892667f1eebSIngo Weinhold
893667f1eebSIngo Weinhold return error;
894667f1eebSIngo Weinhold }
895667f1eebSIngo Weinhold
896667f1eebSIngo Weinhold
897667f1eebSIngo Weinhold status_t
arch_clear_kernel_watchpoint(void * address)898667f1eebSIngo Weinhold arch_clear_kernel_watchpoint(void* address)
899667f1eebSIngo Weinhold {
900667f1eebSIngo Weinhold status_t error = clear_kernel_breakpoint(address, true);
901667f1eebSIngo Weinhold
902667f1eebSIngo Weinhold if (error != B_OK) {
903667f1eebSIngo Weinhold panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s",
904667f1eebSIngo Weinhold strerror(error));
905667f1eebSIngo Weinhold }
906667f1eebSIngo Weinhold
907667f1eebSIngo Weinhold return error;
908667f1eebSIngo Weinhold }
909667f1eebSIngo Weinhold
910667f1eebSIngo Weinhold #endif // KERNEL_BREAKPOINTS
911667f1eebSIngo Weinhold
912667f1eebSIngo Weinhold
913667f1eebSIngo Weinhold // #pragma mark - x86 implementation interface
914667f1eebSIngo Weinhold
9152d690920SAxel Dörfler
9162d690920SAxel Dörfler /**
9178ad4a2e9SIngo Weinhold * Interrupts are disabled. \a frame is unused, i.e. can be \c NULL.
9182d690920SAxel Dörfler */
9192d690920SAxel Dörfler void
x86_init_user_debug_at_kernel_exit(iframe * frame)9208a190335SAlex Smith x86_init_user_debug_at_kernel_exit(iframe* frame)
9212d690920SAxel Dörfler {
9224535495dSIngo Weinhold Thread* thread = thread_get_current_thread();
9232d690920SAxel Dörfler
92434b3b26bSIngo Weinhold if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED))
92534b3b26bSIngo Weinhold return;
926b4476702SIngo Weinhold
927b4476702SIngo Weinhold // disable kernel breakpoints
928b4476702SIngo Weinhold disable_breakpoints();
92934b3b26bSIngo Weinhold
93024df6592SIngo Weinhold // install the user breakpoints
9312d690920SAxel Dörfler GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
9322d690920SAxel Dörfler
9332d690920SAxel Dörfler arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info;
9342d690920SAxel Dörfler
9352d690920SAxel Dörfler install_breakpoints(teamInfo);
9362d690920SAxel Dörfler
93734b3b26bSIngo Weinhold atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED);
9382d690920SAxel Dörfler
9392d690920SAxel Dörfler RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
9402d690920SAxel Dörfler }
9412d690920SAxel Dörfler
9422d690920SAxel Dörfler
9432d690920SAxel Dörfler /**
94434b3b26bSIngo Weinhold * Interrupts are disabled.
9452d690920SAxel Dörfler */
9462d690920SAxel Dörfler void
x86_exit_user_debug_at_kernel_entry()94734b3b26bSIngo Weinhold x86_exit_user_debug_at_kernel_entry()
9482d690920SAxel Dörfler {
9494535495dSIngo Weinhold Thread* thread = thread_get_current_thread();
9502d690920SAxel Dörfler
951feddedabSIngo Weinhold // We need to save the current values of dr6 and dr7 in the CPU structure,
952feddedabSIngo Weinhold // since in case of a debug exception we might overwrite them before
95313b81a3bSIngo Weinhold // x86_handle_debug_exception() is called. Debug exceptions occur when
95413b81a3bSIngo Weinhold // hitting a hardware break/watchpoint or when single-stepping.
9558a190335SAlex Smith asm("mov %%dr6, %0" : "=r"(thread->cpu->arch.dr6));
9568a190335SAlex Smith asm("mov %%dr7, %0" : "=r"(thread->cpu->arch.dr7));
957feddedabSIngo Weinhold
95813b81a3bSIngo Weinhold // The remainder needs only be done, when user breakpoints are installed.
95913b81a3bSIngo Weinhold if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED))
96013b81a3bSIngo Weinhold return;
96113b81a3bSIngo Weinhold
962b4476702SIngo Weinhold // disable user breakpoints
963667f1eebSIngo Weinhold disable_breakpoints();
9642d690920SAxel Dörfler
965b4476702SIngo Weinhold // install kernel breakpoints
9664535495dSIngo Weinhold Team* kernelTeam = team_get_kernel_team();
96724df6592SIngo Weinhold
968667f1eebSIngo Weinhold GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
96924df6592SIngo Weinhold
970667f1eebSIngo Weinhold install_breakpoints(kernelTeam->debug_info.arch_info);
971667f1eebSIngo Weinhold
97234b3b26bSIngo Weinhold atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED);
97334b3b26bSIngo Weinhold
97424df6592SIngo Weinhold RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
9752d690920SAxel Dörfler }
9762d690920SAxel Dörfler
9772d690920SAxel Dörfler
9782d690920SAxel Dörfler /**
979b4476702SIngo Weinhold * Interrupts are disabled and will possibly be enabled by the function.
9802d690920SAxel Dörfler */
98134b3b26bSIngo Weinhold void
x86_handle_debug_exception(iframe * frame)9828a190335SAlex Smith x86_handle_debug_exception(iframe* frame)
9832d690920SAxel Dörfler {
9844535495dSIngo Weinhold Thread* thread = thread_get_current_thread();
98545538a5eSIngo Weinhold
98645538a5eSIngo Weinhold // Get dr6 and dr7. If the given iframe is a userland frame, the exception
98745538a5eSIngo Weinhold // obviously occurred in userland. In that case
98845538a5eSIngo Weinhold // x86_exit_user_debug_at_kernel_entry() has already been invoked and dr6
98945538a5eSIngo Weinhold // and dr7 are stored in the cpu info. Otherwise we need to fetch the
99045538a5eSIngo Weinhold // current values from the registers.
9918a190335SAlex Smith size_t dr6;
9928a190335SAlex Smith size_t dr7;
99345538a5eSIngo Weinhold if (IFRAME_IS_USER(frame)) {
99445538a5eSIngo Weinhold dr6 = thread->cpu->arch.dr6;
99545538a5eSIngo Weinhold dr7 = thread->cpu->arch.dr7;
99645538a5eSIngo Weinhold } else {
9978a190335SAlex Smith asm("mov %%dr6, %0" : "=r"(dr6));
9988a190335SAlex Smith asm("mov %%dr7, %0" : "=r"(dr7));
99945538a5eSIngo Weinhold }
10002d690920SAxel Dörfler
10015e9bb17dSAlex Smith TRACE(("x86_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7));
10022d690920SAxel Dörfler
10032d690920SAxel Dörfler // check, which exception condition applies
10042d690920SAxel Dörfler if (dr6 & X86_DR6_BREAKPOINT_MASK) {
10052d690920SAxel Dörfler // breakpoint
10062d690920SAxel Dörfler
10072d690920SAxel Dörfler // check which breakpoint was taken
10082d690920SAxel Dörfler bool watchpoint = true;
10092d690920SAxel Dörfler for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
10102d690920SAxel Dörfler if (dr6 & (1 << sDR6B[i])) {
10118a190335SAlex Smith size_t type = (dr7 >> sDR7RW[i]) & 0x3;
1012568ade58SIngo Weinhold if (type == X86_INSTRUCTION_BREAKPOINT)
10132d690920SAxel Dörfler watchpoint = false;
10142d690920SAxel Dörfler }
10152d690920SAxel Dörfler }
10162d690920SAxel Dörfler
10178753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) {
10182d690920SAxel Dörfler // enable interrupts and notify the debugger
10192d690920SAxel Dörfler enable_interrupts();
10202d690920SAxel Dörfler
10212d690920SAxel Dörfler if (watchpoint)
10222d690920SAxel Dörfler user_debug_watchpoint_hit();
10232d690920SAxel Dörfler else
10242d690920SAxel Dörfler user_debug_breakpoint_hit(false);
10258753babdSIngo Weinhold } else {
10268753babdSIngo Weinhold panic("hit kernel %spoint: dr6: 0x%lx, dr7: 0x%lx",
10278753babdSIngo Weinhold watchpoint ? "watch" : "break", dr6, dr7);
10288753babdSIngo Weinhold }
10292d690920SAxel Dörfler } else if (dr6 & (1 << X86_DR6_BD)) {
10302d690920SAxel Dörfler // general detect exception
10312d690920SAxel Dörfler // Occurs only, if GD in DR7 is set (which we don't do) and someone
10322d690920SAxel Dörfler // tries to write to the debug registers.
10338753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) {
10345e9bb17dSAlex Smith dprintf("x86_handle_debug_exception(): ignoring spurious general "
10352d690920SAxel Dörfler "detect exception\n");
10362d690920SAxel Dörfler
10372d690920SAxel Dörfler enable_interrupts();
10388753babdSIngo Weinhold } else
10398753babdSIngo Weinhold panic("spurious general detect exception in kernel mode");
10402d690920SAxel Dörfler } else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) {
10412d690920SAxel Dörfler // single step
10422d690920SAxel Dörfler
10438753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) {
10442d690920SAxel Dörfler // enable interrupts and notify the debugger
10452d690920SAxel Dörfler enable_interrupts();
10462d690920SAxel Dörfler
10472d690920SAxel Dörfler user_debug_single_stepped();
10488342d4cdSIngo Weinhold } else {
10498342d4cdSIngo Weinhold // Disable single-stepping -- the next "step" command will re-enable
10508342d4cdSIngo Weinhold // it, but we don't want it when continuing otherwise.
10518342d4cdSIngo Weinhold frame->flags &= ~(1 << X86_EFLAGS_TF);
10528342d4cdSIngo Weinhold
10538b3d3d8aSIngo Weinhold // Determine whether the exception occurred at a syscall/trap
10548b3d3d8aSIngo Weinhold // kernel entry or whether this is genuine kernel single-stepping.
10558b3d3d8aSIngo Weinhold bool inKernel = true;
10568b3d3d8aSIngo Weinhold if (thread->team != team_get_kernel_team()
10575e9bb17dSAlex Smith && x86_get_user_iframe() == NULL) {
10588b3d3d8aSIngo Weinhold // TODO: This is not yet fully correct, since a newly created
105913b81a3bSIngo Weinhold // thread that hasn't entered userland yet also has this
10608b3d3d8aSIngo Weinhold // property.
10618b3d3d8aSIngo Weinhold inKernel = false;
10628b3d3d8aSIngo Weinhold }
10638b3d3d8aSIngo Weinhold
10648b3d3d8aSIngo Weinhold if (inKernel) {
10658753babdSIngo Weinhold panic("kernel single step");
10668b3d3d8aSIngo Weinhold } else {
10678b3d3d8aSIngo Weinhold // The thread is a userland thread and it just entered the
10688b3d3d8aSIngo Weinhold // kernel when the single-step exception occurred. This happens
10698b3d3d8aSIngo Weinhold // e.g. when sysenter is called with single-stepping enabled.
10708b3d3d8aSIngo Weinhold // We need to ignore the exception now and send a single-step
10718b3d3d8aSIngo Weinhold // notification later, when the thread wants to return from the
10728b3d3d8aSIngo Weinhold // kernel.
107324df6592SIngo Weinhold InterruptsSpinLocker threadDebugInfoLocker(
107424df6592SIngo Weinhold thread->debug_info.lock);
10758b3d3d8aSIngo Weinhold
10768b3d3d8aSIngo Weinhold // Check whether the team is still being debugged and set
10778b3d3d8aSIngo Weinhold // the B_THREAD_DEBUG_NOTIFY_SINGLE_STEP and
10788b3d3d8aSIngo Weinhold // B_THREAD_DEBUG_STOP flags, so that the thread will be
10798b3d3d8aSIngo Weinhold // stopped when it is going to leave the kernel and notify the
10808b3d3d8aSIngo Weinhold // debugger about the single-step event.
10818b3d3d8aSIngo Weinhold int32 teamDebugFlags
10828b3d3d8aSIngo Weinhold = atomic_get(&thread->team->debug_info.flags);
10838b3d3d8aSIngo Weinhold if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
10848b3d3d8aSIngo Weinhold atomic_or(&thread->debug_info.flags,
10858b3d3d8aSIngo Weinhold B_THREAD_DEBUG_NOTIFY_SINGLE_STEP
10868b3d3d8aSIngo Weinhold | B_THREAD_DEBUG_STOP);
108713b81a3bSIngo Weinhold
108813b81a3bSIngo Weinhold // also set the respective thread flag
108913b81a3bSIngo Weinhold atomic_or(&thread->flags, THREAD_FLAGS_DEBUG_THREAD);
10908b3d3d8aSIngo Weinhold }
10918b3d3d8aSIngo Weinhold }
10928342d4cdSIngo Weinhold }
10932d690920SAxel Dörfler } else if (dr6 & (1 << X86_DR6_BT)) {
10942d690920SAxel Dörfler // task switch
10952d690920SAxel Dörfler // Occurs only, if T in EFLAGS is set (which we don't do).
10968753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) {
10975e9bb17dSAlex Smith dprintf("x86_handle_debug_exception(): ignoring spurious task switch "
10982d690920SAxel Dörfler "exception\n");
10992d690920SAxel Dörfler
11002d690920SAxel Dörfler enable_interrupts();
11018753babdSIngo Weinhold } else
11028753babdSIngo Weinhold panic("spurious task switch exception in kernel mode");
11032d690920SAxel Dörfler } else {
11048753babdSIngo Weinhold if (IFRAME_IS_USER(frame)) {
11055e9bb17dSAlex Smith TRACE(("x86_handle_debug_exception(): ignoring spurious debug "
110606be24a7SAxel Dörfler "exception (no condition recognized)\n"));
11072d690920SAxel Dörfler
11082d690920SAxel Dörfler enable_interrupts();
11098753babdSIngo Weinhold } else {
11108753babdSIngo Weinhold panic("spurious debug exception in kernel mode (no condition "
11118753babdSIngo Weinhold "recognized)");
11128753babdSIngo Weinhold }
11132d690920SAxel Dörfler }
11142d690920SAxel Dörfler }
11152d690920SAxel Dörfler
11162d690920SAxel Dörfler
11172d690920SAxel Dörfler /**
1118b4476702SIngo Weinhold * Interrupts are disabled and will possibly be enabled by the function.
11192d690920SAxel Dörfler */
112034b3b26bSIngo Weinhold void
x86_handle_breakpoint_exception(iframe * frame)11218a190335SAlex Smith x86_handle_breakpoint_exception(iframe* frame)
11222d690920SAxel Dörfler {
11235e9bb17dSAlex Smith TRACE(("x86_handle_breakpoint_exception()\n"));
11242d690920SAxel Dörfler
1125b0f12d64SIngo Weinhold // reset eip to the int3 instruction
1126b5c9d24aSAlex Smith frame->ip--;
1127b0f12d64SIngo Weinhold
1128bb107c4eSAxel Dörfler if (!IFRAME_IS_USER(frame)) {
1129667f1eebSIngo Weinhold panic("breakpoint exception in kernel mode");
113034b3b26bSIngo Weinhold return;
1131667f1eebSIngo Weinhold }
1132667f1eebSIngo Weinhold
11332d690920SAxel Dörfler enable_interrupts();
11342d690920SAxel Dörfler
11352d690920SAxel Dörfler user_debug_breakpoint_hit(true);
11362d690920SAxel Dörfler }
11372d690920SAxel Dörfler
11382d690920SAxel Dörfler
11392d690920SAxel Dörfler void
x86_init_user_debug()114034b3b26bSIngo Weinhold x86_init_user_debug()
11412d690920SAxel Dörfler {
11422d690920SAxel Dörfler // get debug settings
11432d690920SAxel Dörfler if (void* handle = load_driver_settings("kernel")) {
11442d690920SAxel Dörfler sQEmuSingleStepHack = get_driver_boolean_parameter(handle,
11452d690920SAxel Dörfler "qemu_single_step_hack", false, false);;
11462d690920SAxel Dörfler
11472d690920SAxel Dörfler unload_driver_settings(handle);
11482d690920SAxel Dörfler }
1149bc5f008aSIngo Weinhold
1150bc5f008aSIngo Weinhold #if KERNEL_BREAKPOINTS
1151bc5f008aSIngo Weinhold // install debugger commands
11528342d4cdSIngo Weinhold add_debugger_command_etc("breakpoints", &debugger_breakpoints,
11538342d4cdSIngo Weinhold "Lists current break-/watchpoints",
11548342d4cdSIngo Weinhold "\n"
11558342d4cdSIngo Weinhold "Lists the current kernel break-/watchpoints.\n", 0);
11568342d4cdSIngo Weinhold add_debugger_command_alias("watchpoints", "breakpoints", NULL);
11578342d4cdSIngo Weinhold add_debugger_command_etc("breakpoint", &debugger_breakpoint,
11588342d4cdSIngo Weinhold "Set/clears a breakpoint",
11598342d4cdSIngo Weinhold "<address> [ clear ]\n"
11608342d4cdSIngo Weinhold "Sets respectively clears the breakpoint at address <address>.\n", 0);
11618342d4cdSIngo Weinhold add_debugger_command_etc("watchpoint", &debugger_watchpoint,
11628342d4cdSIngo Weinhold "Set/clears a watchpoint",
11638342d4cdSIngo Weinhold "<address> <address> ( [ rw ] [ <size> ] | clear )\n"
11648342d4cdSIngo Weinhold "Sets respectively clears the watchpoint at address <address>.\n"
11658342d4cdSIngo Weinhold "If \"rw\" is given the new watchpoint is a read/write watchpoint\n"
11668342d4cdSIngo Weinhold "otherwise a write watchpoint only.\n", 0);
11678342d4cdSIngo Weinhold add_debugger_command_etc("step", &debugger_single_step,
11688342d4cdSIngo Weinhold "Single-steps to the next instruction",
11698342d4cdSIngo Weinhold "\n"
11708342d4cdSIngo Weinhold "Single-steps to the next instruction.\n", 0);
1171bc5f008aSIngo Weinhold #endif
11722d690920SAxel Dörfler }
11732d690920SAxel Dörfler
1174