xref: /haiku/src/system/kernel/arch/x86/arch_user_debugger.cpp (revision 1b8f7f13a3dc70e0e903cb94248220b40b732204)
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 static status_t
216 set_kernel_breakpoint(void *address, uint32 type, uint32 length)
217 {
218 	if (!address)
219 		return B_BAD_VALUE;
220 
221 	struct team* kernelTeam = team_get_kernel_team();
222 
223 	cpu_status state = disable_interrupts();
224 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
225 
226 	status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address,
227 		type, length, true);
228 
229 	install_breakpoints(kernelTeam->debug_info.arch_info);
230 
231 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
232 	restore_interrupts(state);
233 
234 	return error;
235 }
236 
237 
238 static status_t
239 clear_kernel_breakpoint(void *address, bool watchpoint)
240 {
241 	if (!address)
242 		return B_BAD_VALUE;
243 
244 	struct team* kernelTeam = team_get_kernel_team();
245 
246 	cpu_status state = disable_interrupts();
247 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
248 
249 	status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info,
250 		address, watchpoint);
251 
252 	install_breakpoints(kernelTeam->debug_info.arch_info);
253 
254 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
255 	restore_interrupts(state);
256 
257 	return error;
258 }
259 
260 #endif	// KERNEL_BREAKPOINTS
261 
262 
263 static inline status_t
264 check_watch_point_parameters(void* address, uint32 type, int32 length,
265 	uint32& archType, uint32& archLength)
266 {
267 	// check type
268 	switch (type) {
269 		case B_DATA_WRITE_WATCHPOINT:
270 			archType = X86_DATA_WRITE_BREAKPOINT;
271 			break;
272 		case B_DATA_READ_WRITE_WATCHPOINT:
273 			archType = X86_DATA_READ_WRITE_BREAKPOINT;
274 			break;
275 		case B_DATA_READ_WATCHPOINT:
276 		default:
277 			return B_WATCHPOINT_TYPE_NOT_SUPPORTED;
278 			break;
279 	}
280 
281 	// check length and alignment
282 	switch (length) {
283 		case 1:
284 			archLength = X86_BREAKPOINT_LENGTH_1;
285 			break;
286 		case 2:
287 			if ((uint32)address & 0x1)
288 				return B_BAD_WATCHPOINT_ALIGNMENT;
289 			archLength = X86_BREAKPOINT_LENGTH_2;
290 			break;
291 		case 4:
292 			if ((uint32)address & 0x3)
293 				return B_BAD_WATCHPOINT_ALIGNMENT;
294 			archLength = X86_BREAKPOINT_LENGTH_4;
295 			break;
296 		default:
297 			return B_WATCHPOINT_LENGTH_NOT_SUPPORTED;
298 	}
299 
300 	return B_OK;
301 }
302 
303 
304 // #pragma mark - kernel debugger commands
305 
306 #if KERNEL_BREAKPOINTS
307 
308 static int
309 debugger_breakpoints(int argc, char** argv)
310 {
311 	struct team* kernelTeam = team_get_kernel_team();
312 	arch_team_debug_info& info = kernelTeam->debug_info.arch_info;
313 
314 	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
315 		kprintf("breakpoint[%ld] ", i);
316 
317 		if (info.breakpoints[i].address != NULL) {
318 			kprintf("%p ", info.breakpoints[i].address);
319 			switch (info.breakpoints[i].type) {
320 				case X86_INSTRUCTION_BREAKPOINT:
321 					kprintf("instruction");
322 					break;
323 				case X86_IO_READ_WRITE_BREAKPOINT:
324 					kprintf("io read/write");
325 					break;
326 				case X86_DATA_WRITE_BREAKPOINT:
327 					kprintf("data write");
328 					break;
329 				case X86_DATA_READ_WRITE_BREAKPOINT:
330 					kprintf("data read/write");
331 					break;
332 			}
333 
334 			int length = 1;
335 			switch (info.breakpoints[i].length) {
336 				case X86_BREAKPOINT_LENGTH_1:
337 					length = 1;
338 					break;
339 				case X86_BREAKPOINT_LENGTH_2:
340 					length = 2;
341 					break;
342 				case X86_BREAKPOINT_LENGTH_4:
343 					length = 4;
344 					break;
345 			}
346 
347 			if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT)
348 				kprintf(" %d byte%s", length, (length > 1 ? "s" : ""));
349 		} else
350 			kprintf("unused");
351 
352 		kprintf("\n");
353 	}
354 
355 	return 0;
356 }
357 
358 
359 static int
360 debugger_breakpoint_usage(const char* command)
361 {
362 	if (command[0] == 'b') {
363 		kprintf("Usage: breakpoint <address>\n");
364 		kprintf("       breakpoint <address> clear\n");
365 	} else {
366 		kprintf("Usage: watchpoint <address> [ rw ] [ <size> ]\n");
367 		kprintf("       watchpoint <address> clear\n");
368 	}
369 	return 0;
370 }
371 
372 
373 static int
374 debugger_breakpoint(int argc, char** argv)
375 {
376 	// get arguments
377 
378 	if (argc < 2 || argc > 3)
379 		return debugger_breakpoint_usage(argv[0]);
380 
381 	addr_t address = strtoul(argv[1], NULL, 0);
382 	if (address == 0)
383 		return debugger_breakpoint_usage(argv[0]);
384 
385 	bool clear = false;
386 	if (argc == 3) {
387 		if (strcmp(argv[2], "clear") == 0)
388 			clear = true;
389 		else
390 			return debugger_breakpoint_usage(argv[0]);
391 	}
392 
393 	// set/clear breakpoint
394 
395 	arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
396 
397 	status_t error;
398 
399 	if (clear) {
400 		error = clear_breakpoint(info, (void*)address, false);
401 	} else {
402 		error = set_breakpoint(info, (void*)address, X86_INSTRUCTION_BREAKPOINT,
403 			X86_BREAKPOINT_LENGTH_1, true);
404 	}
405 
406 	if (error == B_OK)
407 		install_breakpoints(info);
408 	else
409 		kprintf("Failed to install breakpoint: %s\n", strerror(error));
410 
411 	return 0;
412 }
413 
414 
415 static int
416 debugger_watchpoint(int argc, char** argv)
417 {
418 	// get arguments
419 
420 	if (argc < 2 || argc > 4)
421 		return debugger_breakpoint_usage(argv[0]);
422 
423 	addr_t address = strtoul(argv[1], NULL, 0);
424 	if (address == 0)
425 		return debugger_breakpoint_usage(argv[0]);
426 
427 	bool clear = false;
428 	bool readWrite = false;
429 	int argi = 2;
430 	int length = 1;
431 	if (argc >= 3) {
432 		if (strcmp(argv[argi], "clear") == 0) {
433 			clear = true;
434 			argi++;
435 		} else if (strcmp(argv[argi], "rw") == 0) {
436 			readWrite = true;
437 			argi++;
438 		}
439 
440 		if (!clear && argi < argc)
441 			length = strtoul(argv[argi++], NULL, 0);
442 
443 		if (length == 0 || argi < argc)
444 			return debugger_breakpoint_usage(argv[0]);
445 	}
446 
447 	// set/clear breakpoint
448 
449 	arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
450 
451 	status_t error;
452 
453 	if (clear) {
454 		error = clear_breakpoint(info, (void*)address, true);
455 	} else {
456 		uint32 type = readWrite ? B_DATA_READ_WRITE_WATCHPOINT
457 			: B_DATA_WRITE_WATCHPOINT;
458 
459 		uint32 archType, archLength;
460 		error = check_watch_point_parameters((void*)address, type, length,
461 			archType, archLength);
462 
463 		if (error == B_OK) {
464 			error = set_breakpoint(info, (void*)address, archType, archLength,
465 				true);
466 		}
467 	}
468 
469 	if (error == B_OK)
470 		install_breakpoints(info);
471 	else
472 		kprintf("Failed to install breakpoint: %s\n", strerror(error));
473 
474 	return 0;
475 }
476 
477 #endif	// KERNEL_BREAKPOINTS
478 
479 
480 // #pragma mark - in-kernel public interface
481 
482 
483 void
484 arch_clear_team_debug_info(struct arch_team_debug_info *info)
485 {
486 	for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++)
487 		info->breakpoints[i].address = NULL;
488 
489 	info->dr7 = X86_BREAKPOINTS_DISABLED_DR7;
490 }
491 
492 
493 void
494 arch_destroy_team_debug_info(struct arch_team_debug_info *info)
495 {
496 	arch_clear_team_debug_info(info);
497 }
498 
499 
500 void
501 arch_clear_thread_debug_info(struct arch_thread_debug_info *info)
502 {
503 	info->flags = 0;
504 }
505 
506 
507 void
508 arch_destroy_thread_debug_info(struct arch_thread_debug_info *info)
509 {
510 	arch_clear_thread_debug_info(info);
511 }
512 
513 
514 void
515 arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState)
516 {
517 	if (struct iframe *frame = i386_get_user_iframe()) {
518 		struct thread *thread = thread_get_current_thread();
519 
520 		i386_frstor(cpuState->extended_regs);
521 			// For this to be correct the calling function must not use these
522 			// registers (not even indirectly).
523 
524 //		frame->gs = cpuState->gs;
525 //		frame->fs = cpuState->fs;
526 //		frame->es = cpuState->es;
527 //		frame->ds = cpuState->ds;
528 		frame->edi = cpuState->edi;
529 		frame->esi = cpuState->esi;
530 		frame->ebp = cpuState->ebp;
531 		frame->esp = cpuState->esp;
532 		frame->ebx = cpuState->ebx;
533 		frame->edx = cpuState->edx;
534 		frame->ecx = cpuState->ecx;
535 		frame->eax = cpuState->eax;
536 //		frame->vector = cpuState->vector;
537 //		frame->error_code = cpuState->error_code;
538 		frame->eip = cpuState->eip;
539 //		frame->cs = cpuState->cs;
540 		frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS)
541 			| (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS);
542 		frame->user_esp = cpuState->user_esp;
543 //		frame->user_ss = cpuState->user_ss;
544 	}
545 }
546 
547 
548 void
549 arch_get_debug_cpu_state(struct debug_cpu_state *cpuState)
550 {
551 	if (struct iframe *frame = i386_get_user_iframe()) {
552 		struct thread *thread = thread_get_current_thread();
553 
554 		i386_fnsave(cpuState->extended_regs);
555 			// For this to be correct the calling function must not use these
556 			// registers (not even indirectly).
557 
558 		cpuState->gs = frame->gs;
559 		cpuState->fs = frame->fs;
560 		cpuState->es = frame->es;
561 		cpuState->ds = frame->ds;
562 		cpuState->edi = frame->edi;
563 		cpuState->esi = frame->esi;
564 		cpuState->ebp = frame->ebp;
565 		cpuState->esp = frame->esp;
566 		cpuState->ebx = frame->ebx;
567 		cpuState->edx = frame->orig_edx;
568 		cpuState->ecx = frame->ecx;
569 		cpuState->eax = frame->orig_eax;
570 		cpuState->vector = frame->vector;
571 		cpuState->error_code = frame->error_code;
572 		cpuState->eip = frame->eip;
573 		cpuState->cs = frame->cs;
574 		cpuState->eflags = frame->flags;
575 		cpuState->user_esp = frame->user_esp;
576 		cpuState->user_ss = frame->user_ss;
577 	}
578 }
579 
580 
581 status_t
582 arch_set_breakpoint(void *address)
583 {
584 	return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
585 		X86_BREAKPOINT_LENGTH_1);
586 }
587 
588 
589 status_t
590 arch_clear_breakpoint(void *address)
591 {
592 	return clear_breakpoint(address, false);
593 }
594 
595 
596 status_t
597 arch_set_watchpoint(void *address, uint32 type, int32 length)
598 {
599 	uint32 archType, archLength;
600 	status_t error = check_watch_point_parameters(address, type, length,
601 		archType, archLength);
602 	if (error != B_OK)
603 		return error;
604 
605 	return set_breakpoint(address, archType, archLength);
606 }
607 
608 
609 status_t
610 arch_clear_watchpoint(void *address)
611 {
612 	return clear_breakpoint(address, false);
613 }
614 
615 
616 #if KERNEL_BREAKPOINTS
617 
618 status_t
619 arch_set_kernel_breakpoint(void *address)
620 {
621 	status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
622 		X86_BREAKPOINT_LENGTH_1);
623 
624 	if (error != B_OK) {
625 		panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s",
626 			strerror(error));
627 	}
628 
629 	return error;
630 }
631 
632 
633 status_t
634 arch_clear_kernel_breakpoint(void *address)
635 {
636 	status_t error = clear_kernel_breakpoint(address, false);
637 
638 	if (error != B_OK) {
639 		panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s",
640 			strerror(error));
641 	}
642 
643 	return error;
644 }
645 
646 
647 status_t
648 arch_set_kernel_watchpoint(void *address, uint32 type, int32 length)
649 {
650 	uint32 archType, archLength;
651 	status_t error = check_watch_point_parameters(address, type, length,
652 		archType, archLength);
653 
654 	if (error == B_OK)
655 		error = set_kernel_breakpoint(address, archType, archLength);
656 
657 	if (error != B_OK) {
658 		panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s",
659 			strerror(error));
660 	}
661 
662 	return error;
663 }
664 
665 
666 status_t
667 arch_clear_kernel_watchpoint(void *address)
668 {
669 	status_t error = clear_kernel_breakpoint(address, true);
670 
671 	if (error != B_OK) {
672 		panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s",
673 			strerror(error));
674 	}
675 
676 	return error;
677 }
678 
679 #endif	// KERNEL_BREAKPOINTS
680 
681 
682 // #pragma mark - x86 implementation interface
683 
684 
685 /**
686  *	Interrupts are enabled.
687  */
688 void
689 i386_init_user_debug_at_kernel_exit(struct iframe *frame)
690 {
691 	struct thread *thread = thread_get_current_thread();
692 
693 	cpu_status state = disable_interrupts();
694 	GRAB_THREAD_LOCK();
695 	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
696 
697 	arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info;
698 
699 	// install the breakpoints
700 	install_breakpoints(teamInfo);
701 	thread->debug_info.arch_info.flags |= X86_THREAD_DEBUG_DR7_SET;
702 
703 	// set/clear TF in EFLAGS depending on if single stepping is desired
704 	if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP)
705 		frame->flags |= (1 << X86_EFLAGS_TF);
706 	else
707 		frame->flags &= ~(1 << X86_EFLAGS_TF);
708 		// ToDo: Move into a function called from thread_hit_debug_event().
709 		// No need to have that here in the code executed for ever kernel->user
710 		// mode switch.
711 
712 	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
713 	RELEASE_THREAD_LOCK();
714 	restore_interrupts(state);
715 }
716 
717 
718 /**
719  *	Interrupts may be enabled.
720  */
721 void
722 i386_exit_user_debug_at_kernel_entry()
723 {
724 	struct thread *thread = thread_get_current_thread();
725 
726 	cpu_status state = disable_interrupts();
727 	GRAB_THREAD_LOCK();
728 
729 	// disable breakpoints
730 	disable_breakpoints();
731 	thread->debug_info.arch_info.flags &= ~X86_THREAD_DEBUG_DR7_SET;
732 
733 #if KERNEL_BREAKPOINTS
734 	struct team* kernelTeam = team_get_kernel_team();
735 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
736 	install_breakpoints(kernelTeam->debug_info.arch_info);
737 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
738 #endif
739 
740 	RELEASE_THREAD_LOCK();
741 	restore_interrupts(state);
742 }
743 
744 
745 /**
746  *	Interrupts are disabled and the thread lock is being held.
747  */
748 void
749 i386_reinit_user_debug_after_context_switch(struct thread *thread)
750 {
751 	// This function deals with a race condition: We set up the debugging
752 	// registers in i386_init_user_debug_at_kernel_exit() when a userland
753 	// thread is going to leave the kernel. Afterwards the thread might be
754 	// preempted, though, since interrupts are enabled.
755 	// X86_THREAD_DEBUG_DR7_SET indicates, when this happens.
756 // TODO: We should fix this by disabling interrupts before
757 // i386_init_user_debug_at_kernel_exit() is called and keep them disabled
758 // until returning from the interrupt.
759 
760 	if (thread->debug_info.arch_info.flags & X86_THREAD_DEBUG_DR7_SET) {
761 		GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
762 
763 		install_breakpoints(thread->team->debug_info.arch_info);
764 
765 		RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
766 #if KERNEL_BREAKPOINTS
767 	} else {
768 		// we're still in the kernel
769 		struct team* kernelTeam = team_get_kernel_team();
770 		GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
771 		install_breakpoints(kernelTeam->debug_info.arch_info);
772 		RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
773 #endif
774 	}
775 }
776 
777 
778 /**
779  *	Interrupts are disabled and will be enabled by the function.
780  */
781 int
782 i386_handle_debug_exception(struct iframe *frame)
783 {
784 	// get debug status and control registers
785 	uint32 dr6, dr7;
786 	asm("movl %%dr6, %0" : "=r"(dr6));
787 	asm("movl %%dr7, %0" : "=r"(dr7));
788 
789 	TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7));
790 
791 	if (frame->cs != USER_CODE_SEG) {
792 		panic("debug exception in kernel mode: dr6: 0x%lx, dr7: 0x%lx", dr6,
793 			dr7);
794 		return B_HANDLED_INTERRUPT;
795 	}
796 
797 	// check, which exception condition applies
798 	if (dr6 & X86_DR6_BREAKPOINT_MASK) {
799 		// breakpoint
800 
801 		// check which breakpoint was taken
802 		bool watchpoint = true;
803 		for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
804 			if (dr6 & (1 << sDR6B[i])) {
805 				// If it is an instruction breakpoint, we need to set RF in
806 				// EFLAGS to prevent triggering the same exception
807 				// again (breakpoint instructions are triggered *before*
808 				// executing the instruction).
809 				uint32 type = (dr7 >> sDR7RW[i]) & 0x3;
810 				if (type == X86_INSTRUCTION_BREAKPOINT) {
811 					frame->flags |= (1 << X86_EFLAGS_RF);
812 					watchpoint = false;
813 				}
814 			}
815 		}
816 
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 if (dr6 & (1 << X86_DR6_BD)) {
825 		// general detect exception
826 		// Occurs only, if GD in DR7 is set (which we don't do) and someone
827 		// tries to write to the debug registers.
828 		dprintf("i386_handle_debug_exception(): ignoring spurious general "
829 			"detect exception\n");
830 
831 		enable_interrupts();
832 	} else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) {
833 		// single step
834 
835 		// enable interrupts and notify the debugger
836 		enable_interrupts();
837 
838 		user_debug_single_stepped();
839 	} else if (dr6 & (1 << X86_DR6_BT)) {
840 		// task switch
841 		// Occurs only, if T in EFLAGS is set (which we don't do).
842 		dprintf("i386_handle_debug_exception(): ignoring spurious task switch "
843 			"exception\n");
844 
845 		enable_interrupts();
846 	} else {
847 		TRACE(("i386_handle_debug_exception(): ignoring spurious debug "
848 			"exception (no condition recognized)\n"));
849 
850 		enable_interrupts();
851 	}
852 
853 	return B_HANDLED_INTERRUPT;
854 }
855 
856 
857 /**
858  *	Interrupts are disabled and will be enabled by the function.
859  */
860 int
861 i386_handle_breakpoint_exception(struct iframe *frame)
862 {
863 	TRACE(("i386_handle_breakpoint_exception()\n"));
864 
865 	if (frame->cs != USER_CODE_SEG) {
866 		panic("breakpoint exception in kernel mode");
867 		return B_HANDLED_INTERRUPT;
868 	}
869 
870 	enable_interrupts();
871 
872 	user_debug_breakpoint_hit(true);
873 
874 	return B_HANDLED_INTERRUPT;
875 }
876 
877 
878 void
879 i386_init_user_debug()
880 {
881 	// get debug settings
882 	if (void *handle = load_driver_settings("kernel")) {
883 		sQEmuSingleStepHack = get_driver_boolean_parameter(handle,
884 			"qemu_single_step_hack", false, false);;
885 
886 		unload_driver_settings(handle);
887 	}
888 
889 #if KERNEL_BREAKPOINTS
890 	// install debugger commands
891 	add_debugger_command("breakpoints", &debugger_breakpoints,
892 		"lists current break-/watchpoints");
893 	add_debugger_command("breakpoint", &debugger_breakpoint,
894 		"set/clear a breakpoint");
895 	add_debugger_command("watchpoints", &debugger_breakpoints,
896 		"lists current break-/watchpoints");
897 	add_debugger_command("watchpoint", &debugger_watchpoint,
898 		"set/clear a watchpoint");
899 #endif
900 }
901 
902