From 92cbf60a69f1163968ac2f2cf9626e085633ed33 Mon Sep 17 00:00:00 2001 From: linsmod Date: Sun, 2 Aug 2026 09:25:44 +0800 Subject: [PATCH] Preserve debug registers in breakpoint step-over context ContextControlFlags is used by the debug loop's SetThreadContext calls during breakpoint step-over. Under WoW64 (x64 debugger, 32-bit target) writing back with plain CONTEXT_CONTROL cleared the DR0..DR7 registers armed via hbreak. Include CONTEXT_DEBUG_REGISTERS so a breakpoint step never erases them. --- TitanEngine/Global.Debugger.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/TitanEngine/Global.Debugger.cpp b/TitanEngine/Global.Debugger.cpp index 11e4c5f..0ef78ed 100644 --- a/TitanEngine/Global.Debugger.cpp +++ b/TitanEngine/Global.Debugger.cpp @@ -43,7 +43,12 @@ CRITICAL_SECTION engineStepActiveCr; // Workaround for a bug in the kernel with x64 emulation on ARM DWORD ContextControlFlags = [] { - DWORD flags = CONTEXT_CONTROL; + // CONTEXT_CONTROL alone reads/writes only the control registers. When the + // debugger (x64) cross-debugs a 32-bit target under WoW64, a SetThreadContext + // issued with plain CONTEXT_CONTROL clobbers the debug registers the user + // armed via hbreak (DR0..DR7) — Windows writes back the whole flagged set. + // Include CONTEXT_DEBUG_REGISTERS so breakpoint steps never erase them. + DWORD flags = CONTEXT_CONTROL | CONTEXT_DEBUG_REGISTERS; typedef BOOL(WINAPI * type_IsWow64Process2)(HANDLE, USHORT*, USHORT*); auto p_IsWow64Process2 = (type_IsWow64Process2)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "IsWow64Process2"); if(p_IsWow64Process2)