kernel32: Implement CopyContext().

Signed-off-by: Paul Gofman <pgofman@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Paul Gofman 2020-09-01 12:21:45 +03:00 committed by Alexandre Julliard
parent 85a33ff731
commit 81a08cea79
11 changed files with 512 additions and 6 deletions

View File

@ -1,4 +1,4 @@
@ stub RtlCopyExtendedContext
@ stdcall RtlCopyExtendedContext(ptr long ptr) ntdll.RtlCopyExtendedContext
@ stdcall RtlGetEnabledExtendedFeatures(int64) ntdll.RtlGetEnabledExtendedFeatures
@ stdcall RtlGetExtendedContextLength(long ptr) ntdll.RtlGetExtendedContextLength
@ stdcall -ret64 RtlGetExtendedFeaturesMask(ptr) ntdll.RtlGetExtendedFeaturesMask

View File

@ -1,4 +1,4 @@
@ stub CopyContext
@ stdcall -arch=i386,x86_64 CopyContext(ptr long ptr) kernel32.CopyContext
@ stdcall -ret64 -arch=i386,x86_64 GetEnabledXStateFeatures() kernel32.GetEnabledXStateFeatures
@ stdcall -arch=i386,x86_64 GetXStateFeaturesMask(ptr ptr) kernel32.GetXStateFeaturesMask
@ stdcall -arch=i386,x86_64 InitializeContext(ptr long ptr ptr) kernel32.InitializeContext

View File

@ -256,7 +256,7 @@
@ stdcall -import ConvertThreadToFiber(ptr)
@ stdcall -import ConvertThreadToFiberEx(ptr long)
@ stdcall ConvertToGlobalHandle(long)
# @ stub CopyContext
@ stdcall -import -arch=i386,x86_64 CopyContext(ptr long ptr)
@ stdcall CopyFileA(str str long)
@ stdcall CopyFileExA (str str ptr ptr ptr long)
@ stdcall -import CopyFileExW(wstr wstr ptr ptr ptr long)

View File

@ -165,7 +165,7 @@
@ stdcall ConvertThreadToFiber(ptr)
@ stdcall ConvertThreadToFiberEx(ptr long)
@ stdcall ConvertToAutoInheritPrivateObjectSecurity(ptr ptr ptr ptr long ptr)
# @ stub CopyContext
@ stdcall -arch=i386,x86_64 CopyContext(ptr long ptr)
# @ stub CopyFile2
@ stdcall CopyFileExW(wstr wstr ptr ptr ptr long)
@ stdcall CopyFileW(wstr wstr long)

View File

@ -1233,6 +1233,62 @@ BOOL WINAPI InitializeContext( void *buffer, DWORD context_flags, CONTEXT **cont
{
return InitializeContext2( buffer, context_flags, context, length, ~(ULONG64)0 );
}
/***********************************************************************
* CopyContext (kernelbase.@)
*/
BOOL WINAPI CopyContext( CONTEXT *dst, DWORD context_flags, CONTEXT *src )
{
DWORD context_size, arch_flag, flags_offset, dst_flags, src_flags;
static const DWORD arch_mask = 0x110000;
NTSTATUS status;
BYTE *d, *s;
TRACE("dst %p, context_flags %#x, src %p.\n", dst, context_flags, src);
if (context_flags & 0x40 && !RtlGetEnabledExtendedFeatures( ~(ULONG64)0 ))
{
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
arch_flag = context_flags & arch_mask;
switch (arch_flag)
{
case 0x10000: context_size = 0x2cc; flags_offset = 0; break;
case 0x100000: context_size = 0x4d0; flags_offset = 0x30; break;
default:
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
d = (BYTE *)dst;
s = (BYTE *)src;
dst_flags = *(DWORD *)(d + flags_offset);
src_flags = *(DWORD *)(s + flags_offset);
if ((dst_flags & arch_mask) != arch_flag
|| (src_flags & arch_mask) != arch_flag)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
context_flags &= src_flags;
if (context_flags & ~dst_flags & 0x40)
{
SetLastError(ERROR_MORE_DATA);
return FALSE;
}
if ((status = RtlCopyExtendedContext( (CONTEXT_EX *)(d + context_size), context_flags,
(CONTEXT_EX *)(s + context_size) )))
return set_ntstatus( status );
return TRUE;
}
#endif

View File

@ -666,6 +666,24 @@ ULONG64 WINAPI RtlGetEnabledExtendedFeatures(ULONG64 feature_mask)
return user_shared_data->XState.EnabledFeatures & feature_mask;
}
struct context_copy_range
{
ULONG start;
ULONG flag;
};
static const struct context_copy_range copy_ranges_amd64[] =
{
{0x38, 0x1}, {0x3a, 0x4}, { 0x42, 0x1}, { 0x48, 0x10}, { 0x78, 0x2}, { 0x98, 0x1},
{0xa0, 0x2}, {0xf8, 0x1}, {0x100, 0x8}, {0x2a0, 0}, {0x4b0, 0x10}, {0x4d0, 0}
};
static const struct context_copy_range copy_ranges_x86[] =
{
{ 0x4, 0x10}, {0x1c, 0x8}, {0x8c, 0x4}, {0x9c, 0x2}, {0xb4, 0x1}, {0xcc, 0x20}, {0x1ec, 0},
{0x2cc, 0},
};
static const struct context_parameters
{
ULONG arch_flag;
@ -676,11 +694,12 @@ static const struct context_parameters
ULONG alignment; /* Used when computing size of context. */
ULONG true_alignment; /* Used for actual alignment. */
ULONG flags_offset;
const struct context_copy_range *copy_ranges;
}
arch_context_paramaters[] =
{
{0x00100000, 0xd810005f, 0x4d0, 0x4d0, 0x20, 7, 0xf, 0x30},
{0x00010000, 0xd801007f, 0x2cc, 0xcc, 0x18, 3, 0x3, 0},
{0x00100000, 0xd810005f, 0x4d0, 0x4d0, 0x20, 7, 0xf, 0x30, copy_ranges_amd64},
{0x00010000, 0xd801007f, 0x2cc, 0xcc, 0x18, 3, 0x3, 0, copy_ranges_x86},
};
static const struct context_parameters *context_get_parameters( ULONG context_flags )
@ -882,3 +901,65 @@ ULONG64 WINAPI RtlGetExtendedFeaturesMask( CONTEXT_EX *context_ex )
return xs->Mask & ~(ULONG64)3;
}
/**********************************************************************
* RtlCopyExtendedContext (NTDLL.@)
*/
NTSTATUS WINAPI RtlCopyExtendedContext( CONTEXT_EX *dst, ULONG context_flags, CONTEXT_EX *src )
{
const struct context_copy_range *range;
const struct context_parameters *p;
XSTATE *dst_xs, *src_xs;
ULONG64 feature_mask;
unsigned int start;
BYTE *d, *s;
TRACE( "dst %p, context_flags %#x, src %p.\n", dst, context_flags, src );
if (!(p = context_get_parameters( context_flags )))
return STATUS_INVALID_PARAMETER;
if (!(feature_mask = RtlGetEnabledExtendedFeatures( ~(ULONG64)0 )) && context_flags & 0x40)
return STATUS_NOT_SUPPORTED;
d = RtlLocateLegacyContext( dst, NULL );
s = RtlLocateLegacyContext( src, NULL );
*((ULONG *)(d + p->flags_offset)) |= context_flags;
start = 0;
range = p->copy_ranges;
do
{
if (range->flag & context_flags)
{
if (!start)
start = range->start;
}
else if (start)
{
memcpy( d + start, s + start, range->start - start );
start = 0;
}
}
while (range++->start != p->context_size);
if (!(context_flags & 0x40))
return STATUS_SUCCESS;
if (dst->XState.Length < offsetof(XSTATE, YmmContext))
return STATUS_BUFFER_OVERFLOW;
dst_xs = (XSTATE *)((BYTE *)dst + dst->XState.Offset);
src_xs = (XSTATE *)((BYTE *)src + src->XState.Offset);
memset(dst_xs, 0, offsetof(XSTATE, YmmContext));
dst_xs->Mask = (src_xs->Mask & ~(ULONG64)3) & feature_mask;
dst_xs->CompactionMask = user_shared_data->XState.CompactionEnabled
? ((ULONG64)1 << 63) | (src_xs->CompactionMask & feature_mask) : 0;
if (dst_xs->Mask & 4 && src->XState.Length >= sizeof(XSTATE) && dst->XState.Length >= sizeof(XSTATE))
memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) );
return STATUS_SUCCESS;
}

View File

@ -525,6 +525,7 @@
@ stub RtlConvertUiListToApiList
@ stdcall -arch=win32 -ret64 RtlConvertUlongToLargeInteger(long)
# @ stub RtlConvertVariantToProperty
@ stdcall RtlCopyExtendedContext(ptr long ptr)
@ stdcall RtlCopyLuid(ptr ptr)
@ stdcall RtlCopyLuidAndAttributesArray(long ptr ptr)
@ stdcall -arch=x86_64 RtlCopyMemory(ptr ptr long)

View File

@ -51,6 +51,7 @@ static NTSTATUS (WINAPI *pRtlGetExtendedContextLength2)(ULONG context_flags, UL
static NTSTATUS (WINAPI *pRtlInitializeExtendedContext)(void *context, ULONG context_flags, CONTEXT_EX **context_ex);
static NTSTATUS (WINAPI *pRtlInitializeExtendedContext2)(void *context, ULONG context_flags, CONTEXT_EX **context_ex,
ULONG64 compaction_mask);
static NTSTATUS (WINAPI *pRtlCopyExtendedContext)(CONTEXT_EX *dst, ULONG context_flags, CONTEXT_EX *src);
static void * (WINAPI *pRtlLocateExtendedFeature)(CONTEXT_EX *context_ex, ULONG feature_id, ULONG *length);
static void * (WINAPI *pRtlLocateLegacyContext)(CONTEXT_EX *context_ex, ULONG *length);
static void (WINAPI *pRtlSetExtendedFeaturesMask)(CONTEXT_EX *context_ex, ULONG64 feature_mask);
@ -71,6 +72,7 @@ static BOOL (WINAPI *pInitializeContext2)(void *buffer, DWORD context_flags
static void * (WINAPI *pLocateXStateFeature)(CONTEXT *context, DWORD feature_id, DWORD *length);
static BOOL (WINAPI *pSetXStateFeaturesMask)(CONTEXT *context, DWORD64 feature_mask);
static BOOL (WINAPI *pGetXStateFeaturesMask)(CONTEXT *context, DWORD64 *feature_mask);
static BOOL (WINAPI *pCopyContext)(CONTEXT *dst, DWORD context_flags, CONTEXT *src);
#define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
@ -6811,6 +6813,365 @@ static void test_extended_context(void)
for (i = 0; i < 8; ++i)
ok(data[i] == test_extended_context_data[i], "Got unexpected data %#x, i %u.\n", data[i], i);
}
struct modified_range
{
ULONG start;
ULONG flag;
};
#define check_changes_in_range(a, b, c, d) check_changes_in_range_(__FILE__, __LINE__, a, b, c, d)
static void check_changes_in_range_(const char *file, unsigned int line, const BYTE *p,
const struct modified_range *range, ULONG flags, unsigned int length)
{
ULONG range_flag, flag;
unsigned int once = 0;
unsigned int i;
range_flag = 0;
for (i = 0; i < length; i++)
{
if (i == range->start)
{
range_flag = range->flag;
++range;
}
if ((flag = range_flag) == ~0)
continue;
if (flag & 0x80000000)
{
if (flag & flags && p[i] == 0xcc)
{
if (!once++)
ok(broken(1), "Matched broken result at %#x, flags %#x.\n", i, flags);
continue;
}
flag = 0;
}
if (flag & flags && p[i] != 0xcc)
{
ok_(file, line)(0, "Got unexected byte %#x at %#x, flags %#x.\n", p[i], i, flags);
return;
}
else if (!(flag & flags) && p[i] != 0xdd)
{
ok_(file, line)(0, "Got unexected byte %#x at %#x, flags %#x.\n", p[i], i, flags);
return;
}
}
ok_(file, line)(1, "Range matches.\n");
}
static void test_copy_context(void)
{
static const struct modified_range ranges_amd64[] =
{
{0x30, ~0}, {0x38, 0x1}, {0x3a, 0x4}, {0x42, 0x1}, {0x48, 0x10}, {0x78, 0x2}, {0x98, 0x1},
{0xa0, 0x2}, {0xf8, 0x1}, {0x100, 0x8}, {0x2a0, 0x80000008}, {0x4b0, 0x10}, {0x4d0, ~0},
{0x4e8, 0}, {0x500, ~0}, {0x640, 0}, {0x1000, 0},
};
static const struct modified_range ranges_x86[] =
{
{0x0, ~0}, {0x4, 0x10}, {0x1c, 0x8}, {0x8c, 0x4}, {0x9c, 0x2}, {0xb4, 0x1}, {0xcc, 0x20}, {0x1ec, 0x80000020},
{0x2cc, ~0}, {0x294, 0}, {0x1000, 0},
};
static const struct modified_range single_range[] =
{
{0x0, 0x1}, {0x1000, 0},
};
static const struct
{
ULONG flags;
}
tests[] =
{
/* AMD64 */
{0x100000 | 0x01}, /* CONTEXT_CONTROL */
{0x100000 | 0x02}, /* CONTEXT_INTEGER */
{0x100000 | 0x04}, /* CONTEXT_SEGMENTS */
{0x100000 | 0x08}, /* CONTEXT_FLOATING_POINT */
{0x100000 | 0x10}, /* CONTEXT_DEBUG_REGISTERS */
{0x100000 | 0x0b}, /* CONTEXT_FULL */
{0x100000 | 0x40}, /* CONTEXT_XSTATE */
{0x100000 | 0x1f}, /* CONTEXT_ALL */
/* X86 */
{ 0x10000 | 0x01}, /* CONTEXT_CONTROL */
{ 0x10000 | 0x02}, /* CONTEXT_INTEGER */
{ 0x10000 | 0x04}, /* CONTEXT_SEGMENTS */
{ 0x10000 | 0x08}, /* CONTEXT_FLOATING_POINT */
{ 0x10000 | 0x10}, /* CONTEXT_DEBUG_REGISTERS */
{ 0x10000 | 0x20}, /* CONTEXT_EXTENDED_REGISTERS */
{ 0x10000 | 0x40}, /* CONTEXT_XSTATE */
{ 0x10000 | 0x3f}, /* CONTEXT_ALL */
};
static const ULONG arch_flags[] = {0x100000, 0x10000};
DECLSPEC_ALIGN(64) BYTE src_context_buffer[4096];
DECLSPEC_ALIGN(64) BYTE dst_context_buffer[4096];
ULONG64 enabled_features, expected_compaction;
unsigned int context_length, flags_offset, i;
CONTEXT_EX *src_ex, *dst_ex;
XSTATE *dst_xs, *src_xs;
BOOL compaction, bret;
CONTEXT *src, *dst;
NTSTATUS status;
DWORD length;
ULONG flags;
if (!pRtlCopyExtendedContext)
{
win_skip("RtlCopyExtendedContext is not available.\n");
return;
}
if (!pRtlGetEnabledExtendedFeatures)
{
skip("RtlGetEnabledExtendedFeatures is not available.\n");
return;
}
enabled_features = pRtlGetEnabledExtendedFeatures(~(ULONG64)0);
for (i = 0; i < ARRAY_SIZE(tests); ++i)
{
flags = tests[i].flags;
flags_offset = (flags & 0x100000) ? 0x30 : 0;
memset(dst_context_buffer, 0xdd, sizeof(dst_context_buffer));
memset(src_context_buffer, 0xcc, sizeof(src_context_buffer));
status = pRtlInitializeExtendedContext(src_context_buffer, flags, &src_ex);
if (enabled_features || !(flags & 0x40))
{
ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags);
}
else
{
ok(status == STATUS_NOT_SUPPORTED, "Got unexpected status %#x, flags %#x.\n", status, flags);
continue;
}
status = pRtlInitializeExtendedContext(dst_context_buffer, flags, &dst_ex);
ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags);
src = pRtlLocateLegacyContext(src_ex, NULL);
dst = pRtlLocateLegacyContext(dst_ex, NULL);
*(DWORD *)((BYTE *)dst + flags_offset) = 0;
*(DWORD *)((BYTE *)src + flags_offset) = 0;
src_xs = (XSTATE *)((BYTE *)src_ex + src_ex->XState.Offset);
memset(src_xs, 0xcc, sizeof(XSTATE));
src_xs->Mask = 3;
src_xs->CompactionMask = ~(ULONG64)0;
status = pRtlCopyExtendedContext(dst_ex, flags, src_ex);
ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags);
context_length = (BYTE *)dst_ex - (BYTE *)dst + dst_ex->All.Length;
check_changes_in_range((BYTE *)dst, flags & 0x100000 ? &ranges_amd64[0] : &ranges_x86[0],
flags, context_length);
ok(*(DWORD *)((BYTE *)dst + flags_offset) == flags, "Got unexpected ContextFlags %#x, flags %#x.\n",
*(DWORD *)((BYTE *)dst + flags_offset), flags);
memset(dst_context_buffer, 0xdd, sizeof(dst_context_buffer));
status = pRtlInitializeExtendedContext(dst_context_buffer, flags, &dst_ex);
ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags);
*(DWORD *)((BYTE *)src + flags_offset) = 0;
*(DWORD *)((BYTE *)dst + flags_offset) = 0;
SetLastError(0xdeadbeef);
bret = pCopyContext(dst, flags | 0x40, src);
ok((!bret && GetLastError() == (enabled_features ? ERROR_INVALID_PARAMETER : ERROR_NOT_SUPPORTED))
|| broken(!bret && GetLastError() == ERROR_INVALID_PARAMETER),
"Got unexpected bret %#x, GetLastError() %#x, flags %#x.\n",
bret, GetLastError(), flags);
ok(*(DWORD *)((BYTE *)dst + flags_offset) == 0, "Got unexpected ContextFlags %#x, flags %#x.\n",
*(DWORD *)((BYTE *)dst + flags_offset), flags);
check_changes_in_range((BYTE *)dst, flags & 0x100000 ? &ranges_amd64[0] : &ranges_x86[0],
0, context_length);
*(DWORD *)((BYTE *)dst + flags_offset) = flags & 0x110000;
*(DWORD *)((BYTE *)src + flags_offset) = flags;
SetLastError(0xdeadbeef);
bret = pCopyContext(dst, flags, src);
if (flags & 0x40)
ok((!bret && GetLastError() == ERROR_MORE_DATA)
|| broken(!(flags & CONTEXT_NATIVE) && !bret && GetLastError() == ERROR_INVALID_PARAMETER),
"Got unexpected bret %#x, GetLastError() %#x, flags %#x.\n",
bret, GetLastError(), flags);
else
ok((bret && GetLastError() == 0xdeadbeef)
|| broken(!(flags & CONTEXT_NATIVE) && !bret && GetLastError() == ERROR_INVALID_PARAMETER),
"Got unexpected bret %#x, GetLastError() %#x, flags %#x.\n",
bret, GetLastError(), flags);
if (bret)
{
ok(*(DWORD *)((BYTE *)dst + flags_offset) == flags, "Got unexpected ContextFlags %#x, flags %#x.\n",
*(DWORD *)((BYTE *)dst + flags_offset), flags);
check_changes_in_range((BYTE *)dst, flags & 0x100000 ? &ranges_amd64[0] : &ranges_x86[0],
flags, context_length);
}
else
{
ok(*(DWORD *)((BYTE *)dst + flags_offset) == (flags & 0x110000),
"Got unexpected ContextFlags %#x, flags %#x.\n",
*(DWORD *)((BYTE *)dst + flags_offset), flags);
check_changes_in_range((BYTE *)dst, flags & 0x100000 ? &ranges_amd64[0] : &ranges_x86[0],
0, context_length);
}
}
for (i = 0; i < ARRAY_SIZE(arch_flags); ++i)
{
flags = arch_flags[i] | 0x42;
flags_offset = (flags & 0x100000) ? 0x30 : 0;
context_length = (flags & 0x100000) ? 0x4d0 : 0x2cc;
memset(dst_context_buffer, 0xdd, sizeof(dst_context_buffer));
memset(src_context_buffer, 0xcc, sizeof(src_context_buffer));
length = sizeof(src_context_buffer);
bret = pInitializeContext(src_context_buffer, flags, &src, &length);
ok(bret, "Got unexpected bret %#x, flags %#x.\n", bret, flags);
length = sizeof(dst_context_buffer);
bret = pInitializeContext(dst_context_buffer, flags, &dst, &length);
ok(bret, "Got unexpected bret %#x, flags %#x.\n", bret, flags);
dst_ex = (CONTEXT_EX *)((BYTE *)dst + context_length);
src_ex = (CONTEXT_EX *)((BYTE *)src + context_length);
dst_xs = (XSTATE *)((BYTE *)dst_ex + dst_ex->XState.Offset);
src_xs = (XSTATE *)((BYTE *)src_ex + src_ex->XState.Offset);
*(DWORD *)((BYTE *)dst + flags_offset) = 0;
*(DWORD *)((BYTE *)src + flags_offset) = 0;
compaction = !!(src_xs->CompactionMask & ((ULONG64)1 << 63));
expected_compaction = (compaction ? ((ULONG64)1 << (ULONG64)63) | enabled_features : 0);
memset(&src_xs->YmmContext, 0xcc, sizeof(src_xs->YmmContext));
src_xs->CompactionMask = ~(ULONG64)0;
src_xs->Mask = 0;
memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext));
dst_xs->CompactionMask = 0xdddddddddddddddd;
dst_xs->Mask = 0xdddddddddddddddd;
dst_ex->XState.Length = 0;
status = pRtlCopyExtendedContext(dst_ex, flags, src_ex);
ok(status == (enabled_features ? STATUS_BUFFER_OVERFLOW : STATUS_NOT_SUPPORTED),
"Got unexpected status %#x, flags %#x.\n", status, flags);
if (!enabled_features)
continue;
ok(*(DWORD *)((BYTE *)dst + flags_offset) == flags, "Got unexpected ContextFlags %#x, flags %#x.\n",
*(DWORD *)((BYTE *)dst + flags_offset), flags);
src_xs->Mask = ~(ULONG64)0;
memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext));
dst_xs->CompactionMask = 0xdddddddddddddddd;
dst_xs->Mask = 0xdddddddddddddddd;
dst_ex->XState.Length = 0;
status = pRtlCopyExtendedContext(dst_ex, flags, src_ex);
ok(status == STATUS_BUFFER_OVERFLOW, "Got unexpected status %#x, flags %#x.\n", status, flags);
ok(*(DWORD *)((BYTE *)dst + flags_offset) == flags, "Got unexpected ContextFlags %#x, flags %#x.\n",
*(DWORD *)((BYTE *)dst + flags_offset), flags);
ok(dst_xs->Mask == 0xdddddddddddddddd, "Got unexpected Mask %s.\n",
wine_dbgstr_longlong(dst_xs->Mask));
ok(dst_xs->CompactionMask == 0xdddddddddddddddd, "Got unexpected CompactionMask %s.\n",
wine_dbgstr_longlong(dst_xs->CompactionMask));
check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 0, sizeof(dst_xs->YmmContext));
src_xs->Mask = 3;
memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext));
dst_xs->CompactionMask = 0xdddddddddddddddd;
dst_xs->Mask = 0xdddddddddddddddd;
dst_ex->XState.Length = offsetof(XSTATE, YmmContext);
status = pRtlCopyExtendedContext(dst_ex, flags, src_ex);
ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags);
ok(*(DWORD *)((BYTE *)dst + flags_offset) == flags, "Got unexpected ContextFlags %#x, flags %#x.\n",
*(DWORD *)((BYTE *)dst + flags_offset), flags);
ok(dst_xs->Mask == 0, "Got unexpected Mask %s.\n",
wine_dbgstr_longlong(dst_xs->Mask));
ok(dst_xs->CompactionMask == expected_compaction,
"Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(dst_xs->CompactionMask));
check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 0, sizeof(dst_xs->YmmContext));
memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext));
dst_xs->CompactionMask = 0xdddddddddddddddd;
dst_xs->Mask = 0xdddddddddddddddd;
dst_ex->XState.Length = sizeof(XSTATE);
status = pRtlCopyExtendedContext(dst_ex, flags, src_ex);
ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags);
ok(dst_xs->Mask == 0, "Got unexpected Mask %s.\n",
wine_dbgstr_longlong(dst_xs->Mask));
ok(dst_xs->CompactionMask == expected_compaction,
"Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(dst_xs->CompactionMask));
check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 0, sizeof(dst_xs->YmmContext));
src_xs->Mask = 4;
memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext));
dst_xs->CompactionMask = 0xdddddddddddddddd;
dst_xs->Mask = 0xdddddddddddddddd;
status = pRtlCopyExtendedContext(dst_ex, flags, src_ex);
ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags);
ok(dst_xs->Mask == 4, "Got unexpected Mask %s.\n",
wine_dbgstr_longlong(dst_xs->Mask));
ok(dst_xs->CompactionMask == expected_compaction,
"Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(dst_xs->CompactionMask));
check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 1, sizeof(dst_xs->YmmContext));
src_xs->Mask = 3;
memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext));
dst_xs->CompactionMask = 0xdddddddddddddddd;
dst_xs->Mask = 0xdddddddddddddddd;
status = pRtlCopyExtendedContext(dst_ex, flags, src_ex);
ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags);
ok(dst_xs->Mask == 0, "Got unexpected Mask %s.\n",
wine_dbgstr_longlong(dst_xs->Mask));
ok(dst_xs->CompactionMask == expected_compaction,
"Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(dst_xs->CompactionMask));
check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 0, sizeof(dst_xs->YmmContext));
*(DWORD *)((BYTE *)src + flags_offset) = arch_flags[i];
src_xs->Mask = 7;
memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext));
dst_xs->CompactionMask = 0xdddddddddddddddd;
dst_xs->Mask = 0xdddddddddddddddd;
status = pRtlCopyExtendedContext(dst_ex, flags, src_ex);
ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags);
ok(dst_xs->Mask == 4, "Got unexpected Mask %s.\n",
wine_dbgstr_longlong(dst_xs->Mask));
ok(dst_xs->CompactionMask == expected_compaction,
"Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(dst_xs->CompactionMask));
check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 1, sizeof(dst_xs->YmmContext));
src_xs->Mask = 7;
memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext));
dst_xs->CompactionMask = 0xdddddddddddddddd;
dst_xs->Mask = 0xdddddddddddddddd;
SetLastError(0xdeadbeef);
bret = pCopyContext(dst, flags, src);
ok((bret && GetLastError() == 0xdeadbeef)
|| broken(!(flags & CONTEXT_NATIVE) && !bret && GetLastError() == ERROR_INVALID_PARAMETER),
"Got unexpected bret %#x, GetLastError() %#x, flags %#x.\n",
bret, GetLastError(), flags);
ok(dst_xs->Mask == 0xdddddddddddddddd || broken(dst_xs->Mask == 4), "Got unexpected Mask %s, flags %#x.\n",
wine_dbgstr_longlong(dst_xs->Mask), flags);
ok(dst_xs->CompactionMask == 0xdddddddddddddddd || broken(dst_xs->CompactionMask == expected_compaction),
"Got unexpected CompactionMask %s, flags %#x.\n", wine_dbgstr_longlong(dst_xs->CompactionMask), flags);
check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range,
dst_xs->Mask == 4, sizeof(dst_xs->YmmContext));
}
}
#endif
START_TEST(exception)
@ -6865,6 +7226,7 @@ START_TEST(exception)
X(RtlLocateLegacyContext);
X(RtlSetExtendedFeaturesMask);
X(RtlGetExtendedFeaturesMask);
X(RtlCopyExtendedContext);
#undef X
#define X(f) p##f = (void*)GetProcAddress(hkernel32, #f)
@ -6876,6 +7238,7 @@ START_TEST(exception)
X(LocateXStateFeature);
X(SetXStateFeaturesMask);
X(GetXStateFeaturesMask);
X(CopyContext);
#undef X
if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler)
@ -6956,6 +7319,7 @@ START_TEST(exception)
test_prot_fault();
test_kiuserexceptiondispatcher();
test_extended_context();
test_copy_context();
#elif defined(__x86_64__)
@ -6995,6 +7359,7 @@ START_TEST(exception)
else
skip( "Dynamic unwind functions not found\n" );
test_extended_context();
test_copy_context();
#elif defined(__aarch64__)

View File

@ -1010,6 +1010,7 @@
@ stdcall -arch=win32 -ret64 RtlConvertLongToLargeInteger(long)
@ stdcall RtlConvertSidToUnicodeString(ptr ptr long)
@ stdcall -arch=win32 -ret64 RtlConvertUlongToLargeInteger(long)
@ stdcall RtlCopyExtendedContext(ptr long ptr)
@ stdcall RtlCopyLuid(ptr ptr)
@ stdcall RtlCopyLuidAndAttributesArray(long ptr ptr)
@ stdcall -arch=x86_64 RtlCopyMemory(ptr ptr long)

View File

@ -1837,6 +1837,7 @@ BOOLEAN WINAPI PsGetVersion(ULONG*,ULONG*,ULONG*,UNICODE_STRING*);
NTSTATUS WINAPI PsTerminateSystemThread(NTSTATUS);
#if defined(__x86_64__) || defined(__i386__)
NTSTATUS WINAPI RtlCopyExtendedContext(CONTEXT_EX*,ULONG,CONTEXT_EX*);
NTSTATUS WINAPI RtlInitializeExtendedContext(void*,ULONG,CONTEXT_EX**);
NTSTATUS WINAPI RtlInitializeExtendedContext2(void*,ULONG,CONTEXT_EX**,ULONG64);
ULONG64 WINAPI RtlGetEnabledExtendedFeatures(ULONG64);

View File

@ -1827,6 +1827,7 @@ WINBASEAPI BOOL WINAPI CommConfigDialogW(LPCWSTR,HWND,LPCOMMCONFIG);
WINBASEAPI BOOL WINAPI ConnectNamedPipe(HANDLE,LPOVERLAPPED);
WINBASEAPI BOOL WINAPI ContinueDebugEvent(DWORD,DWORD,DWORD);
WINBASEAPI HANDLE WINAPI ConvertToGlobalHandle(HANDLE hSrc);
WINBASEAPI BOOL WINAPI CopyContext(CONTEXT*, DWORD, CONTEXT*);
WINBASEAPI BOOL WINAPI CopyFileA(LPCSTR,LPCSTR,BOOL);
WINBASEAPI BOOL WINAPI CopyFileW(LPCWSTR,LPCWSTR,BOOL);
#define CopyFile WINELIB_NAME_AW(CopyFile)