ntdll: Implement RtlVirtualUnwind2.
This commit is contained in:
parent
9ac8d63e22
commit
ca5984059c
5 changed files with 242 additions and 81 deletions
|
@ -125,10 +125,9 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX
|
|||
|
||||
dispatch->FunctionEntry = RtlLookupFunctionEntry( pc, (DWORD_PTR *)&dispatch->ImageBase,
|
||||
dispatch->HistoryTable );
|
||||
dispatch->LanguageHandler = RtlVirtualUnwind( type, dispatch->ImageBase, pc, dispatch->FunctionEntry,
|
||||
context, &dispatch->HandlerData,
|
||||
(ULONG_PTR *)&dispatch->EstablisherFrame, NULL );
|
||||
if (!context->Pc)
|
||||
if (RtlVirtualUnwind2( type, dispatch->ImageBase, pc, dispatch->FunctionEntry, context,
|
||||
NULL, &dispatch->HandlerData, (ULONG_PTR *)&dispatch->EstablisherFrame,
|
||||
NULL, NULL, NULL, &dispatch->LanguageHandler, 0 ))
|
||||
{
|
||||
WARN( "exception data not found for pc %p, lr %p\n", (void *)pc, (void *)context->Lr );
|
||||
return STATUS_INVALID_DISPOSITION;
|
||||
|
|
|
@ -155,10 +155,10 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX
|
|||
if (dispatch->ControlPcIsUnwound) pc -= 4;
|
||||
|
||||
dispatch->FunctionEntry = RtlLookupFunctionEntry( pc, &dispatch->ImageBase, dispatch->HistoryTable );
|
||||
dispatch->LanguageHandler = RtlVirtualUnwind( type, dispatch->ImageBase, pc, dispatch->FunctionEntry,
|
||||
context, &dispatch->HandlerData,
|
||||
&dispatch->EstablisherFrame, NULL );
|
||||
if (!context->Pc)
|
||||
|
||||
if (RtlVirtualUnwind2( type, dispatch->ImageBase, pc, dispatch->FunctionEntry, context,
|
||||
NULL, &dispatch->HandlerData, &dispatch->EstablisherFrame,
|
||||
NULL, NULL, NULL, &dispatch->LanguageHandler, 0 ))
|
||||
{
|
||||
WARN( "exception data not found for pc %p, lr %p\n", (void *)pc, (void *)context->Lr );
|
||||
return STATUS_INVALID_DISPOSITION;
|
||||
|
|
|
@ -119,11 +119,9 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX
|
|||
}
|
||||
else WARN( "exception data not found for pc %p\n", (void *)context->Rip );
|
||||
|
||||
dispatch->LanguageHandler = RtlVirtualUnwind( type, dispatch->ImageBase, context->Rip,
|
||||
dispatch->FunctionEntry, context,
|
||||
&dispatch->HandlerData, &dispatch->EstablisherFrame,
|
||||
NULL );
|
||||
return STATUS_SUCCESS;
|
||||
return RtlVirtualUnwind2( type, dispatch->ImageBase, context->Rip, dispatch->FunctionEntry,
|
||||
context, NULL, &dispatch->HandlerData, &dispatch->EstablisherFrame,
|
||||
NULL, NULL, NULL, &dispatch->LanguageHandler, 0 );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ static BOOLEAN (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
|
|||
static DWORD (WINAPI *pRtlAddGrowableFunctionTable)(void**, RUNTIME_FUNCTION*, DWORD, DWORD, ULONG_PTR, ULONG_PTR);
|
||||
static void (WINAPI *pRtlGrowFunctionTable)(void*, DWORD);
|
||||
static void (WINAPI *pRtlDeleteGrowableFunctionTable)(void*);
|
||||
static NTSTATUS (WINAPI *pRtlVirtualUnwind2)(ULONG,ULONG_PTR,ULONG_PTR,RUNTIME_FUNCTION*,CONTEXT*,BOOLEAN*,void**,ULONG_PTR*,KNONVOLATILE_CONTEXT_POINTERS*,ULONG_PTR*,ULONG_PTR*,PEXCEPTION_ROUTINE*,ULONG);
|
||||
static NTSTATUS (WINAPI *pNtAllocateVirtualMemoryEx)(HANDLE,PVOID*,SIZE_T*,ULONG,ULONG,MEM_EXTENDED_PARAMETER*,ULONG);
|
||||
|
||||
#ifdef __arm__
|
||||
|
@ -125,8 +126,10 @@ static void call_virtual_unwind_arm( int testnum, const struct unwind_test_arm *
|
|||
{
|
||||
static const int code_offset = 1024;
|
||||
static const int unwind_offset = 2048;
|
||||
void *handler, *data;
|
||||
void *data;
|
||||
CONTEXT context;
|
||||
NTSTATUS status;
|
||||
PEXCEPTION_ROUTINE handler;
|
||||
RUNTIME_FUNCTION runtime_func;
|
||||
KNONVOLATILE_CONTEXT_POINTERS ctx_ptr;
|
||||
UINT i, j, k;
|
||||
|
@ -163,11 +166,44 @@ static void call_virtual_unwind_arm( int testnum, const struct unwind_test_arm *
|
|||
trace( "%u/%u: pc=%p (%02x) fp=%p sp=%p\n", testnum, i,
|
||||
(void *)orig_pc, *(UINT *)orig_pc, (void *)orig_fp, (void *)context.Sp );
|
||||
|
||||
if (test->results[i].handler == -2) orig_pc = context.Lr;
|
||||
|
||||
if (pRtlVirtualUnwind2)
|
||||
{
|
||||
CONTEXT new_context = context;
|
||||
|
||||
handler = (void *)0xdeadbeef;
|
||||
data = (void *)0xdeadbeef;
|
||||
frame = 0xdeadbeef;
|
||||
status = pRtlVirtualUnwind2( UNW_FLAG_EHANDLER, (ULONG)code_mem, orig_pc,
|
||||
test->unwind_info ? &runtime_func : NULL, &new_context,
|
||||
NULL, &data, &frame, &ctx_ptr, NULL, NULL, &handler, 0 );
|
||||
if (test->results[i].handler > 0)
|
||||
{
|
||||
ok( !status, "RtlVirtualUnwind2 failed %lx\n", status );
|
||||
ok( (char *)handler == (char *)code_mem + 0x200,
|
||||
"%u/%u: wrong handler %p/%p\n", testnum, i, handler, (char *)code_mem + 0x200 );
|
||||
if (handler) ok( *(DWORD *)data == 0x08070605,
|
||||
"%u/%u: wrong handler data %lx\n", testnum, i, *(DWORD *)data );
|
||||
}
|
||||
else if (test->results[i].handler < -1)
|
||||
{
|
||||
ok( status == STATUS_BAD_FUNCTION_TABLE, "RtlVirtualUnwind2 failed %lx\n", status );
|
||||
ok( handler == (void *)0xdeadbeef, "handler set to %p\n", handler );
|
||||
ok( data == (void *)0xdeadbeef, "handler data set to %p\n", data );
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( !status, "RtlVirtualUnwind2 failed %lx\n", status );
|
||||
ok( handler == NULL, "handler %p instead of NULL\n", handler );
|
||||
ok( data == NULL, "handler data set to %p\n", data );
|
||||
}
|
||||
}
|
||||
|
||||
data = (void *)0xdeadbeef;
|
||||
frame = 0xdeadbeef;
|
||||
if (test->results[i].handler == -2) orig_pc = context.Lr;
|
||||
handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG)code_mem, orig_pc,
|
||||
test->unwind_info ? (RUNTIME_FUNCTION *)&runtime_func : NULL,
|
||||
test->unwind_info ? &runtime_func : NULL,
|
||||
&context, &data, &frame, &ctx_ptr );
|
||||
if (test->results[i].handler > 0)
|
||||
{
|
||||
|
@ -1558,15 +1594,17 @@ static void call_virtual_unwind_arm64( void *code_mem, int testnum, const struct
|
|||
{
|
||||
static const int code_offset = 1024;
|
||||
static const int unwind_offset = 2048;
|
||||
void *handler, *data;
|
||||
void *data;
|
||||
#ifdef __x86_64__
|
||||
ARM64EC_NT_CONTEXT context;
|
||||
ARM64EC_NT_CONTEXT context, new_context;
|
||||
#else
|
||||
ARM64_NT_CONTEXT context;
|
||||
ARM64_NT_CONTEXT context, new_context;
|
||||
#endif
|
||||
PEXCEPTION_ROUTINE handler;
|
||||
ARM64_RUNTIME_FUNCTION runtime_func;
|
||||
KNONVOLATILE_CONTEXT_POINTERS ctx_ptr;
|
||||
UINT i, j, k;
|
||||
NTSTATUS status;
|
||||
ULONG64 fake_stack[256];
|
||||
ULONG64 frame, orig_pc, orig_fp, unset_reg, sp_offset = 0, regval, *regptr;
|
||||
static const UINT nb_regs = ARRAY_SIZE(test->results[i].regs);
|
||||
|
@ -1604,9 +1642,42 @@ static void call_virtual_unwind_arm64( void *code_mem, int testnum, const struct
|
|||
|
||||
trace( "pc=%p (%02x) fp=%p sp=%p\n", (void *)orig_pc, *(UINT *)orig_pc, (void *)orig_fp, (void *)context.Sp );
|
||||
|
||||
if (test->results[i].handler == -2) orig_pc = context.Lr;
|
||||
|
||||
if (pRtlVirtualUnwind2)
|
||||
{
|
||||
new_context = context;
|
||||
handler = (void *)0xdeadbeef;
|
||||
data = (void *)0xdeadbeef;
|
||||
frame = 0xdeadbeef;
|
||||
status = pRtlVirtualUnwind2( UNW_FLAG_EHANDLER, (ULONG_PTR)code_mem, orig_pc,
|
||||
test->unwind_info ? (RUNTIME_FUNCTION *)&runtime_func : NULL,
|
||||
(CONTEXT *)&new_context, NULL, &data,
|
||||
&frame, &ctx_ptr, NULL, NULL, &handler, 0 );
|
||||
if (test->results[i].handler > 0)
|
||||
{
|
||||
ok( !status, "RtlVirtualUnwind2 failed %lx\n", status );
|
||||
ok( (char *)handler == (char *)code_mem + 0x200,
|
||||
"wrong handler %p/%p\n", handler, (char *)code_mem + 0x200 );
|
||||
if (handler) ok( *(DWORD *)data == 0x08070605,
|
||||
"wrong handler data %lx\n", *(DWORD *)data );
|
||||
}
|
||||
else if (test->results[i].handler < -1)
|
||||
{
|
||||
ok( status == STATUS_BAD_FUNCTION_TABLE, "RtlVirtualUnwind2 failed %lx\n", status );
|
||||
ok( handler == (void *)0xdeadbeef, "handler set to %p\n", handler );
|
||||
ok( data == (void *)0xdeadbeef, "handler data set to %p\n", data );
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( !status, "RtlVirtualUnwind2 failed %lx\n", status );
|
||||
ok( handler == NULL, "handler %p instead of NULL\n", handler );
|
||||
ok( data == NULL, "handler data set to %p\n", data );
|
||||
}
|
||||
}
|
||||
|
||||
data = (void *)0xdeadbeef;
|
||||
frame = 0xdeadbeef;
|
||||
if (test->results[i].handler == -2) orig_pc = context.Lr;
|
||||
handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG64)code_mem, orig_pc,
|
||||
test->unwind_info ? (RUNTIME_FUNCTION *)&runtime_func : NULL,
|
||||
(CONTEXT *)&context, &data, &frame, &ctx_ptr );
|
||||
|
@ -2625,8 +2696,10 @@ static void call_virtual_unwind_x86( int testnum, const struct unwind_test_x86 *
|
|||
{
|
||||
static const int code_offset = 1024;
|
||||
static const int unwind_offset = 2048;
|
||||
void *handler, *data;
|
||||
void *data;
|
||||
NTSTATUS status;
|
||||
CONTEXT context;
|
||||
PEXCEPTION_ROUTINE handler;
|
||||
RUNTIME_FUNCTION runtime_func;
|
||||
KNONVOLATILE_CONTEXT_POINTERS ctx_ptr;
|
||||
UINT i, j, k, broken_k;
|
||||
|
@ -2661,8 +2734,31 @@ static void call_virtual_unwind_x86( int testnum, const struct unwind_test_x86 *
|
|||
trace( "%u/%u: rip=%p (%02x) rbp=%p rsp=%p\n", testnum, i,
|
||||
(void *)orig_rip, *(BYTE *)orig_rip, (void *)orig_rbp, (void *)context.Rsp );
|
||||
|
||||
data = (void *)0xdeadbeef;
|
||||
if (!test->unwind_info) fake_stack[0] = 0x1234;
|
||||
expected_handler = test->results[i].handler ? (char *)code_mem + 0x200 : NULL;
|
||||
broken_handler = test->broken_results && test->broken_results[i].handler ? (char *)code_mem + 0x200 : NULL;
|
||||
|
||||
if (pRtlVirtualUnwind2)
|
||||
{
|
||||
CONTEXT new_context = context;
|
||||
|
||||
handler = (void *)0xdeadbeef;
|
||||
data = (void *)0xdeadbeef;
|
||||
status = pRtlVirtualUnwind2( UNW_FLAG_EHANDLER, (ULONG_PTR)code_mem, orig_rip,
|
||||
test->unwind_info ? &runtime_func : NULL, &new_context,
|
||||
NULL, &data, &frame, &ctx_ptr, NULL, NULL, &handler, 0 );
|
||||
ok( !status, "RtlVirtualUnwind2 failed %lx\n", status );
|
||||
|
||||
ok( handler == expected_handler || broken( test->broken_results && handler == broken_handler ),
|
||||
"%u/%u: wrong handler %p/%p\n", testnum, i, handler, expected_handler );
|
||||
if (handler)
|
||||
ok( *(DWORD *)data == 0x08070605, "%u/%u: wrong handler data %lx\n", testnum, i, *(DWORD *)data );
|
||||
else
|
||||
ok( data == (test->unwind_info ? (void *)0xdeadbeef : NULL),
|
||||
"%u/%u: handler data set to %p\n", testnum, i, data );
|
||||
}
|
||||
|
||||
data = (void *)0xdeadbeef;
|
||||
handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG64)code_mem, orig_rip,
|
||||
test->unwind_info ? &runtime_func : NULL,
|
||||
&context, &data, &frame, &ctx_ptr );
|
||||
|
@ -3329,6 +3425,7 @@ START_TEST(unwind)
|
|||
X(RtlInstallFunctionTableCallback);
|
||||
X(RtlLookupFunctionEntry);
|
||||
X(RtlLookupFunctionTable);
|
||||
X(RtlVirtualUnwind2);
|
||||
#undef X
|
||||
|
||||
#ifdef __arm__
|
||||
|
|
|
@ -766,9 +766,43 @@ static ARM64_RUNTIME_FUNCTION *find_function_info_arm64( ULONG_PTR pc, ULONG_PTR
|
|||
|
||||
#ifdef __arm64ec__
|
||||
#define RtlVirtualUnwind RtlVirtualUnwind_arm64
|
||||
#define RtlVirtualUnwind2 RtlVirtualUnwind2_arm64
|
||||
#define RtlLookupFunctionEntry RtlLookupFunctionEntry_arm64
|
||||
#endif
|
||||
|
||||
/**********************************************************************
|
||||
* RtlVirtualUnwind2 (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI RtlVirtualUnwind2( ULONG type, ULONG_PTR base, ULONG_PTR pc,
|
||||
ARM64_RUNTIME_FUNCTION *func, ARM64_NT_CONTEXT *context,
|
||||
BOOLEAN *mach_frame_unwound, void **handler_data,
|
||||
ULONG_PTR *frame_ret, KNONVOLATILE_CONTEXT_POINTERS_ARM64 *ctx_ptr,
|
||||
ULONG_PTR *limit_low, ULONG_PTR *limit_high,
|
||||
PEXCEPTION_ROUTINE *handler_ret, ULONG flags )
|
||||
{
|
||||
TRACE( "type %lx base %I64x pc %I64x rva %I64x sp %I64x\n", type, base, pc, pc - base, context->Sp );
|
||||
if (limit_low || limit_high) FIXME( "limits not supported\n" );
|
||||
|
||||
if (!func && pc == context->Lr) return STATUS_BAD_FUNCTION_TABLE; /* invalid leaf function */
|
||||
|
||||
*handler_data = NULL;
|
||||
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
|
||||
|
||||
if (!func) /* leaf function */
|
||||
*handler_ret = NULL;
|
||||
else if (func->Flag)
|
||||
*handler_ret = unwind_packed_data( base, pc, func, context, ctx_ptr );
|
||||
else
|
||||
*handler_ret = unwind_full_data( base, pc, func, context, handler_data, ctx_ptr );
|
||||
|
||||
if (context->ContextFlags & CONTEXT_UNWOUND_TO_CALL) context->Pc = context->Lr;
|
||||
|
||||
TRACE( "ret: pc=%I64x lr=%I64x sp=%I64x handler=%p\n", context->Pc, context->Lr, context->Sp, *handler_ret );
|
||||
*frame_ret = context->Sp;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlVirtualUnwind (NTDLL.@)
|
||||
*/
|
||||
|
@ -779,29 +813,12 @@ PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind( ULONG type, ULONG_PTR base, ULONG_PT
|
|||
{
|
||||
PEXCEPTION_ROUTINE handler;
|
||||
|
||||
TRACE( "type %lx pc %I64x sp %I64x\n", type, pc, context->Sp );
|
||||
if (!RtlVirtualUnwind2( type, base, pc, func, context, NULL, handler_data,
|
||||
frame_ret, ctx_ptr, NULL, NULL, &handler, 0 ))
|
||||
return handler;
|
||||
|
||||
if (!func && pc == context->Lr) /* invalid leaf function */
|
||||
{
|
||||
context->Pc = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*handler_data = NULL;
|
||||
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
|
||||
|
||||
if (!func) /* leaf function */
|
||||
handler = NULL;
|
||||
else if (func->Flag)
|
||||
handler = unwind_packed_data( base, pc, func, context, ctx_ptr );
|
||||
else
|
||||
handler = unwind_full_data( base, pc, func, context, handler_data, ctx_ptr );
|
||||
|
||||
if (context->ContextFlags & CONTEXT_UNWOUND_TO_CALL) context->Pc = context->Lr;
|
||||
|
||||
TRACE( "ret: pc=%I64x lr=%I64x sp=%I64x handler=%p\n", context->Pc, context->Lr, context->Sp, handler );
|
||||
*frame_ret = context->Sp;
|
||||
return handler;
|
||||
context->Pc = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -850,6 +867,7 @@ BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, ULONG_P
|
|||
}
|
||||
#else
|
||||
#undef RtlVirtualUnwind
|
||||
#undef RtlVirtualUnwind2
|
||||
#undef RtlLookupFunctionEntry
|
||||
#endif
|
||||
|
||||
|
@ -1367,6 +1385,44 @@ static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, ULONG_PTR base,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlVirtualUnwind2 (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI RtlVirtualUnwind2( ULONG type, ULONG_PTR base, ULONG_PTR pc,
|
||||
RUNTIME_FUNCTION *func, CONTEXT *context,
|
||||
BOOLEAN *mach_frame_unwound, void **handler_data,
|
||||
ULONG_PTR *frame_ret, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr,
|
||||
ULONG_PTR *limit_low, ULONG_PTR *limit_high,
|
||||
PEXCEPTION_ROUTINE *handler_ret, ULONG flags )
|
||||
{
|
||||
TRACE( "type %lx base %Ix pc %Ix rva %Ix sp %lx\n", type, base, pc, pc - base, context->Sp );
|
||||
if (limit_low || limit_high) FIXME( "limits not supported\n" );
|
||||
|
||||
context->Pc = 0;
|
||||
|
||||
if (!func && pc == context->Lr) return STATUS_BAD_FUNCTION_TABLE; /* invalid leaf function */
|
||||
|
||||
*handler_data = NULL;
|
||||
|
||||
if (!func) /* leaf function */
|
||||
*handler_ret = NULL;
|
||||
else if (func->Flag)
|
||||
*handler_ret = unwind_packed_data( base, pc, func, context, ctx_ptr );
|
||||
else
|
||||
*handler_ret = unwind_full_data( base, pc, func, context, handler_data, ctx_ptr );
|
||||
|
||||
TRACE( "ret: pc=%lx lr=%lx sp=%lx handler=%p\n", context->Pc, context->Lr, context->Sp, *handler_ret );
|
||||
if (!context->Pc)
|
||||
{
|
||||
context->Pc = context->Lr;
|
||||
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
|
||||
}
|
||||
*frame_ret = context->Sp;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* RtlVirtualUnwind (NTDLL.@)
|
||||
*/
|
||||
|
@ -1377,29 +1433,12 @@ PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind( ULONG type, ULONG_PTR base, ULONG_PT
|
|||
{
|
||||
PEXCEPTION_ROUTINE handler;
|
||||
|
||||
TRACE( "type %lx pc %Ix sp %lx\n", type, pc, context->Sp );
|
||||
if (!RtlVirtualUnwind2( type, base, pc, func, context, NULL, handler_data,
|
||||
frame_ret, ctx_ptr, NULL, NULL, &handler, 0 ))
|
||||
return handler;
|
||||
|
||||
context->Pc = 0;
|
||||
|
||||
if (!func && pc == context->Lr) return NULL; /* invalid leaf function */
|
||||
|
||||
*handler_data = NULL;
|
||||
|
||||
if (!func) /* leaf function */
|
||||
handler = NULL;
|
||||
else if (func->Flag)
|
||||
handler = unwind_packed_data( base, pc, func, context, ctx_ptr );
|
||||
else
|
||||
handler = unwind_full_data( base, pc, func, context, handler_data, ctx_ptr );
|
||||
|
||||
TRACE( "ret: pc=%lx lr=%lx sp=%lx handler=%p\n", context->Pc, context->Lr, context->Sp, handler );
|
||||
if (!context->Pc)
|
||||
{
|
||||
context->Pc = context->Lr;
|
||||
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
|
||||
}
|
||||
*frame_ret = context->Sp;
|
||||
return handler;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1808,12 +1847,14 @@ static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, ULONG_PTR base,
|
|||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlVirtualUnwind (NTDLL.@)
|
||||
* RtlVirtualUnwind2 (NTDLL.@)
|
||||
*/
|
||||
PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc,
|
||||
RUNTIME_FUNCTION *function, CONTEXT *context,
|
||||
PVOID *data, ULONG64 *frame_ret,
|
||||
KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr )
|
||||
NTSTATUS WINAPI RtlVirtualUnwind2( ULONG type, ULONG_PTR base, ULONG_PTR pc,
|
||||
RUNTIME_FUNCTION *function, CONTEXT *context,
|
||||
BOOLEAN *mach_frame_unwound, void **data,
|
||||
ULONG_PTR *frame_ret, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr,
|
||||
ULONG_PTR *limit_low, ULONG_PTR *limit_high,
|
||||
PEXCEPTION_ROUTINE *handler_ret, ULONG flags )
|
||||
{
|
||||
union handler_data *handler_data;
|
||||
ULONG64 frame, off;
|
||||
|
@ -1826,18 +1867,20 @@ PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc
|
|||
{
|
||||
DWORD flags = context->ContextFlags & ~CONTEXT_UNWOUND_TO_CALL;
|
||||
ARM64_NT_CONTEXT arm_context;
|
||||
PEXCEPTION_ROUTINE ret;
|
||||
NTSTATUS status;
|
||||
|
||||
context_x64_to_arm( &arm_context, (ARM64EC_NT_CONTEXT *)context );
|
||||
ret = RtlVirtualUnwind_arm64( type, base, pc, (ARM64_RUNTIME_FUNCTION *)function,
|
||||
&arm_context, data, frame_ret, NULL );
|
||||
status = RtlVirtualUnwind2_arm64( type, base, pc, (ARM64_RUNTIME_FUNCTION *)function,
|
||||
&arm_context, NULL, data, frame_ret, NULL,
|
||||
limit_low, limit_high, handler_ret, flags );
|
||||
context_arm_to_x64( (ARM64EC_NT_CONTEXT *)context, &arm_context );
|
||||
context->ContextFlags = flags | (arm_context.ContextFlags & CONTEXT_UNWOUND_TO_CALL);
|
||||
return ret;
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE( "type %lx rip %I64x rsp %I64x\n", type, pc, context->Rsp );
|
||||
TRACE( "type %lx base %I64x rip %I64x rva %I64x rsp %I64x\n", type, base, pc, pc - base, context->Rsp );
|
||||
if (limit_low || limit_high) FIXME( "limits not supported\n" );
|
||||
|
||||
frame = *frame_ret = context->Rsp;
|
||||
|
||||
|
@ -1846,7 +1889,8 @@ PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc
|
|||
context->Rip = *(ULONG64 *)context->Rsp;
|
||||
context->Rsp += sizeof(ULONG64);
|
||||
*data = NULL;
|
||||
return NULL;
|
||||
*handler_ret = NULL;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (TRACE_ON(unwind)) dump_unwind_info( base, function );
|
||||
|
@ -1859,7 +1903,7 @@ PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc
|
|||
if (info->version != 1 && info->version != 2)
|
||||
{
|
||||
FIXME( "unknown unwind info version %u at %p\n", info->version, info );
|
||||
return NULL;
|
||||
return STATUS_BAD_FUNCTION_TABLE;
|
||||
}
|
||||
|
||||
if (info->frame_reg)
|
||||
|
@ -1880,7 +1924,8 @@ PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc
|
|||
TRACE("inside epilog.\n");
|
||||
interpret_epilog( (BYTE *)pc, context, ctx_ptr );
|
||||
*frame_ret = frame;
|
||||
return NULL;
|
||||
*handler_ret = NULL;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1959,11 +2004,33 @@ PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc
|
|||
context->Rsp += sizeof(ULONG64);
|
||||
}
|
||||
|
||||
if (!(info->flags & type)) return NULL; /* no matching handler */
|
||||
if (prolog_offset != ~0) return NULL; /* inside prolog */
|
||||
*handler_ret = NULL;
|
||||
|
||||
if (!(info->flags & type)) return STATUS_SUCCESS; /* no matching handler */
|
||||
if (prolog_offset != ~0) return STATUS_SUCCESS; /* inside prolog */
|
||||
|
||||
*handler_ret = (PEXCEPTION_ROUTINE)((char *)base + handler_data->handler);
|
||||
*data = &handler_data->handler + 1;
|
||||
return (PEXCEPTION_ROUTINE)((char *)base + handler_data->handler);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlVirtualUnwind (NTDLL.@)
|
||||
*/
|
||||
PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc,
|
||||
RUNTIME_FUNCTION *func, CONTEXT *context,
|
||||
PVOID *handler_data, ULONG64 *frame_ret,
|
||||
KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr )
|
||||
{
|
||||
PEXCEPTION_ROUTINE handler;
|
||||
|
||||
if (!RtlVirtualUnwind2( type, base, pc, func, context, NULL, handler_data,
|
||||
frame_ret, ctx_ptr, NULL, NULL, &handler, 0 ))
|
||||
return handler;
|
||||
|
||||
context->Rip = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue