Peter Beutner : ntdll: Add more exception tests.

Alexandre Julliard julliard at wine.codeweavers.com
Fri Dec 1 06:29:30 CST 2006


Module: wine
Branch: master
Commit: 6c9af2bdcb334a9d7f33bcd8d1f410ba728eedd2
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=6c9af2bdcb334a9d7f33bcd8d1f410ba728eedd2

Author: Peter Beutner <p.beutner at gmx.net>
Date:   Thu Nov 30 17:54:05 2006 +0100

ntdll: Add more exception tests.

---

 dlls/ntdll/tests/exception.c |   95 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 92 insertions(+), 3 deletions(-)

diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index fad46ca..ec86579 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -38,6 +38,7 @@
 
 static struct _TEB * (WINAPI *pNtCurrentTeb)(void);
 static NTSTATUS  (WINAPI *pNtGetContextThread)(HANDLE,CONTEXT*);
+static NTSTATUS  (WINAPI *pNtSetContextThread)(HANDLE,CONTEXT*);
 static void *code_mem;
 
 /* Test various instruction combinations that cause a protection fault on the i386,
@@ -258,6 +259,16 @@ static DWORD single_step_handler( EXCEPT
 {
     got_exception++;
     ok (!(context->EFlags & 0x100), "eflags has single stepping bit set\n");
+
+    if( got_exception < 3)
+        context->EFlags |= 0x100;  /* single step until popf instruction */
+    else {
+        /* show that the last single step exception on the popf instruction
+         * (which removed the TF bit), still is a EXCEPTION_SINGLE_STEP exception */
+        todo_wine { ok( rec->ExceptionCode == EXCEPTION_SINGLE_STEP,
+            "exception is not EXCEPTION_SINGLE_STEP: %x\n", rec->ExceptionCode); };
+    }
+
     return ExceptionContinueExecution;
 }
 
@@ -301,15 +312,78 @@ static DWORD align_check_handler( EXCEPT
     return ExceptionContinueExecution;
 }
 
+/* test single stepping over hardware breakpoint */
+static DWORD bpx_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
+                          CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
+{
+    got_exception++;
+    ok( rec->ExceptionCode == EXCEPTION_SINGLE_STEP,
+        "wrong exception code: %x\n", rec->ExceptionCode);
+
+    if(got_exception == 1) {
+        /* hw bp exception on first nop */
+        ok( context->Eip == (DWORD)code_mem, "eip is wrong:  %x instead of %x\n",
+                                             context->Eip, (DWORD)code_mem);
+        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 = context->Dr0 + 1;  /* set hw bp again on next instruction */
+        context->EFlags |= 0x100;       /* enable single stepping */
+    } else if(  got_exception == 2) {
+        /* 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 & 0xf) == 0, "B0...3 flags in Dr6 shouldn't be set\n");
+        context->EFlags |= 0x100;
+    } else if( got_exception == 3) {
+        /* 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 & 0x4000), "BS flag is set in Dr6\n");
+        context->Dr0 = 0;       /* clear breakpoint */
+        context->EFlags |= 0x100;
+    } else {
+        /* single step exception on ret */
+        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"); };
+    }
+
+    context->Dr6 = 0;  /* clear status register */
+    return ExceptionContinueExecution;
+}
+
+static const BYTE dummy_code[] = { 0x90, 0x90, 0xc3 };  /* nop, nop, ret */
+
+/* test int3 handling */
+static DWORD int3_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
+                           CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
+{
+    ok( rec->ExceptionAddress == code_mem, "exception address not at: %p, but at %p\n",
+                                           code_mem,  rec->ExceptionAddress);
+    todo_wine {
+        ok( context->Eip == (DWORD)code_mem, "eip not at: %p, but at %#x\n", code_mem, context->Eip);
+    }
+    if(context->Eip == (DWORD)code_mem) context->Eip++; /* skip breakpoint */
+
+    return ExceptionContinueExecution;
+}
+
+static const BYTE int3_code[] = { 0xCC, 0xc3 };  /* int 3, ret */
+
+
 static void test_exceptions(void)
 {
     CONTEXT ctx;
     NTSTATUS res;
 
     pNtGetContextThread = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtGetContextThread" );
-    if (!pNtGetContextThread)
+    pNtSetContextThread = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtSetContextThread" );
+    if (!pNtGetContextThread || !pNtSetContextThread)
     {
-        trace( "NtGetContextThread not found, skipping tests\n" );
+        trace( "NtGetContextThread/NtSetContextThread not found, skipping tests\n" );
         return;
     }
 
@@ -325,12 +399,27 @@ static void test_exceptions(void)
     /* test single stepping behavior */
     got_exception = 0;
     run_exception_test(single_step_handler, NULL, &single_stepcode, sizeof(single_stepcode));
-    ok(got_exception == 1, "expected 1 single step exceptions, got %d\n", got_exception);
+    ok(got_exception == 3, "expected 3 single step exceptions, got %d\n", got_exception);
 
     /* test alignment exceptions */
     got_exception = 0;
     run_exception_test(align_check_handler, NULL, align_check_code, sizeof(align_check_code));
     ok(got_exception == 0, "got %d alignment faults, expected 0\n", got_exception);
+
+    /* test single stepping over hardware breakpoint */
+    memset(&ctx, 0, sizeof(ctx));
+    ctx.Dr0 = (DWORD) code_mem;  /* set hw bp on first nop */
+    ctx.Dr7 = 3;
+    ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+    res = pNtSetContextThread( GetCurrentThread(), &ctx);
+    ok( res == STATUS_SUCCESS, "NtSetContextThread faild with %x\n", res);
+
+    got_exception = 0;
+    run_exception_test(bpx_handler, NULL, dummy_code, sizeof(dummy_code));
+    ok( got_exception == 4,"expected 4 exceptions, got %d\n", got_exception);
+
+    /* test int3 handling */
+    run_exception_test(int3_handler, NULL, int3_code, sizeof(int3_code));
 }
 
 #endif  /* __i386__ */




More information about the wine-cvs mailing list