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