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