Author: bonefish Date: 2010-02-25 21:20:16 +0100 (Thu, 25 Feb 2010) New Revision: 35620 Changeset: http://dev.haiku-os.org/changeset/35620/haiku Ticket: http://dev.haiku-os.org/ticket/3487 Modified: haiku/trunk/headers/private/kernel/user_debugger.h haiku/trunk/src/system/kernel/arch/x86/arch_user_debugger.cpp haiku/trunk/src/system/kernel/debug/user_debugger.cpp Log: Correctly handle cases when a thread single-steps into the kernel as it can happen on syscalls or "int" instructions. The debug exception handler sets the thread debug flags B_THREAD_DEBUG_STOP and B_THREAD_DEBUG_NOTIFY_SINGLE_STEP (new) and lets the thread continue. Before leaving the kernel the thread is stopped and a single-step notification is sent. Fixes #3487. Modified: haiku/trunk/headers/private/kernel/user_debugger.h =================================================================== --- haiku/trunk/headers/private/kernel/user_debugger.h 2010-02-25 19:10:44 UTC (rev 35619) +++ haiku/trunk/headers/private/kernel/user_debugger.h 2010-02-25 20:20:16 UTC (rev 35620) @@ -154,17 +154,18 @@ // thread debugging flags (user-specifiable flags are in <debugger.h>) 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 Modified: haiku/trunk/src/system/kernel/arch/x86/arch_user_debugger.cpp =================================================================== --- haiku/trunk/src/system/kernel/arch/x86/arch_user_debugger.cpp 2010-02-25 19:10:44 UTC (rev 35619) +++ haiku/trunk/src/system/kernel/arch/x86/arch_user_debugger.cpp 2010-02-25 20:20:16 UTC (rev 35620) @@ -886,7 +886,42 @@ // 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 Modified: haiku/trunk/src/system/kernel/debug/user_debugger.cpp =================================================================== --- haiku/trunk/src/system/kernel/debug/user_debugger.cpp 2010-02-25 19:10:44 UTC (rev 35619) +++ haiku/trunk/src/system/kernel/debug/user_debugger.cpp 2010-02-25 20:20:16 UTC (rev 35620) @@ -954,11 +954,25 @@ 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)); + } }