1/*
2 * Copyright 2005-2016, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <arch/user_debugger.h>
8
9#include <string.h>
10
11#include <debugger.h>
12#include <driver_settings.h>
13#include <int.h>
14#include <team.h>
15#include <thread.h>
16#include <util/AutoLock.h>
17
18
19//#define TRACE_ARCH_USER_DEBUGGER
20#ifdef TRACE_ARCH_USER_DEBUGGER
21#	define TRACE(x) dprintf x
22#else
23#	define TRACE(x) ;
24#endif
25
26#define B_NO_MORE_BREAKPOINTS				B_BUSY
27#define B_NO_MORE_WATCHPOINTS				B_BUSY
28#define B_BAD_WATCHPOINT_ALIGNMENT			B_BAD_VALUE
29#define B_WATCHPOINT_TYPE_NOT_SUPPORTED		B_NOT_SUPPORTED
30#define B_WATCHPOINT_LENGTH_NOT_SUPPORTED	B_NOT_SUPPORTED
31#define B_BREAKPOINT_NOT_FOUND				B_NAME_NOT_FOUND
32#define B_WATCHPOINT_NOT_FOUND				B_NAME_NOT_FOUND
33	// TODO: Make those real error codes.
34
35
36#ifdef __x86_64__
37extern bool gHasXsave;
38#else
39extern bool gHasSSE;
40#endif
41
42// The software breakpoint instruction (int3).
43const uint8 kX86SoftwareBreakpoint[1] = { 0xcc };
44
45// maps breakpoint slot index to LEN_i LSB number
46static const size_t sDR7Len[4] = {
47	X86_DR7_LEN0_LSB, X86_DR7_LEN1_LSB, X86_DR7_LEN2_LSB, X86_DR7_LEN3_LSB
48};
49
50// maps breakpoint slot index to R/W_i LSB number
51static const size_t sDR7RW[4] = {
52	X86_DR7_RW0_LSB, X86_DR7_RW1_LSB, X86_DR7_RW2_LSB, X86_DR7_RW3_LSB
53};
54
55// maps breakpoint slot index to L_i bit number
56static const size_t sDR7L[4] = {
57	X86_DR7_L0, X86_DR7_L1, X86_DR7_L2, X86_DR7_L3
58};
59
60// maps breakpoint slot index to G_i bit number
61static const size_t sDR7G[4] = {
62	X86_DR7_G0, X86_DR7_G1, X86_DR7_G2, X86_DR7_G3
63};
64
65// maps breakpoint slot index to B_i bit number
66static const size_t sDR6B[4] = {
67	X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3
68};
69
70// Enables a hack to make single stepping work under qemu. Set via kernel
71// driver settings.
72static bool sQEmuSingleStepHack = false;
73
74
75#ifdef __x86_64__
76
77
78static void
79get_iframe_registers(const iframe* frame, debug_cpu_state* cpuState)
80{
81	// Get general purpose registers.
82	cpuState->r15 = frame->r15;
83	cpuState->r14 = frame->r14;
84	cpuState->r13 = frame->r13;
85	cpuState->r12 = frame->r12;
86	cpuState->r11 = frame->r11;
87	cpuState->r10 = frame->r10;
88	cpuState->r9 = frame->r9;
89	cpuState->r8 = frame->r8;
90	cpuState->rbp = frame->bp;
91	cpuState->rsi = frame->si;
92	cpuState->rdi = frame->di;
93	cpuState->rdx = frame->dx;
94	cpuState->rcx = frame->cx;
95	cpuState->rbx = frame->bx;
96	cpuState->rax = frame->ax;
97	cpuState->vector = frame->vector;
98	cpuState->error_code = frame->error_code;
99	cpuState->rip = frame->ip;
100	cpuState->cs = frame->cs;
101	cpuState->rflags = frame->flags;
102	cpuState->rsp = frame->sp;
103	cpuState->ss = frame->ss;
104
105	// Other segment registers are not saved or changed on interrupts, so
106	// get their value here.
107	uint16 seg;
108	__asm__ volatile ("movw %%ds, %0" : "=r" (seg));
109	cpuState->ds = seg;
110	__asm__ volatile ("movw %%es, %0" : "=r" (seg));
111	cpuState->es = seg;
112	__asm__ volatile ("movw %%fs, %0" : "=r" (seg));
113	cpuState->fs = seg;
114	__asm__ volatile ("movw %%gs, %0" : "=r" (seg));
115	cpuState->gs = seg;
116}
117
118
119static void
120set_iframe_registers(iframe* frame, const debug_cpu_state* cpuState)
121{
122	frame->r15 = cpuState->r15;
123	frame->r14 = cpuState->r14;
124	frame->r13 = cpuState->r13;
125	frame->r12 = cpuState->r12;
126	frame->r11 = cpuState->r11;
127	frame->r10 = cpuState->r10;
128	frame->r9 = cpuState->r9;
129	frame->r8 = cpuState->r8;
130	frame->bp = cpuState->rbp;
131	frame->si = cpuState->rsi;
132	frame->di = cpuState->rdi;
133	frame->dx = cpuState->rdx;
134	frame->cx = cpuState->rcx;
135	frame->bx = cpuState->rbx;
136	frame->ax = cpuState->rax;
137	frame->ip = cpuState->rip;
138	frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS)
139		| (cpuState->rflags & X86_EFLAGS_USER_SETTABLE_FLAGS);
140	frame->sp = cpuState->rsp;
141}
142
143
144#else	// __x86_64__
145
146
147static void
148get_iframe_registers(const iframe* frame, debug_cpu_state* cpuState)
149{
150	cpuState->gs = frame->gs;
151	cpuState->fs = frame->fs;
152	cpuState->es = frame->es;
153	cpuState->ds = frame->ds;
154	cpuState->edi = frame->di;
155	cpuState->esi = frame->si;
156	cpuState->ebp = frame->bp;
157	cpuState->esp = frame->sp;
158	cpuState->ebx = frame->bx;
159	cpuState->edx = frame->orig_edx;
160	cpuState->ecx = frame->cx;
161	cpuState->eax = frame->orig_eax;
162	cpuState->vector = frame->vector;
163	cpuState->error_code = frame->error_code;
164	cpuState->eip = frame->ip;
165	cpuState->cs = frame->cs;
166	cpuState->eflags = frame->flags;
167	cpuState->user_esp = frame->user_sp;
168	cpuState->user_ss = frame->user_ss;
169}
170
171
172static void
173set_iframe_registers(iframe* frame, const debug_cpu_state* cpuState)
174{
175//	frame->gs = cpuState->gs;
176//	frame->fs = cpuState->fs;
177//	frame->es = cpuState->es;
178//	frame->ds = cpuState->ds;
179	frame->di = cpuState->edi;
180	frame->si = cpuState->esi;
181	frame->bp = cpuState->ebp;
182//	frame->esp = cpuState->esp;
183	frame->bx = cpuState->ebx;
184	frame->dx = cpuState->edx;
185	frame->cx = cpuState->ecx;
186	frame->ax = cpuState->eax;
187//	frame->vector = cpuState->vector;
188//	frame->error_code = cpuState->error_code;
189	frame->ip = cpuState->eip;
190//	frame->cs = cpuState->cs;
191	frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS)
192		| (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS);
193	frame->user_sp = cpuState->user_esp;
194//	frame->user_ss = cpuState->user_ss;
195}
196
197
198#endif	// __x86_64__
199
200
201static void
202get_cpu_state(Thread* thread, iframe* frame, debug_cpu_state* cpuState)
203{
204	// For the floating point state to be correct the calling function must
205	// not use these registers (not even indirectly).
206#ifdef __x86_64__
207	memset(&cpuState->extended_registers, 0,
208		sizeof(cpuState->extended_registers));
209
210	if (frame->fpu != nullptr) {
211		if (gHasXsave) {
212			// TODO check the xsave header to know the actual size of the
213			// register context depending on what is saved. For now we assume
214			// there is only the YMM AVX registers
215			memcpy(&cpuState->extended_registers, frame->fpu,
216				sizeof(cpuState->extended_registers));
217		} else {
218			// Only the "legacy area" saved by fxsave is available
219			memcpy(&cpuState->extended_registers, frame->fpu,
220				sizeof(cpuState->extended_registers.fp_fxsave));
221		}
222	}
223#else
224	Thread* thisThread = thread_get_current_thread();
225	if (gHasSSE) {
226		if (thread == thisThread) {
227			// Since fxsave requires 16-byte alignment and this isn't guaranteed
228			// for the passed buffer, we use our thread's fpu_state field as
229			// temporary buffer. We need to disable interrupts to make use of
230			// it.
231			Thread* thread = thread_get_current_thread();
232			InterruptsLocker locker;
233			x86_fxsave(thread->arch_info.fpu_state);
234				// unlike fnsave, fxsave doesn't reinit the FPU state
235		}
236		memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state,
237			sizeof(cpuState->extended_registers));
238	} else {
239		if (thread == thisThread) {
240			x86_fnsave(&cpuState->extended_registers);
241			// fnsave reinits the FPU state after saving, so we need to
242			// load it again
243			x86_frstor(&cpuState->extended_registers);
244		} else {
245			memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state,
246				sizeof(cpuState->extended_registers));
247		}
248		// TODO: Convert to fxsave format!
249	}
250#endif
251	get_iframe_registers(frame, cpuState);
252}
253
254
255static inline void
256install_breakpoints(const arch_team_debug_info& teamInfo)
257{
258	// set breakpoints
259	asm("mov %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address));
260	asm("mov %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address));
261	asm("mov %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address));
262	asm("mov %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address));
263
264	// enable breakpoints
265	asm("mov %0, %%dr7" : : "r"(teamInfo.dr7));
266}
267
268
269static inline void
270disable_breakpoints()
271{
272	asm("mov %0, %%dr7" : : "r"((size_t)X86_BREAKPOINTS_DISABLED_DR7));
273}
274
275
276/*! Sets a break-/watchpoint in the given team info.
277	Interrupts must be disabled and the team debug info lock be held.
278*/
279static inline status_t
280set_breakpoint(arch_team_debug_info& info, void* address, size_t type,
281	size_t length, bool setGlobalFlag)
282{
283	// check, if there is already a breakpoint at that address
284	bool alreadySet = false;
285	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
286		if (info.breakpoints[i].address == address
287			&& info.breakpoints[i].type == type) {
288			alreadySet = true;
289			break;
290		}
291	}
292
293	if (!alreadySet) {
294		// find a free slot
295		int32 slot = -1;
296		for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
297			if (!info.breakpoints[i].address) {
298				slot = i;
299				break;
300			}
301		}
302
303		// init the breakpoint
304		if (slot >= 0) {
305			info.breakpoints[slot].address = address;
306			info.breakpoints[slot].type = type;
307			info.breakpoints[slot].length = length;
308
309			info.dr7 |= (length << sDR7Len[slot])
310				| (type << sDR7RW[slot])
311				| (1 << sDR7L[slot]);
312			if (setGlobalFlag)
313				info.dr7 |= (1 << sDR7G[slot]);
314		} else {
315			if (type == X86_INSTRUCTION_BREAKPOINT)
316				return B_NO_MORE_BREAKPOINTS;
317			else
318				return B_NO_MORE_WATCHPOINTS;
319		}
320	}
321
322	return B_OK;
323}
324
325
326/*! Clears a break-/watchpoint in the given team info.
327	Interrupts must be disabled and the team debug info lock be held.
328*/
329static inline status_t
330clear_breakpoint(arch_team_debug_info& info, void* address, bool watchpoint)
331{
332	// find the breakpoint
333	int32 slot = -1;
334	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
335		if (info.breakpoints[i].address == address
336			&& (watchpoint
337				!= (info.breakpoints[i].type == X86_INSTRUCTION_BREAKPOINT))) {
338			slot = i;
339			break;
340		}
341	}
342
343	// clear the breakpoint
344	if (slot >= 0) {
345		info.breakpoints[slot].address = NULL;
346
347		info.dr7 &= ~((0x3 << sDR7Len[slot])
348			| (0x3 << sDR7RW[slot])
349			| (1 << sDR7L[slot])
350			| (1 << sDR7G[slot]));
351	} else {
352		if (watchpoint)
353			return B_WATCHPOINT_NOT_FOUND;
354		else
355			return B_BREAKPOINT_NOT_FOUND;
356	}
357
358	return B_OK;
359}
360
361
362static status_t
363set_breakpoint(void* address, size_t type, size_t length)
364{
365	if (!address)
366		return B_BAD_VALUE;
367
368	Thread* thread = thread_get_current_thread();
369
370	cpu_status state = disable_interrupts();
371	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
372
373	status_t error = set_breakpoint(thread->team->debug_info.arch_info, address,
374		type, length, false);
375
376	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
377	restore_interrupts(state);
378
379	return error;
380}
381
382
383static status_t
384clear_breakpoint(void* address, bool watchpoint)
385{
386	if (!address)
387		return B_BAD_VALUE;
388
389	Thread* thread = thread_get_current_thread();
390
391	cpu_status state = disable_interrupts();
392	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
393
394	status_t error = clear_breakpoint(thread->team->debug_info.arch_info,
395		address, watchpoint);
396
397	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
398	restore_interrupts(state);
399
400	return error;
401}
402
403
404#if KERNEL_BREAKPOINTS
405
406
407static void
408install_breakpoints_per_cpu(void* /*cookie*/, int cpu)
409{
410	Team* kernelTeam = team_get_kernel_team();
411
412	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
413
414	install_breakpoints(kernelTeam->debug_info.arch_info);
415
416	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
417}
418
419
420static status_t
421set_kernel_breakpoint(void* address, size_t type, size_t length)
422{
423	if (!address)
424		return B_BAD_VALUE;
425
426	Team* kernelTeam = team_get_kernel_team();
427
428	cpu_status state = disable_interrupts();
429	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
430
431	status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address,
432		type, length, true);
433
434	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
435
436	call_all_cpus(install_breakpoints_per_cpu, NULL);
437
438	restore_interrupts(state);
439
440	return error;
441}
442
443
444static status_t
445clear_kernel_breakpoint(void* address, bool watchpoint)
446{
447	if (!address)
448		return B_BAD_VALUE;
449
450	Team* kernelTeam = team_get_kernel_team();
451
452	cpu_status state = disable_interrupts();
453	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
454
455	status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info,
456		address, watchpoint);
457
458	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
459
460	call_all_cpus(install_breakpoints_per_cpu, NULL);
461
462	restore_interrupts(state);
463
464	return error;
465}
466
467#endif	// KERNEL_BREAKPOINTS
468
469
470static inline status_t
471check_watch_point_parameters(void* address, uint32 type, int32 length,
472	size_t& archType, size_t& archLength)
473{
474	// check type
475	switch (type) {
476		case B_DATA_WRITE_WATCHPOINT:
477			archType = X86_DATA_WRITE_BREAKPOINT;
478			break;
479		case B_DATA_READ_WRITE_WATCHPOINT:
480			archType = X86_DATA_READ_WRITE_BREAKPOINT;
481			break;
482		case B_DATA_READ_WATCHPOINT:
483		default:
484			return B_WATCHPOINT_TYPE_NOT_SUPPORTED;
485			break;
486	}
487
488	// check length and alignment
489	switch (length) {
490		case 1:
491			archLength = X86_BREAKPOINT_LENGTH_1;
492			break;
493		case 2:
494			if ((addr_t)address & 0x1)
495				return B_BAD_WATCHPOINT_ALIGNMENT;
496			archLength = X86_BREAKPOINT_LENGTH_2;
497			break;
498		case 4:
499			if ((addr_t)address & 0x3)
500				return B_BAD_WATCHPOINT_ALIGNMENT;
501			archLength = X86_BREAKPOINT_LENGTH_4;
502			break;
503		default:
504			return B_WATCHPOINT_LENGTH_NOT_SUPPORTED;
505	}
506
507	return B_OK;
508}
509
510
511// #pragma mark - kernel debugger commands
512
513
514#if KERNEL_BREAKPOINTS
515
516static int
517debugger_breakpoints(int argc, char** argv)
518{
519	Team* kernelTeam = team_get_kernel_team();
520	arch_team_debug_info& info = kernelTeam->debug_info.arch_info;
521
522	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
523		kprintf("breakpoint[%" B_PRId32 "] ", i);
524
525		if (info.breakpoints[i].address != NULL) {
526			kprintf("%p ", info.breakpoints[i].address);
527			switch (info.breakpoints[i].type) {
528				case X86_INSTRUCTION_BREAKPOINT:
529					kprintf("instruction");
530					break;
531				case X86_IO_READ_WRITE_BREAKPOINT:
532					kprintf("io read/write");
533					break;
534				case X86_DATA_WRITE_BREAKPOINT:
535					kprintf("data write");
536					break;
537				case X86_DATA_READ_WRITE_BREAKPOINT:
538					kprintf("data read/write");
539					break;
540			}
541
542			int length = 1;
543			switch (info.breakpoints[i].length) {
544				case X86_BREAKPOINT_LENGTH_1:
545					length = 1;
546					break;
547				case X86_BREAKPOINT_LENGTH_2:
548					length = 2;
549					break;
550				case X86_BREAKPOINT_LENGTH_4:
551					length = 4;
552					break;
553			}
554
555			if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT)
556				kprintf(" %d byte%s", length, (length > 1 ? "s" : ""));
557		} else
558			kprintf("unused");
559
560		kprintf("\n");
561	}
562
563	return 0;
564}
565
566
567static int
568debugger_breakpoint(int argc, char** argv)
569{
570	// get arguments
571
572	if (argc < 2 || argc > 3)
573		return print_debugger_command_usage(argv[0]);
574
575	addr_t address = strtoul(argv[1], NULL, 0);
576	if (address == 0)
577		return print_debugger_command_usage(argv[0]);
578
579	bool clear = false;
580	if (argc == 3) {
581		if (strcmp(argv[2], "clear") == 0)
582			clear = true;
583		else
584			return print_debugger_command_usage(argv[0]);
585	}
586
587	// set/clear breakpoint
588
589	arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
590
591	status_t error;
592
593	if (clear) {
594		error = clear_breakpoint(info, (void*)address, false);
595	} else {
596		error = set_breakpoint(info, (void*)address, X86_INSTRUCTION_BREAKPOINT,
597			X86_BREAKPOINT_LENGTH_1, true);
598	}
599
600	if (error == B_OK)
601		call_all_cpus_sync(install_breakpoints_per_cpu, NULL);
602	else
603		kprintf("Failed to install breakpoint: %s\n", strerror(error));
604
605	return 0;
606}
607
608
609static int
610debugger_watchpoint(int argc, char** argv)
611{
612	// get arguments
613
614	if (argc < 2 || argc > 4)
615		return print_debugger_command_usage(argv[0]);
616
617	addr_t address = strtoul(argv[1], NULL, 0);
618	if (address == 0)
619		return print_debugger_command_usage(argv[0]);
620
621	bool clear = false;
622	bool readWrite = false;
623	int argi = 2;
624	int length = 1;
625	if (argc >= 3) {
626		if (strcmp(argv[argi], "clear") == 0) {
627			clear = true;
628			argi++;
629		} else if (strcmp(argv[argi], "rw") == 0) {
630			readWrite = true;
631			argi++;
632		}
633
634		if (!clear && argi < argc)
635			length = strtoul(argv[argi++], NULL, 0);
636
637		if (length == 0 || argi < argc)
638			return print_debugger_command_usage(argv[0]);
639	}
640
641	// set/clear breakpoint
642
643	arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
644
645	status_t error;
646
647	if (clear) {
648		error = clear_breakpoint(info, (void*)address, true);
649	} else {
650		uint32 type = readWrite ? B_DATA_READ_WRITE_WATCHPOINT
651			: B_DATA_WRITE_WATCHPOINT;
652
653		size_t archType, archLength;
654		error = check_watch_point_parameters((void*)address, type, length,
655			archType, archLength);
656
657		if (error == B_OK) {
658			error = set_breakpoint(info, (void*)address, archType, archLength,
659				true);
660		}
661	}
662
663	if (error == B_OK)
664		call_all_cpus_sync(install_breakpoints_per_cpu, NULL);
665	else
666		kprintf("Failed to install breakpoint: %s\n", strerror(error));
667
668	return 0;
669}
670
671
672static int
673debugger_single_step(int argc, char** argv)
674{
675	// TODO: Since we need an iframe, this doesn't work when KDL wasn't entered
676	// via an exception.
677
678	iframe* frame = x86_get_current_iframe();
679	if (frame == NULL) {
680		kprintf("Failed to get the current iframe!\n");
681		return 0;
682	}
683
684	frame->flags |= (1 << X86_EFLAGS_TF);
685
686	return B_KDEBUG_QUIT;
687}
688
689
690#endif	// KERNEL_BREAKPOINTS
691
692
693// #pragma mark - in-kernel public interface
694
695
696void
697arch_clear_team_debug_info(arch_team_debug_info* info)
698{
699	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++)
700		info->breakpoints[i].address = NULL;
701
702	info->dr7 = X86_BREAKPOINTS_DISABLED_DR7;
703}
704
705
706void
707arch_destroy_team_debug_info(arch_team_debug_info* info)
708{
709	arch_clear_team_debug_info(info);
710}
711
712
713void
714arch_clear_thread_debug_info(arch_thread_debug_info* info)
715{
716	info->flags = 0;
717}
718
719
720void
721arch_destroy_thread_debug_info(arch_thread_debug_info* info)
722{
723	arch_clear_thread_debug_info(info);
724}
725
726
727void
728arch_update_thread_single_step()
729{
730	if (iframe* frame = x86_get_user_iframe()) {
731		Thread* thread = thread_get_current_thread();
732
733		// set/clear TF in EFLAGS depending on whether single stepping is
734		// desired
735		if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP)
736			frame->flags |= (1 << X86_EFLAGS_TF);
737		else
738			frame->flags &= ~(1 << X86_EFLAGS_TF);
739	}
740}
741
742
743void
744arch_set_debug_cpu_state(const debug_cpu_state* cpuState)
745{
746	if (iframe* frame = x86_get_user_iframe()) {
747		// For the floating point state to be correct the calling function must
748		// not use these registers (not even indirectly).
749#ifdef __x86_64__
750		Thread* thread = thread_get_current_thread();
751		memcpy(thread->arch_info.fpu_state, &cpuState->extended_registers,
752			sizeof(cpuState->extended_registers));
753		frame->fpu = &thread->arch_info.fpu_state;
754#else
755		if (gHasSSE) {
756			// Since fxrstor requires 16-byte alignment and this isn't
757			// guaranteed passed buffer, we use our thread's fpu_state field as
758			// temporary buffer. We need to disable interrupts to make use of
759			// it.
760			Thread* thread = thread_get_current_thread();
761			InterruptsLocker locker;
762			memcpy(thread->arch_info.fpu_state, &cpuState->extended_registers,
763				sizeof(cpuState->extended_registers));
764			x86_fxrstor(thread->arch_info.fpu_state);
765		} else {
766			// TODO: Implement! We need to convert the format first.
767//			x86_frstor(&cpuState->extended_registers);
768		}
769#endif
770		set_iframe_registers(frame, cpuState);
771	}
772}
773
774
775void
776arch_get_debug_cpu_state(debug_cpu_state* cpuState)
777{
778	if (iframe* frame = x86_get_user_iframe())
779		get_cpu_state(thread_get_current_thread(), frame, cpuState);
780}
781
782
783/*!	\brief Retrieves the CPU state for the given thread.
784	The thread must not be running and the thread's scheduler spinlock must be
785	held.
786	\param thread The thread whose CPU state to retrieve.
787	\param cpuState Pointer to pre-allocated storage for the CPU state.
788	\return \c B_OK, if everything goes fine, another error code, if the CPU
789		state could not be retrieved.
790*/
791status_t
792arch_get_thread_debug_cpu_state(Thread* thread, debug_cpu_state* cpuState)
793{
794	iframe* frame = x86_get_thread_user_iframe(thread);
795	if (frame == NULL)
796		return B_BAD_VALUE;
797
798	get_cpu_state(thread, frame, cpuState);
799	return B_OK;
800}
801
802
803status_t
804arch_set_breakpoint(void* address)
805{
806	return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
807		X86_BREAKPOINT_LENGTH_1);
808}
809
810
811status_t
812arch_clear_breakpoint(void* address)
813{
814	return clear_breakpoint(address, false);
815}
816
817
818status_t
819arch_set_watchpoint(void* address, uint32 type, int32 length)
820{
821	size_t archType, archLength;
822	status_t error = check_watch_point_parameters(address, type, length,
823		archType, archLength);
824	if (error != B_OK)
825		return error;
826
827	return set_breakpoint(address, archType, archLength);
828}
829
830
831status_t
832arch_clear_watchpoint(void* address)
833{
834	return clear_breakpoint(address, true);
835}
836
837
838bool
839arch_has_breakpoints(arch_team_debug_info* info)
840{
841	// Reading info->dr7 is atomically, so we don't need to lock. The caller
842	// has to ensure, that the info doesn't go away.
843	return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7);
844}
845
846
847#if KERNEL_BREAKPOINTS
848
849status_t
850arch_set_kernel_breakpoint(void* address)
851{
852	status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
853		X86_BREAKPOINT_LENGTH_1);
854
855	if (error != B_OK) {
856		panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s",
857			strerror(error));
858	}
859
860	return error;
861}
862
863
864status_t
865arch_clear_kernel_breakpoint(void* address)
866{
867	status_t error = clear_kernel_breakpoint(address, false);
868
869	if (error != B_OK) {
870		panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s",
871			strerror(error));
872	}
873
874	return error;
875}
876
877
878status_t
879arch_set_kernel_watchpoint(void* address, uint32 type, int32 length)
880{
881	size_t archType, archLength;
882	status_t error = check_watch_point_parameters(address, type, length,
883		archType, archLength);
884
885	if (error == B_OK)
886		error = set_kernel_breakpoint(address, archType, archLength);
887
888	if (error != B_OK) {
889		panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s",
890			strerror(error));
891	}
892
893	return error;
894}
895
896
897status_t
898arch_clear_kernel_watchpoint(void* address)
899{
900	status_t error = clear_kernel_breakpoint(address, true);
901
902	if (error != B_OK) {
903		panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s",
904			strerror(error));
905	}
906
907	return error;
908}
909
910#endif	// KERNEL_BREAKPOINTS
911
912
913// #pragma mark - x86 implementation interface
914
915
916/**
917 *	Interrupts are disabled. \a frame is unused, i.e. can be \c NULL.
918 */
919void
920x86_init_user_debug_at_kernel_exit(iframe* frame)
921{
922	Thread* thread = thread_get_current_thread();
923
924	if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED))
925		return;
926
927	// disable kernel breakpoints
928	disable_breakpoints();
929
930	// install the user breakpoints
931	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
932
933	arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info;
934
935	install_breakpoints(teamInfo);
936
937	atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED);
938
939	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
940}
941
942
943/**
944 *	Interrupts are disabled.
945 */
946void
947x86_exit_user_debug_at_kernel_entry()
948{
949	Thread* thread = thread_get_current_thread();
950
951	// We need to save the current values of dr6 and dr7 in the CPU structure,
952	// since in case of a debug exception we might overwrite them before
953	// x86_handle_debug_exception() is called. Debug exceptions occur when
954	// hitting a hardware break/watchpoint or when single-stepping.
955	asm("mov %%dr6, %0" : "=r"(thread->cpu->arch.dr6));
956	asm("mov %%dr7, %0" : "=r"(thread->cpu->arch.dr7));
957
958	// The remainder needs only be done, when user breakpoints are installed.
959	if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED))
960		return;
961
962	// disable user breakpoints
963	disable_breakpoints();
964
965	// install kernel breakpoints
966	Team* kernelTeam = team_get_kernel_team();
967
968	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
969
970	install_breakpoints(kernelTeam->debug_info.arch_info);
971
972	atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED);
973
974	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
975}
976
977
978/**
979 *	Interrupts are disabled and will possibly be enabled by the function.
980 */
981void
982x86_handle_debug_exception(iframe* frame)
983{
984	Thread* thread = thread_get_current_thread();
985
986	// Get dr6 and dr7. If the given iframe is a userland frame, the exception
987	// obviously occurred in userland. In that case
988	// x86_exit_user_debug_at_kernel_entry() has already been invoked and dr6
989	// and dr7 are stored in the cpu info. Otherwise we need to fetch the
990	// current values from the registers.
991	size_t dr6;
992	size_t dr7;
993	if (IFRAME_IS_USER(frame)) {
994		dr6 = thread->cpu->arch.dr6;
995		dr7 = thread->cpu->arch.dr7;
996	} else {
997		asm("mov %%dr6, %0" : "=r"(dr6));
998		asm("mov %%dr7, %0" : "=r"(dr7));
999	}
1000
1001	TRACE(("x86_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7));
1002
1003	// check, which exception condition applies
1004	if (dr6 & X86_DR6_BREAKPOINT_MASK) {
1005		// breakpoint
1006
1007		// check which breakpoint was taken
1008		bool watchpoint = true;
1009		for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
1010			if (dr6 & (1 << sDR6B[i])) {
1011				size_t type = (dr7 >> sDR7RW[i]) & 0x3;
1012				if (type == X86_INSTRUCTION_BREAKPOINT)
1013					watchpoint = false;
1014			}
1015		}
1016
1017		if (IFRAME_IS_USER(frame)) {
1018			// enable interrupts and notify the debugger
1019			enable_interrupts();
1020
1021			if (watchpoint)
1022				user_debug_watchpoint_hit();
1023			else
1024				user_debug_breakpoint_hit(false);
1025		} else {
1026			panic("hit kernel %spoint: dr6: 0x%lx, dr7: 0x%lx",
1027				watchpoint ? "watch" : "break", dr6, dr7);
1028		}
1029	} else if (dr6 & (1 << X86_DR6_BD)) {
1030		// general detect exception
1031		// Occurs only, if GD in DR7 is set (which we don't do) and someone
1032		// tries to write to the debug registers.
1033		if (IFRAME_IS_USER(frame)) {
1034			dprintf("x86_handle_debug_exception(): ignoring spurious general "
1035				"detect exception\n");
1036
1037			enable_interrupts();
1038		} else
1039			panic("spurious general detect exception in kernel mode");
1040	} else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) {
1041		// single step
1042
1043		if (IFRAME_IS_USER(frame)) {
1044			// enable interrupts and notify the debugger
1045			enable_interrupts();
1046
1047			user_debug_single_stepped();
1048		} else {
1049			// Disable single-stepping -- the next "step" command will re-enable
1050			// it, but we don't want it when continuing otherwise.
1051			frame->flags &= ~(1 << X86_EFLAGS_TF);
1052
1053			// Determine whether the exception occurred at a syscall/trap
1054			// kernel entry or whether this is genuine kernel single-stepping.
1055			bool inKernel = true;
1056			if (thread->team != team_get_kernel_team()
1057				&& x86_get_user_iframe() == NULL) {
1058				// TODO: This is not yet fully correct, since a newly created
1059				// thread that hasn't entered userland yet also has this
1060				// property.
1061				inKernel = false;
1062			}
1063
1064			if (inKernel) {
1065				panic("kernel single step");
1066			} else {
1067				// The thread is a userland thread and it just entered the
1068				// kernel when the single-step exception occurred. This happens
1069				// e.g. when sysenter is called with single-stepping enabled.
1070				// We need to ignore the exception now and send a single-step
1071				// notification later, when the thread wants to return from the
1072				// kernel.
1073				InterruptsSpinLocker threadDebugInfoLocker(
1074					thread->debug_info.lock);
1075
1076				// Check whether the team is still being debugged and set
1077				// the B_THREAD_DEBUG_NOTIFY_SINGLE_STEP and
1078				// B_THREAD_DEBUG_STOP flags, so that the thread will be
1079				// stopped when it is going to leave the kernel and notify the
1080				// debugger about the single-step event.
1081				int32 teamDebugFlags
1082					= atomic_get(&thread->team->debug_info.flags);
1083				if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
1084					atomic_or(&thread->debug_info.flags,
1085						B_THREAD_DEBUG_NOTIFY_SINGLE_STEP
1086							| B_THREAD_DEBUG_STOP);
1087
1088					// also set the respective thread flag
1089					atomic_or(&thread->flags, THREAD_FLAGS_DEBUG_THREAD);
1090				}
1091			}
1092		}
1093	} else if (dr6 & (1 << X86_DR6_BT)) {
1094		// task switch
1095		// Occurs only, if T in EFLAGS is set (which we don't do).
1096		if (IFRAME_IS_USER(frame)) {
1097			dprintf("x86_handle_debug_exception(): ignoring spurious task switch "
1098				"exception\n");
1099
1100			enable_interrupts();
1101		} else
1102			panic("spurious task switch exception in kernel mode");
1103	} else {
1104		if (IFRAME_IS_USER(frame)) {
1105			TRACE(("x86_handle_debug_exception(): ignoring spurious debug "
1106				"exception (no condition recognized)\n"));
1107
1108			enable_interrupts();
1109		} else {
1110			panic("spurious debug exception in kernel mode (no condition "
1111				"recognized)");
1112		}
1113	}
1114}
1115
1116
1117/**
1118 *	Interrupts are disabled and will possibly be enabled by the function.
1119 */
1120void
1121x86_handle_breakpoint_exception(iframe* frame)
1122{
1123	TRACE(("x86_handle_breakpoint_exception()\n"));
1124
1125	// reset eip to the int3 instruction
1126	frame->ip--;
1127
1128	if (!IFRAME_IS_USER(frame)) {
1129		panic("breakpoint exception in kernel mode");
1130		return;
1131	}
1132
1133	enable_interrupts();
1134
1135	user_debug_breakpoint_hit(true);
1136}
1137
1138
1139void
1140x86_init_user_debug()
1141{
1142	// get debug settings
1143	if (void* handle = load_driver_settings("kernel")) {
1144		sQEmuSingleStepHack = get_driver_boolean_parameter(handle,
1145			"qemu_single_step_hack", false, false);;
1146
1147		unload_driver_settings(handle);
1148	}
1149
1150#if KERNEL_BREAKPOINTS
1151	// install debugger commands
1152	add_debugger_command_etc("breakpoints", &debugger_breakpoints,
1153		"Lists current break-/watchpoints",
1154		"\n"
1155		"Lists the current kernel break-/watchpoints.\n", 0);
1156	add_debugger_command_alias("watchpoints", "breakpoints", NULL);
1157	add_debugger_command_etc("breakpoint", &debugger_breakpoint,
1158		"Set/clears a breakpoint",
1159		"<address> [ clear ]\n"
1160		"Sets respectively clears the breakpoint at address <address>.\n", 0);
1161	add_debugger_command_etc("watchpoint", &debugger_watchpoint,
1162		"Set/clears a watchpoint",
1163		"<address> <address> ( [ rw ] [ <size> ] | clear )\n"
1164		"Sets respectively clears the watchpoint at address <address>.\n"
1165		"If \"rw\" is given the new watchpoint is a read/write watchpoint\n"
1166		"otherwise a write watchpoint only.\n", 0);
1167	add_debugger_command_etc("step", &debugger_single_step,
1168		"Single-steps to the next instruction",
1169		"\n"
1170		"Single-steps to the next instruction.\n", 0);
1171#endif
1172}
1173
1174