[PATCH 2/2] ntdll: better trap exception handling

Peter Beutner p.beutner at gmx.net
Fri Nov 9 10:49:06 CST 2007


The current code uses the TF flag to distinguish between hardware breakpoint
and single stepping interrupt, which simply doesn't work because the hw bp can
as well happen while single stepping. The best solution I came up with, avoiding
a server call at every instruction, is to check the cached value of dr7 and only
do the server call if there is actually a hw bp set.

fixes bug #8029.
---
 dlls/ntdll/signal_i386.c     |   15 ++++++++++-----
 dlls/ntdll/tests/exception.c |    6 +++---
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index 793b22e..df62a30 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -1040,16 +1040,21 @@ static void WINAPI raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context
 {
     if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP)
     {
-        if (context->EFlags & 0x100)
-        {
-            context->EFlags &= ~0x100;  /* clear single-step flag */
-        }
-        else  /* hardware breakpoint, fetch the debug registers */
+        struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
+
+        /* when single stepping can't tell whether this is a hw bp or a
+         * single step interrupt. try to avoid as much overhead as possible
+         * and only do a server call if there is any hw bp enabled. */
+
+        if( !(context->EFlags & 0x100) || (regs->dr7 & 0xff) )
         {
+            /* (possible) hardware breakpoint, fetch the debug registers */
             context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
             NtGetContextThread(GetCurrentThread(), context);
             context->ContextFlags |= CONTEXT_FULL;  /* restore flags */
         }
+
+        context->EFlags &= ~0x100;  /* clear single-step flag */
     }
 
     __regs_RtlRaiseException( rec, context );
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index ce5d31b..9bd5678 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -489,7 +489,7 @@ static DWORD bpx_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *
         /* single step exception on second nop */
         ok( context->Eip == (DWORD)code_mem + 1, "eip is wrong: %x instead of %x\n",
                                                  context->Eip, (DWORD)code_mem + 1);
-        todo_wine{ ok( (context->Dr6 & 0x4000), "BS flag is not set in Dr6\n"); };
+        ok( (context->Dr6 & 0x4000), "BS flag is not set in Dr6\n");
        /* depending on the win version the B0 bit is already set here as well
         ok( (context->Dr6 & 0xf) == 0, "B0...3 flags in Dr6 shouldn't be set\n"); */
         context->EFlags |= 0x100;
@@ -497,7 +497,7 @@ static DWORD bpx_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *
         /* hw bp exception on second nop */
         ok( context->Eip == (DWORD)code_mem + 1, "eip is wrong: %x instead of %x\n",
                                                  context->Eip, (DWORD)code_mem + 1);
-        todo_wine{ ok( (context->Dr6 & 0xf) == 1, "B0 flag is not set in Dr6\n"); };
+        ok( (context->Dr6 & 0xf) == 1, "B0 flag is not set in Dr6\n");
         ok( !(context->Dr6 & 0x4000), "BS flag is set in Dr6\n");
         context->Dr0 = 0;       /* clear breakpoint */
         context->EFlags |= 0x100;
@@ -506,7 +506,7 @@ static DWORD bpx_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *
         ok( context->Eip == (DWORD)code_mem + 2, "eip is wrong: %x instead of %x\n",
                                                  context->Eip, (DWORD)code_mem + 2);
         ok( (context->Dr6 & 0xf) == 0, "B0...3 flags in Dr6 shouldn't be set\n");
-        todo_wine{ ok( (context->Dr6 & 0x4000), "BS flag is not set in Dr6\n"); };
+        ok( (context->Dr6 & 0x4000), "BS flag is not set in Dr6\n");
     }
 
     context->Dr6 = 0;  /* clear status register */
-- 
1.5.3.4






More information about the wine-patches mailing list