mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-21 17:09:06 -07:00
ntdll: Implement NtSetInformationProcess( ProcessTlsInformation ).
This commit is contained in:
parent
09d95bb505
commit
4e851a71c7
6 changed files with 181 additions and 5 deletions
|
@ -4139,19 +4139,18 @@ static void test_set_process_tls_info(void)
|
|||
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||
if (wow)
|
||||
{
|
||||
todo_wine ok( !status, "got %#lx.\n", status );
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
ok( tlsinfo->Flags == 1, "got %#lx.\n", tlsinfo->Flags );
|
||||
todo_wine ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||
todo_wine ok( tlsinfo->ThreadData[0].ThreadId == curr_thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||
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
|
||||
{
|
||||
todo_wine ok( status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status );
|
||||
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 );
|
||||
}
|
||||
if (status == STATUS_NOT_IMPLEMENTED) return;
|
||||
|
||||
/* Other PROCESS_TLS_INFORMATION flags are invalid. STATUS_INFO_LENGTH_MISMATCH is weird but that's for any flag
|
||||
* besides 1. */
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue