wow64: Add thunks for the process/thread query information syscalls.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-07-29 15:28:34 +02:00
parent 6159b12330
commit ebb4d3887b
4 changed files with 339 additions and 0 deletions

View file

@ -56,6 +56,21 @@ static BOOL is_process_wow64( HANDLE handle )
}
static BOOL is_process_id_wow64( const CLIENT_ID *id )
{
HANDLE handle;
BOOL ret = FALSE;
if (id->UniqueProcess == ULongToHandle(GetCurrentProcessId())) return TRUE;
if (!NtOpenProcess( &handle, PROCESS_QUERY_LIMITED_INFORMATION, NULL, id ))
{
ret = is_process_wow64( handle );
NtClose( handle );
}
return ret;
}
static RTL_USER_PROCESS_PARAMETERS *process_params_32to64( RTL_USER_PROCESS_PARAMETERS **params,
RTL_USER_PROCESS_PARAMETERS32 *params32 )
{
@ -242,6 +257,23 @@ static void put_ps_attributes( PS_ATTRIBUTE_LIST32 *attr32, const PS_ATTRIBUTE_L
}
void put_vm_counters( VM_COUNTERS_EX32 *info32, const VM_COUNTERS_EX *info, ULONG size )
{
info32->PeakVirtualSize = info->PeakVirtualSize;
info32->VirtualSize = info->VirtualSize;
info32->PageFaultCount = info->PageFaultCount;
info32->PeakWorkingSetSize = info->PeakWorkingSetSize;
info32->WorkingSetSize = info->WorkingSetSize;
info32->QuotaPeakPagedPoolUsage = info->QuotaPeakPagedPoolUsage;
info32->QuotaPagedPoolUsage = info->QuotaPagedPoolUsage;
info32->QuotaPeakNonPagedPoolUsage = info->QuotaPeakNonPagedPoolUsage;
info32->QuotaNonPagedPoolUsage = info->QuotaNonPagedPoolUsage;
info32->PagefileUsage = info->PagefileUsage;
info32->PeakPagefileUsage = info->PeakPagefileUsage;
if (size == sizeof(VM_COUNTERS_EX32)) info32->PrivateUsage = info->PrivateUsage;
}
/**********************************************************************
* wow64_NtAlertResumeThread
*/
@ -480,6 +512,246 @@ NTSTATUS WINAPI wow64_NtOpenThread( UINT *args )
}
/**********************************************************************
* wow64_NtQueryInformationProcess
*/
NTSTATUS WINAPI wow64_NtQueryInformationProcess( UINT *args )
{
HANDLE handle = get_handle( &args );
PROCESSINFOCLASS class = get_ulong( &args );
void *ptr = get_ptr( &args );
ULONG len = get_ulong( &args );
ULONG *retlen = get_ptr( &args );
NTSTATUS status;
switch (class)
{
case ProcessBasicInformation: /* PROCESS_BASIC_INFORMATION */
if (len == sizeof(PROCESS_BASIC_INFORMATION32))
{
PROCESS_BASIC_INFORMATION info;
PROCESS_BASIC_INFORMATION32 *info32 = ptr;
if (!(status = NtQueryInformationProcess( handle, class, &info, sizeof(info), NULL )))
{
if (is_process_wow64( handle ))
info32->PebBaseAddress = PtrToUlong( info.PebBaseAddress ) + 0x1000;
else
info32->PebBaseAddress = 0;
info32->ExitStatus = info.ExitStatus;
info32->AffinityMask = info.AffinityMask;
info32->BasePriority = info.BasePriority;
info32->UniqueProcessId = info.UniqueProcessId;
info32->InheritedFromUniqueProcessId = info.InheritedFromUniqueProcessId;
if (retlen) *retlen = sizeof(*info32);
}
return status;
}
if (retlen) *retlen = sizeof(PROCESS_BASIC_INFORMATION32);
return STATUS_INFO_LENGTH_MISMATCH;
case ProcessIoCounters: /* IO_COUNTERS */
case ProcessTimes: /* KERNEL_USER_TIMES */
case ProcessDefaultHardErrorMode: /* ULONG */
case ProcessPriorityClass: /* PROCESS_PRIORITY_CLASS */
case ProcessHandleCount: /* ULONG */
case ProcessSessionInformation: /* ULONG */
case ProcessDebugFlags: /* ULONG */
case ProcessExecuteFlags: /* ULONG */
case ProcessCookie: /* ULONG */
/* FIXME: check buffer alignment */
return NtQueryInformationProcess( handle, class, ptr, len, retlen );
case ProcessVmCounters: /* VM_COUNTERS_EX */
if (len == sizeof(VM_COUNTERS32) || len == sizeof(VM_COUNTERS_EX32))
{
VM_COUNTERS_EX info;
VM_COUNTERS_EX32 *info32 = ptr;
if (!(status = NtQueryInformationProcess( handle, class, &info, sizeof(info), NULL )))
{
put_vm_counters( info32, &info, len );
if (retlen) *retlen = len;
}
return status;
}
if (retlen) *retlen = sizeof(VM_COUNTERS_EX32);
return STATUS_INFO_LENGTH_MISMATCH;
case ProcessDebugPort: /* ULONG_PTR */
case ProcessAffinityMask: /* ULONG_PTR */
case ProcessWow64Information: /* ULONG_PTR */
case ProcessDebugObjectHandle: /* HANDLE */
if (len == sizeof(ULONG))
{
ULONG_PTR data;
if (!(status = NtQueryInformationProcess( handle, class, &data, sizeof(data), NULL )))
{
*(ULONG *)ptr = data;
if (retlen) *retlen = sizeof(ULONG);
}
else if (status == STATUS_PORT_NOT_SET) *(ULONG *)ptr = 0;
return status;
}
if (retlen) *retlen = sizeof(ULONG);
return STATUS_INFO_LENGTH_MISMATCH;
case ProcessImageFileName:
case ProcessImageFileNameWin32: /* UNICODE_STRING + string */
{
ULONG retsize, size = len + sizeof(UNICODE_STRING) - sizeof(UNICODE_STRING32);
UNICODE_STRING *str = Wow64AllocateTemp( size );
UNICODE_STRING32 *str32 = ptr;
if (!(status = NtQueryInformationProcess( handle, class, str, size, &retsize )))
{
str32->Length = str->Length;
str32->MaximumLength = str->MaximumLength;
str32->Buffer = PtrToUlong( str32 + 1 );
memcpy( str32 + 1, str->Buffer, str->MaximumLength );
}
if (retlen) *retlen = retsize + sizeof(UNICODE_STRING32) - sizeof(UNICODE_STRING);
return status;
}
case ProcessImageInformation: /* SECTION_IMAGE_INFORMATION */
if (len == sizeof(SECTION_IMAGE_INFORMATION32))
{
SECTION_IMAGE_INFORMATION info;
SECTION_IMAGE_INFORMATION32 *info32 = ptr;
if (!(status = NtQueryInformationProcess( handle, class, &info, sizeof(info), NULL )))
{
put_section_image_info( info32, &info );
if (retlen) *retlen = sizeof(*info32);
}
return status;
}
if (retlen) *retlen = sizeof(SECTION_IMAGE_INFORMATION32);
return STATUS_INFO_LENGTH_MISMATCH;
default:
FIXME( "unsupported class %u\n", class );
return STATUS_INVALID_INFO_CLASS;
}
}
/**********************************************************************
* wow64_NtQueryInformationThread
*/
NTSTATUS WINAPI wow64_NtQueryInformationThread( UINT *args )
{
HANDLE handle = get_handle( &args );
THREADINFOCLASS class = get_ulong( &args );
void *ptr = get_ptr( &args );
ULONG len = get_ulong( &args );
ULONG *retlen = get_ptr( &args );
NTSTATUS status;
switch (class)
{
case ThreadBasicInformation: /* THREAD_BASIC_INFORMATION */
{
THREAD_BASIC_INFORMATION32 info32;
THREAD_BASIC_INFORMATION info;
status = NtQueryInformationThread( handle, class, &info, sizeof(info), NULL );
if (!status)
{
info32.ExitStatus = info.ExitStatus;
info32.TebBaseAddress = is_process_id_wow64( &info.ClientId ) ?
PtrToUlong(info.TebBaseAddress) + 0x2000 : 0;
info32.ClientId.UniqueProcess = HandleToULong( info.ClientId.UniqueProcess );
info32.ClientId.UniqueThread = HandleToULong( info.ClientId.UniqueThread );
info32.AffinityMask = info.AffinityMask;
info32.Priority = info.Priority;
info32.BasePriority = info.BasePriority;
memcpy( ptr, &info32, min( len, sizeof(info32) ));
if (retlen) *retlen = min( len, sizeof(info32) );
}
return status;
}
case ThreadTimes: /* KERNEL_USER_TIMES */
case ThreadEnableAlignmentFaultFixup: /* set only */
case ThreadAmILastThread: /* ULONG */
case ThreadIsIoPending: /* ULONG */
case ThreadHideFromDebugger: /* BOOLEAN */
case ThreadSuspendCount: /* ULONG */
/* FIXME: check buffer alignment */
return NtQueryInformationThread( handle, class, ptr, len, retlen );
case ThreadAffinityMask: /* ULONG_PTR */
case ThreadQuerySetWin32StartAddress: /* PRTL_THREAD_START_ROUTINE */
{
ULONG_PTR data;
status = NtQueryInformationThread( handle, class, &data, sizeof(data), NULL );
if (!status)
{
memcpy( ptr, &data, min( len, sizeof(ULONG) ));
if (retlen) *retlen = min( len, sizeof(ULONG) );
}
return status;
}
case ThreadDescriptorTableEntry: /* THREAD_DESCRIPTOR_INFORMATION */
return RtlWow64GetThreadSelectorEntry( handle, ptr, len, retlen );
case ThreadWow64Context: /* WOW64_CONTEXT* */
return STATUS_INVALID_INFO_CLASS;
case ThreadGroupInformation: /* GROUP_AFFINITY */
{
GROUP_AFFINITY info;
status = NtQueryInformationThread( handle, class, &info, sizeof(info), NULL );
if (!status)
{
GROUP_AFFINITY32 info32 = { info.Mask, info.Group };
memcpy( ptr, &info32, min( len, sizeof(info32) ));
if (retlen) *retlen = min( len, sizeof(info32) );
}
return status;
}
case ThreadDescription: /* THREAD_DESCRIPTION_INFORMATION */
{
THREAD_DESCRIPTION_INFORMATION *info;
THREAD_DESCRIPTION_INFORMATION32 *info32 = ptr;
ULONG size, ret_size;
if (len >= sizeof(*info32))
{
size = sizeof(*info) + len - sizeof(*info32);
info = Wow64AllocateTemp( size );
status = NtQueryInformationThread( handle, class, info, size, &ret_size );
if (!status)
{
info32->Description.Length = info->Description.Length;
info32->Description.MaximumLength = info->Description.MaximumLength;
info32->Description.Buffer = PtrToUlong( info32 + 1 );
memcpy( info32 + 1, info + 1, min( len, info->Description.MaximumLength ));
}
}
else status = NtQueryInformationThread( handle, class, NULL, 0, &ret_size );
if (retlen && (status == STATUS_SUCCESS || status == STATUS_BUFFER_TOO_SMALL))
*retlen = sizeof(*info32) + ret_size - sizeof(*info);
return status;
}
default:
FIXME( "unsupported class %u\n", class );
return STATUS_INVALID_INFO_CLASS;
}
}
/**********************************************************************
* wow64_NtQueueApcThread
*/

View file

@ -100,6 +100,13 @@ typedef struct
WCHAR FileName[1];
} FILE_RENAME_INFORMATION32;
typedef struct
{
ULONG Mask;
WORD Group;
WORD Reserved[3];
} GROUP_AFFINITY32;
typedef struct
{
ULONG BaseAddress;
@ -136,6 +143,16 @@ typedef struct
MEMORY_WORKING_SET_EX_BLOCK32 VirtualAttributes;
} MEMORY_WORKING_SET_EX_INFORMATION32;
typedef struct
{
NTSTATUS ExitStatus;
ULONG PebBaseAddress;
ULONG AffinityMask;
LONG BasePriority;
ULONG UniqueProcessId;
ULONG InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION32;
typedef struct
{
ULONG Size;
@ -217,6 +234,52 @@ typedef struct
ULONG CheckSum;
} SECTION_IMAGE_INFORMATION32;
typedef struct
{
NTSTATUS ExitStatus;
ULONG TebBaseAddress;
CLIENT_ID32 ClientId;
ULONG AffinityMask;
LONG Priority;
LONG BasePriority;
} THREAD_BASIC_INFORMATION32;
typedef struct
{
UNICODE_STRING32 Description;
} THREAD_DESCRIPTION_INFORMATION32;
typedef struct
{
ULONG PeakVirtualSize;
ULONG VirtualSize;
ULONG PageFaultCount;
ULONG PeakWorkingSetSize;
ULONG WorkingSetSize;
ULONG QuotaPeakPagedPoolUsage;
ULONG QuotaPagedPoolUsage;
ULONG QuotaPeakNonPagedPoolUsage;
ULONG QuotaNonPagedPoolUsage;
ULONG PagefileUsage;
ULONG PeakPagefileUsage;
} VM_COUNTERS32;
typedef struct
{
ULONG PeakVirtualSize;
ULONG VirtualSize;
ULONG PageFaultCount;
ULONG PeakWorkingSetSize;
ULONG WorkingSetSize;
ULONG QuotaPeakPagedPoolUsage;
ULONG QuotaPagedPoolUsage;
ULONG QuotaPeakNonPagedPoolUsage;
ULONG QuotaNonPagedPoolUsage;
ULONG PagefileUsage;
ULONG PeakPagefileUsage;
ULONG PrivateUsage;
} VM_COUNTERS_EX32;
typedef struct
{
DBG_STATE NewState;

View file

@ -121,6 +121,8 @@
SYSCALL_ENTRY( NtQueryFullAttributesFile ) \
SYSCALL_ENTRY( NtQueryInformationAtom ) \
SYSCALL_ENTRY( NtQueryInformationFile ) \
SYSCALL_ENTRY( NtQueryInformationProcess ) \
SYSCALL_ENTRY( NtQueryInformationThread ) \
SYSCALL_ENTRY( NtQueryInstallUILanguage ) \
SYSCALL_ENTRY( NtQueryIoCompletion ) \
SYSCALL_ENTRY( NtQueryKey ) \

View file

@ -217,5 +217,7 @@ static inline void put_iosb( IO_STATUS_BLOCK32 *io32, const IO_STATUS_BLOCK *io
extern void put_section_image_info( SECTION_IMAGE_INFORMATION32 *info32,
const SECTION_IMAGE_INFORMATION *info ) DECLSPEC_HIDDEN;
extern void put_vm_counters( VM_COUNTERS_EX32 *info32, const VM_COUNTERS_EX *info,
ULONG size ) DECLSPEC_HIDDEN;
#endif /* __WOW64_PRIVATE_H */