From: Akihiro Sagawa <sagawa.aki@gmail.com>
Subject: [PATCH] ntdll: Add exception handling around DbgBreakPoint.
Message-Id: <20190929212853.D5DC.375B48EC@gmail.com>
Date: Sun, 29 Sep 2019 21:28:57 +0900


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47509
Signed-off-by: Akihiro Sagawa <sagawa.aki@gmail.com>
---
 dlls/kernel32/tests/debugger.c | 32 ++++++++++++++++++++++++--------
 dlls/ntdll/process.c           | 19 ++++++++++++++++++-
 2 files changed, 42 insertions(+), 9 deletions(-)

diff --git a/dlls/kernel32/tests/debugger.c b/dlls/kernel32/tests/debugger.c
index 8148c39..926457a 100644
--- a/dlls/kernel32/tests/debugger.c
+++ b/dlls/kernel32/tests/debugger.c
@@ -399,7 +399,7 @@ static void wait_for_breakpoint_(unsigned line, struct debugger_context *ctx)
        ctx->ev.u.Exception.ExceptionRecord.ExceptionCode);
 }
 
-static void process_attach_events(struct debugger_context *ctx)
+static void process_attach_events(struct debugger_context *ctx, BOOL pass_exception)
 {
     DEBUG_EVENT ev;
     BOOL ret;
@@ -445,6 +445,13 @@ static void process_attach_events(struct debugger_context *ctx)
        ctx->ev.u.Exception.ExceptionRecord.ExceptionCode);
     ok(ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress == pDbgBreakPoint, "ExceptionAddress != DbgBreakPoint\n");
 
+    if (pass_exception)
+    {
+        ret = ContinueDebugEvent(ctx->ev.dwProcessId, ctx->ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
+        ok(ret, "ContinueDebugEvent failed, last error %d.\n", GetLastError());
+        ctx->ev.dwDebugEventCode = -1;
+    }
+
     /* flush debug events */
     do next_event(ctx, POLL_EVENT_TIMEOUT);
     while (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx->ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT
@@ -477,7 +484,7 @@ static void doDebugger(int argc, char** argv)
     if (strstr(myARGV[2], "process"))
     {
         strcat(buf, "processing debug messages\n");
-        process_attach_events(&ctx);
+        process_attach_events(&ctx, FALSE);
     }
 
     debug_event=(argc >= 6 ? (HANDLE)(INT_PTR)atol(argv[5]) : NULL);
@@ -1023,7 +1030,7 @@ static void doChildren(int argc, char **argv)
     HeapFree(GetProcessHeap(), 0, cmd);
 }
 
-static void test_debug_children(char *name, DWORD flag, BOOL debug_child)
+static void test_debug_children(char *name, DWORD flag, BOOL debug_child, BOOL pass_exception)
 {
     const char *arguments = "debugger children";
     struct child_blackbox blackbox;
@@ -1096,7 +1103,7 @@ static void test_debug_children(char *name, DWORD flag, BOOL debug_child)
     {
         DWORD last_thread;
 
-        process_attach_events(&ctx);
+        process_attach_events(&ctx, pass_exception);
         ok(ctx.pid == pi.dwProcessId, "unexpected dwProcessId %x\n", ctx.pid);
 
         ret = DebugBreakProcess(pi.hProcess);
@@ -1120,6 +1127,13 @@ static void test_debug_children(char *name, DWORD flag, BOOL debug_child)
         ok(ret, "SetEvent failed, last error %d.\n", GetLastError());
     }
 
+    if (pass_exception)
+    {
+        ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
+        ok(ret, "ContinueDebugEvent failed, last error %d.\n", GetLastError());
+        ctx.ev.dwDebugEventCode = -1;
+    }
+
     do next_event(&ctx, WAIT_EVENT_TIMEOUT);
     while (ctx.ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx.ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT
            || ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT || ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT);
@@ -1487,10 +1501,12 @@ START_TEST(debugger)
         test_ExitCode();
         test_RemoteDebugger();
         test_debug_loop(myARGC, myARGV);
-        test_debug_children(myARGV[0], DEBUG_PROCESS, TRUE);
-        test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE);
-        test_debug_children(myARGV[0], DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS, FALSE);
-        test_debug_children(myARGV[0], 0, FALSE);
+        test_debug_children(myARGV[0], DEBUG_PROCESS, TRUE, FALSE);
+        test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE, FALSE);
+        test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE, TRUE);
+        test_debug_children(myARGV[0], DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS, FALSE, FALSE);
+        test_debug_children(myARGV[0], 0, FALSE, FALSE);
+        test_debug_children(myARGV[0], 0, FALSE, TRUE);
         test_debugger(myARGV[0]);
     }
 }
diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c
index e3c2ba5..eee68cc 100644
--- a/dlls/ntdll/process.c
+++ b/dlls/ntdll/process.c
@@ -46,6 +46,7 @@
 #include "windef.h"
 #include "winternl.h"
 #include "ntdll_misc.h"
+#include "wine/exception.h"
 #include "wine/library.h"
 #include "wine/server.h"
 #include "wine/unicode.h"
@@ -1366,13 +1367,29 @@ done:
     return status;
 }
 
+static LONG WINAPI breakpoint_handler( EXCEPTION_POINTERS *eptr )
+{
+    EXCEPTION_RECORD *rec = eptr->ExceptionRecord;
+    return (rec->ExceptionCode == EXCEPTION_BREAKPOINT) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
+}
+
 /***********************************************************************
  *      DbgUiRemoteBreakin (NTDLL.@)
  */
 void WINAPI DbgUiRemoteBreakin( void *arg )
 {
     TRACE( "\n" );
-    if (NtCurrentTeb()->Peb->BeingDebugged) DbgBreakPoint();
+    if (NtCurrentTeb()->Peb->BeingDebugged) {
+        __TRY
+        {
+            DbgBreakPoint();
+        }
+        __EXCEPT(breakpoint_handler)
+        {
+            ; /* do nothing */
+        }
+        __ENDTRY
+    }
     RtlExitUserThread( STATUS_SUCCESS );
 }