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