ntdll: Implement RtlCaptureContext on ARM64EC.
This commit is contained in:
parent
9591a36ee8
commit
31e3c4316d
3 changed files with 142 additions and 71 deletions
|
@ -1559,12 +1559,75 @@ BOOLEAN WINAPI RtlIsEcCode( const void *ptr )
|
|||
}
|
||||
|
||||
|
||||
/* capture context information; helper for RtlCaptureContext */
|
||||
static void __attribute__((used)) capture_context( CONTEXT *context, UINT cpsr, UINT fpcr, UINT fpsr )
|
||||
{
|
||||
RUNTIME_FUNCTION *func;
|
||||
void *handler_data;
|
||||
ULONG_PTR pc, base, frame;
|
||||
CONTEXT unwind_context;
|
||||
|
||||
context->ContextFlags = CONTEXT_AMD64_FULL;
|
||||
context->EFlags = cpsr_to_eflags( cpsr );
|
||||
context->MxCsr = fpcsr_to_mxcsr( fpcr, fpsr );
|
||||
context->FltSave.ControlWord = 0x27f;
|
||||
context->FltSave.StatusWord = 0;
|
||||
context->FltSave.MxCsr = context->MxCsr;
|
||||
|
||||
/* unwind one level to get register values from caller function */
|
||||
unwind_context = *context;
|
||||
pc = context->Rip - 4;
|
||||
func = RtlLookupFunctionEntry( pc, &base, NULL );
|
||||
RtlVirtualUnwind( UNW_FLAG_NHANDLER, base, pc, func, &unwind_context, &handler_data, &frame, NULL );
|
||||
memcpy( &context->Rax, &unwind_context.Rax, offsetof(CONTEXT,FltSave) - offsetof(CONTEXT,Rax) );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* RtlCaptureContext (NTDLL.@)
|
||||
*/
|
||||
void WINAPI RtlCaptureContext( CONTEXT *context )
|
||||
void __attribute__((naked)) RtlCaptureContext( CONTEXT *context )
|
||||
{
|
||||
FIXME( "not implemented\n" );
|
||||
asm( ".seh_proc RtlCaptureContext\n\t"
|
||||
".seh_endprologue\n\t"
|
||||
"stp x8, x0, [x0, #0x78]\n\t" /* context->Rax,Rcx */
|
||||
"stp x1, x27, [x0, #0x88]\n\t" /* context->Rdx,Rbx */
|
||||
"mov x1, sp\n\t"
|
||||
"stp x1, x29, [x0, #0x98]\n\t" /* context->Rsp,Rbp */
|
||||
"stp x25, x26, [x0, #0xa8]\n\t" /* context->Rsi,Rdi */
|
||||
"stp x2, x3, [x0, #0xb8]\n\t" /* context->R8,R9 */
|
||||
"stp x4, x5, [x0, #0xc8]\n\t" /* context->R10,R11 */
|
||||
"stp x19, x20, [x0, #0xd8]\n\t" /* context->R12,R13 */
|
||||
"stp x21, x22, [x0, #0xe8]\n\t" /* context->R14,R15 */
|
||||
"str x30, [x0, #0xf8]\n\t" /* context->Rip */
|
||||
"ubfx x1, x16, #0, #16\n\t"
|
||||
"stp x30, x1, [x0, #0x120]\n\t" /* context->FloatRegisters[0] */
|
||||
"ubfx x1, x16, #16, #16\n\t"
|
||||
"stp x6, x1, [x0, #0x130]\n\t" /* context->FloatRegisters[1] */
|
||||
"ubfx x1, x16, #32, #16\n\t"
|
||||
"stp x7, x1, [x0, #0x140]\n\t" /* context->FloatRegisters[2] */
|
||||
"ubfx x1, x16, #48, #16\n\t"
|
||||
"stp x9, x1, [x0, #0x150]\n\t" /* context->FloatRegisters[3] */
|
||||
"ubfx x1, x17, #0, #16\n\t"
|
||||
"stp x10, x1, [x0, #0x160]\n\t" /* context->FloatRegisters[4] */
|
||||
"ubfx x1, x17, #16, #16\n\t"
|
||||
"stp x11, x1, [x0, #0x170]\n\t" /* context->FloatRegisters[5] */
|
||||
"ubfx x1, x17, #32, #16\n\t"
|
||||
"stp x12, x1, [x0, #0x180]\n\t" /* context->FloatRegisters[6] */
|
||||
"ubfx x1, x17, #48, #16\n\t"
|
||||
"stp x15, x1, [x0, #0x190]\n\t" /* context->FloatRegisters[7] */
|
||||
"stp q0, q1, [x0, #0x1a0]\n\t" /* context->Xmm0,Xmm1 */
|
||||
"stp q2, q3, [x0, #0x1c0]\n\t" /* context->Xmm2,Xmm3 */
|
||||
"stp q4, q5, [x0, #0x1e0]\n\t" /* context->Xmm4,Xmm5 */
|
||||
"stp q6, q7, [x0, #0x200]\n\t" /* context->Xmm6,Xmm7 */
|
||||
"stp q8, q9, [x0, #0x220]\n\t" /* context->Xmm8,Xmm9 */
|
||||
"stp q10, q11, [x0, #0x240]\n\t" /* context->Xmm10,Xmm11 */
|
||||
"stp q12, q13, [x0, #0x260]\n\t" /* context->Xmm12,Xmm13 */
|
||||
"stp q14, q15, [x0, #0x280]\n\t" /* context->Xmm14,Xmm15 */
|
||||
"mrs x1, nzcv\n\t"
|
||||
"mrs x2, fpcr\n\t"
|
||||
"mrs x3, fpsr\n\t"
|
||||
"b capture_context\n\t"
|
||||
".seh_endproc" );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
|
@ -110,38 +111,6 @@ static void (WINAPI *pRtlGetUnloadEventTraceEx)(ULONG **element_size, ULONG **el
|
|||
#endif
|
||||
|
||||
#if defined(__x86_64__)
|
||||
typedef struct _SETJMP_FLOAT128
|
||||
{
|
||||
unsigned __int64 DECLSPEC_ALIGN(16) Part[2];
|
||||
} SETJMP_FLOAT128;
|
||||
|
||||
typedef struct _JUMP_BUFFER
|
||||
{
|
||||
unsigned __int64 Frame;
|
||||
unsigned __int64 Rbx;
|
||||
unsigned __int64 Rsp;
|
||||
unsigned __int64 Rbp;
|
||||
unsigned __int64 Rsi;
|
||||
unsigned __int64 Rdi;
|
||||
unsigned __int64 R12;
|
||||
unsigned __int64 R13;
|
||||
unsigned __int64 R14;
|
||||
unsigned __int64 R15;
|
||||
unsigned __int64 Rip;
|
||||
unsigned long MxCsr;
|
||||
unsigned short FpCsr;
|
||||
unsigned short Spare;
|
||||
SETJMP_FLOAT128 Xmm6;
|
||||
SETJMP_FLOAT128 Xmm7;
|
||||
SETJMP_FLOAT128 Xmm8;
|
||||
SETJMP_FLOAT128 Xmm9;
|
||||
SETJMP_FLOAT128 Xmm10;
|
||||
SETJMP_FLOAT128 Xmm11;
|
||||
SETJMP_FLOAT128 Xmm12;
|
||||
SETJMP_FLOAT128 Xmm13;
|
||||
SETJMP_FLOAT128 Xmm14;
|
||||
SETJMP_FLOAT128 Xmm15;
|
||||
} _JUMP_BUFFER;
|
||||
|
||||
typedef union _UNWIND_CODE
|
||||
{
|
||||
|
@ -173,12 +142,14 @@ typedef struct _UNWIND_INFO
|
|||
*/
|
||||
} UNWIND_INFO;
|
||||
|
||||
static BOOL is_arm64ec;
|
||||
|
||||
static EXCEPTION_DISPOSITION (WINAPI *p__C_specific_handler)(EXCEPTION_RECORD*, ULONG64, CONTEXT*, DISPATCHER_CONTEXT*);
|
||||
static VOID (WINAPI *pRtlCaptureContext)(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*);
|
||||
static NTSTATUS (WINAPI *pRtlGetNativeSystemInformation)(SYSTEM_INFORMATION_CLASS,void*,ULONG,ULONG*);
|
||||
static int (CDECL *p_setjmp)(_JUMP_BUFFER*);
|
||||
#endif
|
||||
|
||||
|
@ -3745,34 +3716,53 @@ static void test_thread_context(void)
|
|||
memset( &expect, 0xcc, sizeof(expect) );
|
||||
func_ptr( &context, 0, &expect, pRtlCaptureContext );
|
||||
|
||||
ok( context.ContextFlags == (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT),
|
||||
"wrong flags %08lx\n", context.ContextFlags );
|
||||
COMPARE( Rax );
|
||||
if (is_arm64ec)
|
||||
{
|
||||
ok( context.ContextFlags == (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT),
|
||||
"wrong flags %08lx\n", context.ContextFlags );
|
||||
ok( (context.EFlags & ~0xc5) == (expect.EFlags & ~0xc5), "wrong EFlags %lx / %I64x\n",
|
||||
context.EFlags, expect.EFlags );
|
||||
ok( context.SegCs == 0xcccc, "wrong SegCs %x\n", context.SegCs);
|
||||
ok( context.SegDs == 0xcccc, "wrong SegDs %x\n", context.SegDs);
|
||||
ok( context.SegEs == 0xcccc, "wrong SegEs %x\n", context.SegEs);
|
||||
ok( context.SegFs == 0xcccc, "wrong SegFs %x\n", context.SegFs);
|
||||
ok( context.SegGs == 0xcccc, "wrong SegGs %x\n", context.SegGs);
|
||||
ok( context.SegSs == 0xcccc, "wrong SegSs %x\n", context.SegSs);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( context.ContextFlags == (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT),
|
||||
"wrong flags %08lx\n", context.ContextFlags );
|
||||
COMPARE( Rax );
|
||||
COMPARE( Rcx );
|
||||
COMPARE( Rdx );
|
||||
COMPARE( R8 );
|
||||
COMPARE( R9 );
|
||||
COMPARE( R10 );
|
||||
COMPARE( R11 );
|
||||
COMPARE( EFlags );
|
||||
COMPARE( SegCs );
|
||||
COMPARE( SegDs );
|
||||
COMPARE( SegEs );
|
||||
COMPARE( SegFs );
|
||||
COMPARE( SegGs );
|
||||
COMPARE( SegSs );
|
||||
ok( !memcmp( &context.FltSave, &expect.FltSave, offsetof( XMM_SAVE_AREA32, XmmRegisters )),
|
||||
"wrong FltSave\n" );
|
||||
}
|
||||
COMPARE( Rbx );
|
||||
COMPARE( Rcx );
|
||||
COMPARE( Rdx );
|
||||
COMPARE( Rsi );
|
||||
COMPARE( Rdi );
|
||||
COMPARE( R8 );
|
||||
COMPARE( R9 );
|
||||
COMPARE( R10 );
|
||||
COMPARE( R11 );
|
||||
COMPARE( R12 );
|
||||
COMPARE( R13 );
|
||||
COMPARE( R14 );
|
||||
COMPARE( R15 );
|
||||
COMPARE( Rbp );
|
||||
COMPARE( Rsp );
|
||||
COMPARE( EFlags );
|
||||
COMPARE( MxCsr );
|
||||
COMPARE( SegCs );
|
||||
COMPARE( SegDs );
|
||||
COMPARE( SegEs );
|
||||
COMPARE( SegFs );
|
||||
COMPARE( SegGs );
|
||||
COMPARE( SegSs );
|
||||
ok( !memcmp( &context.FltSave, &expect.FltSave, offsetof( XMM_SAVE_AREA32, XmmRegisters )),
|
||||
"wrong FltSave\n" );
|
||||
COMPARE( FltSave.MxCsr );
|
||||
COMPARE( FltSave.ControlWord );
|
||||
COMPARE( FltSave.StatusWord );
|
||||
for (i = 0; i < 16; i++)
|
||||
ok( !memcmp( &context.Xmm0 + i, &expect.FltSave.XmmRegisters[i], sizeof(context.Xmm0) ),
|
||||
"wrong xmm%u\n", i );
|
||||
|
@ -3786,15 +3776,32 @@ static void test_thread_context(void)
|
|||
|
||||
status = func_ptr( GetCurrentThread(), &context, &expect, pNtGetContextThread );
|
||||
ok( status == STATUS_SUCCESS, "NtGetContextThread failed %08lx\n", status );
|
||||
/* other registers are not preserved */
|
||||
COMPARE( Rbx );
|
||||
COMPARE( Rsi );
|
||||
COMPARE( Rdi );
|
||||
COMPARE( R12 );
|
||||
COMPARE( R13 );
|
||||
COMPARE( R14 );
|
||||
COMPARE( R15 );
|
||||
COMPARE( Rbp );
|
||||
|
||||
if (is_arm64ec)
|
||||
{
|
||||
/* Rsp is the stack upon entry to the ARM64 NtGetContextThread syscall */
|
||||
ok( context.Rsp <= expect.Rsp - sizeof(ARM64_NT_CONTEXT) && context.Rsp >= expect.Rsp - 0x1000,
|
||||
"wrong Rsp %p/%p\n", (void *)context.Rsp, (void *)expect.Rsp );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* other registers are not preserved */
|
||||
COMPARE( Rbx );
|
||||
COMPARE( Rsi );
|
||||
COMPARE( Rdi );
|
||||
COMPARE( R12 );
|
||||
COMPARE( R13 );
|
||||
COMPARE( R14 );
|
||||
COMPARE( R15 );
|
||||
COMPARE( Rbp );
|
||||
/* Rsp is the stack upon entry to NtGetContextThread */
|
||||
ok( context.Rsp == expect.Rsp - 8,
|
||||
"wrong Rsp %p/%p\n", (void *)context.Rsp, (void *)expect.Rsp );
|
||||
/* Rip is somewhere close to the NtGetContextThread implementation */
|
||||
ok( (char *)context.Rip >= (char *)pNtGetContextThread - 0x40000 &&
|
||||
(char *)context.Rip <= (char *)pNtGetContextThread + 0x40000,
|
||||
"wrong Rip %p/%p\n", (void *)context.Rip, (void *)pNtGetContextThread );
|
||||
}
|
||||
COMPARE( MxCsr );
|
||||
COMPARE( SegCs );
|
||||
COMPARE( SegDs );
|
||||
|
@ -3812,13 +3819,6 @@ static void test_thread_context(void)
|
|||
for (i = 6; i < 16; i++)
|
||||
ok( !memcmp( &context.Xmm0 + i, &expect.FltSave.XmmRegisters[i], sizeof(context.Xmm0) ),
|
||||
"wrong xmm%u\n", i );
|
||||
/* Rsp is the stack upon entry to NtGetContextThread */
|
||||
ok( context.Rsp == expect.Rsp - 8,
|
||||
"wrong Rsp %p/%p\n", (void *)context.Rsp, (void *)expect.Rsp );
|
||||
/* Rip is somewhere close to the NtGetContextThread implementation */
|
||||
ok( (char *)context.Rip >= (char *)pNtGetContextThread - 0x40000 &&
|
||||
(char *)context.Rip <= (char *)pNtGetContextThread + 0x40000,
|
||||
"wrong Rip %p/%p\n", (void *)context.Rip, (void *)pNtGetContextThread );
|
||||
#undef COMPARE
|
||||
}
|
||||
|
||||
|
@ -10116,14 +10116,22 @@ START_TEST(exception)
|
|||
|
||||
#define X(f) p##f = (void*)GetProcAddress(hntdll, #f)
|
||||
X(__C_specific_handler);
|
||||
X(RtlCaptureContext);
|
||||
X(RtlRestoreContext);
|
||||
X(RtlWow64GetThreadContext);
|
||||
X(RtlWow64SetThreadContext);
|
||||
X(RtlWow64GetCpuAreaInfo);
|
||||
X(RtlGetNativeSystemInformation);
|
||||
#undef X
|
||||
p_setjmp = (void *)GetProcAddress( hmsvcrt, "_setjmp" );
|
||||
|
||||
if (pRtlGetNativeSystemInformation)
|
||||
{
|
||||
SYSTEM_CPU_INFORMATION info;
|
||||
ULONG len;
|
||||
if (!pRtlGetNativeSystemInformation( SystemCpuInformation, &info, sizeof(info), &len ))
|
||||
is_arm64ec = (info.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64);
|
||||
}
|
||||
|
||||
test_exceptions();
|
||||
test_rtlraiseexception();
|
||||
test_debug_registers();
|
||||
|
|
|
@ -63,7 +63,7 @@ static inline UINT eflags_to_cpsr( UINT eflags )
|
|||
|
||||
static inline UINT cpsr_to_eflags( UINT cpsr )
|
||||
{
|
||||
UINT ret = 0;
|
||||
UINT ret = 0x202;
|
||||
|
||||
if (cpsr & 0x10000000) ret |= 0x0800; /* overflow */
|
||||
if (cpsr & 0x20000000) ret |= 0x0001; /* carry */
|
||||
|
|
Loading…
Add table
Reference in a new issue