[haiku-commits] r35620 - in haiku/trunk: headers/private/kernel src/system/kernel/arch/x86 src/system/kernel/debug

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 25 Feb 2010 21:20:16 +0100 (CET)

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));
+       }
 }
 
 


Other related posts:

  • » [haiku-commits] r35620 - in haiku/trunk: headers/private/kernel src/system/kernel/arch/x86 src/system/kernel/debug - ingo_weinhold