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