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