xref: /haiku/src/system/kernel/arch/x86/arch_user_debugger.cpp (revision 62f5ba006a08b0df30631375878effaf67ae5dbc)
1 /*
2  * Copyright 2005-2009, 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 struct 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 	struct 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 	struct 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 	struct 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 	struct 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 	struct 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 	struct 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 		struct thread* thread = thread_get_current_thread();
573 
574 		// set/clear TF in EFLAGS depending on if single stepping is desired
575 		if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP)
576 			frame->flags |= (1 << X86_EFLAGS_TF);
577 		else
578 			frame->flags &= ~(1 << X86_EFLAGS_TF);
579 	}
580 }
581 
582 
583 void
584 arch_set_debug_cpu_state(const debug_cpu_state *cpuState)
585 {
586 	if (struct iframe *frame = i386_get_user_iframe()) {
587 		// For the floating point state to be correct the calling function must
588 		// not use these registers (not even indirectly).
589 		if (gHasSSE) {
590 			// Since fxrstor requires 16-byte alignment and this isn't
591 			// guaranteed passed buffer, we use our thread's fpu_state field as
592 			// temporary buffer. We need to disable interrupts to make use of
593 			// it.
594 			struct thread* thread = thread_get_current_thread();
595 			InterruptsLocker locker;
596 			memcpy(thread->arch_info.fpu_state, &cpuState->extended_registers,
597 				sizeof(&cpuState->extended_registers));
598 			i386_fxrstor(thread->arch_info.fpu_state);
599 		} else {
600 			// TODO: Implement! We need to convert the format first.
601 //			i386_frstor(&cpuState->extended_registers);
602 		}
603 
604 //		frame->gs = cpuState->gs;
605 //		frame->fs = cpuState->fs;
606 //		frame->es = cpuState->es;
607 //		frame->ds = cpuState->ds;
608 		frame->edi = cpuState->edi;
609 		frame->esi = cpuState->esi;
610 		frame->ebp = cpuState->ebp;
611 //		frame->esp = cpuState->esp;
612 		frame->ebx = cpuState->ebx;
613 		frame->edx = cpuState->edx;
614 		frame->ecx = cpuState->ecx;
615 		frame->eax = cpuState->eax;
616 //		frame->vector = cpuState->vector;
617 //		frame->error_code = cpuState->error_code;
618 		frame->eip = cpuState->eip;
619 //		frame->cs = cpuState->cs;
620 		frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS)
621 			| (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS);
622 		frame->user_esp = cpuState->user_esp;
623 //		frame->user_ss = cpuState->user_ss;
624 	}
625 }
626 
627 
628 void
629 arch_get_debug_cpu_state(debug_cpu_state *cpuState)
630 {
631 	if (struct iframe *frame = i386_get_user_iframe()) {
632 		// For the floating point state to be correct the calling function must
633 		// not use these registers (not even indirectly).
634 		if (gHasSSE) {
635 			// Since fxsave requires 16-byte alignment and this isn't guaranteed
636 			// passed buffer, we use our thread's fpu_state field as temporary
637 			// buffer. We need to disable interrupts to make use of it.
638 			struct thread* thread = thread_get_current_thread();
639 			InterruptsLocker locker;
640 			i386_fxsave(thread->arch_info.fpu_state);
641 				// unlike fnsave, fxsave doesn't reinit the FPU state
642 			memcpy(&cpuState->extended_registers, thread->arch_info.fpu_state,
643 				sizeof(&cpuState->extended_registers));
644 		} else {
645 			i386_fnsave(&cpuState->extended_registers);
646 			i386_frstor(&cpuState->extended_registers);
647 				// fnsave reinits the FPU state after saving, so we need to
648 				// load it again
649 			// TODO: Convert to fxsave format!
650 		}
651 		get_iframe_registers(frame, cpuState);
652 	}
653 }
654 
655 
656 status_t
657 arch_set_breakpoint(void *address)
658 {
659 	return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
660 		X86_BREAKPOINT_LENGTH_1);
661 }
662 
663 
664 status_t
665 arch_clear_breakpoint(void *address)
666 {
667 	return clear_breakpoint(address, false);
668 }
669 
670 
671 status_t
672 arch_set_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 	if (error != B_OK)
678 		return error;
679 
680 	return set_breakpoint(address, archType, archLength);
681 }
682 
683 
684 status_t
685 arch_clear_watchpoint(void *address)
686 {
687 	return clear_breakpoint(address, false);
688 }
689 
690 
691 bool
692 arch_has_breakpoints(struct arch_team_debug_info *info)
693 {
694 	// Reading info->dr7 is atomically, so we don't need to lock. The caller
695 	// has to ensure, that the info doesn't go away.
696 	return (info->dr7 != X86_BREAKPOINTS_DISABLED_DR7);
697 }
698 
699 
700 #if KERNEL_BREAKPOINTS
701 
702 status_t
703 arch_set_kernel_breakpoint(void *address)
704 {
705 	status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
706 		X86_BREAKPOINT_LENGTH_1);
707 
708 	if (error != B_OK) {
709 		panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s",
710 			strerror(error));
711 	}
712 
713 	return error;
714 }
715 
716 
717 status_t
718 arch_clear_kernel_breakpoint(void *address)
719 {
720 	status_t error = clear_kernel_breakpoint(address, false);
721 
722 	if (error != B_OK) {
723 		panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s",
724 			strerror(error));
725 	}
726 
727 	return error;
728 }
729 
730 
731 status_t
732 arch_set_kernel_watchpoint(void *address, uint32 type, int32 length)
733 {
734 	uint32 archType, archLength;
735 	status_t error = check_watch_point_parameters(address, type, length,
736 		archType, archLength);
737 
738 	if (error == B_OK)
739 		error = set_kernel_breakpoint(address, archType, archLength);
740 
741 	if (error != B_OK) {
742 		panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s",
743 			strerror(error));
744 	}
745 
746 	return error;
747 }
748 
749 
750 status_t
751 arch_clear_kernel_watchpoint(void *address)
752 {
753 	status_t error = clear_kernel_breakpoint(address, true);
754 
755 	if (error != B_OK) {
756 		panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s",
757 			strerror(error));
758 	}
759 
760 	return error;
761 }
762 
763 #endif	// KERNEL_BREAKPOINTS
764 
765 
766 // #pragma mark - x86 implementation interface
767 
768 
769 /**
770  *	Interrupts are disabled. \a frame is unused, i.e. can be \c NULL.
771  */
772 void
773 x86_init_user_debug_at_kernel_exit(struct iframe *frame)
774 {
775 	struct thread *thread = thread_get_current_thread();
776 
777 	if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED))
778 		return;
779 
780 	// disable kernel breakpoints
781 	disable_breakpoints();
782 
783 	GRAB_THREAD_LOCK();
784 	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
785 
786 	arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info;
787 
788 	// install the user breakpoints
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 	RELEASE_THREAD_LOCK();
795 }
796 
797 
798 /**
799  *	Interrupts are disabled.
800  */
801 void
802 x86_exit_user_debug_at_kernel_entry()
803 {
804 	struct thread *thread = thread_get_current_thread();
805 
806 	if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED))
807 		return;
808 
809 	// We need to save the current values of dr6 and dr7 in the CPU structure,
810 	// since in case of a debug exception we might overwrite them before
811 	// x86_handle_debug_exception() is called.
812 	asm("movl %%dr6, %0" : "=r"(thread->cpu->arch.dr6));
813 	asm("movl %%dr7, %0" : "=r"(thread->cpu->arch.dr7));
814 
815 	GRAB_THREAD_LOCK();
816 
817 	// disable user breakpoints
818 	disable_breakpoints();
819 
820 	// install kernel breakpoints
821 	struct team* kernelTeam = team_get_kernel_team();
822 	GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
823 	install_breakpoints(kernelTeam->debug_info.arch_info);
824 	RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
825 
826 	atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED);
827 
828 	RELEASE_THREAD_LOCK();
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 	// get debug status and control registers (saved earlier in
839 	// x86_exit_user_debug_at_kernel_entry())
840 	struct thread* thread = thread_get_current_thread();
841 	uint32 dr6 = thread->cpu->arch.dr6;
842 	uint32 dr7 = thread->cpu->arch.dr7;
843 
844 	TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7));
845 
846 	// check, which exception condition applies
847 	if (dr6 & X86_DR6_BREAKPOINT_MASK) {
848 		// breakpoint
849 
850 		// check which breakpoint was taken
851 		bool watchpoint = true;
852 		for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
853 			if (dr6 & (1 << sDR6B[i])) {
854 				uint32 type = (dr7 >> sDR7RW[i]) & 0x3;
855 				if (type == X86_INSTRUCTION_BREAKPOINT)
856 					watchpoint = false;
857 			}
858 		}
859 
860 		if (IFRAME_IS_USER(frame)) {
861 			// enable interrupts and notify the debugger
862 			enable_interrupts();
863 
864 			if (watchpoint)
865 				user_debug_watchpoint_hit();
866 			else
867 				user_debug_breakpoint_hit(false);
868 		} else {
869 			panic("hit kernel %spoint: dr6: 0x%lx, dr7: 0x%lx",
870 				watchpoint ? "watch" : "break", dr6, dr7);
871 		}
872 	} else if (dr6 & (1 << X86_DR6_BD)) {
873 		// general detect exception
874 		// Occurs only, if GD in DR7 is set (which we don't do) and someone
875 		// tries to write to the debug registers.
876 		if (IFRAME_IS_USER(frame)) {
877 			dprintf("i386_handle_debug_exception(): ignoring spurious general "
878 				"detect exception\n");
879 
880 			enable_interrupts();
881 		} else
882 			panic("spurious general detect exception in kernel mode");
883 	} else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) {
884 		// single step
885 
886 		if (IFRAME_IS_USER(frame)) {
887 			// enable interrupts and notify the debugger
888 			enable_interrupts();
889 
890 			user_debug_single_stepped();
891 		} else {
892 			// Disable single-stepping -- the next "step" command will re-enable
893 			// it, but we don't want it when continuing otherwise.
894 			frame->flags &= ~(1 << X86_EFLAGS_TF);
895 
896 			// Determine whether the exception occurred at a syscall/trap
897 			// kernel entry or whether this is genuine kernel single-stepping.
898 			bool inKernel = true;
899 			if (thread->team != team_get_kernel_team()
900 				&& i386_get_user_iframe() == NULL) {
901 				// TODO: This is not yet fully correct, since a newly created
902 				// thread that doesn't have entered userland yet also has this
903 				// property.
904 				inKernel = false;
905 			}
906 
907 			if (inKernel) {
908 				panic("kernel single step");
909 			} else {
910 				// The thread is a userland thread and it just entered the
911 				// kernel when the single-step exception occurred. This happens
912 				// e.g. when sysenter is called with single-stepping enabled.
913 				// We need to ignore the exception now and send a single-step
914 				// notification later, when the thread wants to return from the
915 				// kernel.
916 				InterruptsSpinLocker threadLocker(gThreadSpinlock);
917 
918 				// Check whether the team is still being debugged and set
919 				// the B_THREAD_DEBUG_NOTIFY_SINGLE_STEP and
920 				// B_THREAD_DEBUG_STOP flags, so that the thread will be
921 				// stopped when it is going to leave the kernel and notify the
922 				// debugger about the single-step event.
923 				int32 teamDebugFlags
924 					= atomic_get(&thread->team->debug_info.flags);
925 				if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
926 					atomic_or(&thread->debug_info.flags,
927 						B_THREAD_DEBUG_NOTIFY_SINGLE_STEP
928 							| B_THREAD_DEBUG_STOP);
929 				}
930 			}
931 		}
932 	} else if (dr6 & (1 << X86_DR6_BT)) {
933 		// task switch
934 		// Occurs only, if T in EFLAGS is set (which we don't do).
935 		if (IFRAME_IS_USER(frame)) {
936 			dprintf("i386_handle_debug_exception(): ignoring spurious task switch "
937 				"exception\n");
938 
939 			enable_interrupts();
940 		} else
941 			panic("spurious task switch exception in kernel mode");
942 	} else {
943 		if (IFRAME_IS_USER(frame)) {
944 			TRACE(("i386_handle_debug_exception(): ignoring spurious debug "
945 				"exception (no condition recognized)\n"));
946 
947 			enable_interrupts();
948 		} else {
949 			panic("spurious debug exception in kernel mode (no condition "
950 				"recognized)");
951 		}
952 	}
953 }
954 
955 
956 /**
957  *	Interrupts are disabled and will possibly be enabled by the function.
958  */
959 void
960 x86_handle_breakpoint_exception(struct iframe *frame)
961 {
962 	TRACE(("i386_handle_breakpoint_exception()\n"));
963 
964 	// reset eip to the int3 instruction
965 	frame->eip--;
966 
967 	if (!IFRAME_IS_USER(frame)) {
968 		panic("breakpoint exception in kernel mode");
969 		return;
970 	}
971 
972 	enable_interrupts();
973 
974 	user_debug_breakpoint_hit(true);
975 }
976 
977 
978 void
979 x86_init_user_debug()
980 {
981 	// get debug settings
982 	if (void *handle = load_driver_settings("kernel")) {
983 		sQEmuSingleStepHack = get_driver_boolean_parameter(handle,
984 			"qemu_single_step_hack", false, false);;
985 
986 		unload_driver_settings(handle);
987 	}
988 
989 #if KERNEL_BREAKPOINTS
990 	// install debugger commands
991 	add_debugger_command_etc("breakpoints", &debugger_breakpoints,
992 		"Lists current break-/watchpoints",
993 		"\n"
994 		"Lists the current kernel break-/watchpoints.\n", 0);
995 	add_debugger_command_alias("watchpoints", "breakpoints", NULL);
996 	add_debugger_command_etc("breakpoint", &debugger_breakpoint,
997 		"Set/clears a breakpoint",
998 		"<address> [ clear ]\n"
999 		"Sets respectively clears the breakpoint at address <address>.\n", 0);
1000 	add_debugger_command_etc("watchpoint", &debugger_watchpoint,
1001 		"Set/clears a watchpoint",
1002 		"<address> <address> ( [ rw ] [ <size> ] | clear )\n"
1003 		"Sets respectively clears the watchpoint at address <address>.\n"
1004 		"If \"rw\" is given the new watchpoint is a read/write watchpoint\n"
1005 		"otherwise a write watchpoint only.\n", 0);
1006 	add_debugger_command_etc("step", &debugger_single_step,
1007 		"Single-steps to the next instruction",
1008 		"\n"
1009 		"Single-steps to the next instruction.\n", 0);
1010 #endif
1011 }
1012 
1013