diff --git a/headers/private/kernel/user_debugger.h b/headers/private/kernel/user_debugger.h index dc95f36edf..43d5e9d977 100644 --- a/headers/private/kernel/user_debugger.h +++ b/headers/private/kernel/user_debugger.h @@ -154,17 +154,18 @@ enum { // thread debugging flags (user-specifiable flags are in ) enum { - B_THREAD_DEBUG_INITIALIZED = 0x0001, - B_THREAD_DEBUG_DYING = 0x0002, - B_THREAD_DEBUG_STOP = 0x0004, - B_THREAD_DEBUG_STOPPED = 0x0008, - B_THREAD_DEBUG_SINGLE_STEP = 0x0010, + B_THREAD_DEBUG_INITIALIZED = 0x0001, + B_THREAD_DEBUG_DYING = 0x0002, + B_THREAD_DEBUG_STOP = 0x0004, + B_THREAD_DEBUG_STOPPED = 0x0008, + B_THREAD_DEBUG_SINGLE_STEP = 0x0010, + B_THREAD_DEBUG_NOTIFY_SINGLE_STEP = 0x0020, - B_THREAD_DEBUG_NUB_THREAD = 0x0020, // marks the nub thread + B_THREAD_DEBUG_NUB_THREAD = 0x0040, // marks the nub thread - B_THREAD_DEBUG_KERNEL_FLAG_MASK = 0xffff, + B_THREAD_DEBUG_KERNEL_FLAG_MASK = 0xffff, - B_THREAD_DEBUG_DEFAULT_FLAGS = 0, + B_THREAD_DEBUG_DEFAULT_FLAGS = 0, }; // messages sent from the debug nub thread to a debugged thread diff --git a/src/system/kernel/arch/x86/arch_user_debugger.cpp b/src/system/kernel/arch/x86/arch_user_debugger.cpp index f8dc9fa7b0..2c784069a4 100644 --- a/src/system/kernel/arch/x86/arch_user_debugger.cpp +++ b/src/system/kernel/arch/x86/arch_user_debugger.cpp @@ -886,7 +886,42 @@ x86_handle_debug_exception(struct iframe *frame) // it, but we don't want it when continuing otherwise. frame->flags &= ~(1 << X86_EFLAGS_TF); - panic("kernel single step"); + // Determine whether the exception occurred at a syscall/trap + // kernel entry or whether this is genuine kernel single-stepping. + bool inKernel = true; + struct thread* thread = thread_get_current_thread(); + if (thread->team != team_get_kernel_team() + && i386_get_user_iframe() == NULL) { + // TODO: This is not yet fully correct, since a newly created + // thread that doesn't have entered userland yet also has this + // property. + inKernel = false; + } + + if (inKernel) { + panic("kernel single step"); + } else { + // The thread is a userland thread and it just entered the + // kernel when the single-step exception occurred. This happens + // e.g. when sysenter is called with single-stepping enabled. + // We need to ignore the exception now and send a single-step + // notification later, when the thread wants to return from the + // kernel. + InterruptsSpinLocker threadLocker(gThreadSpinlock); + + // Check whether the team is still being debugged and set + // the B_THREAD_DEBUG_NOTIFY_SINGLE_STEP and + // B_THREAD_DEBUG_STOP flags, so that the thread will be + // stopped when it is going to leave the kernel and notify the + // debugger about the single-step event. + int32 teamDebugFlags + = atomic_get(&thread->team->debug_info.flags); + if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) { + atomic_or(&thread->debug_info.flags, + B_THREAD_DEBUG_NOTIFY_SINGLE_STEP + | B_THREAD_DEBUG_STOP); + } + } } } else if (dr6 & (1 << X86_DR6_BT)) { // task switch diff --git a/src/system/kernel/debug/user_debugger.cpp b/src/system/kernel/debug/user_debugger.cpp index 26fc94dacc..f77693a71e 100644 --- a/src/system/kernel/debug/user_debugger.cpp +++ b/src/system/kernel/debug/user_debugger.cpp @@ -954,11 +954,25 @@ user_debug_handle_signal(int signal, struct sigaction *handler, bool deadly) void user_debug_stop_thread() { - // prepare the message - debug_thread_debugged message; + // check whether this is actually an emulated single-step notification + InterruptsSpinLocker threadsLocker(gThreadSpinlock); + struct thread* thread = thread_get_current_thread(); + bool singleStepped = false; + if ((atomic_and(&thread->debug_info.flags, + ~B_THREAD_DEBUG_NOTIFY_SINGLE_STEP) + & B_THREAD_DEBUG_NOTIFY_SINGLE_STEP) != 0) { + singleStepped = true; + } - thread_hit_serious_debug_event(B_DEBUGGER_MESSAGE_THREAD_DEBUGGED, &message, - sizeof(message)); + threadsLocker.Unlock(); + + if (singleStepped) { + user_debug_single_stepped(); + } else { + debug_thread_debugged message; + thread_hit_serious_debug_event(B_DEBUGGER_MESSAGE_THREAD_DEBUGGED, + &message, sizeof(message)); + } }