ntdll: Implement RtlRestoreContext.
Call the consolidate frame callback before resuming. Before calling the callback, fill in ExceptionInformation[10] with the equivalent of dispatch.NonVolatileRegisters. This fixes unwinding of MSVC C++ exceptions in a lot of cases. Signed-off-by: Martin Storsjo <martin@martin.st> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
c22e8645b0
commit
6c11d1d745
|
@ -9,7 +9,7 @@
|
|||
@ stdcall -arch=arm,arm64,x86_64 RtlLookupFunctionEntry(long ptr ptr) ntdll.RtlLookupFunctionEntry
|
||||
@ stdcall RtlPcToFileHeader(ptr ptr) ntdll.RtlPcToFileHeader
|
||||
@ stdcall -norelay RtlRaiseException(ptr) ntdll.RtlRaiseException
|
||||
@ cdecl -arch=x86_64 RtlRestoreContext(ptr ptr) ntdll.RtlRestoreContext
|
||||
@ cdecl -arch=arm64,x86_64 RtlRestoreContext(ptr ptr) ntdll.RtlRestoreContext
|
||||
@ stdcall -norelay RtlUnwind(ptr ptr ptr ptr) ntdll.RtlUnwind
|
||||
@ stdcall -arch=arm64,x86_64 RtlUnwindEx(ptr ptr ptr ptr ptr ptr) ntdll.RtlUnwindEx
|
||||
@ stdcall -arch=arm64,x86_64 RtlVirtualUnwind(long long long ptr ptr ptr ptr ptr) ntdll.RtlVirtualUnwind
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
@ stdcall -arch=arm,arm64,x86_64 RtlLookupFunctionEntry(long ptr ptr) ntdll.RtlLookupFunctionEntry
|
||||
@ stdcall RtlPcToFileHeader(ptr ptr) ntdll.RtlPcToFileHeader
|
||||
@ stdcall -norelay RtlRaiseException(ptr) ntdll.RtlRaiseException
|
||||
@ cdecl -arch=x86_64 RtlRestoreContext(ptr ptr) ntdll.RtlRestoreContext
|
||||
@ cdecl -arch=arm64,x86_64 RtlRestoreContext(ptr ptr) ntdll.RtlRestoreContext
|
||||
@ stdcall -norelay RtlUnwind(ptr ptr ptr ptr) ntdll.RtlUnwind
|
||||
@ stdcall -arch=arm64,x86_64 RtlUnwindEx(ptr ptr ptr ptr ptr ptr) ntdll.RtlUnwindEx
|
||||
@ stdcall -arch=arm64,x86_64 RtlVirtualUnwind(long long long ptr ptr ptr ptr ptr) ntdll.RtlVirtualUnwind
|
||||
|
|
|
@ -913,7 +913,7 @@
|
|||
@ stdcall RtlRemoveVectoredContinueHandler(ptr)
|
||||
@ stdcall RtlRemoveVectoredExceptionHandler(ptr)
|
||||
@ stdcall RtlResetRtlTranslations(ptr)
|
||||
@ cdecl -arch=x86_64 RtlRestoreContext(ptr ptr)
|
||||
@ cdecl -arch=arm64,x86_64 RtlRestoreContext(ptr ptr)
|
||||
@ stdcall RtlRestoreLastWin32Error(long) RtlSetLastWin32Error
|
||||
@ stub RtlRevertMemoryStream
|
||||
@ stub RtlRunDecodeUnicodeString
|
||||
|
|
|
@ -69,6 +69,29 @@ WINE_DECLARE_DEBUG_CHANNEL(relay);
|
|||
|
||||
static pthread_key_t teb_key;
|
||||
|
||||
/* layering violation: the setjmp buffer is defined in msvcrt, but used by RtlUnwindEx */
|
||||
struct MSVCRT_JUMP_BUFFER
|
||||
{
|
||||
unsigned __int64 Frame;
|
||||
unsigned __int64 Reserved;
|
||||
unsigned __int64 X19;
|
||||
unsigned __int64 X20;
|
||||
unsigned __int64 X21;
|
||||
unsigned __int64 X22;
|
||||
unsigned __int64 X23;
|
||||
unsigned __int64 X24;
|
||||
unsigned __int64 X25;
|
||||
unsigned __int64 X26;
|
||||
unsigned __int64 X27;
|
||||
unsigned __int64 X28;
|
||||
unsigned __int64 Fp;
|
||||
unsigned __int64 Lr;
|
||||
unsigned __int64 Sp;
|
||||
unsigned long Fpcr;
|
||||
unsigned long Fpsr;
|
||||
double D[8];
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* signal context platform-specific definitions
|
||||
*/
|
||||
|
@ -1773,6 +1796,115 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG_PTR base, ULONG_PTR pc,
|
|||
return handler;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* call_consolidate_callback
|
||||
*
|
||||
* Wrapper function to call a consolidate callback from a fake frame.
|
||||
* If the callback executes RtlUnwindEx (like for example done in C++ handlers),
|
||||
* we have to skip all frames which were already processed. To do that we
|
||||
* trick the unwinding functions into thinking the call came from somewhere
|
||||
* else. All CFI instructions are either DW_CFA_def_cfa_expression or
|
||||
* DW_CFA_expression, and the expressions have the following format:
|
||||
*
|
||||
* DW_OP_breg29; sleb128 0x10 | Load x29 + 0x10
|
||||
* DW_OP_deref | Get *(x29 + 0x10) == context
|
||||
* DW_OP_plus_uconst; uleb128 <OFFSET> | Add offset to get struct member
|
||||
* [DW_OP_deref] | Dereference, only for CFA
|
||||
*/
|
||||
extern void * WINAPI call_consolidate_callback( CONTEXT *context,
|
||||
void *(CALLBACK *callback)(EXCEPTION_RECORD *),
|
||||
EXCEPTION_RECORD *rec,
|
||||
TEB *teb );
|
||||
__ASM_GLOBAL_FUNC( call_consolidate_callback,
|
||||
"stp x29, x30, [sp, #-0x20]!\n\t"
|
||||
__ASM_CFI(".cfi_def_cfa_offset 32\n\t")
|
||||
__ASM_CFI(".cfi_offset 29, -32\n\t")
|
||||
__ASM_CFI(".cfi_offset 30, -24\n\t")
|
||||
"mov x29, sp\n\t"
|
||||
__ASM_CFI(".cfi_def_cfa_register 29\n\t")
|
||||
"str x0, [sp, 0x10]\n\t"
|
||||
__ASM_CFI(".cfi_remember_state\n\t")
|
||||
__ASM_CFI(".cfi_escape 0x0f,0x07,0x8d,0x10,0x06,0x23,0x80,0x02,0x06\n\t") /* CFA */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x13,0x06,0x8d,0x10,0x06,0x23,0xa0,0x01\n\t") /* x19 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x14,0x06,0x8d,0x10,0x06,0x23,0xa8,0x01\n\t") /* x20 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x15,0x06,0x8d,0x10,0x06,0x23,0xb0,0x01\n\t") /* x21 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x16,0x06,0x8d,0x10,0x06,0x23,0xb8,0x01\n\t") /* x22 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x17,0x06,0x8d,0x10,0x06,0x23,0xc0,0x01\n\t") /* x23 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x18,0x06,0x8d,0x10,0x06,0x23,0xc8,0x01\n\t") /* x24 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x19,0x06,0x8d,0x10,0x06,0x23,0xd0,0x01\n\t") /* x25 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x1a,0x06,0x8d,0x10,0x06,0x23,0xd8,0x01\n\t") /* x26 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x1b,0x06,0x8d,0x10,0x06,0x23,0xe0,0x01\n\t") /* x27 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x1c,0x06,0x8d,0x10,0x06,0x23,0xe8,0x01\n\t") /* x28 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x1d,0x06,0x8d,0x10,0x06,0x23,0xf0,0x01\n\t") /* x29 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x1e,0x06,0x8d,0x10,0x06,0x23,0xf8,0x01\n\t") /* x30 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x48,0x06,0x8d,0x10,0x06,0x23,0x90,0x03\n\t") /* d8 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x49,0x06,0x8d,0x10,0x06,0x23,0xa0,0x03\n\t") /* d9 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4a,0x06,0x8d,0x10,0x06,0x23,0xb0,0x03\n\t") /* d10 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4b,0x06,0x8d,0x10,0x06,0x23,0xc0,0x03\n\t") /* d11 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4c,0x06,0x8d,0x10,0x06,0x23,0xd0,0x03\n\t") /* d12 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4d,0x06,0x8d,0x10,0x06,0x23,0xe0,0x03\n\t") /* d13 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4e,0x06,0x8d,0x10,0x06,0x23,0xf0,0x03\n\t") /* d14 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4f,0x06,0x8d,0x10,0x06,0x23,0x80,0x04\n\t") /* d15 */
|
||||
"mov x0, x2\n\t"
|
||||
"mov x18, x3\n\t"
|
||||
"blr x1\n\t"
|
||||
__ASM_CFI(".cfi_restore_state\n\t")
|
||||
"ldp x29, x30, [sp], #32\n\t"
|
||||
__ASM_CFI(".cfi_restore 30\n\t")
|
||||
__ASM_CFI(".cfi_restore 29\n\t")
|
||||
__ASM_CFI(".cfi_def_cfa 31, 0\n\t")
|
||||
"ret")
|
||||
|
||||
/*******************************************************************
|
||||
* RtlRestoreContext (NTDLL.@)
|
||||
*/
|
||||
void CDECL RtlRestoreContext( CONTEXT *context, EXCEPTION_RECORD *rec )
|
||||
{
|
||||
EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
|
||||
|
||||
if (rec && rec->ExceptionCode == STATUS_LONGJUMP && rec->NumberParameters >= 1)
|
||||
{
|
||||
struct MSVCRT_JUMP_BUFFER *jmp = (struct MSVCRT_JUMP_BUFFER *)rec->ExceptionInformation[0];
|
||||
int i;
|
||||
|
||||
context->u.s.X19 = jmp->X19;
|
||||
context->u.s.X20 = jmp->X20;
|
||||
context->u.s.X21 = jmp->X21;
|
||||
context->u.s.X22 = jmp->X22;
|
||||
context->u.s.X23 = jmp->X23;
|
||||
context->u.s.X24 = jmp->X24;
|
||||
context->u.s.X25 = jmp->X25;
|
||||
context->u.s.X26 = jmp->X26;
|
||||
context->u.s.X27 = jmp->X27;
|
||||
context->u.s.X28 = jmp->X28;
|
||||
context->u.s.Fp = jmp->Fp;
|
||||
context->u.s.Lr = jmp->Lr;
|
||||
context->Sp = jmp->Sp;
|
||||
context->Fpcr = jmp->Fpcr;
|
||||
context->Fpsr = jmp->Fpsr;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
context->V[8+i].D[0] = jmp->D[0];
|
||||
}
|
||||
else if (rec && rec->ExceptionCode == STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters >= 1)
|
||||
{
|
||||
PVOID (CALLBACK *consolidate)(EXCEPTION_RECORD *) = (void *)rec->ExceptionInformation[0];
|
||||
TRACE( "calling consolidate callback %p (rec=%p)\n", consolidate, rec );
|
||||
rec->ExceptionInformation[10] = (ULONG_PTR)&context->u.s.X19;
|
||||
|
||||
context->Pc = (ULONG64)call_consolidate_callback( context, consolidate, rec, NtCurrentTeb() );
|
||||
}
|
||||
|
||||
/* hack: remove no longer accessible TEB frames */
|
||||
while ((ULONG64)teb_frame < context->Sp)
|
||||
{
|
||||
TRACE( "removing TEB frame: %p\n", teb_frame );
|
||||
teb_frame = __wine_pop_frame( teb_frame );
|
||||
}
|
||||
|
||||
TRACE( "returning to %lx stack %lx\n", context->Pc, context->Sp );
|
||||
set_cpu_context( context );
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* RtlUnwindEx (NTDLL.@)
|
||||
|
@ -1909,7 +2041,7 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
|
|||
|
||||
context->u.s.X0 = (ULONG64)retval;
|
||||
context->Pc = (ULONG64)target_ip;
|
||||
set_cpu_context( context );
|
||||
RtlRestoreContext(context, rec);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue