xref: /haiku/src/system/kernel/arch/x86/arch_user_debugger.cpp (revision ed6250c95736c0b55da79d6e9dd01369532260c0)
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_update_thread_single_step()
516 {
517 	if (struct iframe* frame = i386_get_user_iframe()) {
518 		struct thread* thread = thread_get_current_thread();
519 
520 		// set/clear TF in EFLAGS depending on if single stepping is desired
521 		if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP)
522 			frame->flags |= (1 << X86_EFLAGS_TF);
523 		else
524 			frame->flags &= ~(1 << X86_EFLAGS_TF);
525 	}
526 }
527 
528 
529 void
530 arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState)
531 {
532 	if (struct iframe *frame = i386_get_user_iframe()) {
533 		struct thread *thread = thread_get_current_thread();
534 
535 		i386_frstor(cpuState->extended_regs);
536 			// For this to be correct the calling function must not use these
537 			// registers (not even indirectly).
538 
539 //		frame->gs = cpuState->gs;
540 //		frame->fs = cpuState->fs;
541 //		frame->es = cpuState->es;
542 //		frame->ds = cpuState->ds;
543 		frame->edi = cpuState->edi;
544 		frame->esi = cpuState->esi;
545 		frame->ebp = cpuState->ebp;
546 		frame->esp = cpuState->esp;
547 		frame->ebx = cpuState->ebx;
548 		frame->edx = cpuState->edx;
549 		frame->ecx = cpuState->ecx;
550 		frame->eax = cpuState->eax;
551 //		frame->vector = cpuState->vector;
552 //		frame->error_code = cpuState->error_code;
553 		frame->eip = cpuState->eip;
554 //		frame->cs = cpuState->cs;
555 		frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS)
556 			| (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS);
557 		frame->user_esp = cpuState->user_esp;
558 //		frame->user_ss = cpuState->user_ss;
559 	}
560 }
561 
562 
563 void
564 arch_get_debug_cpu_state(struct debug_cpu_state *cpuState)
565 {
566 	if (struct iframe *frame = i386_get_user_iframe()) {
567 		struct thread *thread = thread_get_current_thread();
568 
569 		i386_fnsave(cpuState->extended_regs);
570 			// For this to be correct the calling function must not use these
571 			// registers (not even indirectly).
572 
573 		cpuState->gs = frame->gs;
574 		cpuState->fs = frame->fs;
575 		cpuState->es = frame->es;
576 		cpuState->ds = frame->ds;
577 		cpuState->edi = frame->edi;
578 		cpuState->esi = frame->esi;
579 		cpuState->ebp = frame->ebp;
580 		cpuState->esp = frame->esp;
581 		cpuState->ebx = frame->ebx;
582 		cpuState->edx = frame->orig_edx;
583 		cpuState->ecx = frame->ecx;
584 		cpuState->eax = frame->orig_eax;
585 		cpuState->vector = frame->vector;
586 		cpuState->error_code = frame->error_code;
587 		cpuState->eip = frame->eip;
588 		cpuState->cs = frame->cs;
589 		cpuState->eflags = frame->flags;
590 		cpuState->user_esp = frame->user_esp;
591 		cpuState->user_ss = frame->user_ss;
592 	}
593 }
594 
595 
596 status_t
597 arch_set_breakpoint(void *address)
598 {
599 	return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
600 		X86_BREAKPOINT_LENGTH_1);
601 }
602 
603 
604 status_t
605 arch_clear_breakpoint(void *address)
606 {
607 	return clear_breakpoint(address, false);
608 }
609 
610 
611 status_t
612 arch_set_watchpoint(void *address, uint32 type, int32 length)
613 {
614 	uint32 archType, archLength;
615 	status_t error = check_watch_point_parameters(address, type, length,
616 		archType, archLength);
617 	if (error != B_OK)
618 		return error;
619 
620 	return set_breakpoint(address, archType, archLength);
621 }
622 
623 
624 status_t
625 arch_clear_watchpoint(void *address)
626 {
627 	return clear_breakpoint(address, false);
628 }
629 
630 
631 bool
632 arch_has_breakpoints(struct arch_team_debug_info *info)
633 {
634 	// Reading info->dr7 is atomically, so we don't need to lock. The caller
635 	// has to ensure, that the info doesn't go away.
636 	return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7);
637 }
638 
639 
640 #if KERNEL_BREAKPOINTS
641 
642 status_t
643 arch_set_kernel_breakpoint(void *address)
644 {
645 	status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
646 		X86_BREAKPOINT_LENGTH_1);
647 
648 	if (error != B_OK) {
649 		panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s",
650 			strerror(error));
651 	}
652 
653 	return error;
654 }
655 
656 
657 status_t
658 arch_clear_kernel_breakpoint(void *address)
659 {
660 	status_t error = clear_kernel_breakpoint(address, false);
661 
662 	if (error != B_OK) {
663 		panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s",
664 			strerror(error));
665 	}
666 
667 	return error;
668 }
669 
670 
671 status_t
672 arch_set_kernel_watchpoint(void *address, uint32 type, int32 length)
673 {
674 	uint32 archType, archLength;
675 	status_t error = check_watch_point_parameters(address, type, length,
676 		archType, archLength);
677 
678 	if (error == B_OK)
679 		error = set_kernel_breakpoint(address, archType, archLength);
680 
681 	if (error != B_OK) {
682 		panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s",
683 			strerror(error));
684 	}
685 
686 	return error;
687 }
688 
689 
690 status_t
691 arch_clear_kernel_watchpoint(void *address)
692 {
693 	status_t error = clear_kernel_breakpoint(address, true);
694 
695 	if (error != B_OK) {
696 		panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s",
697 			strerror(error));
698 	}
699 
700 	return error;
701 }
702 
703 #endif	// KERNEL_BREAKPOINTS
704 
705 
706 // #pragma mark - x86 implementation interface
707 
708 
709 /**
710  *	Interrupts are disabled.
711  */
712 void
713 x86_init_user_debug_at_kernel_exit(struct iframe *frame)
714 {
715 	struct thread *thread = thread_get_current_thread();
716 
717 #if !KERNEL_BREAKPOINTS
718 	if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED))
719 		return;
720 #endif
721 
722 	GRAB_THREAD_LOCK();
723 	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
724 
725 	arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info;
726 
727 	// install the breakpoints
728 	install_breakpoints(teamInfo);
729 
730 	atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED);
731 
732 	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
733 	RELEASE_THREAD_LOCK();
734 }
735 
736 
737 /**
738  *	Interrupts are disabled.
739  */
740 void
741 x86_exit_user_debug_at_kernel_entry()
742 {
743 	struct thread *thread = thread_get_current_thread();
744 
745 #if !KERNEL_BREAKPOINTS
746 	if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED))
747 		return;
748 #endif
749 
750 	GRAB_THREAD_LOCK();
751 
752 	// disable breakpoints
753 	disable_breakpoints();
754 
755 #if KERNEL_BREAKPOINTS
756 	struct team* kernelTeam = team_get_kernel_team();
757 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
758 	install_breakpoints(kernelTeam->debug_info.arch_info);
759 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
760 #endif
761 
762 	atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED);
763 
764 	RELEASE_THREAD_LOCK();
765 }
766 
767 
768 /**
769  *	Interrupts are disabled and will be enabled by the function.
770  */
771 void
772 x86_handle_debug_exception(struct iframe *frame)
773 {
774 	// get debug status and control registers
775 	uint32 dr6, dr7;
776 	asm("movl %%dr6, %0" : "=r"(dr6));
777 	asm("movl %%dr7, %0" : "=r"(dr7));
778 
779 	TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7));
780 
781 	if (frame->cs != USER_CODE_SEG) {
782 		panic("debug exception in kernel mode: dr6: 0x%lx, dr7: 0x%lx", dr6,
783 			dr7);
784 		return;
785 	}
786 
787 	// check, which exception condition applies
788 	if (dr6 & X86_DR6_BREAKPOINT_MASK) {
789 		// breakpoint
790 
791 		// check which breakpoint was taken
792 		bool watchpoint = true;
793 		for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
794 			if (dr6 & (1 << sDR6B[i])) {
795 				// If it is an instruction breakpoint, we need to set RF in
796 				// EFLAGS to prevent triggering the same exception
797 				// again (breakpoint instructions are triggered *before*
798 				// executing the instruction).
799 				uint32 type = (dr7 >> sDR7RW[i]) & 0x3;
800 				if (type == X86_INSTRUCTION_BREAKPOINT) {
801 					frame->flags |= (1 << X86_EFLAGS_RF);
802 					watchpoint = false;
803 				}
804 			}
805 		}
806 
807 		// enable interrupts and notify the debugger
808 		enable_interrupts();
809 
810 		if (watchpoint)
811 			user_debug_watchpoint_hit();
812 		else
813 			user_debug_breakpoint_hit(false);
814 	} else if (dr6 & (1 << X86_DR6_BD)) {
815 		// general detect exception
816 		// Occurs only, if GD in DR7 is set (which we don't do) and someone
817 		// tries to write to the debug registers.
818 		dprintf("i386_handle_debug_exception(): ignoring spurious general "
819 			"detect exception\n");
820 
821 		enable_interrupts();
822 	} else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) {
823 		// single step
824 
825 		// enable interrupts and notify the debugger
826 		enable_interrupts();
827 
828 		user_debug_single_stepped();
829 	} else if (dr6 & (1 << X86_DR6_BT)) {
830 		// task switch
831 		// Occurs only, if T in EFLAGS is set (which we don't do).
832 		dprintf("i386_handle_debug_exception(): ignoring spurious task switch "
833 			"exception\n");
834 
835 		enable_interrupts();
836 	} else {
837 		TRACE(("i386_handle_debug_exception(): ignoring spurious debug "
838 			"exception (no condition recognized)\n"));
839 
840 		enable_interrupts();
841 	}
842 }
843 
844 
845 /**
846  *	Interrupts are disabled and will be enabled by the function.
847  */
848 void
849 x86_handle_breakpoint_exception(struct iframe *frame)
850 {
851 	TRACE(("i386_handle_breakpoint_exception()\n"));
852 
853 	if (frame->cs != USER_CODE_SEG) {
854 		panic("breakpoint exception in kernel mode");
855 		return;
856 	}
857 
858 	enable_interrupts();
859 
860 	user_debug_breakpoint_hit(true);
861 }
862 
863 
864 void
865 x86_init_user_debug()
866 {
867 	// get debug settings
868 	if (void *handle = load_driver_settings("kernel")) {
869 		sQEmuSingleStepHack = get_driver_boolean_parameter(handle,
870 			"qemu_single_step_hack", false, false);;
871 
872 		unload_driver_settings(handle);
873 	}
874 
875 #if KERNEL_BREAKPOINTS
876 	// install debugger commands
877 	add_debugger_command("breakpoints", &debugger_breakpoints,
878 		"lists current break-/watchpoints");
879 	add_debugger_command("breakpoint", &debugger_breakpoint,
880 		"set/clear a breakpoint");
881 	add_debugger_command("watchpoints", &debugger_breakpoints,
882 		"lists current break-/watchpoints");
883 	add_debugger_command("watchpoint", &debugger_watchpoint,
884 		"set/clear a watchpoint");
885 #endif
886 }
887 
888