vfs: check userland buffers before reading them.
[haiku.git] / src / system / kernel / arch / x86 / arch_user_debugger.cpp
blob952c091924e3fd715828069d53f5a6aca929405d
1 /*
2 * Copyright 2005-2016, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <arch/user_debugger.h>
9 #include <string.h>
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>
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
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.
36 #ifndef __x86_64__
37 extern bool gHasSSE;
38 #endif
40 // The software breakpoint instruction (int3).
41 const uint8 kX86SoftwareBreakpoint[1] = { 0xcc };
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
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
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
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
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
68 // Enables a hack to make single stepping work under qemu. Set via kernel
69 // driver settings.
70 static bool sQEmuSingleStepHack = false;
73 #ifdef __x86_64__
76 static void
77 get_iframe_registers(const iframe* frame, debug_cpu_state* cpuState)
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;
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;
117 static void
118 set_iframe_registers(iframe* frame, const debug_cpu_state* cpuState)
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;
142 #else // __x86_64__
145 static void
146 get_iframe_registers(const iframe* frame, debug_cpu_state* cpuState)
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;
170 static void
171 set_iframe_registers(iframe* frame, const debug_cpu_state* cpuState)
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;
196 #endif // __x86_64__
199 static void
200 get_cpu_state(Thread* thread, iframe* frame, debug_cpu_state* cpuState)
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));
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
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));
237 // TODO: Convert to fxsave format!
239 #endif
240 get_iframe_registers(frame, cpuState);
244 static inline void
245 install_breakpoints(const arch_team_debug_info& teamInfo)
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));
253 // enable breakpoints
254 asm("mov %0, %%dr7" : : "r"(teamInfo.dr7));
258 static inline void
259 disable_breakpoints()
261 asm("mov %0, %%dr7" : : "r"((size_t)X86_BREAKPOINTS_DISABLED_DR7));
265 /*! Sets a break-/watchpoint in the given team info.
266 Interrupts must be disabled and the team debug info lock be held.
268 static inline status_t
269 set_breakpoint(arch_team_debug_info& info, void* address, size_t type,
270 size_t length, bool setGlobalFlag)
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;
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;
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;
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;
311 return B_OK;
315 /*! Clears a break-/watchpoint in the given team info.
316 Interrupts must be disabled and the team debug info lock be held.
318 static inline status_t
319 clear_breakpoint(arch_team_debug_info& info, void* address, bool watchpoint)
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;
332 // clear the breakpoint
333 if (slot >= 0) {
334 info.breakpoints[slot].address = NULL;
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;
347 return B_OK;
351 static status_t
352 set_breakpoint(void* address, size_t type, size_t length)
354 if (!address)
355 return B_BAD_VALUE;
357 Thread* thread = thread_get_current_thread();
359 cpu_status state = disable_interrupts();
360 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
362 status_t error = set_breakpoint(thread->team->debug_info.arch_info, address,
363 type, length, false);
365 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
366 restore_interrupts(state);
368 return error;
372 static status_t
373 clear_breakpoint(void* address, bool watchpoint)
375 if (!address)
376 return B_BAD_VALUE;
378 Thread* thread = thread_get_current_thread();
380 cpu_status state = disable_interrupts();
381 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
383 status_t error = clear_breakpoint(thread->team->debug_info.arch_info,
384 address, watchpoint);
386 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
387 restore_interrupts(state);
389 return error;
393 #if KERNEL_BREAKPOINTS
396 static void
397 install_breakpoints_per_cpu(void* /*cookie*/, int cpu)
399 Team* kernelTeam = team_get_kernel_team();
401 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
403 install_breakpoints(kernelTeam->debug_info.arch_info);
405 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
409 static status_t
410 set_kernel_breakpoint(void* address, size_t type, size_t length)
412 if (!address)
413 return B_BAD_VALUE;
415 Team* kernelTeam = team_get_kernel_team();
417 cpu_status state = disable_interrupts();
418 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
420 status_t error = set_breakpoint(kernelTeam->debug_info.arch_info, address,
421 type, length, true);
423 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
425 call_all_cpus(install_breakpoints_per_cpu, NULL);
427 restore_interrupts(state);
429 return error;
433 static status_t
434 clear_kernel_breakpoint(void* address, bool watchpoint)
436 if (!address)
437 return B_BAD_VALUE;
439 Team* kernelTeam = team_get_kernel_team();
441 cpu_status state = disable_interrupts();
442 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
444 status_t error = clear_breakpoint(kernelTeam->debug_info.arch_info,
445 address, watchpoint);
447 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
449 call_all_cpus(install_breakpoints_per_cpu, NULL);
451 restore_interrupts(state);
453 return error;
456 #endif // KERNEL_BREAKPOINTS
459 static inline status_t
460 check_watch_point_parameters(void* address, uint32 type, int32 length,
461 size_t& archType, size_t& archLength)
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;
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;
496 return B_OK;
500 // #pragma mark - kernel debugger commands
503 #if KERNEL_BREAKPOINTS
505 static int
506 debugger_breakpoints(int argc, char** argv)
508 Team* kernelTeam = team_get_kernel_team();
509 arch_team_debug_info& info = kernelTeam->debug_info.arch_info;
511 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) {
512 kprintf("breakpoint[%" B_PRId32 "] ", i);
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;
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;
544 if (info.breakpoints[i].type != X86_INSTRUCTION_BREAKPOINT)
545 kprintf(" %d byte%s", length, (length > 1 ? "s" : ""));
546 } else
547 kprintf("unused");
549 kprintf("\n");
552 return 0;
556 static int
557 debugger_breakpoint(int argc, char** argv)
559 // get arguments
561 if (argc < 2 || argc > 3)
562 return print_debugger_command_usage(argv[0]);
564 addr_t address = strtoul(argv[1], NULL, 0);
565 if (address == 0)
566 return print_debugger_command_usage(argv[0]);
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]);
576 // set/clear breakpoint
578 arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
580 status_t error;
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);
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));
594 return 0;
598 static int
599 debugger_watchpoint(int argc, char** argv)
601 // get arguments
603 if (argc < 2 || argc > 4)
604 return print_debugger_command_usage(argv[0]);
606 addr_t address = strtoul(argv[1], NULL, 0);
607 if (address == 0)
608 return print_debugger_command_usage(argv[0]);
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++;
623 if (!clear && argi < argc)
624 length = strtoul(argv[argi++], NULL, 0);
626 if (length == 0 || argi < argc)
627 return print_debugger_command_usage(argv[0]);
630 // set/clear breakpoint
632 arch_team_debug_info& info = team_get_kernel_team()->debug_info.arch_info;
634 status_t error;
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;
642 size_t archType, archLength;
643 error = check_watch_point_parameters((void*)address, type, length,
644 archType, archLength);
646 if (error == B_OK) {
647 error = set_breakpoint(info, (void*)address, archType, archLength,
648 true);
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));
657 return 0;
661 static int
662 debugger_single_step(int argc, char** argv)
664 // TODO: Since we need an iframe, this doesn't work when KDL wasn't entered
665 // via an exception.
667 iframe* frame = x86_get_current_iframe();
668 if (frame == NULL) {
669 kprintf("Failed to get the current iframe!\n");
670 return 0;
673 frame->flags |= (1 << X86_EFLAGS_TF);
675 return B_KDEBUG_QUIT;
679 #endif // KERNEL_BREAKPOINTS
682 // #pragma mark - in-kernel public interface
685 void
686 arch_clear_team_debug_info(arch_team_debug_info* info)
688 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++)
689 info->breakpoints[i].address = NULL;
691 info->dr7 = X86_BREAKPOINTS_DISABLED_DR7;
695 void
696 arch_destroy_team_debug_info(arch_team_debug_info* info)
698 arch_clear_team_debug_info(info);
702 void
703 arch_clear_thread_debug_info(arch_thread_debug_info* info)
705 info->flags = 0;
709 void
710 arch_destroy_thread_debug_info(arch_thread_debug_info* info)
712 arch_clear_thread_debug_info(info);
716 void
717 arch_update_thread_single_step()
719 if (iframe* frame = x86_get_user_iframe()) {
720 Thread* thread = thread_get_current_thread();
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);
732 void
733 arch_set_debug_cpu_state(const debug_cpu_state* cpuState)
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);
758 #endif
759 set_iframe_registers(frame, cpuState);
764 void
765 arch_get_debug_cpu_state(debug_cpu_state* cpuState)
767 if (iframe* frame = x86_get_user_iframe())
768 get_cpu_state(thread_get_current_thread(), frame, cpuState);
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.
780 status_t
781 arch_get_thread_debug_cpu_state(Thread* thread, debug_cpu_state* cpuState)
783 iframe* frame = x86_get_thread_user_iframe(thread);
784 if (frame == NULL)
785 return B_BAD_VALUE;
787 get_cpu_state(thread, frame, cpuState);
788 return B_OK;
792 status_t
793 arch_set_breakpoint(void* address)
795 return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
796 X86_BREAKPOINT_LENGTH_1);
800 status_t
801 arch_clear_breakpoint(void* address)
803 return clear_breakpoint(address, false);
807 status_t
808 arch_set_watchpoint(void* address, uint32 type, int32 length)
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;
816 return set_breakpoint(address, archType, archLength);
820 status_t
821 arch_clear_watchpoint(void* address)
823 return clear_breakpoint(address, true);
827 bool
828 arch_has_breakpoints(arch_team_debug_info* info)
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);
836 #if KERNEL_BREAKPOINTS
838 status_t
839 arch_set_kernel_breakpoint(void* address)
841 status_t error = set_kernel_breakpoint(address, X86_INSTRUCTION_BREAKPOINT,
842 X86_BREAKPOINT_LENGTH_1);
844 if (error != B_OK) {
845 panic("arch_set_kernel_breakpoint() failed to set breakpoint: %s",
846 strerror(error));
849 return error;
853 status_t
854 arch_clear_kernel_breakpoint(void* address)
856 status_t error = clear_kernel_breakpoint(address, false);
858 if (error != B_OK) {
859 panic("arch_clear_kernel_breakpoint() failed to clear breakpoint: %s",
860 strerror(error));
863 return error;
867 status_t
868 arch_set_kernel_watchpoint(void* address, uint32 type, int32 length)
870 size_t archType, archLength;
871 status_t error = check_watch_point_parameters(address, type, length,
872 archType, archLength);
874 if (error == B_OK)
875 error = set_kernel_breakpoint(address, archType, archLength);
877 if (error != B_OK) {
878 panic("arch_set_kernel_watchpoint() failed to set watchpoint: %s",
879 strerror(error));
882 return error;
886 status_t
887 arch_clear_kernel_watchpoint(void* address)
889 status_t error = clear_kernel_breakpoint(address, true);
891 if (error != B_OK) {
892 panic("arch_clear_kernel_watchpoint() failed to clear watchpoint: %s",
893 strerror(error));
896 return error;
899 #endif // KERNEL_BREAKPOINTS
902 // #pragma mark - x86 implementation interface
906 * Interrupts are disabled. \a frame is unused, i.e. can be \c NULL.
908 void
909 x86_init_user_debug_at_kernel_exit(iframe* frame)
911 Thread* thread = thread_get_current_thread();
913 if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED))
914 return;
916 // disable kernel breakpoints
917 disable_breakpoints();
919 // install the user breakpoints
920 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
922 arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info;
924 install_breakpoints(teamInfo);
926 atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED);
928 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
933 * Interrupts are disabled.
935 void
936 x86_exit_user_debug_at_kernel_entry()
938 Thread* thread = thread_get_current_thread();
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));
947 // The remainder needs only be done, when user breakpoints are installed.
948 if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED))
949 return;
951 // disable user breakpoints
952 disable_breakpoints();
954 // install kernel breakpoints
955 Team* kernelTeam = team_get_kernel_team();
957 GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
959 install_breakpoints(kernelTeam->debug_info.arch_info);
961 atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED);
963 RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
968 * Interrupts are disabled and will possibly be enabled by the function.
970 void
971 x86_handle_debug_exception(iframe* frame)
973 Thread* thread = thread_get_current_thread();
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));
990 TRACE(("x86_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7));
992 // check, which exception condition applies
993 if (dr6 & X86_DR6_BREAKPOINT_MASK) {
994 // breakpoint
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;
1006 if (IFRAME_IS_USER(frame)) {
1007 // enable interrupts and notify the debugger
1008 enable_interrupts();
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);
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");
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
1032 if (IFRAME_IS_USER(frame)) {
1033 // enable interrupts and notify the debugger
1034 enable_interrupts();
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);
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;
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);
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);
1077 // also set the respective thread flag
1078 atomic_or(&thread->flags, THREAD_FLAGS_DEBUG_THREAD);
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");
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"));
1097 enable_interrupts();
1098 } else {
1099 panic("spurious debug exception in kernel mode (no condition "
1100 "recognized)");
1107 * Interrupts are disabled and will possibly be enabled by the function.
1109 void
1110 x86_handle_breakpoint_exception(iframe* frame)
1112 TRACE(("x86_handle_breakpoint_exception()\n"));
1114 // reset eip to the int3 instruction
1115 frame->ip--;
1117 if (!IFRAME_IS_USER(frame)) {
1118 panic("breakpoint exception in kernel mode");
1119 return;
1122 enable_interrupts();
1124 user_debug_breakpoint_hit(true);
1128 void
1129 x86_init_user_debug()
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);;
1136 unload_driver_settings(handle);
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