mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-19 17:06:04 -07:00
Merge branch 'ntdll_process_tls_info' into 'master'
ntdll: Implement NtSetInformationProcess( ProcessTlsInformation ) and use that in loader. See merge request wine/wine!6549
This commit is contained in:
commit
e6ab7187f3
9 changed files with 600 additions and 51 deletions
|
@ -1708,7 +1708,10 @@ static void test_tls_links(void)
|
|||
TEB *teb = NtCurrentTeb(), *thread_teb;
|
||||
THREAD_BASIC_INFORMATION tbi;
|
||||
NTSTATUS status;
|
||||
ULONG i, count;
|
||||
HANDLE thread;
|
||||
SIZE_T size;
|
||||
void **ptr;
|
||||
|
||||
ok(!!teb->ThreadLocalStoragePointer, "got NULL.\n");
|
||||
|
||||
|
@ -1728,6 +1731,26 @@ static void test_tls_links(void)
|
|||
ResumeThread(thread);
|
||||
WaitForSingleObject(test_tls_links_started, INFINITE);
|
||||
|
||||
if (!is_old_loader_struct())
|
||||
{
|
||||
ptr = teb->ThreadLocalStoragePointer;
|
||||
count = (ULONG_PTR)ptr[-2];
|
||||
size = HeapSize(GetProcessHeap(), 0, ptr - 2);
|
||||
ok(size == (count + 2) * sizeof(void *), "got count %lu, size %Iu.\n", count, size);
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
if (!ptr[i]) continue;
|
||||
size = HeapSize(GetProcessHeap(), 0, (void **)ptr[i] - 2);
|
||||
ok(size && size < 100000, "got %Iu.\n", size);
|
||||
}
|
||||
|
||||
ptr = thread_teb->ThreadLocalStoragePointer;
|
||||
count = (ULONG_PTR)ptr[-2];
|
||||
size = HeapSize(GetProcessHeap(), 0, ptr - 2);
|
||||
ok(size == (count + 2) * sizeof(void *), "got count %lu, size %Iu.\n", count, size);
|
||||
}
|
||||
|
||||
ok(!!thread_teb->ThreadLocalStoragePointer, "got NULL.\n");
|
||||
ok(!teb->TlsLinks.Flink, "got %p.\n", teb->TlsLinks.Flink);
|
||||
ok(!teb->TlsLinks.Blink, "got %p.\n", teb->TlsLinks.Blink);
|
||||
|
|
|
@ -142,6 +142,7 @@ typedef struct _wine_modref
|
|||
|
||||
static UINT tls_module_count = 32; /* number of modules with TLS directory */
|
||||
static IMAGE_TLS_DIRECTORY *tls_dirs; /* array of TLS directories */
|
||||
static ULONG tls_thread_count; /* number of threads for which ThreadLocalStoragePointer is allocated in TEB. */
|
||||
|
||||
static RTL_CRITICAL_SECTION loader_section;
|
||||
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
|
||||
|
@ -1332,6 +1333,36 @@ static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_H
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* alloc_tls_memory
|
||||
*
|
||||
* Allocate memory for TLS vector or index with an extra data.
|
||||
*/
|
||||
static void *alloc_tls_memory( BOOL vector, ULONG_PTR size )
|
||||
{
|
||||
ULONG_PTR *ptr;
|
||||
|
||||
if (!(ptr = RtlAllocateHeap( GetProcessHeap(), vector ? HEAP_ZERO_MEMORY : 0, size + sizeof(void *) * 2 ))) return NULL;
|
||||
ptr += 2;
|
||||
if (vector) ptr[-2] = size / sizeof(void *);
|
||||
else ptr[-2] = ptr[-1] = 0;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* free_tls_memory
|
||||
*
|
||||
* Free TLS vector or index memory.
|
||||
*/
|
||||
static void free_tls_memory( void *ptr )
|
||||
{
|
||||
if (!ptr) return;
|
||||
RtlFreeHeap( GetProcessHeap(), 0, (void **)ptr - 2 );
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* alloc_tls_slot
|
||||
*
|
||||
|
@ -1341,10 +1372,10 @@ static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_H
|
|||
static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
|
||||
{
|
||||
const IMAGE_TLS_DIRECTORY *dir;
|
||||
ULONG i, size;
|
||||
ULONG i, j, size;
|
||||
void *new_ptr;
|
||||
UINT old_module_count = tls_module_count;
|
||||
HANDLE thread = NULL, next;
|
||||
PROCESS_TLS_INFORMATION *t;
|
||||
|
||||
if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
|
||||
return FALSE;
|
||||
|
@ -1373,57 +1404,66 @@ static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
|
|||
tls_dirs = new_ptr;
|
||||
tls_module_count = new_count;
|
||||
}
|
||||
*(DWORD *)dir->AddressOfIndex = i;
|
||||
tls_dirs[i] = *dir;
|
||||
|
||||
/* allocate the data block in all running threads */
|
||||
while (!NtGetNextThread( GetCurrentProcess(), thread, THREAD_QUERY_LIMITED_INFORMATION, 0, 0, &next ))
|
||||
if (!tls_thread_count) return TRUE;
|
||||
t = RtlAllocateHeap( GetProcessHeap(), 0, offsetof( PROCESS_TLS_INFORMATION, ThreadData[tls_thread_count] ));
|
||||
if (!t) return FALSE;
|
||||
|
||||
t->Flags = 0;
|
||||
t->ThreadDataCount = tls_thread_count;
|
||||
if (old_module_count < tls_module_count)
|
||||
{
|
||||
THREAD_BASIC_INFORMATION tbi;
|
||||
TEB *teb;
|
||||
t->OperationType = ProcessTlsReplaceVector;
|
||||
t->TlsVectorLength = old_module_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
t->OperationType = ProcessTlsReplaceIndex;
|
||||
t->TlsIndex = i;
|
||||
}
|
||||
for (j = 0; j < tls_thread_count; ++j)
|
||||
{
|
||||
void **vector;
|
||||
|
||||
if (thread) NtClose( thread );
|
||||
thread = next;
|
||||
if (NtQueryInformationThread( thread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL ) || !tbi.TebBaseAddress)
|
||||
{
|
||||
ERR( "NtQueryInformationThread failed.\n" );
|
||||
continue;
|
||||
}
|
||||
teb = tbi.TebBaseAddress;
|
||||
if (!teb->ThreadLocalStoragePointer)
|
||||
{
|
||||
/* Thread is not initialized by loader yet or already teared down. */
|
||||
TRACE( "thread %04lx NULL tls block.\n", HandleToULong(tbi.ClientId.UniqueThread) );
|
||||
continue;
|
||||
}
|
||||
t->ThreadData[j].Flags = 0;
|
||||
|
||||
if (old_module_count < tls_module_count)
|
||||
{
|
||||
void **old = teb->ThreadLocalStoragePointer;
|
||||
void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_module_count * sizeof(*new));
|
||||
|
||||
if (!new) return FALSE;
|
||||
if (old) memcpy( new, old, old_module_count * sizeof(*new) );
|
||||
teb->ThreadLocalStoragePointer = new;
|
||||
#ifdef __x86_64__ /* macOS-specific hack */
|
||||
if (teb->Instrumentation[0]) ((TEB *)teb->Instrumentation[0])->ThreadLocalStoragePointer = new;
|
||||
#endif
|
||||
TRACE( "thread %04lx tls block %p -> %p\n", HandleToULong(teb->ClientId.UniqueThread), old, new );
|
||||
/* FIXME: can't free old block here, should be freed at thread exit */
|
||||
}
|
||||
|
||||
if (!(new_ptr = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill ))) return -1;
|
||||
if (!(new_ptr = alloc_tls_memory( FALSE, size + dir->SizeOfZeroFill ))) return FALSE;
|
||||
memcpy( new_ptr, (void *)dir->StartAddressOfRawData, size );
|
||||
memset( (char *)new_ptr + size, 0, dir->SizeOfZeroFill );
|
||||
|
||||
TRACE( "thread %04lx slot %lu: %lu/%lu bytes at %p\n",
|
||||
HandleToULong(teb->ClientId.UniqueThread), i, size, dir->SizeOfZeroFill, new_ptr );
|
||||
|
||||
RtlFreeHeap( GetProcessHeap(), 0,
|
||||
InterlockedExchangePointer( (void **)teb->ThreadLocalStoragePointer + i, new_ptr ));
|
||||
if (t->OperationType == ProcessTlsReplaceVector)
|
||||
{
|
||||
vector = alloc_tls_memory( TRUE, tls_module_count * sizeof(*vector) );
|
||||
if (!vector) return FALSE;
|
||||
t->ThreadData[j].TlsVector = vector;
|
||||
vector[i] = new_ptr;
|
||||
}
|
||||
else t->ThreadData[j].TlsModulePointer = new_ptr;
|
||||
}
|
||||
if (NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, t,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[t->ThreadDataCount])))
|
||||
{
|
||||
ERR( "ProcessTlsInformation failed.\n" );
|
||||
return FALSE;
|
||||
}
|
||||
if (thread) NtClose( thread );
|
||||
|
||||
*(DWORD *)dir->AddressOfIndex = i;
|
||||
tls_dirs[i] = *dir;
|
||||
for (j = 0; j < tls_thread_count; ++j)
|
||||
{
|
||||
if (!(t->ThreadData[j].Flags & THREAD_TLS_INFORMATION_ASSIGNED) && t->OperationType == ProcessTlsReplaceVector)
|
||||
{
|
||||
/* There could be fewer active threads than we counted here due to force terminated threads, first
|
||||
* free extra TLS directory data set in the new TLS vector. */
|
||||
free_tls_memory( ((void **)t->ThreadData[j].TlsVector)[i] );
|
||||
}
|
||||
if (!(t->ThreadData[j].Flags & THREAD_TLS_INFORMATION_ASSIGNED) || t->OperationType == ProcessTlsReplaceIndex)
|
||||
{
|
||||
/* FIXME: can't free old Tls vector here, should be freed at thread exit. */
|
||||
free_tls_memory( t->ThreadData[j].TlsVector );
|
||||
}
|
||||
}
|
||||
RtlFreeHeap( GetProcessHeap(), 0, t );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1633,8 +1673,7 @@ static NTSTATUS alloc_thread_tls(void)
|
|||
void **pointers;
|
||||
UINT i, size;
|
||||
|
||||
if (!(pointers = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
tls_module_count * sizeof(*pointers) )))
|
||||
if (!(pointers = alloc_tls_memory( TRUE, tls_module_count * sizeof(*pointers) )))
|
||||
return STATUS_NO_MEMORY;
|
||||
|
||||
for (i = 0; i < tls_module_count; i++)
|
||||
|
@ -1645,10 +1684,10 @@ static NTSTATUS alloc_thread_tls(void)
|
|||
size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
|
||||
if (!size && !dir->SizeOfZeroFill) continue;
|
||||
|
||||
if (!(pointers[i] = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill )))
|
||||
if (!(pointers[i] = alloc_tls_memory( FALSE, size + dir->SizeOfZeroFill )))
|
||||
{
|
||||
while (i) RtlFreeHeap( GetProcessHeap(), 0, pointers[--i] );
|
||||
RtlFreeHeap( GetProcessHeap(), 0, pointers );
|
||||
while (i) free_tls_memory( pointers[--i] );
|
||||
free_tls_memory( pointers );
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
memcpy( pointers[i], (void *)dir->StartAddressOfRawData, size );
|
||||
|
@ -1656,6 +1695,7 @@ static NTSTATUS alloc_thread_tls(void)
|
|||
|
||||
TRACE( "slot %u: %u/%lu bytes at %p\n", i, size, dir->SizeOfZeroFill, pointers[i] );
|
||||
}
|
||||
++tls_thread_count;
|
||||
NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
|
||||
#ifdef __x86_64__ /* macOS-specific hack */
|
||||
if (NtCurrentTeb()->Instrumentation[0])
|
||||
|
@ -3947,12 +3987,13 @@ void WINAPI LdrShutdownThread(void)
|
|||
if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
|
||||
{
|
||||
NtCurrentTeb()->ThreadLocalStoragePointer = NULL;
|
||||
--tls_thread_count;
|
||||
#ifdef __x86_64__ /* macOS-specific hack */
|
||||
if (NtCurrentTeb()->Instrumentation[0])
|
||||
((TEB *)NtCurrentTeb()->Instrumentation[0])->ThreadLocalStoragePointer = NULL;
|
||||
#endif
|
||||
for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
|
||||
RtlFreeHeap( GetProcessHeap(), 0, pointers );
|
||||
for (i = 0; i < tls_module_count; i++) free_tls_memory( pointers[i] );
|
||||
free_tls_memory( pointers );
|
||||
}
|
||||
RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 2 );
|
||||
NtCurrentTeb()->FlsSlots = NULL;
|
||||
|
|
|
@ -4087,6 +4087,278 @@ static void test_processor_idle_cycle_time(void)
|
|||
ok( size == cpu_count * sizeof(*buffer), "got %#lx.\n", size );
|
||||
}
|
||||
|
||||
static DWORD WINAPI test_set_process_tls_info_thread(void *param)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_set_process_tls_info(void)
|
||||
{
|
||||
THREAD_BASIC_INFORMATION tbi;
|
||||
TEB *teb = NtCurrentTeb(), *thread_teb;
|
||||
char buffer[1024];
|
||||
PROCESS_TLS_INFORMATION *tlsinfo = (PROCESS_TLS_INFORMATION *)buffer;
|
||||
void **save_tls_pointers[2];
|
||||
void *tls_pointer[4], *new_tls_pointer[4], *tls_pointer2[4], *new_tls_pointer2[4];
|
||||
unsigned int i;
|
||||
DWORD thread_id, curr_thread_id = GetCurrentThreadId();
|
||||
NTSTATUS status;
|
||||
HANDLE thread;
|
||||
BOOL wow = is_wow64 && !old_wow64;
|
||||
|
||||
thread = CreateThread( NULL, 0, test_set_process_tls_info_thread, NULL, CREATE_SUSPENDED, &thread_id );
|
||||
do
|
||||
{
|
||||
/* workaround currently present Wine bug when thread teb may be not available immediately
|
||||
* after creating a thread before it is initialized on the Unix side. */
|
||||
Sleep( 1 );
|
||||
status = NtQueryInformationThread( thread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL );
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
} while (!(thread_teb = tbi.TebBaseAddress));
|
||||
ok( !thread_teb->ThreadLocalStoragePointer, "got %p.\n", thread_teb->ThreadLocalStoragePointer );
|
||||
|
||||
save_tls_pointers[0] = teb->ThreadLocalStoragePointer;
|
||||
save_tls_pointers[1] = thread_teb->ThreadLocalStoragePointer;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tls_pointer); ++i)
|
||||
{
|
||||
tls_pointer[i] = (void *)(ULONG_PTR)(i + 1);
|
||||
new_tls_pointer[i] = (void *)(ULONG_PTR)(i + 20);
|
||||
}
|
||||
teb->ThreadLocalStoragePointer = tls_pointer;
|
||||
|
||||
/* This flag probably requests WOW64 teb update. */
|
||||
tlsinfo->Flags = 1;
|
||||
tlsinfo->ThreadDataCount = 1;
|
||||
tlsinfo->OperationType = ProcessTlsReplaceVector;
|
||||
tlsinfo->TlsVectorLength = 2;
|
||||
tlsinfo->ThreadData[0].Flags = 0;
|
||||
tlsinfo->ThreadData[0].ThreadId = thread_id;
|
||||
tlsinfo->ThreadData[0].TlsVector = new_tls_pointer;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
if (wow)
|
||||
{
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
ok( tlsinfo->Flags == 1, "got %#lx.\n", tlsinfo->Flags );
|
||||
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
ok( tlsinfo->ThreadData[0].ThreadId == curr_thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status );
|
||||
ok( tlsinfo->Flags == 1, "got %#lx.\n", tlsinfo->Flags );
|
||||
ok( !tlsinfo->ThreadData[0].Flags, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
ok( tlsinfo->ThreadData[0].ThreadId == thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
}
|
||||
|
||||
/* Other PROCESS_TLS_INFORMATION flags are invalid. STATUS_INFO_LENGTH_MISMATCH is weird but that's for any flag
|
||||
* besides 1. */
|
||||
tlsinfo->Flags = 2;
|
||||
tlsinfo->ThreadData[0].Flags = 0;
|
||||
tlsinfo->ThreadData[0].ThreadId = thread_id;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "got %#lx.\n", status );
|
||||
ok( tlsinfo->Flags == 2, "got %#lx.\n", tlsinfo->Flags );
|
||||
ok( !tlsinfo->ThreadData[0].Flags, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
ok( tlsinfo->ThreadData[0].ThreadId == thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
|
||||
/* Nonzero THREAD_TLS_INFORMATION flags on input are invalid. */
|
||||
tlsinfo->Flags = 0;
|
||||
tlsinfo->ThreadData[0].Flags = 1;
|
||||
tlsinfo->ThreadData[0].ThreadId = thread_id;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
ok( status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status );
|
||||
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||
ok( tlsinfo->ThreadData[0].Flags == 1, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
ok( tlsinfo->ThreadData[0].ThreadId == thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
|
||||
tlsinfo->ThreadData[0].Flags = 0;
|
||||
tlsinfo->OperationType = MaxProcessTlsOperation;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
/* Unknown operation type. */
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status );
|
||||
|
||||
tlsinfo->OperationType = ProcessTlsReplaceVector;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]) + 8);
|
||||
/* Larger data size. */
|
||||
ok( (!wow && status == STATUS_INFO_LENGTH_MISMATCH) || (wow && !status), "got %#lx.\n", status );
|
||||
|
||||
/* Zero thread count. */
|
||||
tlsinfo->ThreadData[0].Flags = 0;
|
||||
tlsinfo->ThreadDataCount = 0;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "got %#lx.\n", status );
|
||||
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||
|
||||
tlsinfo->ThreadDataCount = 1;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
/* ThreadId is output parameter, ignored on input and contains the thread where the data were assigned on
|
||||
* output. */
|
||||
ok( tlsinfo->ThreadData[0].ThreadId == curr_thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
/* TlsVector contains the repaced vector on output. */
|
||||
ok( tlsinfo->ThreadData[0].TlsVector == tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||
for (i = 0; i < ARRAY_SIZE(tls_pointer); ++i)
|
||||
{
|
||||
ok( tls_pointer[i] == (void *)(ULONG_PTR)(i + 1), "got %p.\n", tls_pointer );
|
||||
/* TlsVectorLength pointers are copied from the old vector to the new one. */
|
||||
if (i < 2)
|
||||
ok( new_tls_pointer[i] == (void *)(ULONG_PTR)(i + 1), "got %p.\n", tls_pointer );
|
||||
else
|
||||
ok( new_tls_pointer[i] == (void *)(ULONG_PTR)(i + 20), "got %p.\n", tls_pointer );
|
||||
}
|
||||
|
||||
teb->ThreadLocalStoragePointer = NULL;
|
||||
tlsinfo->ThreadData[0].Flags = 0;
|
||||
tlsinfo->ThreadData[0].TlsVector = new_tls_pointer;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||
/* Threads with NULL ThreadLocalStoragePointer are ignored. */
|
||||
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||
ok( !tlsinfo->ThreadData[0].Flags, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
ok( tlsinfo->ThreadData[0].TlsVector == new_tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||
|
||||
memcpy( tls_pointer2, tls_pointer, sizeof(tls_pointer2) );
|
||||
thread_teb->ThreadLocalStoragePointer = tls_pointer2;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
ok( thread_teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||
ok( tlsinfo->ThreadData[0].ThreadId == thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
ok( tlsinfo->ThreadData[0].TlsVector == tls_pointer2, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||
|
||||
/* Two eligible threads, data for only one are provided, that succeeds. */
|
||||
teb->ThreadLocalStoragePointer = tls_pointer;
|
||||
thread_teb->ThreadLocalStoragePointer = tls_pointer2;
|
||||
tlsinfo->ThreadData[0].Flags = 0;
|
||||
tlsinfo->ThreadData[0].TlsVector = new_tls_pointer;
|
||||
thread_teb->ThreadLocalStoragePointer = tls_pointer2;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||
ok( tlsinfo->ThreadDataCount == 1, "got %#lx.\n", tlsinfo->ThreadDataCount );
|
||||
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||
ok( tlsinfo->ThreadData[0].ThreadId == curr_thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
ok( tlsinfo->ThreadData[0].TlsVector == tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||
ok( thread_teb->ThreadLocalStoragePointer == tls_pointer2, "wrong vector.\n" );
|
||||
|
||||
/* Set for both threads at once as probably intended. Provide an extra data for the missing third thread
|
||||
* which won't be used. */
|
||||
teb->ThreadLocalStoragePointer = tls_pointer;
|
||||
thread_teb->ThreadLocalStoragePointer = tls_pointer2;
|
||||
memcpy( new_tls_pointer2, new_tls_pointer, sizeof(new_tls_pointer2) );
|
||||
tlsinfo->ThreadDataCount = 3;
|
||||
tlsinfo->ThreadData[0].TlsVector = new_tls_pointer;
|
||||
tlsinfo->ThreadData[0].Flags = 0;
|
||||
tlsinfo->ThreadData[1].TlsVector = new_tls_pointer2;
|
||||
tlsinfo->ThreadData[1].Flags = 0;
|
||||
tlsinfo->ThreadData[2].TlsVector = (void *)0xdeadbeef;
|
||||
tlsinfo->ThreadData[2].Flags = 0;
|
||||
tlsinfo->ThreadData[2].ThreadId = 0xdeadbeef;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||
ok( tlsinfo->ThreadDataCount == 3, "got %#lx.\n", tlsinfo->ThreadDataCount );
|
||||
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||
ok( tlsinfo->ThreadData[0].ThreadId == curr_thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
ok( tlsinfo->ThreadData[0].TlsVector == tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||
ok( tlsinfo->ThreadData[1].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[1].Flags );
|
||||
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||
ok( tlsinfo->ThreadData[1].ThreadId == thread_id, "got %#Ix.\n", tlsinfo->ThreadData[1].ThreadId );
|
||||
ok( tlsinfo->ThreadData[1].TlsVector == tls_pointer2, "got %p.\n", tlsinfo->ThreadData[1].TlsVector );
|
||||
ok( !tlsinfo->ThreadData[2].Flags, "got %#lx.\n", tlsinfo->ThreadData[2].Flags );
|
||||
ok( tlsinfo->ThreadData[2].ThreadId == 0xdeadbeef, "got %#Ix.\n", tlsinfo->ThreadData[2].ThreadId );
|
||||
ok( tlsinfo->ThreadData[2].TlsVector == (void *)0xdeadbeef, "got %p.\n", tlsinfo->ThreadData[2].TlsVector );
|
||||
|
||||
/* Test with unaccessible data. */
|
||||
tlsinfo->ThreadData[0].TlsVector = new_tls_pointer;
|
||||
tlsinfo->ThreadData[0].ThreadId = 0;
|
||||
tlsinfo->ThreadData[0].Flags = 0;
|
||||
tlsinfo->ThreadData[1].TlsVector = new_tls_pointer2;
|
||||
tlsinfo->ThreadData[1].ThreadId = 0;
|
||||
tlsinfo->ThreadData[1].Flags = 0;
|
||||
teb->ThreadLocalStoragePointer = tls_pointer;
|
||||
thread_teb->ThreadLocalStoragePointer = (void *)0xdeadbee0;
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
ok( status == STATUS_ACCESS_VIOLATION, "got %#lx.\n", status );
|
||||
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||
ok( tlsinfo->ThreadDataCount == 3, "got %#lx.\n", tlsinfo->ThreadDataCount );
|
||||
if (wow)
|
||||
{
|
||||
ok( !tlsinfo->ThreadData[0].Flags, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
ok( !tlsinfo->ThreadData[0].ThreadId, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
ok( tlsinfo->ThreadData[0].TlsVector == new_tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
ok( tlsinfo->ThreadData[0].ThreadId == curr_thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
ok( tlsinfo->ThreadData[0].TlsVector == tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||
}
|
||||
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||
ok( !tlsinfo->ThreadData[1].Flags, "got %#lx.\n", tlsinfo->ThreadData[1].Flags );
|
||||
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||
ok( !tlsinfo->ThreadData[1].ThreadId, "got %#Ix.\n", tlsinfo->ThreadData[1].ThreadId );
|
||||
ok( tlsinfo->ThreadData[1].TlsVector == new_tls_pointer2, "got %p.\n", tlsinfo->ThreadData[1].TlsVector );
|
||||
ok( !tlsinfo->ThreadData[2].Flags, "got %#lx.\n", tlsinfo->ThreadData[2].Flags );
|
||||
ok( tlsinfo->ThreadData[2].ThreadId == 0xdeadbeef, "got %#Ix.\n", tlsinfo->ThreadData[2].ThreadId );
|
||||
ok( tlsinfo->ThreadData[2].TlsVector == (void *)0xdeadbeef, "got %p.\n", tlsinfo->ThreadData[2].TlsVector );
|
||||
|
||||
/* Test replacing TLS index. */
|
||||
teb->ThreadLocalStoragePointer = new_tls_pointer;
|
||||
thread_teb->ThreadLocalStoragePointer = new_tls_pointer2;
|
||||
new_tls_pointer[1] = (void *)0xcccccccc;
|
||||
new_tls_pointer2[1] = (void *)0xdddddddd;
|
||||
tlsinfo->ThreadDataCount = 3;
|
||||
tlsinfo->OperationType = ProcessTlsReplaceIndex;
|
||||
tlsinfo->TlsIndex = 1;
|
||||
for (i = 0; i < 3; ++i)
|
||||
{
|
||||
tlsinfo->ThreadData[i].Flags = 0;
|
||||
tlsinfo->ThreadData[i].ThreadId = 0xdeadbeef;
|
||||
tlsinfo->ThreadData[i].TlsModulePointer = (void *)((ULONG_PTR)i + 1);
|
||||
}
|
||||
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||
ok( tlsinfo->ThreadDataCount == 3, "got %#lx.\n", tlsinfo->ThreadDataCount );
|
||||
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
ok( (ULONG_PTR)new_tls_pointer[1] == 1, "got %p.\n", new_tls_pointer[1] );
|
||||
ok( tlsinfo->ThreadData[0].ThreadId == 0xdeadbeef, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
ok( (ULONG_PTR)tlsinfo->ThreadData[0].TlsModulePointer == 0xcccccccc, "got %p.\n", tlsinfo->ThreadData[0].TlsModulePointer );
|
||||
ok( tlsinfo->ThreadData[1].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[1].Flags );
|
||||
ok( (ULONG_PTR)new_tls_pointer2[1] == 2, "got %p.\n", new_tls_pointer2[1] );
|
||||
ok( tlsinfo->ThreadData[1].ThreadId == 0xdeadbeef, "got %#Ix.\n", tlsinfo->ThreadData[1].ThreadId );
|
||||
ok( (ULONG_PTR)tlsinfo->ThreadData[1].TlsModulePointer == 0xdddddddd, "got %p.\n", tlsinfo->ThreadData[1].TlsModulePointer );
|
||||
ok( !tlsinfo->ThreadData[2].Flags, "got %#lx.\n", tlsinfo->ThreadData[2].Flags );
|
||||
ok( tlsinfo->ThreadData[2].ThreadId == 0xdeadbeef, "got %#Ix.\n", tlsinfo->ThreadData[2].ThreadId );
|
||||
ok( (ULONG_PTR)tlsinfo->ThreadData[2].TlsModulePointer == 3, "got %p.\n", tlsinfo->ThreadData[2].TlsModulePointer );
|
||||
|
||||
/* Restore original TLS data. */
|
||||
teb->ThreadLocalStoragePointer = save_tls_pointers[0];
|
||||
thread_teb->ThreadLocalStoragePointer = save_tls_pointers[1];
|
||||
ResumeThread( thread );
|
||||
WaitForSingleObject( thread, INFINITE );
|
||||
CloseHandle( thread );
|
||||
}
|
||||
|
||||
START_TEST(info)
|
||||
{
|
||||
char **argv;
|
||||
|
@ -4167,4 +4439,5 @@ START_TEST(info)
|
|||
test_process_token(argc, argv);
|
||||
test_process_id();
|
||||
test_processor_idle_cycle_time();
|
||||
test_set_process_tls_info();
|
||||
}
|
||||
|
|
|
@ -1711,6 +1711,33 @@ NTSTATUS WINAPI NtSetInformationProcess( HANDLE handle, PROCESSINFOCLASS class,
|
|||
process_error_mode = *(UINT *)info;
|
||||
break;
|
||||
|
||||
case ProcessTlsInformation:
|
||||
{
|
||||
PROCESS_TLS_INFORMATION *t = info;
|
||||
unsigned int i;
|
||||
|
||||
if (handle != NtCurrentProcess())
|
||||
{
|
||||
FIXME( "ProcessTlsInformation is not supported for the other process yet, handle %p.\n", handle );
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (size < sizeof(*t) || size != offsetof(PROCESS_TLS_INFORMATION, ThreadData[t->ThreadDataCount]))
|
||||
return STATUS_INFO_LENGTH_MISMATCH;
|
||||
if (t->Flags & ~PROCESS_TLS_INFORMATION_WOW64)
|
||||
{
|
||||
WARN( "ProcessTlsInformation: unknown flags %#x.\n", (int)t->Flags );
|
||||
return STATUS_INFO_LENGTH_MISMATCH;
|
||||
}
|
||||
if (t->Flags & PROCESS_TLS_INFORMATION_WOW64 && !(is_win64 && is_wow64()))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (t->OperationType >= MaxProcessTlsOperation) return STATUS_INFO_LENGTH_MISMATCH;
|
||||
for (i = 0; i < t->ThreadDataCount; ++i)
|
||||
if (t->ThreadData[i].Flags) return STATUS_INVALID_PARAMETER;
|
||||
ret = virtual_set_tls_information( t );
|
||||
break;
|
||||
}
|
||||
|
||||
case ProcessAffinityMask:
|
||||
{
|
||||
const ULONG_PTR system_mask = get_system_affinity_mask();
|
||||
|
|
|
@ -282,6 +282,7 @@ extern TEB *virtual_alloc_first_teb(void);
|
|||
extern NTSTATUS virtual_alloc_teb( TEB **ret_teb );
|
||||
extern void virtual_free_teb( TEB *teb );
|
||||
extern NTSTATUS virtual_clear_tls_index( ULONG index );
|
||||
extern NTSTATUS virtual_set_tls_information( PROCESS_TLS_INFORMATION *t );
|
||||
extern NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR limit_low, ULONG_PTR limit_high,
|
||||
SIZE_T reserve_size, SIZE_T commit_size, BOOL guard_page );
|
||||
extern void virtual_map_user_shared_data(void);
|
||||
|
|
|
@ -3874,6 +3874,98 @@ NTSTATUS virtual_clear_tls_index( ULONG index )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* virtual_set_tls_information_teb
|
||||
*/
|
||||
static NTSTATUS virtual_set_tls_information_teb( PROCESS_TLS_INFORMATION *t, unsigned int *idx, TEB *teb )
|
||||
{
|
||||
__TRY
|
||||
{
|
||||
#ifdef _WIN64
|
||||
if (t->Flags & PROCESS_TLS_INFORMATION_WOW64)
|
||||
{
|
||||
WOW_TEB *wow_teb = get_wow_teb( teb );
|
||||
ULONG *ptr;
|
||||
|
||||
if (wow_teb && wow_teb->ThreadLocalStoragePointer)
|
||||
{
|
||||
if (t->OperationType == ProcessTlsReplaceVector)
|
||||
{
|
||||
ptr = t->ThreadData[*idx].TlsVector;
|
||||
memcpy( ptr, ULongToPtr( wow_teb->ThreadLocalStoragePointer ), sizeof(*ptr) * t->TlsVectorLength );
|
||||
t->ThreadData[*idx].TlsVector = ULongToPtr( InterlockedExchange( (LONG *)&wow_teb->ThreadLocalStoragePointer, PtrToLong( ptr )));
|
||||
t->ThreadData[*idx].ThreadId = wow_teb->ClientId.UniqueThread;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = ULongToPtr( wow_teb->ThreadLocalStoragePointer );
|
||||
t->ThreadData[*idx].TlsModulePointer =
|
||||
ULongToPtr( InterlockedExchange( (LONG *)&ptr[t->TlsIndex],
|
||||
PtrToLong( t->ThreadData[*idx].TlsModulePointer )));
|
||||
}
|
||||
t->ThreadData[*idx].Flags = THREAD_TLS_INFORMATION_ASSIGNED;
|
||||
++*idx;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (teb->ThreadLocalStoragePointer)
|
||||
{
|
||||
void **ptr;
|
||||
|
||||
if (t->OperationType == ProcessTlsReplaceVector)
|
||||
{
|
||||
ptr = t->ThreadData[*idx].TlsVector;
|
||||
memcpy( ptr, teb->ThreadLocalStoragePointer, sizeof(*ptr) * t->TlsVectorLength );
|
||||
t->ThreadData[*idx].TlsVector = InterlockedExchangePointer( &teb->ThreadLocalStoragePointer, ptr );
|
||||
t->ThreadData[*idx].ThreadId = HandleToULong( teb->ClientId.UniqueThread );
|
||||
#ifdef __x86_64__ /* macOS-specific hack */
|
||||
if (teb->Instrumentation[0]) ((TEB *)teb->Instrumentation[0])->ThreadLocalStoragePointer = ptr;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = teb->ThreadLocalStoragePointer;
|
||||
t->ThreadData[*idx].TlsModulePointer = InterlockedExchangePointer( &ptr[t->TlsIndex],
|
||||
t->ThreadData[*idx].TlsModulePointer );
|
||||
}
|
||||
t->ThreadData[*idx].Flags = THREAD_TLS_INFORMATION_ASSIGNED;
|
||||
++*idx;
|
||||
}
|
||||
}
|
||||
__EXCEPT
|
||||
{
|
||||
return STATUS_ACCESS_VIOLATION;
|
||||
}
|
||||
__ENDTRY
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* virtual_set_tls_information
|
||||
*/
|
||||
NTSTATUS virtual_set_tls_information( PROCESS_TLS_INFORMATION *t )
|
||||
{
|
||||
struct ntdll_thread_data *thread_data;
|
||||
NTSTATUS ret = STATUS_SUCCESS;
|
||||
unsigned int idx = 0;
|
||||
sigset_t sigset;
|
||||
|
||||
server_enter_uninterrupted_section( &virtual_mutex, &sigset );
|
||||
LIST_FOR_EACH_ENTRY_REV( thread_data, &teb_list, struct ntdll_thread_data, entry )
|
||||
{
|
||||
TEB *teb = CONTAINING_RECORD( thread_data, TEB, GdiTebBatch );
|
||||
|
||||
if (idx == t->ThreadDataCount) break;
|
||||
if ((ret = virtual_set_tls_information_teb( t, &idx, teb ))) break;
|
||||
}
|
||||
server_leave_uninterrupted_section( &virtual_mutex, &sigset );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* virtual_alloc_thread_stack
|
||||
*/
|
||||
|
|
|
@ -894,6 +894,39 @@ NTSTATUS WINAPI wow64_NtSetInformationProcess( UINT *args )
|
|||
}
|
||||
else return STATUS_INVALID_PARAMETER;
|
||||
|
||||
case ProcessTlsInformation:
|
||||
{
|
||||
PROCESS_TLS_INFORMATION32 *t32 = ptr;
|
||||
PROCESS_TLS_INFORMATION *t;
|
||||
ULONG i;
|
||||
|
||||
if (len >= sizeof(*t32) && len >= offsetof(PROCESS_TLS_INFORMATION32, ThreadData[t32->ThreadDataCount]))
|
||||
{
|
||||
t = Wow64AllocateTemp( offsetof(PROCESS_TLS_INFORMATION, ThreadData[t32->ThreadDataCount]) );
|
||||
t->Flags = t32->Flags ? t32->Flags : PROCESS_TLS_INFORMATION_WOW64;
|
||||
t->OperationType = t32->OperationType;
|
||||
t->ThreadDataCount = t32->ThreadDataCount;
|
||||
t->TlsIndex = t32->TlsIndex;
|
||||
for (i = 0; i < t->ThreadDataCount; ++i)
|
||||
{
|
||||
t->ThreadData[i].Flags = t32->ThreadData[i].Flags;
|
||||
t->ThreadData[i].ThreadId = t32->ThreadData[i].ThreadId;
|
||||
t->ThreadData[i].TlsVector = ULongToPtr( t32->ThreadData[i].TlsVector );
|
||||
}
|
||||
if (!(status = NtSetInformationProcess( handle, class, t, offsetof(PROCESS_TLS_INFORMATION, ThreadData[t->ThreadDataCount]) )))
|
||||
{
|
||||
for (i = 0; i < t->ThreadDataCount; ++i)
|
||||
{
|
||||
t32->ThreadData[i].Flags = t->ThreadData[i].Flags;
|
||||
t32->ThreadData[i].ThreadId = t->ThreadData[i].ThreadId;
|
||||
t32->ThreadData[i].TlsVector = PtrToUlong( t->ThreadData[i].TlsVector );
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
else return STATUS_INFO_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
case ProcessInstrumentationCallback: /* PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION */
|
||||
if (len >= sizeof(ULONG))
|
||||
{
|
||||
|
|
|
@ -326,6 +326,30 @@ typedef struct
|
|||
ULONG DefaultBase;
|
||||
} RTL_PROCESS_MODULE_INFORMATION_EX32;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG Flags;
|
||||
union
|
||||
{
|
||||
ULONG TlsVector;
|
||||
ULONG TlsModulePointer;
|
||||
};
|
||||
ULONG ThreadId;
|
||||
} THREAD_TLS_INFORMATION32;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG Flags;
|
||||
ULONG OperationType;
|
||||
ULONG ThreadDataCount;
|
||||
union
|
||||
{
|
||||
ULONG TlsIndex;
|
||||
ULONG TlsVectorLength;
|
||||
};
|
||||
THREAD_TLS_INFORMATION32 ThreadData[1];
|
||||
} PROCESS_TLS_INFORMATION32;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG BaseAddress;
|
||||
|
|
|
@ -2668,6 +2668,41 @@ typedef struct _PROCESS_CYCLE_TIME_INFORMATION {
|
|||
ULONGLONG CurrentCycleCount;
|
||||
} PROCESS_CYCLE_TIME_INFORMATION, *PPROCESS_CYCLE_TIME_INFORMATION;
|
||||
|
||||
typedef struct _THREAD_TLS_INFORMATION
|
||||
{
|
||||
ULONG Flags;
|
||||
union
|
||||
{
|
||||
void *TlsVector;
|
||||
void *TlsModulePointer;
|
||||
};
|
||||
ULONG_PTR ThreadId;
|
||||
} THREAD_TLS_INFORMATION, * PTHREAD_TLS_INFORMATION;
|
||||
|
||||
#define THREAD_TLS_INFORMATION_ASSIGNED 0x2
|
||||
|
||||
typedef enum _PROCESS_TLS_INFORMATION_TYPE
|
||||
{
|
||||
ProcessTlsReplaceIndex,
|
||||
ProcessTlsReplaceVector,
|
||||
MaxProcessTlsOperation
|
||||
} PROCESS_TLS_INFORMATION_TYPE, *PPROCESS_TLS_INFORMATION_TYPE;
|
||||
|
||||
typedef struct _PROCESS_TLS_INFORMATION
|
||||
{
|
||||
ULONG Flags;
|
||||
ULONG OperationType;
|
||||
ULONG ThreadDataCount;
|
||||
union
|
||||
{
|
||||
ULONG TlsIndex;
|
||||
ULONG TlsVectorLength;
|
||||
};
|
||||
THREAD_TLS_INFORMATION ThreadData[1];
|
||||
} PROCESS_TLS_INFORMATION, *PPROCESS_TLS_INFORMATION;
|
||||
|
||||
#define PROCESS_TLS_INFORMATION_WOW64 1
|
||||
|
||||
typedef struct _PROCESS_STACK_ALLOCATION_INFORMATION
|
||||
{
|
||||
SIZE_T ReserveSize;
|
||||
|
|
Loading…
Reference in a new issue