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