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