-- v2: ntdll: Store exception reporting flags for debug events. ntdll: Store exception reporting flags on suspend. ntdll: Store exception reporting flags in server context. ntdll: Set exception reporting flags in NtGetContextThread(). ntdll/tests: Add tests for CONTEXT_EXCEPTION_REQUEST. ntdll/tests: Work around exception test failures on Wine WoW.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/exception.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 771f32bb514..3954b90ef82 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -174,6 +174,7 @@ enum debugger_stages static int my_argc; static char** my_argv; static BOOL is_wow64; +static BOOL old_wow64; /* Wine old-style wow64 */ static BOOL have_vectored_api; static enum debugger_stages test_stage;
@@ -264,6 +265,7 @@ static const struct exception NTSTATUS alt_status; /* alternative status code */ DWORD alt_nb_params; /* alternative number of parameters */ DWORD alt_params[4]; /* alternative parameters */ + BOOL wow64_wine_todo; /* broken in Wine new wow64 mode. */ } exceptions[] = { /* 0 */ @@ -319,7 +321,9 @@ static const struct exception 5, 6, TRUE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, { { 0x0f, 0xa8, 0x31, 0xc0, 0x8e, 0xe8, 0x65, 0xa1, 0, 0, 0, 0, 0x0f, 0xa9, 0xc3 }, /* push %gs; xor %eax,%eax; mov %ax,%gs; mov %gs:(0),%ax; pop %gs; ret */ - 6, 6, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, + 6, 6, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff }, + .wow64_wine_todo = TRUE, + },
/* test moving %cs -> %ss */ { { 0x0e, 0x17, 0x58, 0xc3 }, /* pushl %cs; popl %ss; popl %eax; ret */ @@ -734,6 +738,11 @@ static void test_prot_fault(void) skip( "Exception %u broken on Wow64\n", i ); continue; } + if (is_wow64 && !old_wow64 && exceptions[i].wow64_wine_todo && !strcmp(winetest_platform, "wine")) + { + todo_wine ok( 0, "Exception %u broken on Wow64 (Wine)\n", i ); + continue; + } got_exception = 0; run_exception_test(prot_fault_handler, &exceptions[i], &exceptions[i].code, sizeof(exceptions[i].code), 0); @@ -11021,6 +11030,16 @@ START_TEST(exception) #define X(f) p##f = (void*)GetProcAddress(hkernel32, #f) X(IsWow64Process); if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; + if (is_wow64) + { + TEB64 *teb64 = ULongToPtr( NtCurrentTeb()->GdiBatchCount ); + + if (teb64) + { + PEB64 *peb64 = ULongToPtr(teb64->Peb); + old_wow64 = !peb64->LdrData; + } + }
X(InitializeContext); X(InitializeContext2); @@ -11117,8 +11136,15 @@ START_TEST(exception) test_debuggee_xstate(); test_stage = STAGE_XSTATE_LEGACY_SSE; test_debuggee_xstate(); - test_stage = STAGE_SEGMENTS; - test_debuggee_segments(); + if ((!is_wow64 || old_wow64) || strcmp(winetest_platform, "wine")) + { + test_stage = STAGE_SEGMENTS; + test_debuggee_segments(); + } + else + { + todo_wine ok(0, "skipping test_debuggee_segments().\n"); + } #endif
/* rest of tests only run in parent */
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/exception.c | 321 ++++++++++++++++++++++++++++++++-- dlls/ntdll/tests/ntdll_test.h | 2 + dlls/ntdll/tests/wow64.c | 14 +- include/winnt.h | 5 + 4 files changed, 322 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 3954b90ef82..5b39607e402 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -18,22 +18,15 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include <stdarg.h> +#include "ntdll_test.h" + #include <stdio.h> #include <setjmp.h>
-#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "winnt.h" -#include "winreg.h" #include "winuser.h" -#include "winternl.h" #include "rtlsupportapi.h" #include "ddk/wdm.h" #include "excpt.h" -#include "wine/test.h" #include "intrin.h"
static void *code_mem; @@ -237,6 +230,19 @@ static void test_debugger_xstate(HANDLE thread, CONTEXT *ctx, enum debugger_stag status = pNtSetContextThread(thread, xctx); ok(!status, "NtSetContextThread failed with 0x%lx\n", status); } + +#define check_context_exception_request( a, b ) check_context_exception_request_( a, b, __LINE__ ) +static void check_context_exception_request_( DWORD flags, BOOL hardware_exception, unsigned int line ) +{ + static const DWORD exception_reporting_flags = CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING + | CONTEXT_EXCEPTION_ACTIVE | CONTEXT_SERVICE_ACTIVE; + DWORD expected_flags = CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING; + + if (!(flags & CONTEXT_EXCEPTION_REPORTING)) return; + expected_flags |= hardware_exception ? CONTEXT_EXCEPTION_ACTIVE : CONTEXT_SERVICE_ACTIVE; + ok_(__FILE__, line)( (flags & exception_reporting_flags) == expected_flags, "got %#lx, expected %#lx.\n", + flags, expected_flags ); +} #endif
#ifdef __i386__ @@ -1112,13 +1118,16 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- ctx.ContextFlags = CONTEXT_FULL | CONTEXT_EXTENDED_REGISTERS; + ctx.ContextFlags = CONTEXT_FULL | CONTEXT_EXTENDED_REGISTERS | CONTEXT_EXCEPTION_REQUEST; status = pNtGetContextThread(pi.hThread, &ctx); ok(!status, "NtGetContextThread failed with 0x%lx\n", status); + todo_wine ok(ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING + || broken( !(ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING) ) /* Win7 WoW64 */, + "got %#lx.\n", ctx.ContextFlags);
- trace("exception 0x%lx at %p firstchance=%ld Eip=0x%lx, Eax=0x%lx\n", + trace("exception 0x%lx at %p firstchance=%ld Eip=0x%lx, Eax=0x%lx ctx.ContextFlags %#lx\n", de.u.Exception.ExceptionRecord.ExceptionCode, - de.u.Exception.ExceptionRecord.ExceptionAddress, de.u.Exception.dwFirstChance, ctx.Eip, ctx.Eax); + de.u.Exception.ExceptionRecord.ExceptionAddress, de.u.Exception.dwFirstChance, ctx.Eip, ctx.Eax, ctx.ContextFlags);
if (counter > 100) { @@ -1135,6 +1144,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) (char *)ctx.Eip < (char *)ntdll + nt->OptionalHeader.SizeOfImage, "wrong eip %p ntdll %p-%p\n", (void *)ctx.Eip, ntdll, (char *)ntdll + nt->OptionalHeader.SizeOfImage ); + check_context_exception_request( ctx.ContextFlags, TRUE ); } else { @@ -1148,6 +1158,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) ctx.Eax = 0xf00f00f1; /* let the debuggee handle the exception */ continuestatus = DBG_EXCEPTION_NOT_HANDLED; + check_context_exception_request( ctx.ContextFlags, !is_wow64 ); } else if (stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) { @@ -1184,6 +1195,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) ctx.Eip, (char *)code_mem_address + 0xb); /* here we handle exception */ } + check_context_exception_request( ctx.ContextFlags, !is_wow64 ); } else if (stage == STAGE_SERVICE_CONTINUE || stage == STAGE_SERVICE_NOT_HANDLED) { @@ -1193,6 +1205,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) "expected Eip = %p, got 0x%lx\n", (char *)code_mem_address + 0x1d, ctx.Eip);
if (stage == STAGE_SERVICE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + check_context_exception_request( ctx.ContextFlags, TRUE ); } else if (stage == STAGE_BREAKPOINT_CONTINUE || stage == STAGE_BREAKPOINT_NOT_HANDLED) { @@ -1202,6 +1215,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) "expected Eip = %p, got 0x%lx\n", (char *)code_mem_address + 2, ctx.Eip);
if (stage == STAGE_BREAKPOINT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + check_context_exception_request( ctx.ContextFlags, TRUE ); } else if (stage == STAGE_EXCEPTION_INVHANDLE_CONTINUE || stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) { @@ -1212,14 +1226,17 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) "unexpected number of parameters %ld, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters);
if (stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + check_context_exception_request( ctx.ContextFlags, !is_wow64 ); } else if (stage == STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(FALSE || broken(TRUE) /* < Win10 */, "should not throw exception\n"); continuestatus = DBG_EXCEPTION_NOT_HANDLED; + check_context_exception_request( ctx.ContextFlags, !is_wow64 ); } else if (stage == STAGE_XSTATE || stage == STAGE_XSTATE_LEGACY_SSE) { + check_context_exception_request( ctx.ContextFlags, TRUE ); test_debugger_xstate(pi.hThread, &ctx, stage); } else if (stage == STAGE_SEGMENTS) @@ -1240,6 +1257,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) ok( !ctx.SegEs, "wrong es %04lx / %04lx\n", ctx.SegEs, ctx.SegSs ); ok( !ctx.SegGs, "wrong gs %04lx / %04lx\n", ctx.SegGs, ctx.SegSs ); } + check_context_exception_request( ctx.ContextFlags, TRUE ); } else ok(FALSE, "unexpected stage %u\n", stage); @@ -3573,9 +3591,10 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- ctx.ContextFlags = CONTEXT_FULL | CONTEXT_SEGMENTS; + ctx.ContextFlags = CONTEXT_FULL | CONTEXT_SEGMENTS | CONTEXT_EXCEPTION_REQUEST; status = pNtGetContextThread(pi.hThread, &ctx); ok(!status, "NtGetContextThread failed with 0x%lx\n", status); + todo_wine ok(ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING, "got %#lx.\n", ctx.ContextFlags);
trace("exception 0x%lx at %p firstchance=%ld Rip=%p, Rax=%p\n", de.u.Exception.ExceptionRecord.ExceptionCode, @@ -3596,6 +3615,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) (char *)ctx.Rip < (char *)hntdll + nt->OptionalHeader.SizeOfImage, "wrong rip %p ntdll %p-%p\n", (void *)ctx.Rip, hntdll, (char *)hntdll + nt->OptionalHeader.SizeOfImage ); + check_context_exception_request( ctx.ContextFlags, TRUE ); } else { @@ -3614,6 +3634,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) ctx.Rax = 0xf00f00f1; /* let the debuggee handle the exception */ continuestatus = DBG_EXCEPTION_NOT_HANDLED; + check_context_exception_request( ctx.ContextFlags, FALSE ); } else if (stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) { @@ -3652,6 +3673,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) ctx.Rip, (char *)code_mem_address + 0x0c); /* here we handle exception */ } + check_context_exception_request( ctx.ContextFlags, FALSE ); } else if (stage == STAGE_SERVICE_CONTINUE || stage == STAGE_SERVICE_NOT_HANDLED) { @@ -3660,6 +3682,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) ok((char *)ctx.Rip == (char *)code_mem_address + 0x30, "expected Rip = %p, got %p\n", (char *)code_mem_address + 0x30, (char *)ctx.Rip); if (stage == STAGE_SERVICE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + check_context_exception_request( ctx.ContextFlags, TRUE ); } else if (stage == STAGE_BREAKPOINT_CONTINUE || stage == STAGE_BREAKPOINT_NOT_HANDLED) { @@ -3668,6 +3691,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) ok((char *)ctx.Rip == (char *)code_mem_address + 2, "expected Rip = %p, got %p\n", (char *)code_mem_address + 2, (char *)ctx.Rip); if (stage == STAGE_BREAKPOINT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + check_context_exception_request( ctx.ContextFlags, TRUE ); } else if (stage == STAGE_EXCEPTION_INVHANDLE_CONTINUE || stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) { @@ -3678,14 +3702,17 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) "unexpected number of parameters %ld, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters);
if (stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + check_context_exception_request( ctx.ContextFlags, FALSE ); } else if (stage == STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(FALSE || broken(TRUE) /* < Win10 */, "should not throw exception\n"); continuestatus = DBG_EXCEPTION_NOT_HANDLED; + check_context_exception_request( ctx.ContextFlags, FALSE ); } else if (stage == STAGE_XSTATE || stage == STAGE_XSTATE_LEGACY_SSE) { + check_context_exception_request( ctx.ContextFlags, TRUE ); test_debugger_xstate(pi.hThread, &ctx, stage); } else if (stage == STAGE_SEGMENTS) @@ -3714,6 +3741,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) ok( ctx.SegEs == ctx.SegSs, "wrong es %04x / %04x\n", ctx.SegEs, ctx.SegSs ); todo_wine ok( ctx.SegFs != ctx.SegSs, "wrong fs %04x / %04x\n", ctx.SegFs, ctx.SegSs ); ok( ctx.SegGs == ctx.SegSs, "wrong gs %04x / %04x\n", ctx.SegGs, ctx.SegSs ); + check_context_exception_request( ctx.ContextFlags, TRUE ); } else ok(FALSE, "unexpected stage %u\n", stage); @@ -4325,9 +4353,21 @@ static void test_wow64_context(void) ret = pRtlWow64GetThreadContext( pi.hThread, &ctx ); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok( ctx.ContextFlags == WOW64_CONTEXT_ALL, "got context flags %#lx\n", ctx.ContextFlags ); + + ctx.ContextFlags = WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST; + ret = pRtlWow64GetThreadContext( pi.hThread, &ctx ); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + todo_wine ok( (ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING) || broken( ctx.ContextFlags == WOW64_CONTEXT_ALL ) /*Win 7*/, + "got context flags %#lx\n", ctx.ContextFlags ); + if (context.SegCs == cs32) { trace( "in 32-bit mode %04x\n", context.SegCs ); + if (ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING) + ok( ctx.ContextFlags == (WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING) + || ctx.ContextFlags == (WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING + | CONTEXT_EXCEPTION_ACTIVE), + "got %#lx.\n", ctx.ContextFlags ); ok( ctx.Eip == context.Rip, "cs32: eip %08lx / %p\n", ctx.Eip, (void *)context.Rip ); ok( ctx.Ebp == context.Rbp, "cs32: ebp %08lx / %p\n", ctx.Ebp, (void *)context.Rbp ); ok( ctx.Esp == context.Rsp, "cs32: esp %08lx / %p\n", ctx.Esp, (void *)context.Rsp ); @@ -4404,6 +4444,12 @@ static void test_wow64_context(void) else { trace( "in 64-bit mode %04x\n", context.SegCs ); + if (ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING) + ok( ctx.ContextFlags == (WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST + | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE) + || ctx.ContextFlags == (WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST + | CONTEXT_EXCEPTION_REPORTING | CONTEXT_EXCEPTION_ACTIVE), + "got %#lx.\n", ctx.ContextFlags ); ok( ctx.Eip != context.Rip, "cs64: eip %08lx / %p\n", ctx.Eip, (void *)context.Rip); ok( ctx.SegCs == cs32, "cs64: wrong cs %04lx / %04x\n", ctx.SegCs, cs32 ); if (!is_arm64ec) @@ -10950,6 +10996,254 @@ static void test_backtrace(void) module, debugstr_w(name), count - 1, buffer[count - 1] ); }
+struct context_exception_request_thread_param +{ + LONG volatile sync; + HANDLE event; +}; +static volatile int *p_context_exception_request_value; +struct context_exception_request_thread_param *context_exception_request_param; + +static LONG CALLBACK test_context_exception_request_handler( EXCEPTION_POINTERS *info ) +{ + PEXCEPTION_RECORD rec = info->ExceptionRecord; + CONTEXT *c = info->ContextRecord; + DWORD old_prot; + + ok( !(c->ContextFlags & (CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE + | CONTEXT_EXCEPTION_ACTIVE)), "got %#lx.\n", c->ContextFlags ); + + ok( rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION, "got %#lx.\n", rec->ExceptionCode ); + VirtualProtect( (void *)p_context_exception_request_value, sizeof(*p_context_exception_request_value), + PAGE_READWRITE, &old_prot ); + + WriteRelease( &context_exception_request_param->sync, 5 ); + while (ReadAcquire( &context_exception_request_param->sync ) != 6) + ; + + return EXCEPTION_CONTINUE_EXECUTION; +} + +static DWORD WINAPI test_context_exception_request_thread( void *arg ) +{ +#ifndef _WIN64 + static BYTE wait_sync_x64_code[] = + { + 0x89, 0x11, /* mov %edx,(%rcx) */ + 0x83, 0xc2, 0x01, /* add $0x1,%edx */ + 0x0f, 0x1f, 0x00, /* 1: nopl (%rax) */ + 0x8b, 0x01, /* mov (%rcx),%eax */ + 0x39, 0xd0, /* cmp %edx,%eax */ + 0x75, 0xfa, /* jne 1b */ + 0xc3, /* ret */ + }; + ULONG64 args[2]; +#endif + struct context_exception_request_thread_param *p = arg; + void *vectored_handler; + + context_exception_request_param = p; + vectored_handler = pRtlAddVectoredExceptionHandler( TRUE, test_context_exception_request_handler ); + ok( !!vectored_handler, "failed.\n" ); + + WriteRelease( &p->sync, 1 ); + while (ReadAcquire( &p->sync ) != 2) + ; + + WaitForSingleObject( p->event, INFINITE ); + +#ifndef _WIN64 + memcpy( (char *)code_mem + 1024, wait_sync_x64_code, sizeof(wait_sync_x64_code) ); + args[0] = (ULONG_PTR)&p->sync; + args[1] = 3; + if (is_wow64 && !old_wow64) call_func64( (ULONG64)(ULONG_PTR)code_mem + 1024, ARRAY_SIZE(args), args, code_mem ); +#endif + + p_context_exception_request_value = VirtualAlloc( NULL, sizeof(*p_context_exception_request_value), + MEM_RESERVE | MEM_COMMIT, PAGE_READONLY ); + ok( !!p_context_exception_request_value, "got NULL.\n" ); + *p_context_exception_request_value = 1; + ok( *p_context_exception_request_value == 1, "got %d.\n", *p_context_exception_request_value ); + VirtualFree( (void *)p_context_exception_request_value, 0, MEM_RELEASE ); + pRtlRemoveVectoredExceptionHandler( vectored_handler ); + +#ifndef _WIN64 + args[1] = 7; + if (is_wow64 && !old_wow64) call_func64( (ULONG64)(ULONG_PTR)code_mem + 1024, ARRAY_SIZE(args), args, code_mem ); +#endif + + return 0; +} + +static void test_context_exception_request(void) +{ + struct context_exception_request_thread_param p; + DWORD expected_flags; + HANDLE thread; + CONTEXT c; + BOOL ret; + + if (!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler) + { + skip( "RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found.\n" ); + return; + } + + c.ContextFlags = CONTEXT_CONTROL; + ret = GetThreadContext( GetCurrentThread(), &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + ok( c.ContextFlags == CONTEXT_CONTROL, "got %#lx.\n", c.ContextFlags ); + + expected_flags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE; + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; + ret = GetThreadContext( GetCurrentThread(), &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags || broken( c.ContextFlags == 0x10001 ) /* Win7 WoW64 */, + "got %#lx.\n", c.ContextFlags ); + if (c.ContextFlags == 0x10001) + { + win_skip( "Old WoW64 behaviour, skipping tests.\n" ); + return; + } + + ret = DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &thread, 0, TRUE, DUPLICATE_SAME_ACCESS ); + ok( ret, "got error %lu.\n", GetLastError() ); + c.ContextFlags = expected_flags | CONTEXT_EXCEPTION_REQUEST; + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; + ret = GetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + CloseHandle( thread ); + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE + | CONTEXT_EXCEPTION_ACTIVE; + ret = GetThreadContext( GetCurrentThread(), &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + + p.event = CreateEventW( NULL, FALSE, FALSE, NULL ); + thread = CreateThread( NULL, 0, test_context_exception_request_thread, &p, CREATE_SUSPENDED, NULL ); + ok( !!thread, "got error %lu.\n", GetLastError() ); + + expected_flags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_EXCEPTION_ACTIVE; + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; + ret = GetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags || broken( c.ContextFlags == (CONTEXT_CONTROL + | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING)) /* Win7 64 */, "got %#lx.\n", c.ContextFlags ); + + p.sync = 0; + ResumeThread(thread); + + while (ReadAcquire( &p.sync ) != 1) + SwitchToThread(); + /* thread is in user code. */ + SuspendThread( thread ); + + c.ContextFlags = CONTEXT_CONTROL; + ret = GetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + ok( c.ContextFlags == CONTEXT_CONTROL, "got %#lx.\n", c.ContextFlags ); + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE; + ret = SetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + + expected_flags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING; + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; + ret = GetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE + | CONTEXT_EXCEPTION_ACTIVE; + ret = GetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + + ResumeThread(thread); + WriteRelease( &p.sync, 2 ); + /* Try to make sure the thread entered WaitForSingleObject(). */ + Sleep(30); + + expected_flags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE; + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; + ret = GetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + + c.ContextFlags = CONTEXT_CONTROL; + ret = SetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE + | CONTEXT_EXCEPTION_ACTIVE; + ret = GetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + + SetEvent( p.event ); + + if (is_wow64 && !old_wow64) + { + while (ReadAcquire( &p.sync ) != 3) + SwitchToThread(); + /* thread is in x64 code. */ + + expected_flags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_EXCEPTION_ACTIVE; + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; + ret = GetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags, "got %#lx, expected %#lx.\n", c.ContextFlags, expected_flags ); + + WriteRelease( &p.sync, 4 ); + } + + while (ReadAcquire( &p.sync ) != 5) + SwitchToThread(); + + expected_flags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING; + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; + ret = GetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE + | CONTEXT_EXCEPTION_ACTIVE; + ret = GetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + + WriteRelease( &p.sync, 6 ); + + if (is_wow64 && !old_wow64) + { + while (ReadAcquire( &p.sync ) != 7) + SwitchToThread(); + /* thread is in x64 code. */ + + expected_flags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_EXCEPTION_ACTIVE; + + c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; + ret = GetThreadContext( thread, &c ); + ok( ret, "got error %lu.\n", GetLastError() ); + todo_wine ok( c.ContextFlags == expected_flags, "got %#lx, expected %#lx.\n", c.ContextFlags, expected_flags ); + + WriteRelease( &p.sync, 8 ); + } + + WaitForSingleObject( thread, INFINITE ); + CloseHandle( thread ); + CloseHandle( p.event ); +} + START_TEST(exception) { HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); @@ -11244,5 +11538,6 @@ START_TEST(exception) test_suspend_process(); test_unload_trace(); test_backtrace(); + test_context_exception_request(); VirtualFree(code_mem, 0, MEM_RELEASE); } diff --git a/dlls/ntdll/tests/ntdll_test.h b/dlls/ntdll/tests/ntdll_test.h index 67278358b29..ed824583870 100644 --- a/dlls/ntdll/tests/ntdll_test.h +++ b/dlls/ntdll/tests/ntdll_test.h @@ -30,3 +30,5 @@
#include "wine/test.h" #include "wine/heap.h" + +extern NTSTATUS call_func64( ULONG64 func64, int nb_args, ULONG64 *args, void *code_mem ); diff --git a/dlls/ntdll/tests/wow64.c b/dlls/ntdll/tests/wow64.c index e0dd7bab13b..28d7ec2406a 100644 --- a/dlls/ntdll/tests/wow64.c +++ b/dlls/ntdll/tests/wow64.c @@ -1569,7 +1569,7 @@ static const BYTE call_func64_code[] = 0xcb, /* lret */ };
-static NTSTATUS call_func64( ULONG64 func64, int nb_args, ULONG64 *args ) +NTSTATUS call_func64( ULONG64 func64, int nb_args, ULONG64 *args, void *code_mem ) { NTSTATUS (WINAPI *func)( ULONG64 func64, int nb_args, ULONG64 *args ) = code_mem;
@@ -2070,7 +2070,7 @@ static void test_iosb(void) iosb64.Information = 0xdeadbeef;
args[0] = (LONG_PTR)server; - status = call_func64( func, ARRAY_SIZE(args), args ); + status = call_func64( func, ARRAY_SIZE(args), args, code_mem ); ok( status == STATUS_PENDING, "NtFsControlFile returned %lx\n", status ); ok( iosb32.Status == 0x55555555, "status changed to %lx\n", iosb32.Status ); ok( iosb64.Pointer == PtrToUlong(&iosb32), "status changed to %lx\n", iosb64.Status ); @@ -2095,7 +2095,7 @@ static void test_iosb(void) args[8] = (ULONG_PTR)&id; args[9] = sizeof(id);
- status = call_func64( func, ARRAY_SIZE(args), args ); + status = call_func64( func, ARRAY_SIZE(args), args, code_mem ); ok( status == STATUS_PENDING || status == STATUS_SUCCESS, "NtFsControlFile returned %lx\n", status ); todo_wine { @@ -2125,7 +2125,7 @@ static void test_iosb(void) id = 0xdeadbeef;
args[0] = (LONG_PTR)server; - status = call_func64( func, ARRAY_SIZE(args), args ); + status = call_func64( func, ARRAY_SIZE(args), args, code_mem ); ok( status == STATUS_SUCCESS, "NtFsControlFile returned %lx\n", status ); ok( iosb32.Status == 0x55555555, "status changed to %lx\n", iosb32.Status ); ok( iosb32.Information == 0x55555555, "info changed to %Ix\n", iosb32.Information ); @@ -2148,7 +2148,7 @@ static NTSTATUS invoke_syscall( const char *name, ULONG args32[] ) else win_skip( "syscall thunk %s not recognized\n", name );
- return call_func64( func, ARRAY_SIZE(args64), args64 ); + return call_func64( func, ARRAY_SIZE(args64), args64, code_mem ); }
static void test_syscalls(void) @@ -2254,14 +2254,14 @@ static void test_cpu_area(void) ULONG64 context, context_ex; ULONG64 args[] = { (ULONG_PTR)&machine, (ULONG_PTR)&context, (ULONG_PTR)&context_ex };
- status = call_func64( ptr, ARRAY_SIZE(args), args ); + status = call_func64( ptr, ARRAY_SIZE(args), args, code_mem ); ok( !status, "RtlWow64GetCpuAreaInfo failed %lx\n", status ); ok( machine == IMAGE_FILE_MACHINE_I386, "wrong machine %x\n", machine ); ok( context == teb64->TlsSlots[WOW64_TLS_CPURESERVED] + 4, "wrong context %s / %s\n", wine_dbgstr_longlong(context), wine_dbgstr_longlong(teb64->TlsSlots[WOW64_TLS_CPURESERVED]) ); ok( !context_ex, "got context_ex %s\n", wine_dbgstr_longlong(context_ex) ); args[0] = args[1] = args[2] = 0; - status = call_func64( ptr, ARRAY_SIZE(args), args ); + status = call_func64( ptr, ARRAY_SIZE(args), args, code_mem ); ok( !status, "RtlWow64GetCpuAreaInfo failed %lx\n", status ); } else win_skip( "RtlWow64GetCpuAreaInfo not supported\n" ); diff --git a/include/winnt.h b/include/winnt.h index e7c322fd127..1bf38616b87 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -1536,6 +1536,11 @@ typedef struct _CONTEXT_EX #endif } CONTEXT_EX, *PCONTEXT_EX;
+#define CONTEXT_EXCEPTION_ACTIVE 0x08000000 +#define CONTEXT_SERVICE_ACTIVE 0x10000000 +#define CONTEXT_EXCEPTION_REQUEST 0x40000000 +#define CONTEXT_EXCEPTION_REPORTING 0x80000000 + #define CONTEXT_ARM 0x0200000 #define CONTEXT_ARM_CONTROL (CONTEXT_ARM | 0x00000001) #define CONTEXT_ARM_INTEGER (CONTEXT_ARM | 0x00000002)
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/exception.c | 8 ++++---- dlls/ntdll/unix/signal_arm.c | 1 + dlls/ntdll/unix/signal_arm64.c | 3 +++ dlls/ntdll/unix/signal_i386.c | 1 + dlls/ntdll/unix/signal_x86_64.c | 2 ++ dlls/ntdll/unix/unix_private.h | 11 +++++++++++ 6 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 5b39607e402..0f697fd3bd0 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -11099,8 +11099,8 @@ static void test_context_exception_request(void) c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; ret = GetThreadContext( GetCurrentThread(), &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags || broken( c.ContextFlags == 0x10001 ) /* Win7 WoW64 */, - "got %#lx.\n", c.ContextFlags ); + ok( c.ContextFlags == expected_flags || broken( c.ContextFlags == 0x10001 ) /* Win7 WoW64 */, + "got %#lx.\n", c.ContextFlags ); if (c.ContextFlags == 0x10001) { win_skip( "Old WoW64 behaviour, skipping tests.\n" ); @@ -11114,14 +11114,14 @@ static void test_context_exception_request(void) c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; ret = GetThreadContext( thread, &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); CloseHandle( thread );
c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE | CONTEXT_EXCEPTION_ACTIVE; ret = GetThreadContext( GetCurrentThread(), &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags );
p.event = CreateEventW( NULL, FALSE, FALSE, NULL ); thread = CreateThread( NULL, 0, test_context_exception_request_thread, &p, CREATE_SUSPENDED, NULL ); diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index d4711e27319..44e79d0abdf 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -513,6 +513,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) memcpy( context->D, frame->d, sizeof(frame->d) ); context->ContextFlags |= CONTEXT_FLOATING_POINT; } + set_context_exception_reporting_flags( &context->ContextFlags, CONTEXT_SERVICE_ACTIVE ); return STATUS_SUCCESS; }
diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index fcebbab76cf..11340d88672 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -433,6 +433,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) context->ContextFlags |= CONTEXT_FLOATING_POINT; } if (needed_flags & CONTEXT_DEBUG_REGISTERS) FIXME( "debug registers not supported\n" ); + set_context_exception_reporting_flags( &context->ContextFlags, CONTEXT_SERVICE_ACTIVE ); return STATUS_SUCCESS; }
@@ -640,6 +641,7 @@ NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size ) context->Dr7 = wow_frame->Dr7; } /* FIXME: CONTEXT_I386_XSTATE */ + set_context_exception_reporting_flags( &context->ContextFlags, CONTEXT_SERVICE_ACTIVE ); break; }
@@ -679,6 +681,7 @@ NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size ) memcpy( context->D, wow_frame->D, sizeof(wow_frame->D) ); context->ContextFlags |= CONTEXT_FLOATING_POINT; } + set_context_exception_reporting_flags( &context->ContextFlags, CONTEXT_SERVICE_ACTIVE ); break; }
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 61f42806f5d..6e2752745d3 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1153,6 +1153,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) x86_thread_data()->dr6 = context->Dr6; x86_thread_data()->dr7 = context->Dr7; } + set_context_exception_reporting_flags( &context->ContextFlags, CONTEXT_SERVICE_ACTIVE ); }
if (context->ContextFlags & (CONTEXT_INTEGER & ~CONTEXT_i386)) diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 4fc2727595d..41e5f9531d5 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1186,6 +1186,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) amd64_thread_data()->dr6 = context->Dr6; amd64_thread_data()->dr7 = context->Dr7; } + set_context_exception_reporting_flags( &context->ContextFlags, CONTEXT_SERVICE_ACTIVE ); return STATUS_SUCCESS; }
@@ -1390,6 +1391,7 @@ NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size ) frame->restore_flags |= CONTEXT_XSTATE; } } + set_context_exception_reporting_flags( &context->ContextFlags, CONTEXT_SERVICE_ACTIVE ); return STATUS_SUCCESS; }
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index b249570d421..ec11f9d4795 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -215,6 +215,17 @@ extern int server_pipe( int fd[2] ); extern void fpux_to_fpu( I386_FLOATING_SAVE_AREA *fpu, const XSAVE_FORMAT *fpux ); extern void fpu_to_fpux( XSAVE_FORMAT *fpux, const I386_FLOATING_SAVE_AREA *fpu );
+static inline void set_context_exception_reporting_flags( DWORD *context_flags, DWORD reporting_flag ) +{ + if (!(*context_flags & CONTEXT_EXCEPTION_REQUEST)) + { + *context_flags &= ~(CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE | CONTEXT_EXCEPTION_ACTIVE); + return; + } + *context_flags = (*context_flags & ~(CONTEXT_SERVICE_ACTIVE | CONTEXT_EXCEPTION_ACTIVE)) + | CONTEXT_EXCEPTION_REPORTING | reporting_flag; +} + extern BOOL xstate_compaction_enabled; extern UINT64 xstate_supported_features_mask; extern UINT64 xstate_features_size;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/exception.c | 18 ++++++------- dlls/ntdll/unix/server.c | 4 +++ dlls/ntdll/unix/thread.c | 50 +++++++++++++++++++++++++++++++++--- server/protocol.def | 13 ++++++++++ server/thread.c | 5 ++-- server/trace.c | 13 ++++++++++ tools/make_requests | 2 +- 7 files changed, 89 insertions(+), 16 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 0f697fd3bd0..e4cd8f8f8b5 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -240,7 +240,7 @@ static void check_context_exception_request_( DWORD flags, BOOL hardware_excepti
if (!(flags & CONTEXT_EXCEPTION_REPORTING)) return; expected_flags |= hardware_exception ? CONTEXT_EXCEPTION_ACTIVE : CONTEXT_SERVICE_ACTIVE; - ok_(__FILE__, line)( (flags & exception_reporting_flags) == expected_flags, "got %#lx, expected %#lx.\n", + todo_wine ok_(__FILE__, line)( (flags & exception_reporting_flags) == expected_flags, "got %#lx, expected %#lx.\n", flags, expected_flags ); } #endif @@ -1121,7 +1121,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) ctx.ContextFlags = CONTEXT_FULL | CONTEXT_EXTENDED_REGISTERS | CONTEXT_EXCEPTION_REQUEST; status = pNtGetContextThread(pi.hThread, &ctx); ok(!status, "NtGetContextThread failed with 0x%lx\n", status); - todo_wine ok(ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING + ok(ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING || broken( !(ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING) ) /* Win7 WoW64 */, "got %#lx.\n", ctx.ContextFlags);
@@ -3594,7 +3594,7 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) ctx.ContextFlags = CONTEXT_FULL | CONTEXT_SEGMENTS | CONTEXT_EXCEPTION_REQUEST; status = pNtGetContextThread(pi.hThread, &ctx); ok(!status, "NtGetContextThread failed with 0x%lx\n", status); - todo_wine ok(ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING, "got %#lx.\n", ctx.ContextFlags); + ok(ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING, "got %#lx.\n", ctx.ContextFlags);
trace("exception 0x%lx at %p firstchance=%ld Rip=%p, Rax=%p\n", de.u.Exception.ExceptionRecord.ExceptionCode, @@ -4357,7 +4357,7 @@ static void test_wow64_context(void) ctx.ContextFlags = WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST; ret = pRtlWow64GetThreadContext( pi.hThread, &ctx ); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); - todo_wine ok( (ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING) || broken( ctx.ContextFlags == WOW64_CONTEXT_ALL ) /*Win 7*/, + ok( (ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING) || broken( ctx.ContextFlags == WOW64_CONTEXT_ALL ) /*Win 7*/, "got context flags %#lx\n", ctx.ContextFlags );
if (context.SegCs == cs32) @@ -4445,7 +4445,7 @@ static void test_wow64_context(void) { trace( "in 64-bit mode %04x\n", context.SegCs ); if (ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING) - ok( ctx.ContextFlags == (WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST + todo_wine ok( ctx.ContextFlags == (WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE) || ctx.ContextFlags == (WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_EXCEPTION_ACTIVE), @@ -11157,13 +11157,13 @@ static void test_context_exception_request(void) c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; ret = GetThreadContext( thread, &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags );
c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE | CONTEXT_EXCEPTION_ACTIVE; ret = GetThreadContext( thread, &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags );
ResumeThread(thread); WriteRelease( &p.sync, 2 ); @@ -11213,13 +11213,13 @@ static void test_context_exception_request(void) c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; ret = GetThreadContext( thread, &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags );
c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE | CONTEXT_EXCEPTION_ACTIVE; ret = GetThreadContext( thread, &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags );
WriteRelease( &p.sync, 6 );
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 438c16518bd..f3ffd99c3fc 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -751,7 +751,11 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT
if (ret == STATUS_USER_APC) *user_apc = reply_data.call.user; if (reply_size > sizeof(reply_data.call)) + { memcpy( context, reply_data.context, reply_size - sizeof(reply_data.call) ); + context[0].flags &= ~SERVER_CTX_EXEC_SPACE; + context[1].flags &= ~SERVER_CTX_EXEC_SPACE; + } return ret; }
diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 7ae5c022fb2..21b581ddc7c 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -166,7 +166,7 @@ void fpu_to_fpux( XMM_SAVE_AREA32 *fpux, const I386_FLOATING_SAVE_AREA *fpu ) */ static unsigned int get_server_context_flags( const void *context, USHORT machine ) { - unsigned int flags, ret = 0; + unsigned int flags = 0, ret = 0;
switch (machine) { @@ -204,6 +204,7 @@ static unsigned int get_server_context_flags( const void *context, USHORT machin if (flags & CONTEXT_ARM64_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS; break; } + if (flags & CONTEXT_EXCEPTION_REQUEST) ret |= SERVER_CTX_EXEC_SPACE; return ret; }
@@ -218,11 +219,11 @@ static unsigned int get_native_context_flags( USHORT native_machine, USHORT wow_ switch (MAKELONG( native_machine, wow_machine )) { case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386 ): - return SERVER_CTX_DEBUG_REGISTERS | SERVER_CTX_FLOATING_POINT | SERVER_CTX_YMM_REGISTERS; + return SERVER_CTX_DEBUG_REGISTERS | SERVER_CTX_FLOATING_POINT | SERVER_CTX_YMM_REGISTERS | SERVER_CTX_EXEC_SPACE; case MAKELONG( IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARMNT ): - return SERVER_CTX_DEBUG_REGISTERS | SERVER_CTX_FLOATING_POINT; + return SERVER_CTX_DEBUG_REGISTERS | SERVER_CTX_FLOATING_POINT | SERVER_CTX_EXEC_SPACE; default: - return 0; + return SERVER_CTX_EXEC_SPACE; } }
@@ -242,6 +243,21 @@ static void xstate_to_server( context_t *to, const CONTEXT_EX *xctx ) }
+/*********************************************************************** + * exception_request_flags_to_server + * + * Copy exception reporting flags to the server format. + */ +static void exception_request_flags_to_server( context_t *to, DWORD context_flags ) +{ + if (!(context_flags & CONTEXT_EXCEPTION_REPORTING)) return; + to->flags |= SERVER_CTX_EXEC_SPACE; + if (context_flags & CONTEXT_SERVICE_ACTIVE) to->exec_space.space.space = EXEC_SPACE_SYSCALL; + else if (context_flags & CONTEXT_EXCEPTION_ACTIVE) to->exec_space.space.space = EXEC_SPACE_EXCEPTION; + else to->exec_space.space.space = EXEC_SPACE_USERMODE; +} + + /*********************************************************************** * context_to_server * @@ -319,6 +335,7 @@ static NTSTATUS context_to_server( context_t *to, USHORT to_machine, const void } if (flags & CONTEXT_I386_XSTATE) xstate_to_server( to, (const CONTEXT_EX *)(from + 1) ); + exception_request_flags_to_server( to, flags ); return STATUS_SUCCESS; }
@@ -377,6 +394,7 @@ static NTSTATUS context_to_server( context_t *to, USHORT to_machine, const void } if (flags & CONTEXT_I386_XSTATE) xstate_to_server( to, (const CONTEXT_EX *)(from + 1) ); + exception_request_flags_to_server( to, flags ); return STATUS_SUCCESS; }
@@ -438,6 +456,7 @@ static NTSTATUS context_to_server( context_t *to, USHORT to_machine, const void } if (flags & CONTEXT_AMD64_XSTATE) xstate_to_server( to, (const CONTEXT_EX *)(from + 1) ); + exception_request_flags_to_server( to, flags ); return STATUS_SUCCESS; }
@@ -503,6 +522,7 @@ static NTSTATUS context_to_server( context_t *to, USHORT to_machine, const void } if (flags & CONTEXT_AMD64_XSTATE) xstate_to_server( to, (const CONTEXT_EX *)(from + 1) ); + exception_request_flags_to_server( to, flags ); return STATUS_SUCCESS; }
@@ -550,6 +570,7 @@ static NTSTATUS context_to_server( context_t *to, USHORT to_machine, const void for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wvr[i] = from->Wvr[i]; for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wcr[i] = from->Wcr[i]; } + exception_request_flags_to_server( to, flags ); return STATUS_SUCCESS; }
@@ -591,6 +612,7 @@ static NTSTATUS context_to_server( context_t *to, USHORT to_machine, const void for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wcr[i] = from->Wcr[i]; for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wvr[i] = from->Wvr[i]; } + exception_request_flags_to_server( to, flags ); return STATUS_SUCCESS; }
@@ -632,6 +654,20 @@ static void xstate_from_server( CONTEXT_EX *xctx, const context_t *from ) }
+/*********************************************************************** + * exception_request_flags_from_server + * + * Copy exception reporting flags from the server format. + */ +static void exception_request_flags_from_server( DWORD *context_flags, const context_t *from ) +{ + if (!(*context_flags & CONTEXT_EXCEPTION_REQUEST) || !(from->flags & SERVER_CTX_EXEC_SPACE)) return; + *context_flags = (*context_flags & ~(CONTEXT_SERVICE_ACTIVE | CONTEXT_EXCEPTION_ACTIVE)) | CONTEXT_EXCEPTION_REPORTING; + if (from->exec_space.space.space == EXEC_SPACE_SYSCALL) *context_flags |= CONTEXT_SERVICE_ACTIVE; + else if (from->exec_space.space.space == EXEC_SPACE_EXCEPTION) *context_flags |= CONTEXT_EXCEPTION_ACTIVE; +} + + /*********************************************************************** * context_from_server * @@ -706,6 +742,7 @@ static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT ma } if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_I386_XSTATE)) xstate_from_server( (CONTEXT_EX *)(to + 1), from ); + exception_request_flags_from_server( &to->ContextFlags, from ); return STATUS_SUCCESS; }
@@ -767,6 +804,7 @@ static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT ma } if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_I386_XSTATE)) xstate_from_server( (CONTEXT_EX *)(to + 1), from ); + exception_request_flags_from_server( &to->ContextFlags, from ); return STATUS_SUCCESS; }
@@ -829,6 +867,7 @@ static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT ma } if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_AMD64_XSTATE)) xstate_from_server( (CONTEXT_EX *)(to + 1), from ); + exception_request_flags_from_server( &to->ContextFlags, from ); return STATUS_SUCCESS; }
@@ -898,6 +937,7 @@ static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT ma } if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_AMD64_XSTATE)) xstate_from_server( (CONTEXT_EX *)(to + 1), from ); + exception_request_flags_from_server( &to->ContextFlags, from ); return STATUS_SUCCESS; }
@@ -945,6 +985,7 @@ static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT ma for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm_regs.wvr[i]; for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm_regs.wcr[i]; } + exception_request_flags_from_server( &to->ContextFlags, from ); return STATUS_SUCCESS; }
@@ -986,6 +1027,7 @@ static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT ma for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm64_regs.wcr[i]; for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm64_regs.wvr[i]; } + exception_request_flags_from_server( &to->ContextFlags, from ); return STATUS_SUCCESS; }
diff --git a/server/protocol.def b/server/protocol.def index 55dda2d7636..69b8db3ebef 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -126,6 +126,14 @@ typedef union } unload_dll; } debug_event_t;
+ +enum context_exec_space +{ + EXEC_SPACE_USERMODE, + EXEC_SPACE_SYSCALL, + EXEC_SPACE_EXCEPTION, +}; + /* context data */ typedef struct { @@ -172,6 +180,10 @@ typedef struct unsigned char i386_regs[512]; } ext; /* selected by SERVER_CTX_EXTENDED_REGISTERS */ union + { + struct { enum context_exec_space space; int __pad; } space; + } exec_space; /* selected by SERVER_CTX_EXEC_SPACE */ + union { struct { struct { unsigned __int64 low, high; } ymm_high[16]; } regs; } ymm; /* selected by SERVER_CTX_YMM_REGISTERS */ @@ -184,6 +196,7 @@ typedef struct #define SERVER_CTX_DEBUG_REGISTERS 0x10 #define SERVER_CTX_EXTENDED_REGISTERS 0x20 #define SERVER_CTX_YMM_REGISTERS 0x40 +#define SERVER_CTX_EXEC_SPACE 0x80
/* structure used in sending an fd from client to server */ struct send_fd diff --git a/server/thread.c b/server/thread.c index 56f57cefd8f..55bd63d3030 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1303,6 +1303,7 @@ static void copy_context( context_t *to, const context_t *from, unsigned int fla if (flags & SERVER_CTX_DEBUG_REGISTERS) to->debug = from->debug; if (flags & SERVER_CTX_EXTENDED_REGISTERS) to->ext = from->ext; if (flags & SERVER_CTX_YMM_REGISTERS) to->ymm = from->ymm; + if (flags & SERVER_CTX_EXEC_SPACE) to->exec_space = from->exec_space; }
/* gets the current impersonation token */ @@ -1941,14 +1942,14 @@ DECL_HANDLER(set_thread_context) /* If context is in a pending state, we don't know if we will use WoW or native * context, so store both and discard irrevelant one in select request. */ const int is_pending = thread->context->status == STATUS_PENDING; - unsigned int native_flags = contexts[CTX_NATIVE].flags; + unsigned int native_flags = contexts[CTX_NATIVE].flags & ~SERVER_CTX_EXEC_SPACE;
if (ctx_count == 2 && (is_pending || thread->context->regs[CTX_WOW].machine)) { context_t *ctx = &thread->context->regs[CTX_WOW];
/* some regs are always set from the native context */ - flags = contexts[CTX_WOW].flags & ~req->native_flags; + flags = contexts[CTX_WOW].flags & ~(req->native_flags | SERVER_CTX_EXEC_SPACE); if (is_pending) ctx->machine = contexts[CTX_WOW].machine; else native_flags &= req->native_flags;
diff --git a/server/trace.c b/server/trace.c index efb4bb03c4a..b254a96f7a4 100644 --- a/server/trace.c +++ b/server/trace.c @@ -822,6 +822,19 @@ static void dump_varargs_context( const char *prefix, data_size_t size ) fprintf( stderr, "%s{machine=%04x", prefix, ctx.machine ); break; } + if (ctx.flags & SERVER_CTX_EXEC_SPACE) + { + const char *space; + + switch (ctx.exec_space.space.space) + { + case EXEC_SPACE_USERMODE: space = "user"; break; + case EXEC_SPACE_SYSCALL: space = "syscall"; break; + case EXEC_SPACE_EXCEPTION: space = "exception"; break; + default: space = "invalid"; break; + } + fprintf( stderr, ",exec_space=%s", space ); + } fputc( '}', stderr ); remove_data( size ); } diff --git a/tools/make_requests b/tools/make_requests index e3eaaf45b6f..419b1264ea4 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -54,7 +54,7 @@ my %formats = "hw_input_t" => [ 40, 8, "&dump_hw_input" ], # varargs-only structures "apc_call_t" => [ 64, 8 ], - "context_t" => [ 1720, 8 ], + "context_t" => [ 1728, 8 ], "cursor_pos_t" => [ 24, 8 ], "debug_event_t" => [ 160, 8 ], "message_data_t" => [ 48, 8 ],
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/exception.c | 10 +++++----- dlls/ntdll/unix/signal_arm.c | 9 +++++++-- dlls/ntdll/unix/signal_arm64.c | 9 +++++++-- dlls/ntdll/unix/signal_i386.c | 9 +++++++-- dlls/ntdll/unix/signal_x86_64.c | 6 ++++-- 5 files changed, 30 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index e4cd8f8f8b5..8d966e8a1cc 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -4445,7 +4445,7 @@ static void test_wow64_context(void) { trace( "in 64-bit mode %04x\n", context.SegCs ); if (ctx.ContextFlags & CONTEXT_EXCEPTION_REPORTING) - todo_wine ok( ctx.ContextFlags == (WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST + ok( ctx.ContextFlags == (WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_SERVICE_ACTIVE) || ctx.ContextFlags == (WOW64_CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING | CONTEXT_EXCEPTION_ACTIVE), @@ -11132,8 +11132,8 @@ static void test_context_exception_request(void) c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; ret = GetThreadContext( thread, &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags || broken( c.ContextFlags == (CONTEXT_CONTROL - | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING)) /* Win7 64 */, "got %#lx.\n", c.ContextFlags ); + ok( c.ContextFlags == expected_flags || broken( c.ContextFlags == (CONTEXT_CONTROL + | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING)) /* Win7 64 */, "got %#lx.\n", c.ContextFlags );
p.sync = 0; ResumeThread(thread); @@ -11175,7 +11175,7 @@ static void test_context_exception_request(void) c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; ret = GetThreadContext( thread, &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags );
c.ContextFlags = CONTEXT_CONTROL; ret = SetThreadContext( thread, &c ); @@ -11185,7 +11185,7 @@ static void test_context_exception_request(void) | CONTEXT_EXCEPTION_ACTIVE; ret = GetThreadContext( thread, &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags ); + ok( c.ContextFlags == expected_flags, "got %#lx.\n", c.ContextFlags );
SetEvent( p.event );
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index 44e79d0abdf..9c67309a4c7 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -1021,7 +1021,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
if (is_inside_syscall( sigcontext )) { - context.ContextFlags = CONTEXT_FULL; + context.ContextFlags = CONTEXT_FULL | CONTEXT_EXCEPTION_REQUEST; NtGetContextThread( GetCurrentThread(), &context ); wait_suspend( &context ); NtSetContextThread( GetCurrentThread(), &context ); @@ -1029,6 +1029,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) else { save_context( &context, sigcontext ); + context.ContextFlags |= CONTEXT_EXCEPTION_REPORTING; wait_suspend( &context ); restore_context( &context, sigcontext ); } @@ -1135,7 +1136,11 @@ void call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB if (context.Pc & 1) context.Cpsr |= 0x20; /* thumb mode */ if ((ctx = get_cpu_area( IMAGE_FILE_MACHINE_ARMNT ))) *ctx = context;
- if (suspend) wait_suspend( &context ); + if (suspend) + { + context.ContextFlags |= CONTEXT_EXCEPTION_REPORTING | CONTEXT_EXCEPTION_ACTIVE; + wait_suspend( &context ); + }
ctx = (CONTEXT *)((ULONG_PTR)context.Sp & ~15) - 1; *ctx = context; diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 11340d88672..afb5964758e 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -1225,7 +1225,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
if (is_inside_syscall( sigcontext )) { - context.ContextFlags = CONTEXT_FULL; + context.ContextFlags = CONTEXT_FULL | CONTEXT_EXCEPTION_REQUEST; NtGetContextThread( GetCurrentThread(), &context ); wait_suspend( &context ); NtSetContextThread( GetCurrentThread(), &context ); @@ -1233,6 +1233,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) else { save_context( &context, sigcontext ); + context.ContextFlags |= CONTEXT_EXCEPTION_REPORTING; wait_suspend( &context ); restore_context( &context, sigcontext ); } @@ -1418,7 +1419,11 @@ void call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB if (arm_context->Pc & 1) arm_context->Cpsr |= 0x20; /* thumb mode */ }
- if (suspend) wait_suspend( &context ); + if (suspend) + { + context.ContextFlags |= CONTEXT_EXCEPTION_REPORTING | CONTEXT_EXCEPTION_ACTIVE; + wait_suspend( &context ); + }
ctx = (CONTEXT *)((ULONG_PTR)context.Sp & ~15) - 1; *ctx = context; diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 6e2752745d3..9588d480a42 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2130,7 +2130,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) ERR_(seh)( "kernel stack overflow.\n" ); return; } - context->c.ContextFlags = CONTEXT_FULL; + context->c.ContextFlags = CONTEXT_FULL | CONTEXT_EXCEPTION_REQUEST; NtGetContextThread( GetCurrentThread(), &context->c ); if (xstate_extended_features()) { @@ -2153,6 +2153,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) struct xcontext context;
save_context( &context, ucontext ); + context.c.ContextFlags |= CONTEXT_EXCEPTION_REPORTING; wait_suspend( &context.c ); restore_context( &context, ucontext ); } @@ -2514,7 +2515,11 @@ void call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB ((XSAVE_FORMAT *)context.ExtendedRegisters)->MxCsr = 0x1f80; if ((ctx = get_cpu_area( IMAGE_FILE_MACHINE_I386 ))) *ctx = context;
- if (suspend) wait_suspend( &context ); + if (suspend) + { + context.ContextFlags |= CONTEXT_EXCEPTION_REPORTING | CONTEXT_EXCEPTION_ACTIVE; + wait_suspend( &context ); + }
ctx = (CONTEXT *)((ULONG_PTR)context.Esp & ~3) - 1; *ctx = context; diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 41e5f9531d5..d439848a113 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2172,7 +2172,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) ERR_(seh)( "kernel stack overflow.\n" ); return; } - context->c.ContextFlags = CONTEXT_FULL | CONTEXT_SEGMENTS; + context->c.ContextFlags = CONTEXT_FULL | CONTEXT_SEGMENTS | CONTEXT_EXCEPTION_REQUEST; NtGetContextThread( GetCurrentThread(), &context->c ); if (xstate_extended_features()) { @@ -2195,6 +2195,8 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) struct xcontext context;
save_context( &context, ucontext ); + context.c.ContextFlags |= CONTEXT_EXCEPTION_REPORTING; + if (is_wow64() && context.c.SegCs == cs64_sel) context.c.ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; wait_suspend( &context.c ); restore_context( &context, ucontext ); } @@ -2536,7 +2538,7 @@ void call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB # error Please define setting %gs for your architecture #endif
- context.ContextFlags = CONTEXT_ALL; + context.ContextFlags = CONTEXT_ALL | CONTEXT_EXCEPTION_REPORTING | CONTEXT_EXCEPTION_ACTIVE; context.Rcx = (ULONG_PTR)entry; context.Rdx = (ULONG_PTR)arg; context.Rsp = (ULONG_PTR)teb->Tib.StackBase - 0x28;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/exception.c | 6 +++--- dlls/ntdll/unix/signal_arm.c | 2 +- dlls/ntdll/unix/signal_arm64.c | 2 +- dlls/ntdll/unix/signal_i386.c | 2 +- dlls/ntdll/unix/signal_x86_64.c | 2 +- dlls/ntdll/unix/thread.c | 6 ++++-- dlls/ntdll/unix/unix_private.h | 2 +- 7 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 8d966e8a1cc..8ca83d1611d 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -240,7 +240,7 @@ static void check_context_exception_request_( DWORD flags, BOOL hardware_excepti
if (!(flags & CONTEXT_EXCEPTION_REPORTING)) return; expected_flags |= hardware_exception ? CONTEXT_EXCEPTION_ACTIVE : CONTEXT_SERVICE_ACTIVE; - todo_wine ok_(__FILE__, line)( (flags & exception_reporting_flags) == expected_flags, "got %#lx, expected %#lx.\n", + ok_(__FILE__, line)( (flags & exception_reporting_flags) == expected_flags, "got %#lx, expected %#lx.\n", flags, expected_flags ); } #endif @@ -11200,7 +11200,7 @@ static void test_context_exception_request(void) c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; ret = GetThreadContext( thread, &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags, "got %#lx, expected %#lx.\n", c.ContextFlags, expected_flags ); + ok( c.ContextFlags == expected_flags, "got %#lx, expected %#lx.\n", c.ContextFlags, expected_flags );
WriteRelease( &p.sync, 4 ); } @@ -11234,7 +11234,7 @@ static void test_context_exception_request(void) c.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; ret = GetThreadContext( thread, &c ); ok( ret, "got error %lu.\n", GetLastError() ); - todo_wine ok( c.ContextFlags == expected_flags, "got %#lx, expected %#lx.\n", c.ContextFlags, expected_flags ); + ok( c.ContextFlags == expected_flags, "got %#lx, expected %#lx.\n", c.ContextFlags, expected_flags );
WriteRelease( &p.sync, 8 ); } diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index 9c67309a4c7..1a49fc8f957 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -545,7 +545,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec void *stack_ptr = (void *)(SP_sig(sigcontext) & ~7); NTSTATUS status;
- status = send_debug_event( rec, context, TRUE ); + status = send_debug_event( rec, context, TRUE, TRUE ); if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) { restore_context( context, sigcontext ); diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index afb5964758e..58911d9b1f2 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -699,7 +699,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec void *stack_ptr = (void *)(SP_sig(sigcontext) & ~15); NTSTATUS status;
- status = send_debug_event( rec, context, TRUE ); + status = send_debug_event( rec, context, TRUE, TRUE ); if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) { restore_context( context, sigcontext ); diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 9588d480a42..6457f0221bd 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1450,7 +1450,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, void *stack_ptr, struct exc_stack_layout *stack; size_t stack_size; unsigned int xstate_size; - NTSTATUS status = send_debug_event( rec, context, TRUE ); + NTSTATUS status = send_debug_event( rec, context, TRUE, TRUE );
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) { diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index d439848a113..a163d5d0b33 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1426,7 +1426,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec context->EFlags &= ~0x100; /* clear single-step flag */ }
- status = send_debug_event( rec, context, TRUE ); + status = send_debug_event( rec, context, TRUE, TRUE ); if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) { restore_context( xcontext, sigcontext ); diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 21b581ddc7c..6922ad2cba6 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1506,7 +1506,7 @@ void wait_suspend( CONTEXT *context ) * * Send an EXCEPTION_DEBUG_EVENT event to the debugger. */ -NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ) +NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance, BOOL exception ) { unsigned int ret; DWORD i; @@ -1543,6 +1543,8 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c select_op.wait.handles[0] = handle;
contexts_to_server( server_contexts, context ); + server_contexts[0].flags |= SERVER_CTX_EXEC_SPACE; + server_contexts[0].exec_space.space.space = exception ? EXEC_SPACE_EXCEPTION : EXEC_SPACE_SYSCALL; server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, TIMEOUT_INFINITE, server_contexts, NULL );
@@ -1565,7 +1567,7 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c */ NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ) { - NTSTATUS status = send_debug_event( rec, context, first_chance ); + NTSTATUS status = send_debug_event( rec, context, first_chance, !(is_win64 || is_wow64() || is_old_wow64()) );
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) return NtContinue( context, FALSE ); diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index ec11f9d4795..b278ab8df84 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -244,7 +244,7 @@ extern void DECLSPEC_NORETURN abort_thread( int status ); extern void DECLSPEC_NORETURN abort_process( int status ); extern void DECLSPEC_NORETURN exit_process( int status ); extern void wait_suspend( CONTEXT *context ); -extern NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ); +extern NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance, BOOL exception ); extern NTSTATUS set_thread_context( HANDLE handle, const void *context, BOOL *self, USHORT machine ); extern NTSTATUS get_thread_context( HANDLE handle, void *context, BOOL *self, USHORT machine ); extern unsigned int alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret,
On Mon Apr 15 08:25:13 2024 +0000, Alexandre Julliard wrote:
What failure do you see that requires disabling tests?
``` 0090:err:winediag:is_broken_driver Broken NVIDIA RandR detected, falling back to RandR 1.0. Please consider using the Nouveau driver instead. 0024:err:environ:init_peb starting L"Z:\home\qqq\build32\dlls\ntdll\tests\i386-windows\ntdll_test.exe" in experimental wow64 mode exception.c:589: exception: c0000027 flags:2 addr:00FE0022 context: Eip:fe0022 exception.c:1588: DEP hardware support: Yes exception.c:670: exception 0: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 1: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 2: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 3: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 4: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 5: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 6: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 7: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 8: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 9: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 10: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 11: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 12: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 13: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 14: c0000005 flags:0 addr:00FE0000 exception.c:670: exception 15: c0000005 flags:0 addr:00FE0006 exception.c:670: exception 16: c0000005 flags:0 addr:00FE0005 exception.c:670: exception 17: c0000005 flags:0 addr:00FE0005 0024:err:virtual:virtual_setup_exception stack overflow 832 bytes addr 0x6fffffc9aa07 stack 0x7ffffe100cc0 (0x7ffffe100000-0x7ffffe101000-0x7ffffe1ffd20) ```
That is about setting %gs to 0 which results in nested access violations on the way to delivering wow64 exceptions and in the end stack overflow.
I erroneously disabled the previous test additionally, resending without that.
On Mon Apr 15 16:48:04 2024 +0000, Paul Gofman wrote:
0090:err:winediag:is_broken_driver Broken NVIDIA RandR detected, falling back to RandR 1.0. Please consider using the Nouveau driver instead. 0024:err:environ:init_peb starting L"Z:\\home\\qqq\\build32\\dlls\\ntdll\\tests\\i386-windows\\ntdll_test.exe" in experimental wow64 mode exception.c:589: exception: c0000027 flags:2 addr:00FE0022 context: Eip:fe0022 exception.c:1588: DEP hardware support: Yes exception.c:670: exception 0: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 1: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 2: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 3: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 4: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 5: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 6: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 7: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 8: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 9: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 10: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 11: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 12: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 13: c0000096 flags:0 addr:00FE0000 exception.c:670: exception 14: c0000005 flags:0 addr:00FE0000 exception.c:670: exception 15: c0000005 flags:0 addr:00FE0006 exception.c:670: exception 16: c0000005 flags:0 addr:00FE0005 exception.c:670: exception 17: c0000005 flags:0 addr:00FE0005 0024:err:virtual:virtual_setup_exception stack overflow 832 bytes addr 0x6fffffc9aa07 stack 0x7ffffe100cc0 (0x7ffffe100000-0x7ffffe101000-0x7ffffe1ffd20)
That is about setting %gs to 0 which results in nested access violations on the way to delivering wow64 exceptions and in the end stack overflow. I erroneously disabled the previous test additionally, resending without that.
I don't see that here:
``` 0024:err:environ:init_peb starting L"Z:\home\julliard\wine\wine\dlls\ntdll\tests\i386-windows\ntdll_test.exe" in experimental wow64 mode exception.c:585: exception: c0000027 flags:2 addr:00FD0022 context: Eip:fd0022 exception.c:1579: DEP hardware support: Yes exception.c:666: exception 0: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 1: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 2: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 3: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 4: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 5: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 6: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 7: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 8: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 9: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 10: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 11: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 12: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 13: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 14: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 15: c0000005 flags:0 addr:00FD0006 exception.c:666: exception 16: c0000005 flags:0 addr:00FD0005 exception.c:666: exception 17: c0000005 flags:0 addr:00FD0005 exception.c:666: exception 18: c0000005 flags:0 addr:00FD0006 exception.c:666: exception 19: c0000005 flags:0 addr:00FD0001 exception.c:666: exception 20: c000001d flags:0 addr:00FD0000 exception.c:666: exception 21: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 22: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 23: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 24: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 25: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 26: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 27: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 28: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 29: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 30: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 31: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 32: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 33: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 34: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 35: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 36: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 37: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 38: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 39: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 40: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 41: c0000096 flags:0 addr:00FD0008 exception.c:666: Line has been silenced after 42 occurrences ... ```
On Mon Apr 15 17:04:44 2024 +0000, Alexandre Julliard wrote:
I don't see that here:
0024:err:environ:init_peb starting L"Z:\\home\\julliard\\wine\\wine\\dlls\\ntdll\\tests\\i386-windows\\ntdll_test.exe" in experimental wow64 mode exception.c:585: exception: c0000027 flags:2 addr:00FD0022 context: Eip:fd0022 exception.c:1579: DEP hardware support: Yes exception.c:666: exception 0: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 1: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 2: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 3: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 4: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 5: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 6: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 7: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 8: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 9: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 10: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 11: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 12: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 13: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 14: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 15: c0000005 flags:0 addr:00FD0006 exception.c:666: exception 16: c0000005 flags:0 addr:00FD0005 exception.c:666: exception 17: c0000005 flags:0 addr:00FD0005 exception.c:666: exception 18: c0000005 flags:0 addr:00FD0006 exception.c:666: exception 19: c0000005 flags:0 addr:00FD0001 exception.c:666: exception 20: c000001d flags:0 addr:00FD0000 exception.c:666: exception 21: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 22: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 23: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 24: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 25: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 26: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 27: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 28: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 29: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 30: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 31: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 32: c0000096 flags:0 addr:00FD0000 exception.c:666: exception 33: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 34: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 35: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 36: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 37: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 38: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 39: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 40: c0000005 flags:0 addr:00FD0000 exception.c:666: exception 41: c0000096 flags:0 addr:00FD0008 exception.c:666: Line has been silenced after 42 occurrences ...
Weird, it's been here for a long time. I will debug in more details.
On Mon Apr 15 17:20:35 2024 +0000, Paul Gofman wrote:
Weird, it's been here for a long time. I will debug in more details.
Does the patchset look OK otherwise so I would resend without this patch for now?
On Mon Apr 15 17:21:51 2024 +0000, Paul Gofman wrote:
Does the patchset look OK otherwise so I would resend without this patch for now?
Sure.