xref: /haiku/src/system/kernel/arch/x86/arch_user_debugger.cpp (revision feddedab0ca4fa1c553af10a3ed6066a840d0bea)
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 
60b11ecb1SIngo Weinhold 
7667f1eebSIngo Weinhold #include <arch/user_debugger.h>
8667f1eebSIngo Weinhold 
92d690920SAxel Dörfler #include <string.h>
102d690920SAxel Dörfler 
112d690920SAxel Dörfler #include <debugger.h>
122d690920SAxel Dörfler #include <driver_settings.h>
132d690920SAxel Dörfler #include <int.h>
14667f1eebSIngo Weinhold #include <team.h>
152d690920SAxel Dörfler #include <thread.h>
160b11ecb1SIngo Weinhold #include <util/AutoLock.h>
17667f1eebSIngo Weinhold 
182d690920SAxel Dörfler 
192d690920SAxel Dörfler //#define TRACE_ARCH_USER_DEBUGGER
202d690920SAxel Dörfler #ifdef TRACE_ARCH_USER_DEBUGGER
212d690920SAxel Dörfler #	define TRACE(x) dprintf x
222d690920SAxel Dörfler #else
232d690920SAxel Dörfler #	define TRACE(x) ;
242d690920SAxel Dörfler #endif
252d690920SAxel Dörfler 
26667f1eebSIngo Weinhold #define B_NO_MORE_BREAKPOINTS				B_BUSY
27667f1eebSIngo Weinhold #define B_NO_MORE_WATCHPOINTS				B_BUSY
28667f1eebSIngo Weinhold #define B_BAD_WATCHPOINT_ALIGNMENT			B_BAD_VALUE
29667f1eebSIngo Weinhold #define B_WATCHPOINT_TYPE_NOT_SUPPORTED		B_NOT_SUPPORTED
30667f1eebSIngo Weinhold #define B_WATCHPOINT_LENGTH_NOT_SUPPORTED	B_NOT_SUPPORTED
31667f1eebSIngo Weinhold #define B_BREAKPOINT_NOT_FOUND				B_NAME_NOT_FOUND
32667f1eebSIngo Weinhold #define B_WATCHPOINT_NOT_FOUND				B_NAME_NOT_FOUND
330b11ecb1SIngo Weinhold 	// TODO: Make those real error codes.
340b11ecb1SIngo Weinhold 
350b11ecb1SIngo Weinhold 
360b11ecb1SIngo Weinhold extern bool gHasSSE;
372d690920SAxel Dörfler 
38b0f12d64SIngo Weinhold // The software breakpoint instruction (int3).
39b0f12d64SIngo Weinhold const uint8 kX86SoftwareBreakpoint[1] = { 0xcc };
40b0f12d64SIngo Weinhold 
412d690920SAxel Dörfler // maps breakpoint slot index to LEN_i LSB number
422d690920SAxel Dörfler static const uint32 sDR7Len[4] = {
432d690920SAxel Dörfler 	X86_DR7_LEN0_LSB, X86_DR7_LEN1_LSB, X86_DR7_LEN2_LSB, X86_DR7_LEN3_LSB
442d690920SAxel Dörfler };
452d690920SAxel Dörfler 
462d690920SAxel Dörfler // maps breakpoint slot index to R/W_i LSB number
472d690920SAxel Dörfler static const uint32 sDR7RW[4] = {
482d690920SAxel Dörfler 	X86_DR7_RW0_LSB, X86_DR7_RW1_LSB, X86_DR7_RW2_LSB, X86_DR7_RW3_LSB
492d690920SAxel Dörfler };
502d690920SAxel Dörfler 
512d690920SAxel Dörfler // maps breakpoint slot index to L_i bit number
522d690920SAxel Dörfler static const uint32 sDR7L[4] = {
532d690920SAxel Dörfler 	X86_DR7_L0, X86_DR7_L1, X86_DR7_L2, X86_DR7_L3
542d690920SAxel Dörfler };
552d690920SAxel Dörfler 
56667f1eebSIngo Weinhold // maps breakpoint slot index to G_i bit number
57667f1eebSIngo Weinhold static const uint32 sDR7G[4] = {
58667f1eebSIngo Weinhold 	X86_DR7_G0, X86_DR7_G1, X86_DR7_G2, X86_DR7_G3
59667f1eebSIngo Weinhold };
60667f1eebSIngo Weinhold 
612d690920SAxel Dörfler // maps breakpoint slot index to B_i bit number
622d690920SAxel Dörfler static const uint32 sDR6B[4] = {
632d690920SAxel Dörfler 	X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3
642d690920SAxel Dörfler };
652d690920SAxel Dörfler 
662d690920SAxel Dörfler // Enables a hack to make single stepping work under qemu. Set via kernel
672d690920SAxel Dörfler // driver settings.
682d690920SAxel Dörfler static bool sQEmuSingleStepHack = false;
692d690920SAxel Dörfler 
702d690920SAxel Dörfler 
71568ade58SIngo Weinhold static void
720b11ecb1SIngo Weinhold get_iframe_registers(struct iframe *frame, debug_cpu_state *cpuState)
73568ade58SIngo Weinhold {
74568ade58SIngo Weinhold 	cpuState->gs = frame->gs;
75568ade58SIngo Weinhold 	cpuState->fs = frame->fs;
76568ade58SIngo Weinhold 	cpuState->es = frame->es;
77568ade58SIngo Weinhold 	cpuState->ds = frame->ds;
78568ade58SIngo Weinhold 	cpuState->edi = frame->edi;
79568ade58SIngo Weinhold 	cpuState->esi = frame->esi;
80568ade58SIngo Weinhold 	cpuState->ebp = frame->ebp;
81568ade58SIngo Weinhold 	cpuState->esp = frame->esp;
82568ade58SIngo Weinhold 	cpuState->ebx = frame->ebx;
83568ade58SIngo Weinhold 	cpuState->edx = frame->orig_edx;
84568ade58SIngo Weinhold 	cpuState->ecx = frame->ecx;
85568ade58SIngo Weinhold 	cpuState->eax = frame->orig_eax;
86568ade58SIngo Weinhold 	cpuState->vector = frame->vector;
87568ade58SIngo Weinhold 	cpuState->error_code = frame->error_code;
88568ade58SIngo Weinhold 	cpuState->eip = frame->eip;
89568ade58SIngo Weinhold 	cpuState->cs = frame->cs;
90568ade58SIngo Weinhold 	cpuState->eflags = frame->flags;
91568ade58SIngo Weinhold 	cpuState->user_esp = frame->user_esp;
92568ade58SIngo Weinhold 	cpuState->user_ss = frame->user_ss;
93568ade58SIngo Weinhold }
94568ade58SIngo Weinhold 
95568ade58SIngo Weinhold 
96667f1eebSIngo Weinhold static inline void
97667f1eebSIngo Weinhold install_breakpoints(const arch_team_debug_info &teamInfo)
98667f1eebSIngo Weinhold {
99667f1eebSIngo Weinhold 	// set breakpoints
100667f1eebSIngo Weinhold 	asm("movl %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address));
101667f1eebSIngo Weinhold 	asm("movl %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address));
102667f1eebSIngo Weinhold 	asm("movl %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address));
103667f1eebSIngo Weinhold //	asm("movl %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address));
104667f1eebSIngo Weinhold 		// DR3 is used to hold the current struct thread*.
105667f1eebSIngo Weinhold 
106667f1eebSIngo Weinhold 	// enable breakpoints
107667f1eebSIngo Weinhold 	asm("movl %0, %%dr7" : : "r"(teamInfo.dr7));
108667f1eebSIngo Weinhold }
109667f1eebSIngo Weinhold 
110667f1eebSIngo Weinhold 
111667f1eebSIngo Weinhold static inline void
112667f1eebSIngo Weinhold disable_breakpoints()
113667f1eebSIngo Weinhold {
114667f1eebSIngo Weinhold 	asm("movl %0, %%dr7" : : "r"(X86_BREAKPOINTS_DISABLED_DR7));
115667f1eebSIngo Weinhold }
116667f1eebSIngo Weinhold 
117667f1eebSIngo Weinhold 
118667f1eebSIngo Weinhold /*! Sets a break-/watchpoint in the given team info.
119667f1eebSIngo Weinhold 	Interrupts must be disabled and the team debug info lock be held.
120667f1eebSIngo Weinhold */
121667f1eebSIngo Weinhold static inline status_t
122667f1eebSIngo Weinhold set_breakpoint(arch_team_debug_info &info, void *address, uint32 type,
123667f1eebSIngo Weinhold 	uint32 length, bool setGlobalFlag)
124667f1eebSIngo Weinhold {
125667f1eebSIngo Weinhold 	// check, if there is already a breakpoint at that address
126667f1eebSIngo Weinhold 	bool alreadySet = false;
127667f1eebSIngo Weinhold 	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
128667f1eebSIngo Weinhold 		if (info.breakpoints[i].address == address
129667f1eebSIngo Weinhold 			&& info.breakpoints[i].type == type) {
130667f1eebSIngo Weinhold 			alreadySet = true;
131667f1eebSIngo Weinhold 			break;
132667f1eebSIngo Weinhold 		}
133667f1eebSIngo Weinhold 	}
134667f1eebSIngo Weinhold 
135667f1eebSIngo Weinhold 	if (!alreadySet) {
136667f1eebSIngo Weinhold 		// find a free slot
137667f1eebSIngo Weinhold 		int32 slot = -1;
138667f1eebSIngo Weinhold 		for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
139667f1eebSIngo Weinhold 			if (!info.breakpoints[i].address) {
140667f1eebSIngo Weinhold 				slot = i;
141667f1eebSIngo Weinhold 				break;
142667f1eebSIngo Weinhold 			}
143667f1eebSIngo Weinhold 		}
144667f1eebSIngo Weinhold 
145667f1eebSIngo Weinhold 		// init the breakpoint
146667f1eebSIngo Weinhold 		if (slot >= 0) {
147667f1eebSIngo Weinhold 			info.breakpoints[slot].address = address;
148667f1eebSIngo Weinhold 			info.breakpoints[slot].type = type;
149667f1eebSIngo Weinhold 			info.breakpoints[slot].length = length;
150667f1eebSIngo Weinhold 
151667f1eebSIngo Weinhold 			info.dr7 |= (length << sDR7Len[slot])
152667f1eebSIngo Weinhold 				| (type << sDR7RW[slot])
153667f1eebSIngo Weinhold 				| (1 << sDR7L[slot]);
154667f1eebSIngo Weinhold 			if (setGlobalFlag)
155667f1eebSIngo Weinhold 				info.dr7 |= (1 << sDR7G[slot]);
156667f1eebSIngo Weinhold 		} else {
157667f1eebSIngo Weinhold 			if (type == X86_INSTRUCTION_BREAKPOINT)
158667f1eebSIngo Weinhold 				return B_NO_MORE_BREAKPOINTS;
159667f1eebSIngo Weinhold 			else
160667f1eebSIngo Weinhold 				return B_NO_MORE_WATCHPOINTS;
161667f1eebSIngo Weinhold 		}
162667f1eebSIngo Weinhold 	}
163667f1eebSIngo Weinhold 
164667f1eebSIngo Weinhold 	return B_OK;
165667f1eebSIngo Weinhold }
166667f1eebSIngo Weinhold 
167667f1eebSIngo Weinhold 
168667f1eebSIngo Weinhold /*! Clears a break-/watchpoint in the given team info.
169667f1eebSIngo Weinhold 	Interrupts must be disabled and the team debug info lock be held.
170667f1eebSIngo Weinhold */
171667f1eebSIngo Weinhold static inline status_t
172667f1eebSIngo Weinhold clear_breakpoint(arch_team_debug_info &info, void *address, bool watchpoint)
173667f1eebSIngo Weinhold {
174667f1eebSIngo Weinhold 	// find the breakpoint
175667f1eebSIngo Weinhold 	int32 slot = -1;
176667f1eebSIngo Weinhold 	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
177667f1eebSIngo Weinhold 		if (info.breakpoints[i].address == address
178667f1eebSIngo Weinhold 			&& (watchpoint
179667f1eebSIngo Weinhold 				!= (info.breakpoints[i].type == X86_INSTRUCTION_BREAKPOINT))) {
180667f1eebSIngo Weinhold 			slot = i;
181667f1eebSIngo Weinhold 			break;
182667f1eebSIngo Weinhold 		}
183667f1eebSIngo Weinhold 	}
184667f1eebSIngo Weinhold 
185667f1eebSIngo Weinhold 	// clear the breakpoint
186667f1eebSIngo Weinhold 	if (slot >= 0) {
187667f1eebSIngo Weinhold 		info.breakpoints[slot].address = NULL;
188667f1eebSIngo Weinhold 
189667f1eebSIngo Weinhold 		info.dr7 &= ~((0x3 << sDR7Len[slot])
190667f1eebSIngo Weinhold 			| (0x3 << sDR7RW[slot])
191667f1eebSIngo Weinhold 			| (1 << sDR7L[slot])
192667f1eebSIngo Weinhold 			| (1 << sDR7G[slot]));
193667f1eebSIngo Weinhold 	} else {
194667f1eebSIngo Weinhold 		if (watchpoint)
195667f1eebSIngo Weinhold 			return B_WATCHPOINT_NOT_FOUND;
196667f1eebSIngo Weinhold 		else
197667f1eebSIngo Weinhold 			return B_BREAKPOINT_NOT_FOUND;
198667f1eebSIngo Weinhold 	}
199667f1eebSIngo Weinhold 
200667f1eebSIngo Weinhold 	return B_OK;
201667f1eebSIngo Weinhold }
202667f1eebSIngo Weinhold 
203667f1eebSIngo Weinhold 
204667f1eebSIngo Weinhold static status_t
205667f1eebSIngo Weinhold set_breakpoint(void *address, uint32 type, uint32 length)
206667f1eebSIngo Weinhold {
207667f1eebSIngo Weinhold 	if (!address)
208667f1eebSIngo Weinhold 		return B_BAD_VALUE;
209667f1eebSIngo Weinhold 
210667f1eebSIngo Weinhold 	struct thread *thread = thread_get_current_thread();
211667f1eebSIngo Weinhold 
212667f1eebSIngo Weinhold 	cpu_status state = disable_interrupts();
213667f1eebSIngo Weinhold 	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
214667f1eebSIngo Weinhold 
215667f1eebSIngo Weinhold 	status_t error = set_breakpoint(thread->team->debug_info.arch_info, address,
216667f1eebSIngo Weinhold 		type, length, false);
217667f1eebSIngo Weinhold 
218667f1eebSIngo Weinhold 	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
219667f1eebSIngo Weinhold 	restore_interrupts(state);
220667f1eebSIngo Weinhold 
221667f1eebSIngo Weinhold 	return error;
222667f1eebSIngo Weinhold }
223667f1eebSIngo Weinhold 
224667f1eebSIngo Weinhold 
225667f1eebSIngo Weinhold static status_t
226667f1eebSIngo Weinhold clear_breakpoint(void *address, bool watchpoint)
227667f1eebSIngo Weinhold {
228667f1eebSIngo Weinhold 	if (!address)
229667f1eebSIngo Weinhold 		return B_BAD_VALUE;
230667f1eebSIngo Weinhold 
231667f1eebSIngo Weinhold 	struct thread *thread = thread_get_current_thread();
232667f1eebSIngo Weinhold 
233667f1eebSIngo Weinhold 	cpu_status state = disable_interrupts();
234667f1eebSIngo Weinhold 	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
235667f1eebSIngo Weinhold 
236667f1eebSIngo Weinhold 	status_t error = clear_breakpoint(thread->team->debug_info.arch_info,
237667f1eebSIngo Weinhold 		address, watchpoint);
238667f1eebSIngo Weinhold 
239667f1eebSIngo Weinhold 	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
240667f1eebSIngo Weinhold 	restore_interrupts(state);
241667f1eebSIngo Weinhold 
242667f1eebSIngo Weinhold 	return error;
243667f1eebSIngo Weinhold }
244667f1eebSIngo Weinhold 
245667f1eebSIngo Weinhold 
246667f1eebSIngo Weinhold #if KERNEL_BREAKPOINTS
247667f1eebSIngo Weinhold 
24831d9352fSIngo Weinhold 
24931d9352fSIngo Weinhold static void
25031d9352fSIngo Weinhold install_breakpoints_per_cpu(void* /*cookie*/, int cpu)
25131d9352fSIngo Weinhold {
25231d9352fSIngo Weinhold 	struct team* kernelTeam = team_get_kernel_team();
25331d9352fSIngo Weinhold 
25431d9352fSIngo Weinhold 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
25531d9352fSIngo Weinhold 
25631d9352fSIngo Weinhold 	install_breakpoints(kernelTeam->debug_info.arch_info);
25731d9352fSIngo Weinhold 
25831d9352fSIngo Weinhold 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
25931d9352fSIngo Weinhold }
26031d9352fSIngo Weinhold 
26131d9352fSIngo Weinhold 
262667f1eebSIngo Weinhold static status_t
263667f1eebSIngo Weinhold set_kernel_breakpoint(void *address, uint32 type, uint32 length)
264667f1eebSIngo Weinhold {
265667f1eebSIngo Weinhold 	if (!address)
266667f1eebSIngo Weinhold 		return B_BAD_VALUE;
267667f1eebSIngo Weinhold 
268667f1eebSIngo Weinhold 	struct team* kernelTeam = team_get_kernel_team();
269667f1eebSIngo Weinhold 
270667f1eebSIngo Weinhold 	cpu_status state = disable_interrupts();
271667f1eebSIngo Weinhold 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
272667f1eebSIngo Weinhold 
273667f1eebSIngo Weinhold 	status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address,
274667f1eebSIngo Weinhold 		type, length, true);
275667f1eebSIngo Weinhold 
276667f1eebSIngo Weinhold 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
27731d9352fSIngo Weinhold 
27831d9352fSIngo Weinhold 	call_all_cpus(install_breakpoints_per_cpu, NULL);
27931d9352fSIngo Weinhold 
280667f1eebSIngo Weinhold 	restore_interrupts(state);
281667f1eebSIngo Weinhold 
282667f1eebSIngo Weinhold 	return error;
283667f1eebSIngo Weinhold }
284667f1eebSIngo Weinhold 
285667f1eebSIngo Weinhold 
286667f1eebSIngo Weinhold static status_t
287667f1eebSIngo Weinhold clear_kernel_breakpoint(void *address, bool watchpoint)
288667f1eebSIngo Weinhold {
289667f1eebSIngo Weinhold 	if (!address)
290667f1eebSIngo Weinhold 		return B_BAD_VALUE;
291667f1eebSIngo Weinhold 
292667f1eebSIngo Weinhold 	struct team* kernelTeam = team_get_kernel_team();
293667f1eebSIngo Weinhold 
294667f1eebSIngo Weinhold 	cpu_status state = disable_interrupts();
295667f1eebSIngo Weinhold 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
296667f1eebSIngo Weinhold 
297667f1eebSIngo Weinhold 	status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info,
298667f1eebSIngo Weinhold 		address, watchpoint);
299667f1eebSIngo Weinhold 
300667f1eebSIngo Weinhold 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
30131d9352fSIngo Weinhold 
30231d9352fSIngo Weinhold 	call_all_cpus(install_breakpoints_per_cpu, NULL);
30331d9352fSIngo Weinhold 
304667f1eebSIngo Weinhold 	restore_interrupts(state);
305667f1eebSIngo Weinhold 
306667f1eebSIngo Weinhold 	return error;
307667f1eebSIngo Weinhold }
308667f1eebSIngo Weinhold 
309667f1eebSIngo Weinhold #endif	// KERNEL_BREAKPOINTS
310667f1eebSIngo Weinhold 
311667f1eebSIngo Weinhold 
312667f1eebSIngo Weinhold static inline status_t
313667f1eebSIngo Weinhold check_watch_point_parameters(void* address, uint32 type, int32 length,
314667f1eebSIngo Weinhold 	uint32& archType, uint32& archLength)
315667f1eebSIngo Weinhold {
316667f1eebSIngo Weinhold 	// check type
317667f1eebSIngo Weinhold 	switch (type) {
318667f1eebSIngo Weinhold 		case B_DATA_WRITE_WATCHPOINT:
319667f1eebSIngo Weinhold 			archType = X86_DATA_WRITE_BREAKPOINT;
320667f1eebSIngo Weinhold 			break;
321667f1eebSIngo Weinhold 		case B_DATA_READ_WRITE_WATCHPOINT:
322667f1eebSIngo Weinhold 			archType = X86_DATA_READ_WRITE_BREAKPOINT;
323667f1eebSIngo Weinhold 			break;
324667f1eebSIngo Weinhold 		case B_DATA_READ_WATCHPOINT:
325667f1eebSIngo Weinhold 		default:
326667f1eebSIngo Weinhold 			return B_WATCHPOINT_TYPE_NOT_SUPPORTED;
327667f1eebSIngo Weinhold 			break;
328667f1eebSIngo Weinhold 	}
329667f1eebSIngo Weinhold 
330667f1eebSIngo Weinhold 	// check length and alignment
331667f1eebSIngo Weinhold 	switch (length) {
332667f1eebSIngo Weinhold 		case 1:
333667f1eebSIngo Weinhold 			archLength = X86_BREAKPOINT_LENGTH_1;
334667f1eebSIngo Weinhold 			break;
335667f1eebSIngo Weinhold 		case 2:
336667f1eebSIngo Weinhold 			if ((uint32)address & 0x1)
337667f1eebSIngo Weinhold 				return B_BAD_WATCHPOINT_ALIGNMENT;
338667f1eebSIngo Weinhold 			archLength = X86_BREAKPOINT_LENGTH_2;
339667f1eebSIngo Weinhold 			break;
340667f1eebSIngo Weinhold 		case 4:
341667f1eebSIngo Weinhold 			if ((uint32)address & 0x3)
342667f1eebSIngo Weinhold 				return B_BAD_WATCHPOINT_ALIGNMENT;
343667f1eebSIngo Weinhold 			archLength = X86_BREAKPOINT_LENGTH_4;
344667f1eebSIngo Weinhold 			break;
345667f1eebSIngo Weinhold 		default:
346667f1eebSIngo Weinhold 			return B_WATCHPOINT_LENGTH_NOT_SUPPORTED;
347667f1eebSIngo Weinhold 	}
348667f1eebSIngo Weinhold 
349667f1eebSIngo Weinhold 	return B_OK;
350667f1eebSIngo Weinhold }
351667f1eebSIngo Weinhold 
352667f1eebSIngo Weinhold 
353bc5f008aSIngo Weinhold // #pragma mark - kernel debugger commands
354bc5f008aSIngo Weinhold 
355bc5f008aSIngo Weinhold #if KERNEL_BREAKPOINTS
356bc5f008aSIngo Weinhold 
357bc5f008aSIngo Weinhold static int
358bc5f008aSIngo Weinhold debugger_breakpoints(int argc, char** argv)
359bc5f008aSIngo Weinhold {
360bc5f008aSIngo Weinhold 	struct team* kernelTeam = team_get_kernel_team();
361bc5f008aSIngo Weinhold 	arch_team_debug_info& info = kernelTeam->debug_info.arch_info;
362bc5f008aSIngo Weinhold 
363bc5f008aSIngo Weinhold 	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
364bc5f008aSIngo Weinhold 		kprintf("breakpoint[%ld] ", i);
365bc5f008aSIngo Weinhold 
366bc5f008aSIngo Weinhold 		if (info.breakpoints[i].address != NULL) {
367bc5f008aSIngo Weinhold 			kprintf("%p ", info.breakpoints[i].address);
368bc5f008aSIngo Weinhold 			switch (info.breakpoints[i].type) {
369bc5f008aSIngo Weinhold 				case X86_INSTRUCTION_BREAKPOINT:
370bc5f008aSIngo Weinhold 					kprintf("instruction");
371bc5f008aSIngo Weinhold 					break;
372bc5f008aSIngo Weinhold 				case X86_IO_READ_WRITE_BREAKPOINT:
373bc5f008aSIngo Weinhold 					kprintf("io read/write");
374bc5f008aSIngo Weinhold 					break;
375bc5f008aSIngo Weinhold 				case X86_DATA_WRITE_BREAKPOINT:
376bc5f008aSIngo Weinhold 					kprintf("data write");
377bc5f008aSIngo Weinhold 					break;
378bc5f008aSIngo Weinhold 				case X86_DATA_READ_WRITE_BREAKPOINT:
379bc5f008aSIngo Weinhold 					kprintf("data read/write");
380bc5f008aSIngo Weinhold 					break;
381bc5f008aSIngo Weinhold 			}
382bc5f008aSIngo Weinhold 
383bc5f008aSIngo Weinhold 			int length = 1;
384bc5f008aSIngo Weinhold 			switch (info.breakpoints[i].length) {
385bc5f008aSIngo Weinhold 				case X86_BREAKPOINT_LENGTH_1:
386bc5f008aSIngo Weinhold 					length = 1;
387bc5f008aSIngo Weinhold 					break;
388bc5f008aSIngo Weinhold 				case X86_BREAKPOINT_LENGTH_2:
389bc5f008aSIngo Weinhold 					length = 2;
390bc5f008aSIngo Weinhold 					break;
391bc5f008aSIngo Weinhold 				case X86_BREAKPOINT_LENGTH_4:
392bc5f008aSIngo Weinhold 					length = 4;
393bc5f008aSIngo Weinhold 					break;
394bc5f008aSIngo Weinhold 			}
395bc5f008aSIngo Weinhold 
396bc5f008aSIngo Weinhold 			if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT)
397bc5f008aSIngo Weinhold 				kprintf(" %d byte%s", length, (length > 1 ? "s" : ""));
398bc5f008aSIngo Weinhold 		} else
399bc5f008aSIngo Weinhold 			kprintf("unused");
400bc5f008aSIngo Weinhold 
401bc5f008aSIngo Weinhold 		kprintf("\n");
402bc5f008aSIngo Weinhold 	}
403bc5f008aSIngo Weinhold 
404bc5f008aSIngo Weinhold 	return 0;
405bc5f008aSIngo Weinhold }
406bc5f008aSIngo Weinhold 
407bc5f008aSIngo Weinhold 
408bc5f008aSIngo Weinhold static int
409bc5f008aSIngo Weinhold debugger_breakpoint(int argc, char** argv)
410bc5f008aSIngo Weinhold {
411bc5f008aSIngo Weinhold 	// get arguments
412bc5f008aSIngo Weinhold 
413bc5f008aSIngo Weinhold 	if (argc < 2 || argc > 3)
4148342d4cdSIngo Weinhold 		return print_debugger_command_usage(argv[0]);
415bc5f008aSIngo Weinhold 
416bc5f008aSIngo Weinhold 	addr_t address = strtoul(argv[1], NULL, 0);
417bc5f008aSIngo Weinhold 	if (address == 0)
4188342d4cdSIngo Weinhold 		return print_debugger_command_usage(argv[0]);
419bc5f008aSIngo Weinhold 
420bc5f008aSIngo Weinhold 	bool clear = false;
421bc5f008aSIngo Weinhold 	if (argc == 3) {
422bc5f008aSIngo Weinhold 		if (strcmp(argv[2], "clear") == 0)
423bc5f008aSIngo Weinhold 			clear = true;
424bc5f008aSIngo Weinhold 		else
4258342d4cdSIngo Weinhold 			return print_debugger_command_usage(argv[0]);
426bc5f008aSIngo Weinhold 	}
427bc5f008aSIngo Weinhold 
428bc5f008aSIngo Weinhold 	// set/clear breakpoint
429bc5f008aSIngo Weinhold 
430bc5f008aSIngo Weinhold 	arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
431bc5f008aSIngo Weinhold 
432bc5f008aSIngo Weinhold 	status_t error;
433bc5f008aSIngo Weinhold 
434bc5f008aSIngo Weinhold 	if (clear) {
435bc5f008aSIngo Weinhold 		error = clear_breakpoint(info, (void*)address, false);
436bc5f008aSIngo Weinhold 	} else {
437bc5f008aSIngo Weinhold 		error = set_breakpoint(info, (void*)address, X86_INSTRUCTION_BREAKPOINT,
438bc5f008aSIngo Weinhold 			X86_BREAKPOINT_LENGTH_1, true);
439bc5f008aSIngo Weinhold 	}
440bc5f008aSIngo Weinhold 
441bc5f008aSIngo Weinhold 	if (error == B_OK)
44231d9352fSIngo Weinhold 		call_all_cpus_sync(install_breakpoints_per_cpu, NULL);
443bc5f008aSIngo Weinhold 	else
444bc5f008aSIngo Weinhold 		kprintf("Failed to install breakpoint: %s\n", strerror(error));
445bc5f008aSIngo Weinhold 
446bc5f008aSIngo Weinhold 	return 0;
447bc5f008aSIngo Weinhold }
448bc5f008aSIngo Weinhold 
449bc5f008aSIngo Weinhold 
450bc5f008aSIngo Weinhold static int
451bc5f008aSIngo Weinhold debugger_watchpoint(int argc, char** argv)
452bc5f008aSIngo Weinhold {
453bc5f008aSIngo Weinhold 	// get arguments
454bc5f008aSIngo Weinhold 
455bc5f008aSIngo Weinhold 	if (argc < 2 || argc > 4)
4568342d4cdSIngo Weinhold 		return print_debugger_command_usage(argv[0]);
457bc5f008aSIngo Weinhold 
458bc5f008aSIngo Weinhold 	addr_t address = strtoul(argv[1], NULL, 0);
459bc5f008aSIngo Weinhold 	if (address == 0)
4608342d4cdSIngo Weinhold 		return print_debugger_command_usage(argv[0]);
461bc5f008aSIngo Weinhold 
462bc5f008aSIngo Weinhold 	bool clear = false;
463bc5f008aSIngo Weinhold 	bool readWrite = false;
464bc5f008aSIngo Weinhold 	int argi = 2;
465bc5f008aSIngo Weinhold 	int length = 1;
466bc5f008aSIngo Weinhold 	if (argc >= 3) {
467bc5f008aSIngo Weinhold 		if (strcmp(argv[argi], "clear") == 0) {
468bc5f008aSIngo Weinhold 			clear = true;
469bc5f008aSIngo Weinhold 			argi++;
470bc5f008aSIngo Weinhold 		} else if (strcmp(argv[argi], "rw") == 0) {
471bc5f008aSIngo Weinhold 			readWrite = true;
472bc5f008aSIngo Weinhold 			argi++;
473bc5f008aSIngo Weinhold 		}
474bc5f008aSIngo Weinhold 
475bc5f008aSIngo Weinhold 		if (!clear && argi < argc)
476bc5f008aSIngo Weinhold 			length = strtoul(argv[argi++], NULL, 0);
477bc5f008aSIngo Weinhold 
478bc5f008aSIngo Weinhold 		if (length == 0 || argi < argc)
4798342d4cdSIngo Weinhold 			return print_debugger_command_usage(argv[0]);
480bc5f008aSIngo Weinhold 	}
481bc5f008aSIngo Weinhold 
482bc5f008aSIngo Weinhold 	// set/clear breakpoint
483bc5f008aSIngo Weinhold 
484bc5f008aSIngo Weinhold 	arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
485bc5f008aSIngo Weinhold 
486bc5f008aSIngo Weinhold 	status_t error;
487bc5f008aSIngo Weinhold 
488bc5f008aSIngo Weinhold 	if (clear) {
489bc5f008aSIngo Weinhold 		error = clear_breakpoint(info, (void*)address, true);
490bc5f008aSIngo Weinhold 	} else {
491bc5f008aSIngo Weinhold 		uint32 type = readWrite ? B_DATA_READ_WRITE_WATCHPOINT
492bc5f008aSIngo Weinhold 			: B_DATA_WRITE_WATCHPOINT;
493bc5f008aSIngo Weinhold 
494bc5f008aSIngo Weinhold 		uint32 archType, archLength;
495bc5f008aSIngo Weinhold 		error = check_watch_point_parameters((void*)address, type, length,
496bc5f008aSIngo Weinhold 			archType, archLength);
497bc5f008aSIngo Weinhold 
498bc5f008aSIngo Weinhold 		if (error == B_OK) {
499bc5f008aSIngo Weinhold 			error = set_breakpoint(info, (void*)address, archType, archLength,
500bc5f008aSIngo Weinhold 				true);
501bc5f008aSIngo Weinhold 		}
502bc5f008aSIngo Weinhold 	}
503bc5f008aSIngo Weinhold 
504bc5f008aSIngo Weinhold 	if (error == B_OK)
50531d9352fSIngo Weinhold 		call_all_cpus_sync(install_breakpoints_per_cpu, NULL);
506bc5f008aSIngo Weinhold 	else
507bc5f008aSIngo Weinhold 		kprintf("Failed to install breakpoint: %s\n", strerror(error));
508bc5f008aSIngo Weinhold 
509bc5f008aSIngo Weinhold 	return 0;
510bc5f008aSIngo Weinhold }
511bc5f008aSIngo Weinhold 
5128342d4cdSIngo Weinhold 
5138342d4cdSIngo Weinhold static int
5148342d4cdSIngo Weinhold debugger_single_step(int argc, char** argv)
5158342d4cdSIngo Weinhold {
5168342d4cdSIngo Weinhold 	// TODO: Since we need an iframe, this doesn't work when KDL wasn't entered
5178342d4cdSIngo Weinhold 	// via an exception.
5188342d4cdSIngo Weinhold 
5198342d4cdSIngo Weinhold 	struct iframe* frame = i386_get_current_iframe();
5208342d4cdSIngo Weinhold 	if (frame == NULL) {
5218342d4cdSIngo Weinhold 		kprintf("Failed to get the current iframe!\n");
5228342d4cdSIngo Weinhold 		return 0;
5238342d4cdSIngo Weinhold 	}
5248342d4cdSIngo Weinhold 
5258342d4cdSIngo Weinhold 	frame->flags |= (1 << X86_EFLAGS_TF);
5268342d4cdSIngo Weinhold 
5278342d4cdSIngo Weinhold 	return B_KDEBUG_QUIT;
5288342d4cdSIngo Weinhold }
5298342d4cdSIngo Weinhold 
5308342d4cdSIngo Weinhold 
531bc5f008aSIngo Weinhold #endif	// KERNEL_BREAKPOINTS
532bc5f008aSIngo Weinhold 
533bc5f008aSIngo Weinhold 
534667f1eebSIngo Weinhold // #pragma mark - in-kernel public interface
535667f1eebSIngo Weinhold 
536667f1eebSIngo Weinhold 
5372d690920SAxel Dörfler void
5382d690920SAxel Dörfler arch_clear_team_debug_info(struct arch_team_debug_info *info)
5392d690920SAxel Dörfler {
5402d690920SAxel Dörfler 	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++)
5412d690920SAxel Dörfler 		info->breakpoints[i].address = NULL;
5422d690920SAxel Dörfler 
5432d690920SAxel Dörfler 	info->dr7 = X86_BREAKPOINTS_DISABLED_DR7;
5442d690920SAxel Dörfler }
5452d690920SAxel Dörfler 
5462d690920SAxel Dörfler 
5472d690920SAxel Dörfler void
5482d690920SAxel Dörfler arch_destroy_team_debug_info(struct arch_team_debug_info *info)
5492d690920SAxel Dörfler {
5502d690920SAxel Dörfler 	arch_clear_team_debug_info(info);
5512d690920SAxel Dörfler }
5522d690920SAxel Dörfler 
5532d690920SAxel Dörfler 
5542d690920SAxel Dörfler void
5552d690920SAxel Dörfler arch_clear_thread_debug_info(struct arch_thread_debug_info *info)
5562d690920SAxel Dörfler {
5572d690920SAxel Dörfler 	info->flags = 0;
5582d690920SAxel Dörfler }
5592d690920SAxel Dörfler 
5602d690920SAxel Dörfler 
5612d690920SAxel Dörfler void
5622d690920SAxel Dörfler arch_destroy_thread_debug_info(struct arch_thread_debug_info *info)
5632d690920SAxel Dörfler {
5642d690920SAxel Dörfler 	arch_clear_thread_debug_info(info);
5652d690920SAxel Dörfler }
5662d690920SAxel Dörfler 
5672d690920SAxel Dörfler 
5682d690920SAxel Dörfler void
56934b3b26bSIngo Weinhold arch_update_thread_single_step()
57034b3b26bSIngo Weinhold {
57134b3b26bSIngo Weinhold 	if (struct iframe* frame = i386_get_user_iframe()) {
57234b3b26bSIngo Weinhold 		struct thread* thread = thread_get_current_thread();
57334b3b26bSIngo Weinhold 
57434b3b26bSIngo Weinhold 		// set/clear TF in EFLAGS depending on if single stepping is desired
57534b3b26bSIngo Weinhold 		if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP)
57634b3b26bSIngo Weinhold 			frame->flags |= (1 << X86_EFLAGS_TF);
57734b3b26bSIngo Weinhold 		else
57834b3b26bSIngo Weinhold 			frame->flags &= ~(1 << X86_EFLAGS_TF);
57934b3b26bSIngo Weinhold 	}
58034b3b26bSIngo Weinhold }
58134b3b26bSIngo Weinhold 
58234b3b26bSIngo Weinhold 
58334b3b26bSIngo Weinhold void
5840b11ecb1SIngo Weinhold arch_set_debug_cpu_state(const debug_cpu_state *cpuState)
5852d690920SAxel Dörfler {
5862d690920SAxel Dörfler 	if (struct iframe *frame = i386_get_user_iframe()) {
5870b11ecb1SIngo Weinhold 		// For the floating point state to be correct the calling function must
5880b11ecb1SIngo Weinhold 		// not use these registers (not even indirectly).
5890b11ecb1SIngo Weinhold 		if (gHasSSE) {
5900b11ecb1SIngo Weinhold 			// Since fxrstor requires 16-byte alignment and this isn't
5910b11ecb1SIngo Weinhold 			// guaranteed passed buffer, we use our thread's fpu_state field as
5920b11ecb1SIngo Weinhold 			// temporary buffer. We need to disable interrupts to make use of
5930b11ecb1SIngo Weinhold 			// it.
5940b11ecb1SIngo Weinhold 			struct thread* thread = thread_get_current_thread();
5950b11ecb1SIngo Weinhold 			InterruptsLocker locker;
5960b11ecb1SIngo Weinhold 			memcpy(thread->arch_info.fpu_state, &cpuState->extended_registers,
5970b11ecb1SIngo Weinhold 				sizeof(&cpuState->extended_registers));
5980b11ecb1SIngo Weinhold 			i386_fxrstor(thread->arch_info.fpu_state);
5990b11ecb1SIngo Weinhold 		} else {
6000b11ecb1SIngo Weinhold 			// TODO: Implement! We need to convert the format first.
6010b11ecb1SIngo Weinhold //			i386_frstor(&cpuState->extended_registers);
6020b11ecb1SIngo Weinhold 		}
6032d690920SAxel Dörfler 
6042d690920SAxel Dörfler //		frame->gs = cpuState->gs;
6052d690920SAxel Dörfler //		frame->fs = cpuState->fs;
6062d690920SAxel Dörfler //		frame->es = cpuState->es;
6072d690920SAxel Dörfler //		frame->ds = cpuState->ds;
6082d690920SAxel Dörfler 		frame->edi = cpuState->edi;
6092d690920SAxel Dörfler 		frame->esi = cpuState->esi;
6102d690920SAxel Dörfler 		frame->ebp = cpuState->ebp;
611568ade58SIngo Weinhold //		frame->esp = cpuState->esp;
6122d690920SAxel Dörfler 		frame->ebx = cpuState->ebx;
6132d690920SAxel Dörfler 		frame->edx = cpuState->edx;
6142d690920SAxel Dörfler 		frame->ecx = cpuState->ecx;
6152d690920SAxel Dörfler 		frame->eax = cpuState->eax;
6162d690920SAxel Dörfler //		frame->vector = cpuState->vector;
6172d690920SAxel Dörfler //		frame->error_code = cpuState->error_code;
6182d690920SAxel Dörfler 		frame->eip = cpuState->eip;
6192d690920SAxel Dörfler //		frame->cs = cpuState->cs;
6202d690920SAxel Dörfler 		frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS)
6212d690920SAxel Dörfler 			| (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS);
6222d690920SAxel Dörfler 		frame->user_esp = cpuState->user_esp;
6232d690920SAxel Dörfler //		frame->user_ss = cpuState->user_ss;
6242d690920SAxel Dörfler 	}
6252d690920SAxel Dörfler }
6262d690920SAxel Dörfler 
627667f1eebSIngo Weinhold 
6282d690920SAxel Dörfler void
6290b11ecb1SIngo Weinhold arch_get_debug_cpu_state(debug_cpu_state *cpuState)
6302d690920SAxel Dörfler {
6312d690920SAxel Dörfler 	if (struct iframe *frame = i386_get_user_iframe()) {
6320b11ecb1SIngo Weinhold 		// For the floating point state to be correct the calling function must
6330b11ecb1SIngo Weinhold 		// not use these registers (not even indirectly).
6340b11ecb1SIngo Weinhold 		if (gHasSSE) {
6350b11ecb1SIngo Weinhold 			// Since fxsave requires 16-byte alignment and this isn't guaranteed
6360b11ecb1SIngo Weinhold 			// passed buffer, we use our thread's fpu_state field as temporary
6370b11ecb1SIngo Weinhold 			// buffer. We need to disable interrupts to make use of it.
6380b11ecb1SIngo Weinhold 			struct thread* thread = thread_get_current_thread();
6390b11ecb1SIngo Weinhold 			InterruptsLocker locker;
6400b11ecb1SIngo Weinhold 			i386_fxsave(thread->arch_info.fpu_state);
6410b11ecb1SIngo Weinhold 				// unlike fnsave, fxsave doesn't reinit the FPU state
6420b11ecb1SIngo Weinhold 			memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state,
6430b11ecb1SIngo Weinhold 				sizeof(&cpuState->extended_registers));
6440b11ecb1SIngo Weinhold 		} else {
6450b11ecb1SIngo Weinhold 			i386_fnsave(&cpuState->extended_registers);
6460b11ecb1SIngo Weinhold 			i386_frstor(&cpuState->extended_registers);
6470b11ecb1SIngo Weinhold 				// fnsave reinits the FPU state after saving, so we need to
6480b11ecb1SIngo Weinhold 				// load it again
6490b11ecb1SIngo Weinhold 			// TODO: Convert to fxsave format!
6500b11ecb1SIngo Weinhold 		}
651568ade58SIngo Weinhold 		get_iframe_registers(frame, cpuState);
6522d690920SAxel Dörfler 	}
6532d690920SAxel Dörfler }
6542d690920SAxel Dörfler 
6552d690920SAxel Dörfler 
6562d690920SAxel Dörfler status_t
6572d690920SAxel Dörfler arch_set_breakpoint(void *address)
6582d690920SAxel Dörfler {
6592d690920SAxel Dörfler 	return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
6602d690920SAxel Dörfler 		X86_BREAKPOINT_LENGTH_1);
6612d690920SAxel Dörfler }
6622d690920SAxel Dörfler 
6632d690920SAxel Dörfler 
6642d690920SAxel Dörfler status_t
6652d690920SAxel Dörfler arch_clear_breakpoint(void *address)
6662d690920SAxel Dörfler {
6672d690920SAxel Dörfler 	return clear_breakpoint(address, false);
6682d690920SAxel Dörfler }
6692d690920SAxel Dörfler 
6702d690920SAxel Dörfler 
6712d690920SAxel Dörfler status_t
6722d690920SAxel Dörfler arch_set_watchpoint(void *address, uint32 type, int32 length)
6732d690920SAxel Dörfler {
674667f1eebSIngo Weinhold 	uint32 archType, archLength;
675667f1eebSIngo Weinhold 	status_t error = check_watch_point_parameters(address, type, length,
676667f1eebSIngo Weinhold 		archType, archLength);
677667f1eebSIngo Weinhold 	if (error != B_OK)
678667f1eebSIngo Weinhold 		return error;
6792d690920SAxel Dörfler 
6802d690920SAxel Dörfler 	return set_breakpoint(address, archType, archLength);
6812d690920SAxel Dörfler }
6822d690920SAxel Dörfler 
6832d690920SAxel Dörfler 
6842d690920SAxel Dörfler status_t
6852d690920SAxel Dörfler arch_clear_watchpoint(void *address)
6862d690920SAxel Dörfler {
6872d690920SAxel Dörfler 	return clear_breakpoint(address, false);
6882d690920SAxel Dörfler }
6892d690920SAxel Dörfler 
6902d690920SAxel Dörfler 
69134b3b26bSIngo Weinhold bool
69234b3b26bSIngo Weinhold arch_has_breakpoints(struct arch_team_debug_info *info)
69334b3b26bSIngo Weinhold {
69434b3b26bSIngo Weinhold 	// Reading info->dr7 is atomically, so we don't need to lock. The caller
69534b3b26bSIngo Weinhold 	// has to ensure, that the info doesn't go away.
69634b3b26bSIngo Weinhold 	return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7);
69734b3b26bSIngo Weinhold }
69834b3b26bSIngo Weinhold 
69934b3b26bSIngo Weinhold 
700667f1eebSIngo Weinhold #if KERNEL_BREAKPOINTS
7012d690920SAxel Dörfler 
702667f1eebSIngo Weinhold status_t
703667f1eebSIngo Weinhold arch_set_kernel_breakpoint(void *address)
704667f1eebSIngo Weinhold {
705667f1eebSIngo Weinhold 	status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
706667f1eebSIngo Weinhold 		X86_BREAKPOINT_LENGTH_1);
707667f1eebSIngo Weinhold 
708667f1eebSIngo Weinhold 	if (error != B_OK) {
709667f1eebSIngo Weinhold 		panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s",
710667f1eebSIngo Weinhold 			strerror(error));
7112d690920SAxel Dörfler 	}
7122d690920SAxel Dörfler 
713667f1eebSIngo Weinhold 	return error;
714667f1eebSIngo Weinhold }
715667f1eebSIngo Weinhold 
716667f1eebSIngo Weinhold 
717667f1eebSIngo Weinhold status_t
718667f1eebSIngo Weinhold arch_clear_kernel_breakpoint(void *address)
719667f1eebSIngo Weinhold {
720667f1eebSIngo Weinhold 	status_t error = clear_kernel_breakpoint(address, false);
721667f1eebSIngo Weinhold 
722667f1eebSIngo Weinhold 	if (error != B_OK) {
723667f1eebSIngo Weinhold 		panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s",
724667f1eebSIngo Weinhold 			strerror(error));
725667f1eebSIngo Weinhold 	}
726667f1eebSIngo Weinhold 
727667f1eebSIngo Weinhold 	return error;
728667f1eebSIngo Weinhold }
729667f1eebSIngo Weinhold 
730667f1eebSIngo Weinhold 
731667f1eebSIngo Weinhold status_t
732667f1eebSIngo Weinhold arch_set_kernel_watchpoint(void *address, uint32 type, int32 length)
733667f1eebSIngo Weinhold {
734667f1eebSIngo Weinhold 	uint32 archType, archLength;
735667f1eebSIngo Weinhold 	status_t error = check_watch_point_parameters(address, type, length,
736667f1eebSIngo Weinhold 		archType, archLength);
737667f1eebSIngo Weinhold 
738667f1eebSIngo Weinhold 	if (error == B_OK)
739667f1eebSIngo Weinhold 		error = set_kernel_breakpoint(address, archType, archLength);
740667f1eebSIngo Weinhold 
741667f1eebSIngo Weinhold 	if (error != B_OK) {
742667f1eebSIngo Weinhold 		panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s",
743667f1eebSIngo Weinhold 			strerror(error));
744667f1eebSIngo Weinhold 	}
745667f1eebSIngo Weinhold 
746667f1eebSIngo Weinhold 	return error;
747667f1eebSIngo Weinhold }
748667f1eebSIngo Weinhold 
749667f1eebSIngo Weinhold 
750667f1eebSIngo Weinhold status_t
751667f1eebSIngo Weinhold arch_clear_kernel_watchpoint(void *address)
752667f1eebSIngo Weinhold {
753667f1eebSIngo Weinhold 	status_t error = clear_kernel_breakpoint(address, true);
754667f1eebSIngo Weinhold 
755667f1eebSIngo Weinhold 	if (error != B_OK) {
756667f1eebSIngo Weinhold 		panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s",
757667f1eebSIngo Weinhold 			strerror(error));
758667f1eebSIngo Weinhold 	}
759667f1eebSIngo Weinhold 
760667f1eebSIngo Weinhold 	return error;
761667f1eebSIngo Weinhold }
762667f1eebSIngo Weinhold 
763667f1eebSIngo Weinhold #endif	// KERNEL_BREAKPOINTS
764667f1eebSIngo Weinhold 
765667f1eebSIngo Weinhold 
766667f1eebSIngo Weinhold // #pragma mark - x86 implementation interface
767667f1eebSIngo Weinhold 
7682d690920SAxel Dörfler 
7692d690920SAxel Dörfler /**
7708ad4a2e9SIngo Weinhold  *	Interrupts are disabled. \a frame is unused, i.e. can be \c NULL.
7712d690920SAxel Dörfler  */
7722d690920SAxel Dörfler void
77334b3b26bSIngo Weinhold x86_init_user_debug_at_kernel_exit(struct iframe *frame)
7742d690920SAxel Dörfler {
7752d690920SAxel Dörfler 	struct thread *thread = thread_get_current_thread();
7762d690920SAxel Dörfler 
77734b3b26bSIngo Weinhold 	if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED))
77834b3b26bSIngo Weinhold 		return;
779b4476702SIngo Weinhold 
780b4476702SIngo Weinhold 	// disable kernel breakpoints
781b4476702SIngo Weinhold 	disable_breakpoints();
78234b3b26bSIngo Weinhold 
7832d690920SAxel Dörfler 	GRAB_THREAD_LOCK();
7842d690920SAxel Dörfler 	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
7852d690920SAxel Dörfler 
7862d690920SAxel Dörfler 	arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info;
7872d690920SAxel Dörfler 
788b4476702SIngo Weinhold 	// install the user breakpoints
7892d690920SAxel Dörfler 	install_breakpoints(teamInfo);
7902d690920SAxel Dörfler 
79134b3b26bSIngo Weinhold 	atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED);
7922d690920SAxel Dörfler 
7932d690920SAxel Dörfler 	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
7942d690920SAxel Dörfler 	RELEASE_THREAD_LOCK();
7952d690920SAxel Dörfler }
7962d690920SAxel Dörfler 
7972d690920SAxel Dörfler 
7982d690920SAxel Dörfler /**
79934b3b26bSIngo Weinhold  *	Interrupts are disabled.
8002d690920SAxel Dörfler  */
8012d690920SAxel Dörfler void
80234b3b26bSIngo Weinhold x86_exit_user_debug_at_kernel_entry()
8032d690920SAxel Dörfler {
8042d690920SAxel Dörfler 	struct thread *thread = thread_get_current_thread();
8052d690920SAxel Dörfler 
80634b3b26bSIngo Weinhold 	if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED))
80734b3b26bSIngo Weinhold 		return;
80834b3b26bSIngo Weinhold 
809*feddedabSIngo Weinhold 	// We need to save the current values of dr6 and dr7 in the CPU structure,
810*feddedabSIngo Weinhold 	// since in case of a debug exception we might overwrite them before
811*feddedabSIngo Weinhold 	// x86_handle_debug_exception() is called.
812*feddedabSIngo Weinhold 	asm("movl %%dr6, %0" : "=r"(thread->cpu->arch.dr6));
813*feddedabSIngo Weinhold 	asm("movl %%dr7, %0" : "=r"(thread->cpu->arch.dr7));
814*feddedabSIngo Weinhold 
8152d690920SAxel Dörfler 	GRAB_THREAD_LOCK();
8162d690920SAxel Dörfler 
817b4476702SIngo Weinhold 	// disable user breakpoints
818667f1eebSIngo Weinhold 	disable_breakpoints();
8192d690920SAxel Dörfler 
820b4476702SIngo Weinhold 	// install kernel breakpoints
821667f1eebSIngo Weinhold 	struct team* kernelTeam = team_get_kernel_team();
822667f1eebSIngo Weinhold 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
823667f1eebSIngo Weinhold 	install_breakpoints(kernelTeam->debug_info.arch_info);
824667f1eebSIngo Weinhold 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
825667f1eebSIngo Weinhold 
82634b3b26bSIngo Weinhold 	atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED);
82734b3b26bSIngo Weinhold 
8282d690920SAxel Dörfler 	RELEASE_THREAD_LOCK();
8292d690920SAxel Dörfler }
8302d690920SAxel Dörfler 
8312d690920SAxel Dörfler 
8322d690920SAxel Dörfler /**
833b4476702SIngo Weinhold  *	Interrupts are disabled and will possibly be enabled by the function.
8342d690920SAxel Dörfler  */
83534b3b26bSIngo Weinhold void
83634b3b26bSIngo Weinhold x86_handle_debug_exception(struct iframe *frame)
8372d690920SAxel Dörfler {
838*feddedabSIngo Weinhold 	// get debug status and control registers (saved earlier in
839*feddedabSIngo Weinhold 	// x86_exit_user_debug_at_kernel_entry())
840*feddedabSIngo Weinhold 	struct thread* thread = thread_get_current_thread();
841*feddedabSIngo Weinhold 	uint32 dr6 = thread->cpu->arch.dr6;
842*feddedabSIngo Weinhold 	uint32 dr7 = thread->cpu->arch.dr7;
8432d690920SAxel Dörfler 
8442d690920SAxel Dörfler 	TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7));
8452d690920SAxel Dörfler 
8462d690920SAxel Dörfler 	// check, which exception condition applies
8472d690920SAxel Dörfler 	if (dr6 & X86_DR6_BREAKPOINT_MASK) {
8482d690920SAxel Dörfler 		// breakpoint
8492d690920SAxel Dörfler 
8502d690920SAxel Dörfler 		// check which breakpoint was taken
8512d690920SAxel Dörfler 		bool watchpoint = true;
8522d690920SAxel Dörfler 		for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
8532d690920SAxel Dörfler 			if (dr6 & (1 << sDR6B[i])) {
8542d690920SAxel Dörfler 				uint32 type = (dr7 >> sDR7RW[i]) & 0x3;
855568ade58SIngo Weinhold 				if (type == X86_INSTRUCTION_BREAKPOINT)
8562d690920SAxel Dörfler 					watchpoint = false;
8572d690920SAxel Dörfler 			}
8582d690920SAxel Dörfler 		}
8592d690920SAxel Dörfler 
8608753babdSIngo Weinhold 		if (IFRAME_IS_USER(frame)) {
8612d690920SAxel Dörfler 			// enable interrupts and notify the debugger
8622d690920SAxel Dörfler 			enable_interrupts();
8632d690920SAxel Dörfler 
8642d690920SAxel Dörfler 			if (watchpoint)
8652d690920SAxel Dörfler 				user_debug_watchpoint_hit();
8662d690920SAxel Dörfler 			else
8672d690920SAxel Dörfler 				user_debug_breakpoint_hit(false);
8688753babdSIngo Weinhold 		} else {
8698753babdSIngo Weinhold 			panic("hit kernel %spoint: dr6: 0x%lx, dr7: 0x%lx",
8708753babdSIngo Weinhold 				watchpoint ? "watch" : "break", dr6, dr7);
8718753babdSIngo Weinhold 		}
8722d690920SAxel Dörfler 	} else if (dr6 & (1 << X86_DR6_BD)) {
8732d690920SAxel Dörfler 		// general detect exception
8742d690920SAxel Dörfler 		// Occurs only, if GD in DR7 is set (which we don't do) and someone
8752d690920SAxel Dörfler 		// tries to write to the debug registers.
8768753babdSIngo Weinhold 		if (IFRAME_IS_USER(frame)) {
8772d690920SAxel Dörfler 			dprintf("i386_handle_debug_exception(): ignoring spurious general "
8782d690920SAxel Dörfler 				"detect exception\n");
8792d690920SAxel Dörfler 
8802d690920SAxel Dörfler 			enable_interrupts();
8818753babdSIngo Weinhold 		} else
8828753babdSIngo Weinhold 			panic("spurious general detect exception in kernel mode");
8832d690920SAxel Dörfler 	} else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) {
8842d690920SAxel Dörfler 		// single step
8852d690920SAxel Dörfler 
8868753babdSIngo Weinhold 		if (IFRAME_IS_USER(frame)) {
8872d690920SAxel Dörfler 			// enable interrupts and notify the debugger
8882d690920SAxel Dörfler 			enable_interrupts();
8892d690920SAxel Dörfler 
8902d690920SAxel Dörfler 			user_debug_single_stepped();
8918342d4cdSIngo Weinhold 		} else {
8928342d4cdSIngo Weinhold 			// Disable single-stepping -- the next "step" command will re-enable
8938342d4cdSIngo Weinhold 			// it, but we don't want it when continuing otherwise.
8948342d4cdSIngo Weinhold 			frame->flags &= ~(1 << X86_EFLAGS_TF);
8958342d4cdSIngo Weinhold 
8968b3d3d8aSIngo Weinhold 			// Determine whether the exception occurred at a syscall/trap
8978b3d3d8aSIngo Weinhold 			// kernel entry or whether this is genuine kernel single-stepping.
8988b3d3d8aSIngo Weinhold 			bool inKernel = true;
8998b3d3d8aSIngo Weinhold 			if (thread->team != team_get_kernel_team()
9008b3d3d8aSIngo Weinhold 				&& i386_get_user_iframe() == NULL) {
9018b3d3d8aSIngo Weinhold 				// TODO: This is not yet fully correct, since a newly created
9028b3d3d8aSIngo Weinhold 				// thread that doesn't have entered userland yet also has this
9038b3d3d8aSIngo Weinhold 				// property.
9048b3d3d8aSIngo Weinhold 				inKernel = false;
9058b3d3d8aSIngo Weinhold 			}
9068b3d3d8aSIngo Weinhold 
9078b3d3d8aSIngo Weinhold 			if (inKernel) {
9088753babdSIngo Weinhold 				panic("kernel single step");
9098b3d3d8aSIngo Weinhold 			} else {
9108b3d3d8aSIngo Weinhold 				// The thread is a userland thread and it just entered the
9118b3d3d8aSIngo Weinhold 				// kernel when the single-step exception occurred. This happens
9128b3d3d8aSIngo Weinhold 				// e.g. when sysenter is called with single-stepping enabled.
9138b3d3d8aSIngo Weinhold 				// We need to ignore the exception now and send a single-step
9148b3d3d8aSIngo Weinhold 				// notification later, when the thread wants to return from the
9158b3d3d8aSIngo Weinhold 				// kernel.
9168b3d3d8aSIngo Weinhold 				InterruptsSpinLocker threadLocker(gThreadSpinlock);
9178b3d3d8aSIngo Weinhold 
9188b3d3d8aSIngo Weinhold 				// Check whether the team is still being debugged and set
9198b3d3d8aSIngo Weinhold 				// the B_THREAD_DEBUG_NOTIFY_SINGLE_STEP and
9208b3d3d8aSIngo Weinhold 				// B_THREAD_DEBUG_STOP flags, so that the thread will be
9218b3d3d8aSIngo Weinhold 				// stopped when it is going to leave the kernel and notify the
9228b3d3d8aSIngo Weinhold 				// debugger about the single-step event.
9238b3d3d8aSIngo Weinhold 				int32 teamDebugFlags
9248b3d3d8aSIngo Weinhold 					= atomic_get(&thread->team->debug_info.flags);
9258b3d3d8aSIngo Weinhold 				if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
9268b3d3d8aSIngo Weinhold 					atomic_or(&thread->debug_info.flags,
9278b3d3d8aSIngo Weinhold 						B_THREAD_DEBUG_NOTIFY_SINGLE_STEP
9288b3d3d8aSIngo Weinhold 							| B_THREAD_DEBUG_STOP);
9298b3d3d8aSIngo Weinhold 				}
9308b3d3d8aSIngo Weinhold 			}
9318342d4cdSIngo Weinhold 		}
9322d690920SAxel Dörfler 	} else if (dr6 & (1 << X86_DR6_BT)) {
9332d690920SAxel Dörfler 		// task switch
9342d690920SAxel Dörfler 		// Occurs only, if T in EFLAGS is set (which we don't do).
9358753babdSIngo Weinhold 		if (IFRAME_IS_USER(frame)) {
9362d690920SAxel Dörfler 			dprintf("i386_handle_debug_exception(): ignoring spurious task switch "
9372d690920SAxel Dörfler 				"exception\n");
9382d690920SAxel Dörfler 
9392d690920SAxel Dörfler 			enable_interrupts();
9408753babdSIngo Weinhold 		} else
9418753babdSIngo Weinhold 			panic("spurious task switch exception in kernel mode");
9422d690920SAxel Dörfler 	} else {
9438753babdSIngo Weinhold 		if (IFRAME_IS_USER(frame)) {
94406be24a7SAxel Dörfler 			TRACE(("i386_handle_debug_exception(): ignoring spurious debug "
94506be24a7SAxel Dörfler 				"exception (no condition recognized)\n"));
9462d690920SAxel Dörfler 
9472d690920SAxel Dörfler 			enable_interrupts();
9488753babdSIngo Weinhold 		} else {
9498753babdSIngo Weinhold 			panic("spurious debug exception in kernel mode (no condition "
9508753babdSIngo Weinhold 				"recognized)");
9518753babdSIngo Weinhold 		}
9522d690920SAxel Dörfler 	}
9532d690920SAxel Dörfler }
9542d690920SAxel Dörfler 
9552d690920SAxel Dörfler 
9562d690920SAxel Dörfler /**
957b4476702SIngo Weinhold  *	Interrupts are disabled and will possibly be enabled by the function.
9582d690920SAxel Dörfler  */
95934b3b26bSIngo Weinhold void
96034b3b26bSIngo Weinhold x86_handle_breakpoint_exception(struct iframe *frame)
9612d690920SAxel Dörfler {
9622d690920SAxel Dörfler 	TRACE(("i386_handle_breakpoint_exception()\n"));
9632d690920SAxel Dörfler 
964b0f12d64SIngo Weinhold 	// reset eip to the int3 instruction
965b0f12d64SIngo Weinhold 	frame->eip--;
966b0f12d64SIngo Weinhold 
967bb107c4eSAxel Dörfler 	if (!IFRAME_IS_USER(frame)) {
968667f1eebSIngo Weinhold 		panic("breakpoint exception in kernel mode");
96934b3b26bSIngo Weinhold 		return;
970667f1eebSIngo Weinhold 	}
971667f1eebSIngo Weinhold 
9722d690920SAxel Dörfler 	enable_interrupts();
9732d690920SAxel Dörfler 
9742d690920SAxel Dörfler 	user_debug_breakpoint_hit(true);
9752d690920SAxel Dörfler }
9762d690920SAxel Dörfler 
9772d690920SAxel Dörfler 
9782d690920SAxel Dörfler void
97934b3b26bSIngo Weinhold x86_init_user_debug()
9802d690920SAxel Dörfler {
9812d690920SAxel Dörfler 	// get debug settings
9822d690920SAxel Dörfler 	if (void *handle = load_driver_settings("kernel")) {
9832d690920SAxel Dörfler 		sQEmuSingleStepHack = get_driver_boolean_parameter(handle,
9842d690920SAxel Dörfler 			"qemu_single_step_hack", false, false);;
9852d690920SAxel Dörfler 
9862d690920SAxel Dörfler 		unload_driver_settings(handle);
9872d690920SAxel Dörfler 	}
988bc5f008aSIngo Weinhold 
989bc5f008aSIngo Weinhold #if KERNEL_BREAKPOINTS
990bc5f008aSIngo Weinhold 	// install debugger commands
9918342d4cdSIngo Weinhold 	add_debugger_command_etc("breakpoints", &debugger_breakpoints,
9928342d4cdSIngo Weinhold 		"Lists current break-/watchpoints",
9938342d4cdSIngo Weinhold 		"\n"
9948342d4cdSIngo Weinhold 		"Lists the current kernel break-/watchpoints.\n", 0);
9958342d4cdSIngo Weinhold 	add_debugger_command_alias("watchpoints", "breakpoints", NULL);
9968342d4cdSIngo Weinhold 	add_debugger_command_etc("breakpoint", &debugger_breakpoint,
9978342d4cdSIngo Weinhold 		"Set/clears a breakpoint",
9988342d4cdSIngo Weinhold 		"<address> [ clear ]\n"
9998342d4cdSIngo Weinhold 		"Sets respectively clears the breakpoint at address <address>.\n", 0);
10008342d4cdSIngo Weinhold 	add_debugger_command_etc("watchpoint", &debugger_watchpoint,
10018342d4cdSIngo Weinhold 		"Set/clears a watchpoint",
10028342d4cdSIngo Weinhold 		"<address> <address> ( [ rw ] [ <size> ] | clear )\n"
10038342d4cdSIngo Weinhold 		"Sets respectively clears the watchpoint at address <address>.\n"
10048342d4cdSIngo Weinhold 		"If \"rw\" is given the new watchpoint is a read/write watchpoint\n"
10058342d4cdSIngo Weinhold 		"otherwise a write watchpoint only.\n", 0);
10068342d4cdSIngo Weinhold 	add_debugger_command_etc("step", &debugger_single_step,
10078342d4cdSIngo Weinhold 		"Single-steps to the next instruction",
10088342d4cdSIngo Weinhold 		"\n"
10098342d4cdSIngo Weinhold 		"Single-steps to the next instruction.\n", 0);
1010bc5f008aSIngo Weinhold #endif
10112d690920SAxel Dörfler }
10122d690920SAxel Dörfler 
1013