Win10 introduced the ability for OutputDebugStringW to send Unicode strings (instead of translating the Unicode string to ANSI and call OutputDebugStringA).
This series: - add a couple of tests for covering various aspects + how exception with unicode string is constructed, + interaction with WaitForDebugEvent and WaitForDebugEventEx - implements WaitForDebugEventEx() - emit unicode string from OutputDebugStringW - introduce manifest constants to describe stages in exception testing (this let adding new stages way easier). Note this has not been tested on ARM.
The tests results are not fully green because of existing issues in ntdll:exception (see https://bugs.winehq.org/show_bug.cgi?id=55111 for win8 and early win10, and all the failing ones in Win11...).
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/ntdll/tests/exception.c | 155 +++++++++++++++++++++++++++++++---- 1 file changed, 138 insertions(+), 17 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 4560de0001b..41e1210a26c 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -76,6 +76,7 @@ static BOOL (WINAPI *pInitializeContext2)(void *buffer, DWORD context_flags static void * (WINAPI *pLocateXStateFeature)(CONTEXT *context, DWORD feature_id, DWORD *length); static BOOL (WINAPI *pSetXStateFeaturesMask)(CONTEXT *context, DWORD64 feature_mask); static BOOL (WINAPI *pGetXStateFeaturesMask)(CONTEXT *context, DWORD64 *feature_mask); +static BOOL (WINAPI *pWaitForDebugEventEx)(DEBUG_EVENT *, DWORD);
#define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
@@ -8564,25 +8565,43 @@ static void test_debug_service(DWORD numexc) } #endif /* defined(__i386__) || defined(__x86_64__) */
-static DWORD outputdebugstring_exceptions; +static DWORD outputdebugstring_exceptions_ansi; +static DWORD outputdebugstring_exceptions_unicode;
static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) { PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord; trace("vect. handler %08lx addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress);
- ok(rec->ExceptionCode == DBG_PRINTEXCEPTION_C, "ExceptionCode is %08lx instead of %08lx\n", - rec->ExceptionCode, DBG_PRINTEXCEPTION_C); - ok(rec->NumberParameters == 2, "ExceptionParameters is %ld instead of 2\n", rec->NumberParameters); - ok(rec->ExceptionInformation[0] == 12, "ExceptionInformation[0] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[0]); - ok(!strcmp((char *)rec->ExceptionInformation[1], "Hello World"), - "ExceptionInformation[1] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[1]); + switch (rec->ExceptionCode) + { + case DBG_PRINTEXCEPTION_C: + ok(rec->NumberParameters == 2, "ExceptionParameters is %ld instead of 2\n", rec->NumberParameters); + ok(rec->ExceptionInformation[0] == 12, "ExceptionInformation[0] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[0]); + ok(!strcmp((char *)rec->ExceptionInformation[1], "Hello World"), + "ExceptionInformation[1] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[1]); + outputdebugstring_exceptions_ansi++; + break; + case DBG_PRINTEXCEPTION_WIDE_C: + ok(outputdebugstring_exceptions_ansi == 0, "Unicode exception should come first\n"); + ok(rec->NumberParameters == 4, "ExceptionParameters is %ld instead of 4\n", rec->NumberParameters); + ok(rec->ExceptionInformation[0] == 12, "ExceptionInformation[0] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[0]); + ok(!wcscmp((WCHAR *)rec->ExceptionInformation[1], L"Hello World"), + "ExceptionInformation[1] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[1]); + ok(rec->ExceptionInformation[2] == 12, "ExceptionInformation[2] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[2]); + ok(!strcmp((char *)rec->ExceptionInformation[3], "Hello World"), + "ExceptionInformation[3] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[3]); + outputdebugstring_exceptions_unicode++; + break; + default: + ok(0, "ExceptionCode is %08lx unexpected\n", rec->ExceptionCode); + break; + }
- outputdebugstring_exceptions++; return EXCEPTION_CONTINUE_SEARCH; }
-static void test_outputdebugstring(DWORD numexc, BOOL todo) +static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_ansi, DWORD numexc_unicode) { PVOID vectored_handler;
@@ -8595,12 +8614,111 @@ static void test_outputdebugstring(DWORD numexc, BOOL todo) vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &outputdebugstring_vectored_handler); ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
- outputdebugstring_exceptions = 0; - OutputDebugStringA("Hello World"); + outputdebugstring_exceptions_ansi = outputdebugstring_exceptions_unicode = 0; + + if (unicode) + OutputDebugStringW(L"Hello World"); + else + OutputDebugStringA("Hello World"); + + todo_wine_if(todo_ansi) + ok(outputdebugstring_exceptions_ansi == numexc_ansi, + "OutputDebugString%c generated %ld ansi exceptions, expected %ld\n", + unicode ? 'W' : 'A', outputdebugstring_exceptions_ansi, numexc_ansi); + todo_wine_if(unicode) + ok(outputdebugstring_exceptions_unicode == numexc_unicode, + "OutputDebugString%c generated %lu unicode exceptions, expected %ld\n", + unicode ? 'W' : 'A', outputdebugstring_exceptions_unicode, numexc_unicode); + + pRtlRemoveVectoredExceptionHandler(vectored_handler); +} + +static DWORD outputdebugstring_exceptions_newmodel_order; +static DWORD outputdebugstring_newmodel_return; + +static LONG CALLBACK outputdebugstring_new_model_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) +{ + PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord; + trace("vect. handler %08lx addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress); + + switch (rec->ExceptionCode) + { + case DBG_PRINTEXCEPTION_C: + ok(rec->NumberParameters == 2, "ExceptionParameters is %ld instead of 2\n", rec->NumberParameters); + ok(rec->ExceptionInformation[0] == 12, "ExceptionInformation[0] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[0]); + ok(!strcmp((char *)rec->ExceptionInformation[1], "Hello World"), + "ExceptionInformation[1] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[1]); + outputdebugstring_exceptions_newmodel_order = + (outputdebugstring_exceptions_newmodel_order << 8) | 'A'; + break; + case DBG_PRINTEXCEPTION_WIDE_C: + ok(rec->NumberParameters == 4, "ExceptionParameters is %ld instead of 4\n", rec->NumberParameters); + ok(rec->ExceptionInformation[0] == 12, "ExceptionInformation[0] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[0]); + ok(!wcscmp((WCHAR *)rec->ExceptionInformation[1], L"Hello World"), + "ExceptionInformation[1] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[1]); + ok(rec->ExceptionInformation[2] == 12, "ExceptionInformation[2] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[2]); + ok(!strcmp((char *)rec->ExceptionInformation[3], "Hello World"), + "ExceptionInformation[3] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[3]); + outputdebugstring_exceptions_newmodel_order = + (outputdebugstring_exceptions_newmodel_order << 8) | 'W'; + break; + default: + ok(0, "ExceptionCode is %08lx unexpected\n", rec->ExceptionCode); + break; + } + + return outputdebugstring_newmodel_return; +} + +static void test_outputdebugstring_newmodel(void) +{ + PVOID vectored_handler; + struct + { + /* input */ + BOOL unicode; + DWORD ret_code; + /* expected output */ + DWORD exceptions_order; + } + tests[] = + { + {FALSE, EXCEPTION_CONTINUE_EXECUTION, 'A'}, + {FALSE, EXCEPTION_CONTINUE_SEARCH, 'A'}, + {TRUE, EXCEPTION_CONTINUE_EXECUTION, 'W'}, + {TRUE, EXCEPTION_CONTINUE_SEARCH, ('W' << 8) | 'A'}, + }; + int i; + + if (!pWaitForDebugEventEx) + { + skip("Unsupported new unicode debug string model\n"); + return; + } + if (!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler) + { + skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n"); + return; + } + + vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &outputdebugstring_new_model_vectored_handler); + ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n"); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + outputdebugstring_exceptions_newmodel_order = 0; + outputdebugstring_newmodel_return = tests[i].ret_code;
- todo_wine_if(todo) - ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %ld exceptions, expected %ld\n", - outputdebugstring_exceptions, numexc); + if (tests[i].unicode) + OutputDebugStringW(L"Hello World"); + else + OutputDebugStringA("Hello World"); + + ok(outputdebugstring_exceptions_newmodel_order == tests[i].exceptions_order, + "OutputDebugString%c/%u generated exceptions %04lxs, expected %04lx\n", + tests[i].unicode ? 'W' : 'A', i, + outputdebugstring_exceptions_newmodel_order, tests[i].exceptions_order); + }
pRtlRemoveVectoredExceptionHandler(vectored_handler); } @@ -11044,6 +11162,7 @@ START_TEST(exception) X(LocateXStateFeature); X(SetXStateFeaturesMask); X(GetXStateFeaturesMask); + X(WaitForDebugEventEx); #undef X
if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler) @@ -11092,9 +11211,9 @@ START_TEST(exception) else skip( "RtlRaiseException not found\n" ); #endif test_stage = 3; - test_outputdebugstring(0, FALSE); + test_outputdebugstring(FALSE, 0, FALSE, 0); test_stage = 4; - test_outputdebugstring(2, TRUE); /* is this a Windows bug? */ + test_outputdebugstring(FALSE, 2, TRUE, 0); /* is 2 a Windows bug? */ test_stage = 5; test_ripevent(0); test_stage = 6; @@ -11209,7 +11328,9 @@ START_TEST(exception) test_debugger(DBG_EXCEPTION_HANDLED); test_debugger(DBG_CONTINUE); test_thread_context(); - test_outputdebugstring(1, FALSE); + test_outputdebugstring(FALSE, 1, FALSE, 0); + test_outputdebugstring(TRUE, 1, FALSE, 1); + test_outputdebugstring_newmodel(); test_ripevent(1); test_fastfail(); test_breakpoint(1);
From: Eric Pouech epouech@codeweavers.com
It'll be easier to add stages.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/ntdll/tests/exception.c | 211 +++++++++++++++++++---------------- 1 file changed, 116 insertions(+), 95 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 41e1210a26c..e0c27110252 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -190,14 +190,34 @@ static VOID (WINAPI *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, static int (CDECL *p_setjmp)(_JUMP_BUFFER*); #endif
+enum debugger_stages +{ + STAGE_RTLRAISE_NOT_HANDLED = 1, + STAGE_RTLRAISE_HANDLE_LAST_CHANCE, + STAGE_OUTPUTDEBUGSTRINGA_CONTINUE, + STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED, + STAGE_RIPEVENT_CONTINUE, + STAGE_RIPEVENT_NOT_HANDLED, + STAGE_SERVICE_CONTINUE, + STAGE_SERVICE_NOT_HANDLED, + STAGE_BREAKPOINT_CONTINUE, + STAGE_BREAKPOINT_NOT_HANDLED, + STAGE_EXCEPTION_INVHANDLE_CONTINUE, + STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED, + STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED, + STAGE_XSTATE, + STAGE_XSTATE_LEGACY_SSE, + STAGE_SEGMENTS, +}; + static int my_argc; static char** my_argv; static BOOL is_wow64; static BOOL have_vectored_api; -static int test_stage; +static enum debugger_stages test_stage;
#if defined(__i386__) || defined(__x86_64__) -static void test_debugger_xstate(HANDLE thread, CONTEXT *ctx, int stage) +static void test_debugger_xstate(HANDLE thread, CONTEXT *ctx, enum debugger_stages stage) { char context_buffer[sizeof(CONTEXT) + sizeof(CONTEXT_EX) + sizeof(XSTATE) + 1024]; CONTEXT_EX *c_ex; @@ -212,7 +232,7 @@ static void test_debugger_xstate(HANDLE thread, CONTEXT *ctx, int stage) if (!pRtlGetEnabledExtendedFeatures || !pRtlGetEnabledExtendedFeatures(1 << XSTATE_AVX)) return;
- if (stage == 14) + if (stage == STAGE_XSTATE) return;
length = sizeof(context_buffer); @@ -525,7 +545,7 @@ static DWORD rtlraiseexception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR
/* give the debugger a chance to examine the state a second time */ /* without the exception handler changing Eip */ - if (test_stage == 2) + if (test_stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) return ExceptionContinueSearch;
/* Eip in context is decreased by 1 @@ -1110,7 +1130,7 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { CONTEXT ctx; - int stage; + enum debugger_stages stage;
counter++; status = pNtReadVirtualMemory(pi.hProcess, &code_mem, &code_mem_address, @@ -1146,7 +1166,7 @@ static void test_debugger(DWORD cont_status) } else { - if (stage == 1) + if (stage == STAGE_RTLRAISE_NOT_HANDLED) { ok((char *)ctx.Eip == (char *)code_mem_address + 0xb, "Eip at %lx instead of %p\n", ctx.Eip, (char *)code_mem_address + 0xb); @@ -1157,7 +1177,7 @@ static void test_debugger(DWORD cont_status) /* let the debuggee handle the exception */ continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 2) + else if (stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) { if (de.u.Exception.dwFirstChance) { @@ -1193,25 +1213,25 @@ static void test_debugger(DWORD cont_status) /* here we handle exception */ } } - else if (stage == 7 || stage == 8) + else if (stage == STAGE_SERVICE_CONTINUE || stage == STAGE_SERVICE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Eip == (char *)code_mem_address + 0x1d, "expected Eip = %p, got 0x%lx\n", (char *)code_mem_address + 0x1d, ctx.Eip);
- if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_SERVICE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 9 || stage == 10) + else if (stage == STAGE_BREAKPOINT_CONTINUE || stage == STAGE_BREAKPOINT_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Eip == (char *)code_mem_address + 2, "expected Eip = %p, got 0x%lx\n", (char *)code_mem_address + 2, ctx.Eip);
- if (stage == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_BREAKPOINT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 11 || stage == 12) + else if (stage == STAGE_EXCEPTION_INVHANDLE_CONTINUE || stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE, "unexpected exception code %08lx, expected %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode, @@ -1219,18 +1239,18 @@ static void test_debugger(DWORD cont_status) ok(de.u.Exception.ExceptionRecord.NumberParameters == 0, "unexpected number of parameters %ld, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters);
- if (stage == 12) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 13) + else if (stage == STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(FALSE || broken(TRUE) /* < Win10 */, "should not throw exception\n"); continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 14 || stage == 15) + else if (stage == STAGE_XSTATE || stage == STAGE_XSTATE_LEGACY_SSE) { test_debugger_xstate(pi.hThread, &ctx, stage); } - else if (stage == 16) + else if (stage == STAGE_SEGMENTS) { USHORT ss; __asm__( "movw %%ss,%0" : "=r" (ss) ); @@ -1258,7 +1278,7 @@ static void test_debugger(DWORD cont_status) } else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { - int stage; + enum debugger_stages stage; char buffer[64];
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, @@ -1274,22 +1294,22 @@ static void test_debugger(DWORD cont_status) de.u.DebugString.nDebugStringLength, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == 3 || stage == 4) + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer);
- if (stage == 4) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { - int stage; + enum debugger_stages stage;
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == 5 || stage == 6) + if (stage == STAGE_RIPEVENT_CONTINUE || stage == STAGE_RIPEVENT_NOT_HANDLED) { ok(de.u.RipInfo.dwError == 0x11223344, "got unexpected rip error code %08lx, expected %08x\n", de.u.RipInfo.dwError, 0x11223344); @@ -1299,7 +1319,7 @@ static void test_debugger(DWORD cont_status) else ok(FALSE, "unexpected stage %x\n", stage);
- if (stage == 6) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_RIPEVENT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; }
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus); @@ -3651,7 +3671,7 @@ static void rtlraiseexception_handler_( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR
/* give the debugger a chance to examine the state a second time */ /* without the exception handler changing pc */ - if (test_stage == 2) + if (test_stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) return;
/* pc in context is decreased by 1 @@ -3665,7 +3685,7 @@ static LONG CALLBACK rtlraiseexception_unhandled_handler(EXCEPTION_POINTERS *Exc PCONTEXT context = ExceptionInfo->ContextRecord; PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord; rtlraiseexception_handler_(rec, NULL, context, NULL, TRUE); - if (test_stage == 2) return EXCEPTION_CONTINUE_SEARCH; + if (test_stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_EXECUTION; }
@@ -3673,7 +3693,7 @@ static DWORD rtlraiseexception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) { rtlraiseexception_handler_(rec, frame, context, dispatcher, FALSE); - if (test_stage == 2) return ExceptionContinueSearch; + if (test_stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) return ExceptionContinueSearch; return ExceptionContinueExecution; }
@@ -3739,7 +3759,7 @@ static void run_rtlraiseexception_test(DWORD exceptioncode)
todo_wine ok( !rtlraiseexception_handler_called, "Frame handler called\n" ); - todo_wine_if (test_stage != 2) + todo_wine_if (test_stage != STAGE_RTLRAISE_HANDLE_LAST_CHANCE) ok( rtlraiseexception_unhandled_handler_called, "UnhandledExceptionFilter wasn't called\n" );
if (have_vectored_api) @@ -3816,7 +3836,7 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { CONTEXT ctx; - int stage; + enum debugger_stages stage;
counter++; status = pNtReadVirtualMemory(pi.hProcess, &code_mem, &code_mem_address, @@ -3853,7 +3873,7 @@ static void test_debugger(DWORD cont_status) } else { - if (stage == 1) + if (stage == STAGE_RTLRAISE_NOT_HANDLED) { ok((char *)ctx.Rip == (char *)code_mem_address + 0x10, "Rip at %p instead of %p\n", (char *)ctx.Rip, (char *)code_mem_address + 0x10); @@ -3864,7 +3884,7 @@ static void test_debugger(DWORD cont_status) /* let the debuggee handle the exception */ continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 2) + else if (stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) { if (de.u.Exception.dwFirstChance) { @@ -3892,23 +3912,23 @@ static void test_debugger(DWORD cont_status) /* here we handle exception */ } } - else if (stage == 7 || stage == 8) + else if (stage == STAGE_SERVICE_CONTINUE || stage == STAGE_SERVICE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); 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 == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_SERVICE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 9 || stage == 10) + else if (stage == STAGE_BREAKPOINT_CONTINUE || stage == STAGE_BREAKPOINT_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); 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 == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_BREAKPOINT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 11 || stage == 12) + else if (stage == STAGE_EXCEPTION_INVHANDLE_CONTINUE || stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE, "unexpected exception code %08lx, expected %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode, @@ -3916,18 +3936,18 @@ static void test_debugger(DWORD cont_status) ok(de.u.Exception.ExceptionRecord.NumberParameters == 0, "unexpected number of parameters %ld, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters);
- if (stage == 12) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 13) + else if (stage == STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(FALSE || broken(TRUE) /* < Win10 */, "should not throw exception\n"); continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 14 || stage == 15) + else if (stage == STAGE_XSTATE || stage == STAGE_XSTATE_LEGACY_SSE) { test_debugger_xstate(pi.hThread, &ctx, stage); } - else if (stage == 16) + else if (stage == STAGE_SEGMENTS) { USHORT ss; __asm__( "movw %%ss,%0" : "=r" (ss) ); @@ -3959,7 +3979,7 @@ static void test_debugger(DWORD cont_status) } else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { - int stage; + enum debugger_stages stage; char buffer[64];
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, @@ -3975,22 +3995,22 @@ static void test_debugger(DWORD cont_status) de.u.DebugString.nDebugStringLength, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == 3 || stage == 4) + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer);
- if (stage == 4) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { - int stage; + enum debugger_stages stage;
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == 5 || stage == 6) + if (stage == STAGE_RIPEVENT_CONTINUE || stage == STAGE_RIPEVENT_NOT_HANDLED) { ok(de.u.RipInfo.dwError == 0x11223344, "got unexpected rip error code %08lx, expected %08x\n", de.u.RipInfo.dwError, 0x11223344); @@ -4000,7 +4020,7 @@ static void test_debugger(DWORD cont_status) else ok(FALSE, "unexpected stage %x\n", stage);
- if (stage == 6) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_RIPEVENT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; }
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus); @@ -6634,7 +6654,7 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { CONTEXT ctx; - int stage; + enum debugger_stages stage;
counter++; status = pNtReadVirtualMemory(pi.hProcess, &code_mem, &code_mem_address, @@ -6671,7 +6691,7 @@ static void test_debugger(DWORD cont_status) } else { - if (stage == 1) + if (stage == STAGE_RTLRAISE_NOT_HANDLED) { ok((char *)ctx.Pc == (char *)code_mem_address + 0xb, "Pc at %lx instead of %p\n", ctx.Pc, (char *)code_mem_address + 0xb); @@ -6682,7 +6702,7 @@ static void test_debugger(DWORD cont_status) /* let the debuggee handle the exception */ continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 2) + else if (stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) { if (de.u.Exception.dwFirstChance) { @@ -6711,23 +6731,23 @@ static void test_debugger(DWORD cont_status) /* here we handle exception */ } } - else if (stage == 7 || stage == 8) + else if (stage == STAGE_SERVICE_CONTINUE || stage == STAGE_SERVICE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Pc == (char *)code_mem_address + 0x1d, "expected Pc = %p, got 0x%lx\n", (char *)code_mem_address + 0x1d, ctx.Pc); - if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_SERVICE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 9 || stage == 10) + else if (stage == STAGE_BREAKPOINT_CONTINUE || stage == STAGE_BREAKPOINT_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Pc == (char *)code_mem_address + 3, "expected Pc = %p, got 0x%lx\n", (char *)code_mem_address + 3, ctx.Pc); - if (stage == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_BREAKPOINT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 11 || stage == 12) + else if (stage == STAGE_EXCEPTION_INVHANDLE_CONTINUE || stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE, "unexpected exception code %08lx, expected %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode, @@ -6735,9 +6755,9 @@ static void test_debugger(DWORD cont_status) ok(de.u.Exception.ExceptionRecord.NumberParameters == 0, "unexpected number of parameters %ld, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters);
- if (stage == 12) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 13) + else if (stage == STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(FALSE || broken(TRUE) /* < Win10 */, "should not throw exception\n"); continuestatus = DBG_EXCEPTION_NOT_HANDLED; @@ -6751,7 +6771,7 @@ static void test_debugger(DWORD cont_status) } else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { - int stage; + enum debugger_stages stage; char buffer[64];
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, @@ -6767,22 +6787,22 @@ static void test_debugger(DWORD cont_status) de.u.DebugString.nDebugStringLength, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == 3 || stage == 4) + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer);
- if (stage == 4) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { - int stage; + enum debugger_stages stage;
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == 5 || stage == 6) + if (stage == STAGE_RIPEVENT_CONTINUE || stage == STAGE_RIPEVENT_NOT_HANDLED) { ok(de.u.RipInfo.dwError == 0x11223344, "got unexpected rip error code %08lx, expected %08x\n", de.u.RipInfo.dwError, 0x11223344); @@ -6792,7 +6812,7 @@ static void test_debugger(DWORD cont_status) else ok(FALSE, "unexpected stage %x\n", stage);
- if (stage == 6) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_RIPEVENT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; }
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus); @@ -7889,7 +7909,7 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { CONTEXT ctx; - int stage; + enum debugger_stages stage;
counter++; status = pNtReadVirtualMemory(pi.hProcess, &code_mem, &code_mem_address, @@ -7926,7 +7946,7 @@ static void test_debugger(DWORD cont_status) } else { - if (stage == 1) + if (stage == STAGE_RTLRAISE_NOT_HANDLED) { ok((char *)ctx.Pc == (char *)code_mem_address + 0xb, "Pc at %p instead of %p\n", (char *)ctx.Pc, (char *)code_mem_address + 0xb); @@ -7937,7 +7957,7 @@ static void test_debugger(DWORD cont_status) /* let the debuggee handle the exception */ continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 2) + else if (stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) { if (de.u.Exception.dwFirstChance) { @@ -7966,23 +7986,23 @@ static void test_debugger(DWORD cont_status) /* here we handle exception */ } } - else if (stage == 7 || stage == 8) + else if (stage == STAGE_SERVICE_CONTINUE || stage == STAGE_SERVICE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Pc == (char *)code_mem_address + 0x1d, "expected Pc = %p, got %p\n", (char *)code_mem_address + 0x1d, (char *)ctx.Pc); - if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_SERVICE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 9 || stage == 10) + else if (stage == STAGE_BREAKPOINT_CONTINUE || stage == STAGE_BREAKPOINT_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Pc == (char *)code_mem_address + 4, "expected Pc = %p, got %p\n", (char *)code_mem_address + 4, (char *)ctx.Pc); - if (stage == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_BREAKPOINT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 11 || stage == 12) + else if (stage == STAGE_EXCEPTION_INVHANDLE_CONTINUE || stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE, "unexpected exception code %08lx, expected %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode, @@ -7990,9 +8010,9 @@ static void test_debugger(DWORD cont_status) ok(de.u.Exception.ExceptionRecord.NumberParameters == 0, "unexpected number of parameters %ld, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters);
- if (stage == 12) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 13) + else if (stage == STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(FALSE || broken(TRUE) /* < Win10 */, "should not throw exception\n"); continuestatus = DBG_EXCEPTION_NOT_HANDLED; @@ -8006,7 +8026,7 @@ static void test_debugger(DWORD cont_status) } else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { - int stage; + enum debugger_stages stage; char buffer[128];
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, @@ -8022,23 +8042,23 @@ static void test_debugger(DWORD cont_status) de.u.DebugString.nDebugStringLength, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == 3 || stage == 4) + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") || !strncmp(buffer, "RTL:", 4), "unexpected stage %x, got debug string event '%s'\n", stage, buffer);
- if (stage == 4) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { - int stage; + enum debugger_stages stage;
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == 5 || stage == 6) + if (stage == STAGE_RIPEVENT_CONTINUE || stage == STAGE_RIPEVENT_NOT_HANDLED) { ok(de.u.RipInfo.dwError == 0x11223344, "got unexpected rip error code %08lx, expected %08x\n", de.u.RipInfo.dwError, 0x11223344); @@ -8048,7 +8068,7 @@ static void test_debugger(DWORD cont_status) else ok(FALSE, "unexpected stage %x\n", stage);
- if (stage == 6) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_RIPEVENT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; }
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus); @@ -8973,12 +8993,12 @@ static void test_debuggee_xstate(void) func();
for (i = 0; i < 4; ++i) - ok(data[i] == (test_stage == 14 ? i + 1 : 0x28282828), + ok(data[i] == (test_stage == STAGE_XSTATE ? i + 1 : 0x28282828), "Got unexpected data %#x, test_stage %u, i %u.\n", data[i], test_stage, i);
for ( ; i < ARRAY_SIZE(data); ++i) - ok(data[i] == (test_stage == 14 ? i + 1 : 0x48484848) - || broken(test_stage == 15 && data[i] == i + 1) /* Win7 */, + ok(data[i] == (test_stage == STAGE_XSTATE ? i + 1 : 0x48484848) + || broken(test_stage == STAGE_XSTATE_LEGACY_SSE && data[i] == i + 1) /* Win7 */, "Got unexpected data %#x, test_stage %u, i %u.\n", data[i], test_stage, i); }
@@ -11199,40 +11219,41 @@ START_TEST(exception) #if defined(__i386__) || defined(__x86_64__) if (pRtlRaiseException) { - test_stage = 1; + test_stage = STAGE_RTLRAISE_NOT_HANDLED; run_rtlraiseexception_test(0x12345); run_rtlraiseexception_test(EXCEPTION_BREAKPOINT); run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); - test_stage = 2; + test_stage = STAGE_RTLRAISE_HANDLE_LAST_CHANCE; run_rtlraiseexception_test(0x12345); run_rtlraiseexception_test(EXCEPTION_BREAKPOINT); run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); } else skip( "RtlRaiseException not found\n" ); #endif - test_stage = 3; + + test_stage = STAGE_OUTPUTDEBUGSTRINGA_CONTINUE; test_outputdebugstring(FALSE, 0, FALSE, 0); - test_stage = 4; + test_stage = STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED; test_outputdebugstring(FALSE, 2, TRUE, 0); /* is 2 a Windows bug? */ - test_stage = 5; + test_stage = STAGE_RIPEVENT_CONTINUE; test_ripevent(0); - test_stage = 6; + test_stage = STAGE_RIPEVENT_NOT_HANDLED; test_ripevent(1); - test_stage = 7; + test_stage = STAGE_SERVICE_CONTINUE; test_debug_service(0); - test_stage = 8; + test_stage = STAGE_SERVICE_NOT_HANDLED; test_debug_service(1); - test_stage = 9; + test_stage = STAGE_BREAKPOINT_CONTINUE; test_breakpoint(0); - test_stage = 10; + test_stage = STAGE_BREAKPOINT_NOT_HANDLED; test_breakpoint(1); - test_stage = 11; + test_stage = STAGE_EXCEPTION_INVHANDLE_CONTINUE; test_closehandle(0, (HANDLE)0xdeadbeef); test_closehandle(0, (HANDLE)0x7fffffff); - test_stage = 12; + test_stage = STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED; test_closehandle(1, (HANDLE)0xdeadbeef); test_closehandle(1, (HANDLE)~(ULONG_PTR)6); - test_stage = 13; /* special cases */ + test_stage = STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED; /* special cases */ test_closehandle(0, 0); test_closehandle(0, INVALID_HANDLE_VALUE); test_closehandle(0, GetCurrentProcess()); @@ -11242,11 +11263,11 @@ START_TEST(exception) test_closehandle(0, GetCurrentThreadToken()); test_closehandle(0, GetCurrentThreadEffectiveToken()); #if defined(__i386__) || defined(__x86_64__) - test_stage = 14; + test_stage = STAGE_XSTATE; test_debuggee_xstate(); - test_stage = 15; + test_stage = STAGE_XSTATE_LEGACY_SSE; test_debuggee_xstate(); - test_stage = 16; + test_stage = STAGE_SEGMENTS; test_debuggee_segments(); #endif
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/ntdll/tests/exception.c | 188 +++++++++++++++++++++++++++-------- 1 file changed, 144 insertions(+), 44 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index e0c27110252..9da6b756c31 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -196,6 +196,8 @@ enum debugger_stages STAGE_RTLRAISE_HANDLE_LAST_CHANCE, STAGE_OUTPUTDEBUGSTRINGA_CONTINUE, STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED, + STAGE_OUTPUTDEBUGSTRINGW_CONTINUE, + STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED, STAGE_RIPEVENT_CONTINUE, STAGE_RIPEVENT_NOT_HANDLED, STAGE_SERVICE_CONTINUE, @@ -1077,7 +1079,7 @@ static void test_exceptions(void) ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %lx\n", res ); }
-static void test_debugger(DWORD cont_status) +static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) { char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; @@ -1097,6 +1099,12 @@ static void test_debugger(DWORD cont_status) return; }
+ if (with_WaitForDebugEventEx && !pWaitForDebugEventEx) + { + skip("WaitForDebugEventEx not found, skipping unicode strings in OutputDebugStringW\n"); + return; + } + sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "could not create child process error: %lu\n", GetLastError()); @@ -1106,7 +1114,8 @@ static void test_debugger(DWORD cont_status) do { continuestatus = cont_status; - ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); + ret = with_WaitForDebugEventEx ? pWaitForDebugEventEx(&de, INFINITE) : WaitForDebugEvent(&de, INFINITE); + ok(ret, "reading debug event\n");
ret = ContinueDebugEvent(de.dwProcessId, de.dwThreadId, 0xdeadbeef); ok(!ret, "ContinueDebugEvent unexpectedly succeeded\n"); @@ -1279,27 +1288,43 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { enum debugger_stages stage; - char buffer[64]; + char buffer[64 * sizeof(WCHAR)]; + unsigned char_size = de.u.DebugString.fUnicode ? sizeof(WCHAR) : sizeof(char);
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- ok(!de.u.DebugString.fUnicode, "unexpected unicode debug string event\n"); - ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) - 1, "buffer not large enough to hold %d bytes\n", - de.u.DebugString.nDebugStringLength); + if (de.u.DebugString.fUnicode) + ok(with_WaitForDebugEventEx && + (stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED), + "unexpected unicode debug string event\n"); + else + ok(!with_WaitForDebugEventEx || stage != STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || cont_status != DBG_CONTINUE, + "unexpected ansi debug string event %u %s %lx\n", + stage, with_WaitForDebugEventEx ? "with" : "without", cont_status); + + ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) / char_size - 1, + "buffer not large enough to hold %d bytes\n", de.u.DebugString.nDebugStringLength);
memset(buffer, 0, sizeof(buffer)); status = pNtReadVirtualMemory(pi.hProcess, de.u.DebugString.lpDebugStringData, buffer, - de.u.DebugString.nDebugStringLength, &size_read); + de.u.DebugString.nDebugStringLength * char_size, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) - ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || + stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + { + if (de.u.DebugString.fUnicode) + ok(!wcscmp((WCHAR*)buffer, L"Hello World"), "got unexpected debug string '%ls'\n", (WCHAR*)buffer); + else + ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + } else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer);
- if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { @@ -3783,7 +3808,7 @@ static void test_rtlraiseexception(void) run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); }
-static void test_debugger(DWORD cont_status) +static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) { char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; @@ -3803,6 +3828,12 @@ static void test_debugger(DWORD cont_status) return; }
+ if (with_WaitForDebugEventEx && !pWaitForDebugEventEx) + { + skip("WaitForDebugEventEx not found, skipping unicode strings in OutputDebugStringW\n"); + return; + } + sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "could not create child process error: %lu\n", GetLastError()); @@ -3812,7 +3843,8 @@ static void test_debugger(DWORD cont_status) do { continuestatus = cont_status; - ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); + ret = with_WaitForDebugEventEx ? pWaitForDebugEventEx(&de, INFINITE) : WaitForDebugEvent(&de, INFINITE); + ok(ret, "reading debug event\n");
ret = ContinueDebugEvent(de.dwProcessId, de.dwThreadId, 0xdeadbeef); ok(!ret, "ContinueDebugEvent unexpectedly succeeded\n"); @@ -3980,27 +4012,43 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { enum debugger_stages stage; - char buffer[64]; + char buffer[64 * sizeof(WCHAR)]; + unsigned char_size = de.u.DebugString.fUnicode ? sizeof(WCHAR) : sizeof(char);
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- ok(!de.u.DebugString.fUnicode, "unexpected unicode debug string event\n"); - ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) - 1, "buffer not large enough to hold %d bytes\n", - de.u.DebugString.nDebugStringLength); + if (de.u.DebugString.fUnicode) + ok(with_WaitForDebugEventEx && + (stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED), + "unexpected unicode debug string event\n"); + else + ok(!with_WaitForDebugEventEx || stage != STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || cont_status != DBG_CONTINUE, + "unexpected ansi debug string event %u %s %lx\n", + stage, with_WaitForDebugEventEx ? "with" : "without", cont_status); + + ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) / char_size - 1, + "buffer not large enough to hold %d bytes\n", de.u.DebugString.nDebugStringLength);
memset(buffer, 0, sizeof(buffer)); status = pNtReadVirtualMemory(pi.hProcess, de.u.DebugString.lpDebugStringData, buffer, - de.u.DebugString.nDebugStringLength, &size_read); + de.u.DebugString.nDebugStringLength * char_size, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) - ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || + stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + { + if (de.u.DebugString.fUnicode) + ok(!wcscmp((WCHAR*)buffer, L"Hello World"), "got unexpected debug string '%ls'\n", (WCHAR*)buffer); + else + ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + } else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer);
- if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { @@ -6601,7 +6649,7 @@ static void test_thread_context(void) #undef COMPARE }
-static void test_debugger(DWORD cont_status) +static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) { char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; @@ -6621,6 +6669,12 @@ static void test_debugger(DWORD cont_status) return; }
+ if (with_WaitForDebugEventEx && !pWaitForDebugEventEx) + { + skip("WaitForDebugEventEx not found, skipping unicode strings in OutputDebugStringW\n"); + return; + } + sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "could not create child process error: %lu\n", GetLastError()); @@ -6630,7 +6684,8 @@ static void test_debugger(DWORD cont_status) do { continuestatus = cont_status; - ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); + ret = with_WaitForDebugEventEx ? pWaitForDebugEventEx(&de, INFINITE) : WaitForDebugEvent(&de, INFINITE); + ok(ret, "reading debug event\n");
ret = ContinueDebugEvent(de.dwProcessId, de.dwThreadId, 0xdeadbeef); ok(!ret, "ContinueDebugEvent unexpectedly succeeded\n"); @@ -6772,27 +6827,43 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { enum debugger_stages stage; - char buffer[64]; + char buffer[64 * sizeof(WCHAR)]; + unsigned char_size = de.u.DebugString.fUnicode ? sizeof(WCHAR) : sizeof(char);
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- ok(!de.u.DebugString.fUnicode, "unexpected unicode debug string event\n"); - ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) - 1, "buffer not large enough to hold %d bytes\n", - de.u.DebugString.nDebugStringLength); + if (de.u.DebugString.fUnicode) + ok(with_WaitForDebugEventEx && + (stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED), + "unexpected unicode debug string event\n"); + else + ok(!with_WaitForDebugEventEx || stage != STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || cont_status != DBG_CONTINUE, + "unexpected ansi debug string event %u %s %lx\n", + stage, with_WaitForDebugEventEx ? "with" : "without", cont_status); + + ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) / char_size - 1, + "buffer not large enough to hold %d bytes\n", de.u.DebugString.nDebugStringLength);
memset(buffer, 0, sizeof(buffer)); status = pNtReadVirtualMemory(pi.hProcess, de.u.DebugString.lpDebugStringData, buffer, - de.u.DebugString.nDebugStringLength, &size_read); + de.u.DebugString.nDebugStringLength * char_size, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) - ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || + stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + { + if (de.u.DebugString.fUnicode) + ok(!wcscmp((WCHAR*)buffer, L"Hello World"), "got unexpected debug string '%ls'\n", (WCHAR*)buffer); + else + ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + } else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer);
- if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { @@ -7856,7 +7927,7 @@ static void test_thread_context(void) #undef COMPARE }
-static void test_debugger(DWORD cont_status) +static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) { char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; @@ -7876,6 +7947,12 @@ static void test_debugger(DWORD cont_status) return; }
+ if (with_WaitForDebugEventEx && !pWaitForDebugEventEx) + { + skip("WaitForDebugEventEx not found, skipping unicode strings in OutputDebugStringW\n"); + return; + } + sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "could not create child process error: %lu\n", GetLastError()); @@ -7885,7 +7962,8 @@ static void test_debugger(DWORD cont_status) do { continuestatus = cont_status; - ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); + ret = with_WaitForDebugEventEx ? pWaitForDebugEventEx(&de, INFINITE) : WaitForDebugEvent(&de, INFINITE); + ok(ret, "reading debug event\n");
ret = ContinueDebugEvent(de.dwProcessId, de.dwThreadId, 0xdeadbeef); ok(!ret, "ContinueDebugEvent unexpectedly succeeded\n"); @@ -8027,28 +8105,44 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { enum debugger_stages stage; - char buffer[128]; + char buffer[128 * sizeof(WCHAR)]; + unsigned char_size = de.u.DebugString.fUnicode ? sizeof(WCHAR) : sizeof(char);
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- ok(!de.u.DebugString.fUnicode, "unexpected unicode debug string event\n"); - ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) - 1, "buffer not large enough to hold %d bytes\n", - de.u.DebugString.nDebugStringLength); + if (de.u.DebugString.fUnicode) + ok(with_WaitForDebugEventEx && + (stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED), + "unexpected unicode debug string event\n"); + else + ok(!with_WaitForDebugEventEx || stage != STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || cont_status != DBG_CONTINUE, + "unexpected ansi debug string event %u %s %lx\n", + stage, with_WaitForDebugEventEx ? "with" : "without", cont_status); + + ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) / char_size - 1, + "buffer not large enough to hold %d bytes\n", de.u.DebugString.nDebugStringLength);
memset(buffer, 0, sizeof(buffer)); status = pNtReadVirtualMemory(pi.hProcess, de.u.DebugString.lpDebugStringData, buffer, - de.u.DebugString.nDebugStringLength, &size_read); + de.u.DebugString.nDebugStringLength * char_size, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status);
- if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) - ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || + stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + { + if (de.u.DebugString.fUnicode) + ok(!wcscmp((WCHAR*)buffer, L"Hello World"), "got unexpected debug string '%ls'\n", (WCHAR*)buffer); + else + ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + } else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") || !strncmp(buffer, "RTL:", 4), - "unexpected stage %x, got debug string event '%s'\n", stage, buffer); + "unexpected stage %x, got debug string event '%s'\n", stage, buffer);
- if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { @@ -8645,7 +8739,7 @@ static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_an ok(outputdebugstring_exceptions_ansi == numexc_ansi, "OutputDebugString%c generated %ld ansi exceptions, expected %ld\n", unicode ? 'W' : 'A', outputdebugstring_exceptions_ansi, numexc_ansi); - todo_wine_if(unicode) + todo_wine_if(unicode && numexc_unicode) ok(outputdebugstring_exceptions_unicode == numexc_unicode, "OutputDebugString%c generated %lu unicode exceptions, expected %ld\n", unicode ? 'W' : 'A', outputdebugstring_exceptions_unicode, numexc_unicode); @@ -11235,6 +11329,10 @@ START_TEST(exception) test_outputdebugstring(FALSE, 0, FALSE, 0); test_stage = STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED; test_outputdebugstring(FALSE, 2, TRUE, 0); /* is 2 a Windows bug? */ + test_stage = STAGE_OUTPUTDEBUGSTRINGW_CONTINUE; + test_outputdebugstring(TRUE, 0, FALSE, 0); + test_stage = STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED; + test_outputdebugstring(TRUE, 2, TRUE, 1); /* is 2 a Windows bug? */ test_stage = STAGE_RIPEVENT_CONTINUE; test_ripevent(0); test_stage = STAGE_RIPEVENT_NOT_HANDLED; @@ -11346,8 +11444,10 @@ START_TEST(exception)
#endif
- test_debugger(DBG_EXCEPTION_HANDLED); - test_debugger(DBG_CONTINUE); + test_debugger(DBG_EXCEPTION_HANDLED, FALSE); + test_debugger(DBG_CONTINUE, FALSE); + test_debugger(DBG_EXCEPTION_HANDLED, TRUE); + test_debugger(DBG_CONTINUE, TRUE); test_thread_context(); test_outputdebugstring(FALSE, 1, FALSE, 0); test_outputdebugstring(TRUE, 1, FALSE, 1);
From: Eric Pouech epouech@codeweavers.com
Also modifying WaitForDebugEvent() to force resending the ansi DBG_PRINTEXCEPTION_C exception instead.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernelbase/debug.c | 29 +++++++++++++++++++++++++- dlls/kernelbase/sync.c | 11 ++++++++++ dlls/ntdll/tests/exception.c | 40 +++++++++++++++++++++--------------- 3 files changed, 62 insertions(+), 18 deletions(-)
diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index 7132f63bb52..e571378e2df 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -264,6 +264,11 @@ void WINAPI DECLSPEC_HOTPATCH OutputDebugStringA( LPCSTR str ) } }
+static LONG WINAPI debug_exception_handler_wide( EXCEPTION_POINTERS *eptr ) +{ + EXCEPTION_RECORD *rec = eptr->ExceptionRecord; + return (rec->ExceptionCode == DBG_PRINTEXCEPTION_WIDE_C) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +}
/*********************************************************************** * OutputDebugStringW (kernelbase.@) @@ -273,10 +278,32 @@ void WINAPI DECLSPEC_HOTPATCH OutputDebugStringW( LPCWSTR str ) UNICODE_STRING strW; STRING strA;
+ WARN( "%s\n", debugstr_w(str) ); + RtlInitUnicodeString( &strW, str ); if (!RtlUnicodeStringToAnsiString( &strA, &strW, TRUE )) { - OutputDebugStringA( strA.Buffer ); + BOOL exc_handled; + + __TRY + { + ULONG_PTR args[4]; + args[0] = wcslen(str) + 1; + args[1] = (ULONG_PTR)str; + args[2] = strlen(strA.Buffer) + 1; + args[3] = (ULONG_PTR)strA.Buffer; + RaiseException( DBG_PRINTEXCEPTION_WIDE_C, 0, 4, args ); + exc_handled = TRUE; + } + __EXCEPT(debug_exception_handler_wide) + { + exc_handled = FALSE; + } + __ENDTRY + + if (!exc_handled) + OutputDebugStringA( strA.Buffer ); + RtlFreeAnsiString( &strA ); } } diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c index 3033a4ea245..3bb4589453f 100644 --- a/dlls/kernelbase/sync.c +++ b/dlls/kernelbase/sync.c @@ -404,6 +404,17 @@ BOOL WINAPI DECLSPEC_HOTPATCH WaitForDebugEvent( DEBUG_EVENT *event, DWORD timeo switch (status) { case STATUS_SUCCESS: + /* continue on wide print exceptions to force resending an ANSI one. */ + if (state.NewState == DbgExceptionStateChange) + { + DBGKM_EXCEPTION *info = &state.StateInfo.Exception; + DWORD code = info->ExceptionRecord.ExceptionCode; + if (code == DBG_PRINTEXCEPTION_WIDE_C && info->ExceptionRecord.NumberParameters >= 2) + { + DbgUiContinue( &state.AppClientId, DBG_EXCEPTION_NOT_HANDLED ); + break; + } + } DbgUiConvertStateChangeStructure( &state, event ); return TRUE; case STATUS_USER_APC: diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 9da6b756c31..f5c0b70de4c 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -8715,7 +8715,8 @@ static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *Exce return EXCEPTION_CONTINUE_SEARCH; }
-static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_ansi, DWORD numexc_unicode) +static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_ansi, + DWORD numexc_unicode_low, DWORD numexc_unicode_high) { PVOID vectored_handler;
@@ -8739,10 +8740,11 @@ static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_an ok(outputdebugstring_exceptions_ansi == numexc_ansi, "OutputDebugString%c generated %ld ansi exceptions, expected %ld\n", unicode ? 'W' : 'A', outputdebugstring_exceptions_ansi, numexc_ansi); - todo_wine_if(unicode && numexc_unicode) - ok(outputdebugstring_exceptions_unicode == numexc_unicode, - "OutputDebugString%c generated %lu unicode exceptions, expected %ld\n", - unicode ? 'W' : 'A', outputdebugstring_exceptions_unicode, numexc_unicode); + todo_wine_if(unicode && numexc_unicode_low) + ok(outputdebugstring_exceptions_unicode >= numexc_unicode_low && + outputdebugstring_exceptions_unicode <= numexc_unicode_high, + "OutputDebugString%c generated %lu unicode exceptions, expected %ld-%ld\n", + unicode ? 'W' : 'A', outputdebugstring_exceptions_unicode, numexc_unicode_low, numexc_unicode_high);
pRtlRemoveVectoredExceptionHandler(vectored_handler); } @@ -8804,11 +8806,6 @@ static void test_outputdebugstring_newmodel(void) }; int i;
- if (!pWaitForDebugEventEx) - { - skip("Unsupported new unicode debug string model\n"); - return; - } if (!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler) { skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n"); @@ -11326,13 +11323,16 @@ START_TEST(exception) #endif
test_stage = STAGE_OUTPUTDEBUGSTRINGA_CONTINUE; - test_outputdebugstring(FALSE, 0, FALSE, 0); + + test_outputdebugstring(FALSE, 0, FALSE, 0, 0); test_stage = STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED; - test_outputdebugstring(FALSE, 2, TRUE, 0); /* is 2 a Windows bug? */ + test_outputdebugstring(FALSE, 2, TRUE, 0, 0); /* is 2 a Windows bug? */ test_stage = STAGE_OUTPUTDEBUGSTRINGW_CONTINUE; - test_outputdebugstring(TRUE, 0, FALSE, 0); + /* depending on value passed DebugContinue we can get the unicode exception or not */ + test_outputdebugstring(TRUE, 0, FALSE, 0, 1); test_stage = STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED; - test_outputdebugstring(TRUE, 2, TRUE, 1); /* is 2 a Windows bug? */ + /* depending on value passed DebugContinue we can get the unicode exception or not */ + test_outputdebugstring(TRUE, 2, TRUE, 0, 1); /* is 2 a Windows bug? */ test_stage = STAGE_RIPEVENT_CONTINUE; test_ripevent(0); test_stage = STAGE_RIPEVENT_NOT_HANDLED; @@ -11449,9 +11449,15 @@ START_TEST(exception) test_debugger(DBG_EXCEPTION_HANDLED, TRUE); test_debugger(DBG_CONTINUE, TRUE); test_thread_context(); - test_outputdebugstring(FALSE, 1, FALSE, 0); - test_outputdebugstring(TRUE, 1, FALSE, 1); - test_outputdebugstring_newmodel(); + test_outputdebugstring(FALSE, 1, FALSE, 0, 0); + if (pWaitForDebugEventEx) + { + test_outputdebugstring(TRUE, 1, FALSE, 1, 1); + test_outputdebugstring_newmodel(); + } + else + skip("Unsupported new unicode debug string model\n"); + test_ripevent(1); test_fastfail(); test_breakpoint(1);
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/kernel32.spec | 1 + dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/sync.c | 28 ++++++++++++++++++++++++++++ dlls/ntdll/process.c | 7 +++++++ dlls/ntdll/tests/exception.c | 1 - 5 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index e51cef57638..eb70a8763b5 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -1604,6 +1604,7 @@ @ stdcall WTSGetActiveConsoleSessionId() @ stdcall -import WaitCommEvent(long ptr ptr) @ stdcall -import WaitForDebugEvent(ptr long) +@ stdcall -import WaitForDebugEventEx(ptr long) @ stdcall -import WaitForMultipleObjects(long ptr long long) @ stdcall -import WaitForMultipleObjectsEx(long ptr long long long) @ stdcall -import WaitForSingleObject(long long) diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 46492a59d92..5d5256eb65f 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1729,7 +1729,7 @@ # @ stub WTSIsServerContainer @ stdcall WaitCommEvent(long ptr ptr) @ stdcall WaitForDebugEvent(ptr long) -# @ stub WaitForDebugEventEx +@ stdcall WaitForDebugEventEx(ptr long) # @ stub WaitForMachinePolicyForegroundProcessingInternal @ stdcall WaitForMultipleObjects(long ptr long long) @ stdcall WaitForMultipleObjectsEx(long ptr long long long) diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c index 3bb4589453f..b2086207caa 100644 --- a/dlls/kernelbase/sync.c +++ b/dlls/kernelbase/sync.c @@ -428,6 +428,34 @@ BOOL WINAPI DECLSPEC_HOTPATCH WaitForDebugEvent( DEBUG_EVENT *event, DWORD timeo } }
+/****************************************************************************** + * WaitForDebugEventEx (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH WaitForDebugEventEx( DEBUG_EVENT *event, DWORD timeout ) +{ + NTSTATUS status; + LARGE_INTEGER time; + DBGUI_WAIT_STATE_CHANGE state; + + for (;;) + { + status = DbgUiWaitStateChange( &state, get_nt_timeout( &time, timeout ) ); + switch (status) + { + case STATUS_SUCCESS: + DbgUiConvertStateChangeStructure( &state, event ); + return TRUE; + case STATUS_USER_APC: + continue; + case STATUS_TIMEOUT: + SetLastError( ERROR_SEM_TIMEOUT ); + return FALSE; + default: + return set_ntstatus( status ); + } + } +} +
/*********************************************************************** * WaitOnAddress (kernelbase.@) diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c index 09cc86889b9..042c505c207 100644 --- a/dlls/ntdll/process.c +++ b/dlls/ntdll/process.c @@ -511,6 +511,13 @@ NTSTATUS WINAPI DbgUiConvertStateChangeStructure( DBGUI_WAIT_STATE_CHANGE *state event->u.DebugString.fUnicode = FALSE; event->u.DebugString.nDebugStringLength = info->ExceptionRecord.ExceptionInformation[0]; } + else if (code == DBG_PRINTEXCEPTION_WIDE_C && info->ExceptionRecord.NumberParameters >= 2) + { + event->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT; + event->u.DebugString.lpDebugStringData = (void *)info->ExceptionRecord.ExceptionInformation[1]; + event->u.DebugString.fUnicode = TRUE; + event->u.DebugString.nDebugStringLength = info->ExceptionRecord.ExceptionInformation[0]; + } else if (code == DBG_RIPEXCEPTION && info->ExceptionRecord.NumberParameters >= 2) { event->dwDebugEventCode = RIP_EVENT; diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index f5c0b70de4c..19aa9992c2d 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -8740,7 +8740,6 @@ static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_an ok(outputdebugstring_exceptions_ansi == numexc_ansi, "OutputDebugString%c generated %ld ansi exceptions, expected %ld\n", unicode ? 'W' : 'A', outputdebugstring_exceptions_ansi, numexc_ansi); - todo_wine_if(unicode && numexc_unicode_low) ok(outputdebugstring_exceptions_unicode >= numexc_unicode_low && outputdebugstring_exceptions_unicode <= numexc_unicode_high, "OutputDebugString%c generated %lu unicode exceptions, expected %ld-%ld\n",
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=136366
Your paranoid android.
=== debian11b (64 bit WoW report) ===
Report validation errors: ntdll:exception prints too much data (36073 bytes)
On Thu Aug 17 14:26:53 2023 +0000, **** wrote:
Marvin replied on the mailing list:
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details: The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=136366 Your paranoid android. === debian11b (64 bit WoW report) === Report validation errors: ntdll:exception prints too much data (36073 bytes)
mostly the usual d3d failing tests