xref: /haiku/src/system/kernel/arch/x86/arch_user_debugger.cpp (revision 91054f1d38dd7827c0f0ba9490c213775ec7b471)
1 /*
2  * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <arch/user_debugger.h>
7 
8 #include <string.h>
9 
10 #include <debugger.h>
11 #include <driver_settings.h>
12 #include <int.h>
13 #include <team.h>
14 #include <thread.h>
15 
16 
17 //#define TRACE_ARCH_USER_DEBUGGER
18 #ifdef TRACE_ARCH_USER_DEBUGGER
19 #	define TRACE(x) dprintf x
20 #else
21 #	define TRACE(x) ;
22 #endif
23 
24 #define B_NO_MORE_BREAKPOINTS				B_BUSY
25 #define B_NO_MORE_WATCHPOINTS				B_BUSY
26 #define B_BAD_WATCHPOINT_ALIGNMENT			B_BAD_VALUE
27 #define B_WATCHPOINT_TYPE_NOT_SUPPORTED		B_NOT_SUPPORTED
28 #define B_WATCHPOINT_LENGTH_NOT_SUPPORTED	B_NOT_SUPPORTED
29 #define B_BREAKPOINT_NOT_FOUND				B_NAME_NOT_FOUND
30 #define B_WATCHPOINT_NOT_FOUND				B_NAME_NOT_FOUND
31 	// ToDo: Make those real error codes.
32 
33 // maps breakpoint slot index to LEN_i LSB number
34 static const uint32 sDR7Len[4] = {
35 	X86_DR7_LEN0_LSB, X86_DR7_LEN1_LSB, X86_DR7_LEN2_LSB, X86_DR7_LEN3_LSB
36 };
37 
38 // maps breakpoint slot index to R/W_i LSB number
39 static const uint32 sDR7RW[4] = {
40 	X86_DR7_RW0_LSB, X86_DR7_RW1_LSB, X86_DR7_RW2_LSB, X86_DR7_RW3_LSB
41 };
42 
43 // maps breakpoint slot index to L_i bit number
44 static const uint32 sDR7L[4] = {
45 	X86_DR7_L0, X86_DR7_L1, X86_DR7_L2, X86_DR7_L3
46 };
47 
48 // maps breakpoint slot index to G_i bit number
49 static const uint32 sDR7G[4] = {
50 	X86_DR7_G0, X86_DR7_G1, X86_DR7_G2, X86_DR7_G3
51 };
52 
53 // maps breakpoint slot index to B_i bit number
54 static const uint32 sDR6B[4] = {
55 	X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3
56 };
57 
58 // Enables a hack to make single stepping work under qemu. Set via kernel
59 // driver settings.
60 static bool sQEmuSingleStepHack = false;
61 
62 
63 static inline void
64 install_breakpoints(const arch_team_debug_info &teamInfo)
65 {
66 	// set breakpoints
67 	asm("movl %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address));
68 	asm("movl %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address));
69 	asm("movl %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address));
70 //	asm("movl %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address));
71 		// DR3 is used to hold the current struct thread*.
72 
73 	// enable breakpoints
74 	asm("movl %0, %%dr7" : : "r"(teamInfo.dr7));
75 }
76 
77 
78 static inline void
79 disable_breakpoints()
80 {
81 	asm("movl %0, %%dr7" : : "r"(X86_BREAKPOINTS_DISABLED_DR7));
82 }
83 
84 
85 /*! Sets a break-/watchpoint in the given team info.
86 	Interrupts must be disabled and the team debug info lock be held.
87 */
88 static inline status_t
89 set_breakpoint(arch_team_debug_info &info, void *address, uint32 type,
90 	uint32 length, bool setGlobalFlag)
91 {
92 	// check, if there is already a breakpoint at that address
93 	bool alreadySet = false;
94 	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
95 		if (info.breakpoints[i].address == address
96 			&& info.breakpoints[i].type == type) {
97 			alreadySet = true;
98 			break;
99 		}
100 	}
101 
102 	if (!alreadySet) {
103 		// find a free slot
104 		int32 slot = -1;
105 		for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
106 			if (!info.breakpoints[i].address) {
107 				slot = i;
108 				break;
109 			}
110 		}
111 
112 		// init the breakpoint
113 		if (slot >= 0) {
114 			info.breakpoints[slot].address = address;
115 			info.breakpoints[slot].type = type;
116 			info.breakpoints[slot].length = length;
117 
118 			info.dr7 |= (length << sDR7Len[slot])
119 				| (type << sDR7RW[slot])
120 				| (1 << sDR7L[slot]);
121 			if (setGlobalFlag)
122 				info.dr7 |= (1 << sDR7G[slot]);
123 		} else {
124 			if (type == X86_INSTRUCTION_BREAKPOINT)
125 				return B_NO_MORE_BREAKPOINTS;
126 			else
127 				return B_NO_MORE_WATCHPOINTS;
128 		}
129 	}
130 
131 	return B_OK;
132 }
133 
134 
135 /*! Clears a break-/watchpoint in the given team info.
136 	Interrupts must be disabled and the team debug info lock be held.
137 */
138 static inline status_t
139 clear_breakpoint(arch_team_debug_info &info, void *address, bool watchpoint)
140 {
141 	// find the breakpoint
142 	int32 slot = -1;
143 	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
144 		if (info.breakpoints[i].address == address
145 			&& (watchpoint
146 				!= (info.breakpoints[i].type == X86_INSTRUCTION_BREAKPOINT))) {
147 			slot = i;
148 			break;
149 		}
150 	}
151 
152 	// clear the breakpoint
153 	if (slot >= 0) {
154 		info.breakpoints[slot].address = NULL;
155 
156 		info.dr7 &= ~((0x3 << sDR7Len[slot])
157 			| (0x3 << sDR7RW[slot])
158 			| (1 << sDR7L[slot])
159 			| (1 << sDR7G[slot]));
160 	} else {
161 		if (watchpoint)
162 			return B_WATCHPOINT_NOT_FOUND;
163 		else
164 			return B_BREAKPOINT_NOT_FOUND;
165 	}
166 
167 	return B_OK;
168 }
169 
170 
171 static status_t
172 set_breakpoint(void *address, uint32 type, uint32 length)
173 {
174 	if (!address)
175 		return B_BAD_VALUE;
176 
177 	struct thread *thread = thread_get_current_thread();
178 
179 	cpu_status state = disable_interrupts();
180 	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
181 
182 	status_t error = set_breakpoint(thread->team->debug_info.arch_info, address,
183 		type, length, false);
184 
185 	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
186 	restore_interrupts(state);
187 
188 	return error;
189 }
190 
191 
192 static status_t
193 clear_breakpoint(void *address, bool watchpoint)
194 {
195 	if (!address)
196 		return B_BAD_VALUE;
197 
198 	struct thread *thread = thread_get_current_thread();
199 
200 	cpu_status state = disable_interrupts();
201 	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
202 
203 	status_t error = clear_breakpoint(thread->team->debug_info.arch_info,
204 		address, watchpoint);
205 
206 	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
207 	restore_interrupts(state);
208 
209 	return error;
210 }
211 
212 
213 #if KERNEL_BREAKPOINTS
214 
215 
216 static void
217 install_breakpoints_per_cpu(void* /*cookie*/, int cpu)
218 {
219 	struct team* kernelTeam = team_get_kernel_team();
220 
221 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
222 
223 	install_breakpoints(kernelTeam->debug_info.arch_info);
224 
225 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
226 }
227 
228 
229 static status_t
230 set_kernel_breakpoint(void *address, uint32 type, uint32 length)
231 {
232 	if (!address)
233 		return B_BAD_VALUE;
234 
235 	struct team* kernelTeam = team_get_kernel_team();
236 
237 	cpu_status state = disable_interrupts();
238 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
239 
240 	status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address,
241 		type, length, true);
242 
243 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
244 
245 	call_all_cpus(install_breakpoints_per_cpu, NULL);
246 
247 	restore_interrupts(state);
248 
249 	return error;
250 }
251 
252 
253 static status_t
254 clear_kernel_breakpoint(void *address, bool watchpoint)
255 {
256 	if (!address)
257 		return B_BAD_VALUE;
258 
259 	struct team* kernelTeam = team_get_kernel_team();
260 
261 	cpu_status state = disable_interrupts();
262 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
263 
264 	status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info,
265 		address, watchpoint);
266 
267 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
268 
269 	call_all_cpus(install_breakpoints_per_cpu, NULL);
270 
271 	restore_interrupts(state);
272 
273 	return error;
274 }
275 
276 #endif	// KERNEL_BREAKPOINTS
277 
278 
279 static inline status_t
280 check_watch_point_parameters(void* address, uint32 type, int32 length,
281 	uint32& archType, uint32& archLength)
282 {
283 	// check type
284 	switch (type) {
285 		case B_DATA_WRITE_WATCHPOINT:
286 			archType = X86_DATA_WRITE_BREAKPOINT;
287 			break;
288 		case B_DATA_READ_WRITE_WATCHPOINT:
289 			archType = X86_DATA_READ_WRITE_BREAKPOINT;
290 			break;
291 		case B_DATA_READ_WATCHPOINT:
292 		default:
293 			return B_WATCHPOINT_TYPE_NOT_SUPPORTED;
294 			break;
295 	}
296 
297 	// check length and alignment
298 	switch (length) {
299 		case 1:
300 			archLength = X86_BREAKPOINT_LENGTH_1;
301 			break;
302 		case 2:
303 			if ((uint32)address & 0x1)
304 				return B_BAD_WATCHPOINT_ALIGNMENT;
305 			archLength = X86_BREAKPOINT_LENGTH_2;
306 			break;
307 		case 4:
308 			if ((uint32)address & 0x3)
309 				return B_BAD_WATCHPOINT_ALIGNMENT;
310 			archLength = X86_BREAKPOINT_LENGTH_4;
311 			break;
312 		default:
313 			return B_WATCHPOINT_LENGTH_NOT_SUPPORTED;
314 	}
315 
316 	return B_OK;
317 }
318 
319 
320 // #pragma mark - kernel debugger commands
321 
322 #if KERNEL_BREAKPOINTS
323 
324 static int
325 debugger_breakpoints(int argc, char** argv)
326 {
327 	struct team* kernelTeam = team_get_kernel_team();
328 	arch_team_debug_info& info = kernelTeam->debug_info.arch_info;
329 
330 	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
331 		kprintf("breakpoint[%ld] ", i);
332 
333 		if (info.breakpoints[i].address != NULL) {
334 			kprintf("%p ", info.breakpoints[i].address);
335 			switch (info.breakpoints[i].type) {
336 				case X86_INSTRUCTION_BREAKPOINT:
337 					kprintf("instruction");
338 					break;
339 				case X86_IO_READ_WRITE_BREAKPOINT:
340 					kprintf("io read/write");
341 					break;
342 				case X86_DATA_WRITE_BREAKPOINT:
343 					kprintf("data write");
344 					break;
345 				case X86_DATA_READ_WRITE_BREAKPOINT:
346 					kprintf("data read/write");
347 					break;
348 			}
349 
350 			int length = 1;
351 			switch (info.breakpoints[i].length) {
352 				case X86_BREAKPOINT_LENGTH_1:
353 					length = 1;
354 					break;
355 				case X86_BREAKPOINT_LENGTH_2:
356 					length = 2;
357 					break;
358 				case X86_BREAKPOINT_LENGTH_4:
359 					length = 4;
360 					break;
361 			}
362 
363 			if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT)
364 				kprintf(" %d byte%s", length, (length > 1 ? "s" : ""));
365 		} else
366 			kprintf("unused");
367 
368 		kprintf("\n");
369 	}
370 
371 	return 0;
372 }
373 
374 
375 static int
376 debugger_breakpoint(int argc, char** argv)
377 {
378 	// get arguments
379 
380 	if (argc < 2 || argc > 3)
381 		return print_debugger_command_usage(argv[0]);
382 
383 	addr_t address = strtoul(argv[1], NULL, 0);
384 	if (address == 0)
385 		return print_debugger_command_usage(argv[0]);
386 
387 	bool clear = false;
388 	if (argc == 3) {
389 		if (strcmp(argv[2], "clear") == 0)
390 			clear = true;
391 		else
392 			return print_debugger_command_usage(argv[0]);
393 	}
394 
395 	// set/clear breakpoint
396 
397 	arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
398 
399 	status_t error;
400 
401 	if (clear) {
402 		error = clear_breakpoint(info, (void*)address, false);
403 	} else {
404 		error = set_breakpoint(info, (void*)address, X86_INSTRUCTION_BREAKPOINT,
405 			X86_BREAKPOINT_LENGTH_1, true);
406 	}
407 
408 	if (error == B_OK)
409 		call_all_cpus_sync(install_breakpoints_per_cpu, NULL);
410 	else
411 		kprintf("Failed to install breakpoint: %s\n", strerror(error));
412 
413 	return 0;
414 }
415 
416 
417 static int
418 debugger_watchpoint(int argc, char** argv)
419 {
420 	// get arguments
421 
422 	if (argc < 2 || argc > 4)
423 		return print_debugger_command_usage(argv[0]);
424 
425 	addr_t address = strtoul(argv[1], NULL, 0);
426 	if (address == 0)
427 		return print_debugger_command_usage(argv[0]);
428 
429 	bool clear = false;
430 	bool readWrite = false;
431 	int argi = 2;
432 	int length = 1;
433 	if (argc >= 3) {
434 		if (strcmp(argv[argi], "clear") == 0) {
435 			clear = true;
436 			argi++;
437 		} else if (strcmp(argv[argi], "rw") == 0) {
438 			readWrite = true;
439 			argi++;
440 		}
441 
442 		if (!clear && argi < argc)
443 			length = strtoul(argv[argi++], NULL, 0);
444 
445 		if (length == 0 || argi < argc)
446 			return print_debugger_command_usage(argv[0]);
447 	}
448 
449 	// set/clear breakpoint
450 
451 	arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
452 
453 	status_t error;
454 
455 	if (clear) {
456 		error = clear_breakpoint(info, (void*)address, true);
457 	} else {
458 		uint32 type = readWrite ? B_DATA_READ_WRITE_WATCHPOINT
459 			: B_DATA_WRITE_WATCHPOINT;
460 
461 		uint32 archType, archLength;
462 		error = check_watch_point_parameters((void*)address, type, length,
463 			archType, archLength);
464 
465 		if (error == B_OK) {
466 			error = set_breakpoint(info, (void*)address, archType, archLength,
467 				true);
468 		}
469 	}
470 
471 	if (error == B_OK)
472 		call_all_cpus_sync(install_breakpoints_per_cpu, NULL);
473 	else
474 		kprintf("Failed to install breakpoint: %s\n", strerror(error));
475 
476 	return 0;
477 }
478 
479 
480 static int
481 debugger_single_step(int argc, char** argv)
482 {
483 	// TODO: Since we need an iframe, this doesn't work when KDL wasn't entered
484 	// via an exception.
485 
486 	struct iframe* frame = i386_get_current_iframe();
487 	if (frame == NULL) {
488 		kprintf("Failed to get the current iframe!\n");
489 		return 0;
490 	}
491 
492 	frame->flags |= (1 << X86_EFLAGS_TF);
493 
494 	return B_KDEBUG_QUIT;
495 }
496 
497 
498 #endif	// KERNEL_BREAKPOINTS
499 
500 
501 // #pragma mark - in-kernel public interface
502 
503 
504 void
505 arch_clear_team_debug_info(struct arch_team_debug_info *info)
506 {
507 	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++)
508 		info->breakpoints[i].address = NULL;
509 
510 	info->dr7 = X86_BREAKPOINTS_DISABLED_DR7;
511 }
512 
513 
514 void
515 arch_destroy_team_debug_info(struct arch_team_debug_info *info)
516 {
517 	arch_clear_team_debug_info(info);
518 }
519 
520 
521 void
522 arch_clear_thread_debug_info(struct arch_thread_debug_info *info)
523 {
524 	info->flags = 0;
525 }
526 
527 
528 void
529 arch_destroy_thread_debug_info(struct arch_thread_debug_info *info)
530 {
531 	arch_clear_thread_debug_info(info);
532 }
533 
534 
535 void
536 arch_update_thread_single_step()
537 {
538 	if (struct iframe* frame = i386_get_user_iframe()) {
539 		struct thread* thread = thread_get_current_thread();
540 
541 		// set/clear TF in EFLAGS depending on if single stepping is desired
542 		if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP)
543 			frame->flags |= (1 << X86_EFLAGS_TF);
544 		else
545 			frame->flags &= ~(1 << X86_EFLAGS_TF);
546 	}
547 }
548 
549 
550 void
551 arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState)
552 {
553 	if (struct iframe *frame = i386_get_user_iframe()) {
554 		i386_frstor(cpuState->extended_regs);
555 			// For this to be correct the calling function must not use these
556 			// registers (not even indirectly).
557 
558 //		frame->gs = cpuState->gs;
559 //		frame->fs = cpuState->fs;
560 //		frame->es = cpuState->es;
561 //		frame->ds = cpuState->ds;
562 		frame->edi = cpuState->edi;
563 		frame->esi = cpuState->esi;
564 		frame->ebp = cpuState->ebp;
565 		frame->esp = cpuState->esp;
566 		frame->ebx = cpuState->ebx;
567 		frame->edx = cpuState->edx;
568 		frame->ecx = cpuState->ecx;
569 		frame->eax = cpuState->eax;
570 //		frame->vector = cpuState->vector;
571 //		frame->error_code = cpuState->error_code;
572 		frame->eip = cpuState->eip;
573 //		frame->cs = cpuState->cs;
574 		frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS)
575 			| (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS);
576 		frame->user_esp = cpuState->user_esp;
577 //		frame->user_ss = cpuState->user_ss;
578 	}
579 }
580 
581 
582 void
583 arch_get_debug_cpu_state(struct debug_cpu_state *cpuState)
584 {
585 	if (struct iframe *frame = i386_get_user_iframe()) {
586 		i386_fnsave(cpuState->extended_regs);
587 			// For this to be correct the calling function must not use these
588 			// registers (not even indirectly).
589 
590 		cpuState->gs = frame->gs;
591 		cpuState->fs = frame->fs;
592 		cpuState->es = frame->es;
593 		cpuState->ds = frame->ds;
594 		cpuState->edi = frame->edi;
595 		cpuState->esi = frame->esi;
596 		cpuState->ebp = frame->ebp;
597 		cpuState->esp = frame->esp;
598 		cpuState->ebx = frame->ebx;
599 		cpuState->edx = frame->orig_edx;
600 		cpuState->ecx = frame->ecx;
601 		cpuState->eax = frame->orig_eax;
602 		cpuState->vector = frame->vector;
603 		cpuState->error_code = frame->error_code;
604 		cpuState->eip = frame->eip;
605 		cpuState->cs = frame->cs;
606 		cpuState->eflags = frame->flags;
607 		cpuState->user_esp = frame->user_esp;
608 		cpuState->user_ss = frame->user_ss;
609 	}
610 }
611 
612 
613 status_t
614 arch_set_breakpoint(void *address)
615 {
616 	return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
617 		X86_BREAKPOINT_LENGTH_1);
618 }
619 
620 
621 status_t
622 arch_clear_breakpoint(void *address)
623 {
624 	return clear_breakpoint(address, false);
625 }
626 
627 
628 status_t
629 arch_set_watchpoint(void *address, uint32 type, int32 length)
630 {
631 	uint32 archType, archLength;
632 	status_t error = check_watch_point_parameters(address, type, length,
633 		archType, archLength);
634 	if (error != B_OK)
635 		return error;
636 
637 	return set_breakpoint(address, archType, archLength);
638 }
639 
640 
641 status_t
642 arch_clear_watchpoint(void *address)
643 {
644 	return clear_breakpoint(address, false);
645 }
646 
647 
648 bool
649 arch_has_breakpoints(struct arch_team_debug_info *info)
650 {
651 	// Reading info->dr7 is atomically, so we don't need to lock. The caller
652 	// has to ensure, that the info doesn't go away.
653 	return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7);
654 }
655 
656 
657 #if KERNEL_BREAKPOINTS
658 
659 status_t
660 arch_set_kernel_breakpoint(void *address)
661 {
662 	status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
663 		X86_BREAKPOINT_LENGTH_1);
664 
665 	if (error != B_OK) {
666 		panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s",
667 			strerror(error));
668 	}
669 
670 	return error;
671 }
672 
673 
674 status_t
675 arch_clear_kernel_breakpoint(void *address)
676 {
677 	status_t error = clear_kernel_breakpoint(address, false);
678 
679 	if (error != B_OK) {
680 		panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s",
681 			strerror(error));
682 	}
683 
684 	return error;
685 }
686 
687 
688 status_t
689 arch_set_kernel_watchpoint(void *address, uint32 type, int32 length)
690 {
691 	uint32 archType, archLength;
692 	status_t error = check_watch_point_parameters(address, type, length,
693 		archType, archLength);
694 
695 	if (error == B_OK)
696 		error = set_kernel_breakpoint(address, archType, archLength);
697 
698 	if (error != B_OK) {
699 		panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s",
700 			strerror(error));
701 	}
702 
703 	return error;
704 }
705 
706 
707 status_t
708 arch_clear_kernel_watchpoint(void *address)
709 {
710 	status_t error = clear_kernel_breakpoint(address, true);
711 
712 	if (error != B_OK) {
713 		panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s",
714 			strerror(error));
715 	}
716 
717 	return error;
718 }
719 
720 #endif	// KERNEL_BREAKPOINTS
721 
722 
723 // #pragma mark - x86 implementation interface
724 
725 
726 /**
727  *	Interrupts are disabled.
728  */
729 void
730 x86_init_user_debug_at_kernel_exit(struct iframe *frame)
731 {
732 	struct thread *thread = thread_get_current_thread();
733 
734 	if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED))
735 		return;
736 
737 	// disable kernel breakpoints
738 	disable_breakpoints();
739 
740 	GRAB_THREAD_LOCK();
741 	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
742 
743 	arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info;
744 
745 	// install the user breakpoints
746 	install_breakpoints(teamInfo);
747 
748 	atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED);
749 
750 	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
751 	RELEASE_THREAD_LOCK();
752 }
753 
754 
755 /**
756  *	Interrupts are disabled.
757  */
758 void
759 x86_exit_user_debug_at_kernel_entry()
760 {
761 	struct thread *thread = thread_get_current_thread();
762 
763 	if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED))
764 		return;
765 
766 	GRAB_THREAD_LOCK();
767 
768 	// disable user breakpoints
769 	disable_breakpoints();
770 
771 	// install kernel breakpoints
772 	struct team* kernelTeam = team_get_kernel_team();
773 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
774 	install_breakpoints(kernelTeam->debug_info.arch_info);
775 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
776 
777 	atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED);
778 
779 	RELEASE_THREAD_LOCK();
780 }
781 
782 
783 /**
784  *	Interrupts are disabled and will possibly be enabled by the function.
785  */
786 void
787 x86_handle_debug_exception(struct iframe *frame)
788 {
789 	// get debug status and control registers
790 	uint32 dr6, dr7;
791 	asm("movl %%dr6, %0" : "=r"(dr6));
792 	asm("movl %%dr7, %0" : "=r"(dr7));
793 
794 	TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7));
795 
796 	// check, which exception condition applies
797 	if (dr6 & X86_DR6_BREAKPOINT_MASK) {
798 		// breakpoint
799 
800 		// check which breakpoint was taken
801 		bool watchpoint = true;
802 		for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
803 			if (dr6 & (1 << sDR6B[i])) {
804 				// If it is an instruction breakpoint, we need to set RF in
805 				// EFLAGS to prevent triggering the same exception
806 				// again (breakpoint instructions are triggered *before*
807 				// executing the instruction).
808 				uint32 type = (dr7 >> sDR7RW[i]) & 0x3;
809 				if (type == X86_INSTRUCTION_BREAKPOINT) {
810 					frame->flags |= (1 << X86_EFLAGS_RF);
811 					watchpoint = false;
812 				}
813 			}
814 		}
815 
816 		if (IFRAME_IS_USER(frame)) {
817 			// enable interrupts and notify the debugger
818 			enable_interrupts();
819 
820 			if (watchpoint)
821 				user_debug_watchpoint_hit();
822 			else
823 				user_debug_breakpoint_hit(false);
824 		} else {
825 			panic("hit kernel %spoint: dr6: 0x%lx, dr7: 0x%lx",
826 				watchpoint ? "watch" : "break", dr6, dr7);
827 		}
828 	} else if (dr6 & (1 << X86_DR6_BD)) {
829 		// general detect exception
830 		// Occurs only, if GD in DR7 is set (which we don't do) and someone
831 		// tries to write to the debug registers.
832 		if (IFRAME_IS_USER(frame)) {
833 			dprintf("i386_handle_debug_exception(): ignoring spurious general "
834 				"detect exception\n");
835 
836 			enable_interrupts();
837 		} else
838 			panic("spurious general detect exception in kernel mode");
839 	} else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) {
840 		// single step
841 
842 		if (IFRAME_IS_USER(frame)) {
843 			// enable interrupts and notify the debugger
844 			enable_interrupts();
845 
846 			user_debug_single_stepped();
847 		} else {
848 			// Disable single-stepping -- the next "step" command will re-enable
849 			// it, but we don't want it when continuing otherwise.
850 			frame->flags &= ~(1 << X86_EFLAGS_TF);
851 
852 			panic("kernel single step");
853 		}
854 	} else if (dr6 & (1 << X86_DR6_BT)) {
855 		// task switch
856 		// Occurs only, if T in EFLAGS is set (which we don't do).
857 		if (IFRAME_IS_USER(frame)) {
858 			dprintf("i386_handle_debug_exception(): ignoring spurious task switch "
859 				"exception\n");
860 
861 			enable_interrupts();
862 		} else
863 			panic("spurious task switch exception in kernel mode");
864 	} else {
865 		if (IFRAME_IS_USER(frame)) {
866 			TRACE(("i386_handle_debug_exception(): ignoring spurious debug "
867 				"exception (no condition recognized)\n"));
868 
869 			enable_interrupts();
870 		} else {
871 			panic("spurious debug exception in kernel mode (no condition "
872 				"recognized)");
873 		}
874 	}
875 }
876 
877 
878 /**
879  *	Interrupts are disabled and will possibly be enabled by the function.
880  */
881 void
882 x86_handle_breakpoint_exception(struct iframe *frame)
883 {
884 	TRACE(("i386_handle_breakpoint_exception()\n"));
885 
886 	if (!IFRAME_IS_USER(frame)) {
887 		panic("breakpoint exception in kernel mode");
888 		return;
889 	}
890 
891 	enable_interrupts();
892 
893 	user_debug_breakpoint_hit(true);
894 }
895 
896 
897 void
898 x86_init_user_debug()
899 {
900 	// get debug settings
901 	if (void *handle = load_driver_settings("kernel")) {
902 		sQEmuSingleStepHack = get_driver_boolean_parameter(handle,
903 			"qemu_single_step_hack", false, false);;
904 
905 		unload_driver_settings(handle);
906 	}
907 
908 #if KERNEL_BREAKPOINTS
909 	// install debugger commands
910 	add_debugger_command_etc("breakpoints", &debugger_breakpoints,
911 		"Lists current break-/watchpoints",
912 		"\n"
913 		"Lists the current kernel break-/watchpoints.\n", 0);
914 	add_debugger_command_alias("watchpoints", "breakpoints", NULL);
915 	add_debugger_command_etc("breakpoint", &debugger_breakpoint,
916 		"Set/clears a breakpoint",
917 		"<address> [ clear ]\n"
918 		"Sets respectively clears the breakpoint at address <address>.\n", 0);
919 	add_debugger_command_etc("watchpoint", &debugger_watchpoint,
920 		"Set/clears a watchpoint",
921 		"<address> <address> ( [ rw ] [ <size> ] | clear )\n"
922 		"Sets respectively clears the watchpoint at address <address>.\n"
923 		"If \"rw\" is given the new watchpoint is a read/write watchpoint\n"
924 		"otherwise a write watchpoint only.\n", 0);
925 	add_debugger_command_etc("step", &debugger_single_step,
926 		"Single-steps to the next instruction",
927 		"\n"
928 		"Single-steps to the next instruction.\n", 0);
929 #endif
930 }
931 
932