xref: /haiku/src/system/kernel/arch/x86/arch_user_debugger.cpp (revision 6f3a5c9ab0c2f388ef0ff6efff713732a710cd93)
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