ntdll: Add support for exceptions inside termination handlers in __C_specific_handler.
Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
7c060d0061
commit
b23de3cd4a
|
@ -3787,7 +3787,6 @@ void WINAPI _local_unwind( void *frame, void *target_ip )
|
||||||
RtlUnwindEx( frame, target_ip, NULL, NULL, &context, NULL );
|
RtlUnwindEx( frame, target_ip, NULL, NULL, &context, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* __C_specific_handler (NTDLL.@)
|
* __C_specific_handler (NTDLL.@)
|
||||||
*/
|
*/
|
||||||
|
@ -3804,10 +3803,10 @@ EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
|
||||||
|
|
||||||
if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
|
if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
|
||||||
{
|
{
|
||||||
for (i = 0; i < table->Count; i++)
|
for (i = dispatch->ScopeIndex; i < table->Count; i++)
|
||||||
{
|
{
|
||||||
if (context->Rip >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
|
if (dispatch->ControlPc >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
|
||||||
context->Rip < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
|
dispatch->ControlPc < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
|
||||||
{
|
{
|
||||||
TERMINATION_HANDLER handler;
|
TERMINATION_HANDLER handler;
|
||||||
|
|
||||||
|
@ -3821,6 +3820,7 @@ EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
|
||||||
}
|
}
|
||||||
|
|
||||||
handler = (TERMINATION_HANDLER)(dispatch->ImageBase + table->ScopeRecord[i].HandlerAddress);
|
handler = (TERMINATION_HANDLER)(dispatch->ImageBase + table->ScopeRecord[i].HandlerAddress);
|
||||||
|
dispatch->ScopeIndex = i+1;
|
||||||
|
|
||||||
TRACE( "calling __finally %p frame %lx\n", handler, frame );
|
TRACE( "calling __finally %p frame %lx\n", handler, frame );
|
||||||
handler( 1, frame );
|
handler( 1, frame );
|
||||||
|
@ -3829,10 +3829,10 @@ EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
|
||||||
return ExceptionContinueSearch;
|
return ExceptionContinueSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < table->Count; i++)
|
for (i = dispatch->ScopeIndex; i < table->Count; i++)
|
||||||
{
|
{
|
||||||
if (context->Rip >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
|
if (dispatch->ControlPc >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
|
||||||
context->Rip < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
|
dispatch->ControlPc < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
|
||||||
{
|
{
|
||||||
if (!table->ScopeRecord[i].JumpTarget) continue;
|
if (!table->ScopeRecord[i].JumpTarget) continue;
|
||||||
if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER)
|
if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
@ -3856,7 +3856,7 @@ EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
|
||||||
}
|
}
|
||||||
TRACE( "unwinding to target %lx\n", dispatch->ImageBase + table->ScopeRecord[i].JumpTarget );
|
TRACE( "unwinding to target %lx\n", dispatch->ImageBase + table->ScopeRecord[i].JumpTarget );
|
||||||
RtlUnwindEx( (void *)frame, (char *)dispatch->ImageBase + table->ScopeRecord[i].JumpTarget,
|
RtlUnwindEx( (void *)frame, (char *)dispatch->ImageBase + table->ScopeRecord[i].JumpTarget,
|
||||||
rec, 0, context, dispatch->HistoryTable );
|
rec, 0, dispatch->ContextRecord, dispatch->HistoryTable );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ExceptionContinueSearch;
|
return ExceptionContinueSearch;
|
||||||
|
|
|
@ -53,10 +53,37 @@ static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PV
|
||||||
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
|
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
|
||||||
|
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ULONG Count;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
ULONG BeginAddress;
|
||||||
|
ULONG EndAddress;
|
||||||
|
ULONG HandlerAddress;
|
||||||
|
ULONG JumpTarget;
|
||||||
|
} ScopeRecord[1];
|
||||||
|
} SCOPE_TABLE;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ULONG64 ControlPc;
|
||||||
|
ULONG64 ImageBase;
|
||||||
|
PRUNTIME_FUNCTION FunctionEntry;
|
||||||
|
ULONG64 EstablisherFrame;
|
||||||
|
ULONG64 TargetIp;
|
||||||
|
PCONTEXT ContextRecord;
|
||||||
|
void* /*PEXCEPTION_ROUTINE*/ LanguageHandler;
|
||||||
|
PVOID HandlerData;
|
||||||
|
PUNWIND_HISTORY_TABLE HistoryTable;
|
||||||
|
ULONG ScopeIndex;
|
||||||
|
} DISPATCHER_CONTEXT;
|
||||||
|
|
||||||
static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
|
static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
|
||||||
static BOOLEAN (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
|
static BOOLEAN (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
|
||||||
static BOOLEAN (CDECL *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR);
|
static BOOLEAN (CDECL *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR);
|
||||||
static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UNWIND_HISTORY_TABLE*);
|
static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UNWIND_HISTORY_TABLE*);
|
||||||
|
static EXCEPTION_DISPOSITION (WINAPI *p__C_specific_handler)(EXCEPTION_RECORD*, ULONG64, CONTEXT*, DISPATCHER_CONTEXT*);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
|
@ -1747,6 +1774,59 @@ static void test_dynamic_unwind(void)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int termination_handler_called;
|
||||||
|
static void WINAPI termination_handler(ULONG flags, ULONG64 frame)
|
||||||
|
{
|
||||||
|
termination_handler_called++;
|
||||||
|
|
||||||
|
ok(flags == 1 || broken(flags == 0x401), "flags = %x\n", flags);
|
||||||
|
ok(frame == 0x1234, "frame = %p\n", (void*)frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test___C_specific_handler(void)
|
||||||
|
{
|
||||||
|
DISPATCHER_CONTEXT dispatch;
|
||||||
|
EXCEPTION_RECORD rec;
|
||||||
|
CONTEXT context;
|
||||||
|
ULONG64 frame;
|
||||||
|
EXCEPTION_DISPOSITION ret;
|
||||||
|
SCOPE_TABLE scope_table;
|
||||||
|
|
||||||
|
if (!p__C_specific_handler)
|
||||||
|
{
|
||||||
|
win_skip("__C_specific_handler not available\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&rec, 0, sizeof(rec));
|
||||||
|
rec.ExceptionFlags = 2; /* EH_UNWINDING */
|
||||||
|
frame = 0x1234;
|
||||||
|
memset(&dispatch, 0, sizeof(dispatch));
|
||||||
|
dispatch.ImageBase = (ULONG_PTR)GetModuleHandleA(NULL);
|
||||||
|
dispatch.ControlPc = dispatch.ImageBase + 0x200;
|
||||||
|
dispatch.HandlerData = &scope_table;
|
||||||
|
dispatch.ContextRecord = &context;
|
||||||
|
scope_table.Count = 1;
|
||||||
|
scope_table.ScopeRecord[0].BeginAddress = 0x200;
|
||||||
|
scope_table.ScopeRecord[0].EndAddress = 0x400;
|
||||||
|
scope_table.ScopeRecord[0].HandlerAddress = (ULONG_PTR)termination_handler-dispatch.ImageBase;
|
||||||
|
scope_table.ScopeRecord[0].JumpTarget = 0;
|
||||||
|
memset(&context, 0, sizeof(context));
|
||||||
|
|
||||||
|
termination_handler_called = 0;
|
||||||
|
ret = p__C_specific_handler(&rec, frame, &context, &dispatch);
|
||||||
|
ok(ret == ExceptionContinueSearch, "__C_specific_handler returned %x\n", ret);
|
||||||
|
ok(termination_handler_called == 1, "termination_handler_called = %d\n",
|
||||||
|
termination_handler_called);
|
||||||
|
ok(dispatch.ScopeIndex == 1, "dispatch.ScopeIndex = %d\n", dispatch.ScopeIndex);
|
||||||
|
|
||||||
|
ret = p__C_specific_handler(&rec, frame, &context, &dispatch);
|
||||||
|
ok(ret == ExceptionContinueSearch, "__C_specific_handler returned %x\n", ret);
|
||||||
|
ok(termination_handler_called == 1, "termination_handler_called = %d\n",
|
||||||
|
termination_handler_called);
|
||||||
|
ok(dispatch.ScopeIndex == 1, "dispatch.ScopeIndex = %d\n", dispatch.ScopeIndex);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __x86_64__ */
|
#endif /* __x86_64__ */
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
|
@ -2267,6 +2347,8 @@ START_TEST(exception)
|
||||||
"RtlInstallFunctionTableCallback" );
|
"RtlInstallFunctionTableCallback" );
|
||||||
pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll,
|
pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll,
|
||||||
"RtlLookupFunctionEntry" );
|
"RtlLookupFunctionEntry" );
|
||||||
|
p__C_specific_handler = (void *)GetProcAddress( hntdll,
|
||||||
|
"__C_specific_handler" );
|
||||||
|
|
||||||
test_debug_registers();
|
test_debug_registers();
|
||||||
test_outputdebugstring(1, FALSE);
|
test_outputdebugstring(1, FALSE);
|
||||||
|
@ -2275,6 +2357,7 @@ START_TEST(exception)
|
||||||
test_breakpoint(1);
|
test_breakpoint(1);
|
||||||
test_vectored_continue_handler();
|
test_vectored_continue_handler();
|
||||||
test_virtual_unwind();
|
test_virtual_unwind();
|
||||||
|
test___C_specific_handler();
|
||||||
|
|
||||||
if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
|
if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
|
||||||
test_dynamic_unwind();
|
test_dynamic_unwind();
|
||||||
|
|
Loading…
Reference in New Issue