ntdll: Port the RtlRestoreContext test to ARM64.
This commit is contained in:
parent
5286ed3b0a
commit
74d1dbb95a
2 changed files with 223 additions and 74 deletions
|
@ -378,81 +378,41 @@ __ASM_GLOBAL_FUNC( KiUserCallbackDispatcher,
|
|||
|
||||
|
||||
/**********************************************************************
|
||||
* call_consolidate_callback
|
||||
* 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_breg31; sleb128 <OFFSET> | Load x31 + struct member offset
|
||||
* [DW_OP_deref] | Dereference, only for CFA
|
||||
* else.
|
||||
*/
|
||||
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, #-0x30]!\n\t"
|
||||
__ASM_CFI(".cfi_def_cfa_offset 48\n\t")
|
||||
__ASM_CFI(".cfi_offset 29, -48\n\t")
|
||||
__ASM_CFI(".cfi_offset 30, -40\n\t")
|
||||
__ASM_SEH(".seh_nop\n\t")
|
||||
"stp x1, x2, [sp, #0x10]\n\t"
|
||||
__ASM_SEH(".seh_nop\n\t")
|
||||
"str x3, [sp, #0x20]\n\t"
|
||||
__ASM_SEH(".seh_nop\n\t")
|
||||
"mov x29, sp\n\t"
|
||||
__ASM_CFI(".cfi_def_cfa_register 29\n\t")
|
||||
__ASM_SEH(".seh_nop\n\t")
|
||||
__ASM_CFI(".cfi_remember_state\n\t")
|
||||
/* Memcpy the context onto the stack */
|
||||
void WINAPI DECLSPEC_NORETURN consolidate_callback( CONTEXT *context,
|
||||
void *(CALLBACK *callback)(EXCEPTION_RECORD *),
|
||||
EXCEPTION_RECORD *rec );
|
||||
__ASM_GLOBAL_FUNC( consolidate_callback,
|
||||
"stp x29, x30, [sp, #-16]!\n\t"
|
||||
".seh_save_fplr_x 16\n\t"
|
||||
"sub sp, sp, #0x390\n\t"
|
||||
__ASM_SEH(".seh_nop\n\t")
|
||||
"mov x1, x0\n\t"
|
||||
__ASM_SEH(".seh_nop\n\t")
|
||||
"mov x0, sp\n\t"
|
||||
__ASM_SEH(".seh_nop\n\t")
|
||||
"mov x2, #0x390\n\t"
|
||||
__ASM_SEH(".seh_nop\n\t")
|
||||
"bl " __ASM_NAME("memcpy") "\n\t"
|
||||
__ASM_CFI(".cfi_def_cfa 31, 0\n\t")
|
||||
__ASM_CFI(".cfi_escape 0x0f,0x04,0x8f,0x80,0x02,0x06\n\t") /* CFA, DW_OP_breg31 + 0x100, DW_OP_deref */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x13,0x03,0x8f,0xa0,0x01\n\t") /* x19, DW_OP_breg31 + 0xA0 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x14,0x03,0x8f,0xa8,0x01\n\t") /* x20 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x15,0x03,0x8f,0xb0,0x01\n\t") /* x21 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x16,0x03,0x8f,0xb8,0x01\n\t") /* x22 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x17,0x03,0x8f,0xc0,0x01\n\t") /* x23 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x18,0x03,0x8f,0xc8,0x01\n\t") /* x24 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x19,0x03,0x8f,0xd0,0x01\n\t") /* x25 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x1a,0x03,0x8f,0xd8,0x01\n\t") /* x26 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x1b,0x03,0x8f,0xe0,0x01\n\t") /* x27 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x1c,0x03,0x8f,0xe8,0x01\n\t") /* x28 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x1d,0x03,0x8f,0xf0,0x01\n\t") /* x29 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x1e,0x03,0x8f,0xf8,0x01\n\t") /* x30 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x48,0x03,0x8f,0x90,0x03\n\t") /* d8 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x49,0x03,0x8f,0x98,0x03\n\t") /* d9 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4a,0x03,0x8f,0xa0,0x03\n\t") /* d10 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4b,0x03,0x8f,0xa8,0x03\n\t") /* d11 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4c,0x03,0x8f,0xb0,0x03\n\t") /* d12 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4d,0x03,0x8f,0xb8,0x03\n\t") /* d13 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4e,0x03,0x8f,0xc0,0x03\n\t") /* d14 */
|
||||
__ASM_CFI(".cfi_escape 0x10,0x4f,0x03,0x8f,0xc8,0x03\n\t") /* d15 */
|
||||
__ASM_SEH(".seh_context\n\t")
|
||||
__ASM_SEH(".seh_endprologue\n\t")
|
||||
"ldp x1, x2, [x29, #0x10]\n\t"
|
||||
"ldr x18, [x29, #0x20]\n\t"
|
||||
"mov x0, x2\n\t"
|
||||
".seh_stackalloc 0x390\n\t"
|
||||
".seh_endprologue\n\t"
|
||||
"mov x4, sp\n\t"
|
||||
/* copy the context onto the stack */
|
||||
"mov x5, #0x390/16\n"
|
||||
"1:\tldp x6, x7, [x0], #16\n\t"
|
||||
"stp x6, x7, [x4], #16\n\t"
|
||||
"subs x5, x5, #1\n\t"
|
||||
"b.ne 1b\n\t"
|
||||
"mov x0, x2\n\t"
|
||||
"b invoke_callback" )
|
||||
__ASM_GLOBAL_FUNC( invoke_callback,
|
||||
".seh_context\n\t"
|
||||
".seh_endprologue\n\t"
|
||||
"blr x1\n\t"
|
||||
"mov sp, x29\n\t"
|
||||
__ASM_CFI(".cfi_restore_state\n\t")
|
||||
"ldp x29, x30, [sp], #48\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")
|
||||
"str x0, [sp, #0x108]\n\t" /* context->Pc */
|
||||
"mov x0, sp\n\t"
|
||||
"mov w1, #0\n\t"
|
||||
"b NtContinue" )
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* RtlRestoreContext (NTDLL.@)
|
||||
|
@ -477,7 +437,7 @@ void CDECL RtlRestoreContext( CONTEXT *context, EXCEPTION_RECORD *rec )
|
|||
context->X27 = jmp->X27;
|
||||
context->X28 = jmp->X28;
|
||||
context->Fp = jmp->Fp;
|
||||
context->Lr = jmp->Lr;
|
||||
context->Pc = jmp->Lr;
|
||||
context->Sp = jmp->Sp;
|
||||
context->Fpcr = jmp->Fpcr;
|
||||
context->Fpsr = jmp->Fpsr;
|
||||
|
@ -489,9 +449,7 @@ void CDECL RtlRestoreContext( CONTEXT *context, EXCEPTION_RECORD *rec )
|
|||
{
|
||||
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->X19;
|
||||
|
||||
context->Pc = (ULONG64)call_consolidate_callback( context, consolidate, rec, NtCurrentTeb() );
|
||||
consolidate_callback( context, consolidate, rec );
|
||||
}
|
||||
|
||||
/* hack: remove no longer accessible TEB frames */
|
||||
|
@ -635,8 +593,12 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
|
|||
*context = new_context;
|
||||
}
|
||||
|
||||
if (rec->ExceptionCode != STATUS_UNWIND_CONSOLIDATE)
|
||||
context->Pc = (ULONG64)target_ip;
|
||||
else if (rec->ExceptionInformation[10] == -1)
|
||||
rec->ExceptionInformation[10] = (ULONG_PTR)&nonvol_regs;
|
||||
|
||||
context->X0 = (ULONG64)retval;
|
||||
context->Pc = (ULONG64)target_ip;
|
||||
RtlRestoreContext(context, rec);
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ static BOOL (WINAPI *pWaitForDebugEventEx)(DEBUG_EVENT *, DWORD);
|
|||
static VOID (WINAPI *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, CONTEXT*, UNWIND_HISTORY_TABLE*);
|
||||
static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
|
||||
static BOOLEAN (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
|
||||
static VOID (CDECL *pRtlRestoreContext)(CONTEXT*, EXCEPTION_RECORD*);
|
||||
#endif
|
||||
|
||||
static void *pKiUserApcDispatcher;
|
||||
|
@ -142,7 +143,6 @@ typedef struct _UNWIND_INFO
|
|||
static BOOL is_arm64ec;
|
||||
|
||||
static EXCEPTION_DISPOSITION (WINAPI *p__C_specific_handler)(EXCEPTION_RECORD*, ULONG64, CONTEXT*, DISPATCHER_CONTEXT*);
|
||||
static VOID (CDECL *pRtlRestoreContext)(CONTEXT*, EXCEPTION_RECORD*);
|
||||
static NTSTATUS (WINAPI *pRtlWow64GetThreadContext)(HANDLE, WOW64_CONTEXT *);
|
||||
static NTSTATUS (WINAPI *pRtlWow64SetThreadContext)(HANDLE, const WOW64_CONTEXT *);
|
||||
static NTSTATUS (WINAPI *pRtlWow64GetCpuAreaInfo)(WOW64_CPURESERVED*,ULONG,WOW64_CPU_AREA_INFO*);
|
||||
|
@ -7324,6 +7324,192 @@ static void test_rtlraiseexception(void)
|
|||
run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE);
|
||||
}
|
||||
|
||||
|
||||
static LONG consolidate_dummy_called;
|
||||
static LONG pass;
|
||||
|
||||
static const DWORD call_rtlunwind[] =
|
||||
{
|
||||
0xa88150f3, /* stp x19, x20, [x7], #0x10 */
|
||||
0xa88158f5, /* stp x21, x22, [x7], #0x10 */
|
||||
0xa88160f7, /* stp x23, x24, [x7], #0x10 */
|
||||
0xa88168f9, /* stp x25, x26, [x7], #0x10 */
|
||||
0xa88170fb, /* stp x27, x28, [x7], #0x10 */
|
||||
0xf80084fd, /* str x29, [x7], #0x8 */
|
||||
0x6c8124e8, /* stp d8, d9, [x7], #0x10 */
|
||||
0x6c812cea, /* stp d10, d11, [x7], #0x10 */
|
||||
0x6c8134ec, /* stp d12, d13, [x7], #0x10 */
|
||||
0x6c813cee, /* stp d14, d15, [x7], #0x10 */
|
||||
0xd61f00c0, /* br x6 */
|
||||
};
|
||||
|
||||
static PVOID CALLBACK test_consolidate_dummy(EXCEPTION_RECORD *rec)
|
||||
{
|
||||
CONTEXT *ctx = (CONTEXT *)rec->ExceptionInformation[1];
|
||||
DWORD64 *saved_regs = (DWORD64 *)rec->ExceptionInformation[3];
|
||||
DISPATCHER_CONTEXT_NONVOLREG_ARM64 *regs;
|
||||
int i;
|
||||
|
||||
switch (InterlockedIncrement(&consolidate_dummy_called))
|
||||
{
|
||||
case 1: /* RtlRestoreContext */
|
||||
ok(ctx->Pc == 0xdeadbeef, "RtlRestoreContext wrong Pc, expected: 0xdeadbeef, got: %Ix\n", ctx->Pc);
|
||||
ok( rec->ExceptionInformation[10] == -1, "wrong info %Ix\n", rec->ExceptionInformation[10] );
|
||||
break;
|
||||
case 2: /* RtlUnwindEx */
|
||||
ok(ctx->Pc != 0xdeadbeef, "RtlUnwindEx wrong Pc, got: %Ix\n", ctx->Pc );
|
||||
ok( rec->ExceptionInformation[10] != -1, "wrong info %Ix\n", rec->ExceptionInformation[10] );
|
||||
regs = (DISPATCHER_CONTEXT_NONVOLREG_ARM64 *)rec->ExceptionInformation[10];
|
||||
for (i = 0; i < 11; i++)
|
||||
ok( saved_regs[i] == regs->GpNvRegs[i], "wrong reg X%u, expected: %Ix, got: %Ix\n",
|
||||
19 + i, saved_regs[i], regs->GpNvRegs[i] );
|
||||
for (i = 0; i < 8; i++)
|
||||
ok( saved_regs[i + 11] == *(DWORD64 *)®s->FpNvRegs[i],
|
||||
"wrong reg D%u, expected: %Ix, got: %Ix\n",
|
||||
i + 8, saved_regs[i + 11], *(DWORD64 *)®s->FpNvRegs[i] );
|
||||
break;
|
||||
}
|
||||
return (PVOID)rec->ExceptionInformation[2];
|
||||
}
|
||||
|
||||
static void test_restore_context(void)
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
_JUMP_BUFFER buf;
|
||||
CONTEXT ctx;
|
||||
int i;
|
||||
|
||||
if (!pRtlUnwindEx || !pRtlRestoreContext || !pRtlCaptureContext)
|
||||
{
|
||||
skip("RtlUnwindEx/RtlCaptureContext/RtlRestoreContext not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* test simple case of capture and restore context */
|
||||
pass = 0;
|
||||
InterlockedIncrement(&pass); /* interlocked to prevent compiler from moving after capture */
|
||||
pRtlCaptureContext(&ctx);
|
||||
if (InterlockedIncrement(&pass) == 2) /* interlocked to prevent compiler from moving before capture */
|
||||
{
|
||||
pRtlRestoreContext(&ctx, NULL);
|
||||
ok(0, "shouldn't be reached\n");
|
||||
}
|
||||
else
|
||||
ok(pass < 4, "unexpected pass %ld\n", pass);
|
||||
|
||||
/* test with jmp using RtlRestoreContext */
|
||||
pass = 0;
|
||||
InterlockedIncrement(&pass);
|
||||
RtlCaptureContext(&ctx);
|
||||
InterlockedIncrement(&pass); /* only called once */
|
||||
setjmp((_JBTYPE *)&buf);
|
||||
InterlockedIncrement(&pass);
|
||||
if (pass == 3)
|
||||
{
|
||||
rec.ExceptionCode = STATUS_LONGJUMP;
|
||||
rec.NumberParameters = 1;
|
||||
rec.ExceptionInformation[0] = (DWORD64)&buf;
|
||||
/* uses buf.Pc instead of ctx.Pc */
|
||||
pRtlRestoreContext(&ctx, &rec);
|
||||
ok(0, "shouldn't be reached\n");
|
||||
}
|
||||
else if (pass == 4)
|
||||
{
|
||||
ok(buf.X19 == ctx.X19, "longjmp failed for X19, expected: %Ix, got: %Ix\n", buf.X19, ctx.X19);
|
||||
ok(buf.X20 == ctx.X20, "longjmp failed for X20, expected: %Ix, got: %Ix\n", buf.X20, ctx.X20);
|
||||
ok(buf.X21 == ctx.X21, "longjmp failed for X21, expected: %Ix, got: %Ix\n", buf.X21, ctx.X21);
|
||||
ok(buf.X22 == ctx.X22, "longjmp failed for X22, expected: %Ix, got: %Ix\n", buf.X22, ctx.X22);
|
||||
ok(buf.X23 == ctx.X23, "longjmp failed for X23, expected: %Ix, got: %Ix\n", buf.X23, ctx.X23);
|
||||
ok(buf.X24 == ctx.X24, "longjmp failed for X24, expected: %Ix, got: %Ix\n", buf.X24, ctx.X24);
|
||||
ok(buf.X25 == ctx.X25, "longjmp failed for X25, expected: %Ix, got: %Ix\n", buf.X25, ctx.X25);
|
||||
ok(buf.X26 == ctx.X26, "longjmp failed for X26, expected: %Ix, got: %Ix\n", buf.X26, ctx.X26);
|
||||
ok(buf.X27 == ctx.X27, "longjmp failed for X27, expected: %Ix, got: %Ix\n", buf.X27, ctx.X27);
|
||||
ok(buf.X28 == ctx.X28, "longjmp failed for X28, expected: %Ix, got: %Ix\n", buf.X28, ctx.X28);
|
||||
ok(buf.Fp == ctx.Fp, "longjmp failed for Fp, expected: %Ix, got: %Ix\n", buf.Fp, ctx.Fp);
|
||||
for (i = 0; i < 8; i++)
|
||||
ok(buf.D[i] == ctx.V[i + 8].D[0], "longjmp failed for D%u, expected: %g, got: %g\n",
|
||||
i + 8, buf.D[i], ctx.V[i + 8].D[0]);
|
||||
pRtlRestoreContext(&ctx, &rec);
|
||||
ok(0, "shouldn't be reached\n");
|
||||
}
|
||||
else
|
||||
ok(pass == 5, "unexpected pass %ld\n", pass);
|
||||
|
||||
/* test with jmp through RtlUnwindEx */
|
||||
pass = 0;
|
||||
InterlockedIncrement(&pass);
|
||||
pRtlCaptureContext(&ctx);
|
||||
InterlockedIncrement(&pass); /* only called once */
|
||||
setjmp((_JBTYPE *)&buf);
|
||||
InterlockedIncrement(&pass);
|
||||
if (pass == 3)
|
||||
{
|
||||
rec.ExceptionCode = STATUS_LONGJUMP;
|
||||
rec.NumberParameters = 1;
|
||||
rec.ExceptionInformation[0] = (DWORD64)&buf;
|
||||
|
||||
/* uses buf.Pc instead of bogus 0xdeadbeef */
|
||||
pRtlUnwindEx((void*)buf.Sp, (void*)0xdeadbeef, &rec, NULL, &ctx, NULL);
|
||||
ok(0, "shouldn't be reached\n");
|
||||
}
|
||||
else
|
||||
ok(pass == 4, "unexpected pass %ld\n", pass);
|
||||
|
||||
|
||||
/* test with consolidate */
|
||||
pass = 0;
|
||||
InterlockedIncrement(&pass);
|
||||
RtlCaptureContext(&ctx);
|
||||
InterlockedIncrement(&pass);
|
||||
if (pass == 2)
|
||||
{
|
||||
rec.ExceptionCode = STATUS_UNWIND_CONSOLIDATE;
|
||||
rec.NumberParameters = 3;
|
||||
rec.ExceptionInformation[0] = (DWORD64)test_consolidate_dummy;
|
||||
rec.ExceptionInformation[1] = (DWORD64)&ctx;
|
||||
rec.ExceptionInformation[2] = ctx.Pc;
|
||||
rec.ExceptionInformation[10] = -1;
|
||||
ctx.Pc = 0xdeadbeef;
|
||||
|
||||
pRtlRestoreContext(&ctx, &rec);
|
||||
ok(0, "shouldn't be reached\n");
|
||||
}
|
||||
else if (pass == 3)
|
||||
ok(consolidate_dummy_called == 1, "test_consolidate_dummy not called\n");
|
||||
else
|
||||
ok(0, "unexpected pass %ld\n", pass);
|
||||
|
||||
/* test with consolidate through RtlUnwindEx */
|
||||
pass = 0;
|
||||
InterlockedIncrement(&pass);
|
||||
pRtlCaptureContext(&ctx);
|
||||
InterlockedIncrement(&pass);
|
||||
setjmp((_JBTYPE *)&buf);
|
||||
if (pass == 2)
|
||||
{
|
||||
void (*func)(DWORD64,DWORD64,EXCEPTION_RECORD*,DWORD64,CONTEXT*,void*,void*,void*) = code_mem;
|
||||
DWORD64 nonvol_regs[19];
|
||||
|
||||
rec.ExceptionCode = STATUS_UNWIND_CONSOLIDATE;
|
||||
rec.NumberParameters = 4;
|
||||
rec.ExceptionInformation[0] = (DWORD64)test_consolidate_dummy;
|
||||
rec.ExceptionInformation[1] = (DWORD64)&ctx;
|
||||
rec.ExceptionInformation[2] = ctx.Pc;
|
||||
rec.ExceptionInformation[3] = (DWORD64)nonvol_regs;
|
||||
rec.ExceptionInformation[10] = -1; /* otherwise it doesn't get set */
|
||||
ctx.Pc = 0xdeadbeef;
|
||||
/* uses consolidate callback Pc instead of bogus 0xdeadbeef */
|
||||
memcpy( code_mem, call_rtlunwind, sizeof(call_rtlunwind) );
|
||||
FlushInstructionCache( GetCurrentProcess(), code_mem, sizeof(call_rtlunwind) );
|
||||
func( buf.Frame, 0xdeadbeef, &rec, 0, &ctx, NULL, pRtlUnwindEx, nonvol_regs );
|
||||
ok(0, "shouldn't be reached\n");
|
||||
}
|
||||
else if (pass == 3)
|
||||
ok(consolidate_dummy_called == 2, "test_consolidate_dummy not called\n");
|
||||
else
|
||||
ok(0, "unexpected pass %ld\n", pass);
|
||||
}
|
||||
|
||||
#endif /* __aarch64__ */
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
|
@ -10428,6 +10614,7 @@ START_TEST(exception)
|
|||
X(KiUserCallbackDispatcher);
|
||||
X(KiUserExceptionDispatcher);
|
||||
#ifndef __i386__
|
||||
X(RtlRestoreContext);
|
||||
X(RtlUnwindEx);
|
||||
X(RtlAddFunctionTable);
|
||||
X(RtlDeleteFunctionTable);
|
||||
|
@ -10559,7 +10746,6 @@ START_TEST(exception)
|
|||
|
||||
#define X(f) p##f = (void*)GetProcAddress(hntdll, #f)
|
||||
X(__C_specific_handler);
|
||||
X(RtlRestoreContext);
|
||||
X(RtlWow64GetThreadContext);
|
||||
X(RtlWow64SetThreadContext);
|
||||
X(RtlWow64GetCpuAreaInfo);
|
||||
|
@ -10599,6 +10785,7 @@ START_TEST(exception)
|
|||
test_continue();
|
||||
test_nested_exception();
|
||||
test_collided_unwind();
|
||||
test_restore_context();
|
||||
|
||||
#elif defined(__arm__)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue