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