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