[PATCH 3/3] ntdll: Implement SystemExtendedProcessInformation system info class.
Paul Gofman
pgofman at codeweavers.com
Mon Oct 25 10:53:32 CDT 2021
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
dlls/ntdll/tests/info.c | 87 +++++++++++++++++++++++++++++++++++-----
dlls/ntdll/unix/system.c | 42 ++++++++++++-------
include/winternl.h | 12 ++++++
server/process.c | 2 +
server/protocol.def | 2 +
5 files changed, 120 insertions(+), 25 deletions(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index 635c551383c..319f86db9e2 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -438,7 +438,7 @@ static void test_query_timeofday(void)
if (winetest_debug > 1) trace("uCurrentTimeZoneId : (%d)\n", sti.uCurrentTimeZoneId);
}
-static void test_query_process(void)
+static void test_query_process( BOOL extended )
{
NTSTATUS status;
DWORD last_pid;
@@ -470,12 +470,27 @@ static void test_query_process(void)
SYSTEM_THREAD_INFORMATION ti[1];
} SYSTEM_PROCESS_INFORMATION_PRIVATE;
+ BOOL is_process_wow64 = FALSE, current_process_found = FALSE;
SYSTEM_PROCESS_INFORMATION_PRIVATE *spi, *spi_buf;
- BOOL current_process_found = FALSE;
+ SYSTEM_EXTENDED_THREAD_INFORMATION *ti;
+ SYSTEM_INFORMATION_CLASS info_class;
+ void *expected_address;
+ ULONG thread_info_size;
+
+ if (extended)
+ {
+ info_class = SystemExtendedProcessInformation;
+ thread_info_size = sizeof(SYSTEM_EXTENDED_THREAD_INFORMATION);
+ }
+ else
+ {
+ info_class = SystemProcessInformation;
+ thread_info_size = sizeof(SYSTEM_THREAD_INFORMATION);
+ }
/* test ReturnLength */
ReturnLength = 0;
- status = pNtQuerySystemInformation(SystemProcessInformation, NULL, 0, &ReturnLength);
+ status = pNtQuerySystemInformation( info_class, NULL, 0, &ReturnLength);
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH got %08x\n", status);
ok( ReturnLength > 0, "got 0 length\n" );
@@ -486,8 +501,10 @@ static void test_query_process(void)
return;
}
+ winetest_push_context( "extended %d", extended );
+
spi_buf = HeapAlloc(GetProcessHeap(), 0, ReturnLength);
- status = pNtQuerySystemInformation(SystemProcessInformation, spi_buf, ReturnLength, &ReturnLength);
+ status = pNtQuerySystemInformation(info_class, spi_buf, ReturnLength, &ReturnLength);
/* Sometimes new process or threads appear between the call and increase the size,
* otherwise the previously returned buffer size should be sufficient. */
@@ -511,16 +528,64 @@ static void test_query_process(void)
if (last_pid == GetCurrentProcessId())
current_process_found = TRUE;
- ok(!(last_pid & 3), "Unexpected PID low bits: %p\n", spi->UniqueProcessId);
+ if (extended && is_wow64 && spi->UniqueProcessId)
+ {
+ InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
+ cid.UniqueProcess = spi->UniqueProcessId;
+ cid.UniqueThread = 0;
+ status = NtOpenProcess( &handle, PROCESS_QUERY_LIMITED_INFORMATION, &attr, &cid );
+ ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
+ "Got unexpected status %#x, pid %p.\n", status, spi->UniqueProcessId );
+
+ if (!status)
+ {
+ ULONG_PTR info;
+
+ status = NtQueryInformationProcess( handle, ProcessWow64Information, &info, sizeof(info), NULL );
+ ok( status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status );
+ is_process_wow64 = !!info;
+ NtClose( handle );
+ }
+ }
+
for (j = 0; j < spi->dwThreadCount; j++)
{
+ ti = (SYSTEM_EXTENDED_THREAD_INFORMATION *)((BYTE *)spi->ti + j * thread_info_size);
+
k++;
- ok ( spi->ti[j].ClientId.UniqueProcess == spi->UniqueProcessId,
+ ok ( ti->ThreadInfo.ClientId.UniqueProcess == spi->UniqueProcessId,
"The owning pid of the thread (%p) doesn't equal the pid (%p) of the process\n",
- spi->ti[j].ClientId.UniqueProcess, spi->UniqueProcessId);
+ ti->ThreadInfo.ClientId.UniqueProcess, spi->UniqueProcessId );
+
+ tid = (DWORD_PTR)ti->ThreadInfo.ClientId.UniqueThread;
+ ok( !(tid & 3), "Unexpected TID low bits: %p\n", ti->ThreadInfo.ClientId.UniqueThread );
- tid = (DWORD_PTR)spi->ti[j].ClientId.UniqueThread;
- ok(!(tid & 3), "Unexpected TID low bits: %p\n", spi->ti[j].ClientId.UniqueThread);
+ if (extended)
+ {
+ todo_wine ok( !!ti->StackBase, "Got NULL StackBase.\n" );
+ todo_wine ok( !!ti->StackLimit, "Got NULL StackLimit.\n" );
+ ok( !!ti->Win32StartAddress, "Got NULL Win32StartAddress.\n" );
+
+ cid.UniqueProcess = 0;
+ cid.UniqueThread = ti->ThreadInfo.ClientId.UniqueThread;
+
+ InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
+ status = NtOpenThread( &handle, THREAD_QUERY_INFORMATION, &attr, &cid );
+ if (!status)
+ {
+ THREAD_BASIC_INFORMATION tbi;
+
+ status = pNtQueryInformationThread( handle, ThreadBasicInformation, &tbi, sizeof(tbi), NULL );
+ ok( status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status );
+ expected_address = tbi.TebBaseAddress;
+ if (is_wow64 && is_process_wow64)
+ expected_address = (BYTE *)expected_address - 0x2000;
+ ok( ti->TebBase == expected_address || (is_wow64 && !expected_address && !!ti->TebBase),
+ "Got unexpected TebBase %p, expected %p.\n", ti->TebBase, expected_address );
+
+ NtClose( handle );
+ }
+ }
}
if (!spi->NextEntryOffset)
@@ -577,6 +642,7 @@ static void test_query_process(void)
NtClose( handle );
}
+ winetest_pop_context();
}
static void test_query_procperf(void)
@@ -3317,7 +3383,8 @@ START_TEST(info)
test_query_cpu();
test_query_performance();
test_query_timeofday();
- test_query_process();
+ test_query_process( TRUE );
+ test_query_process( FALSE );
test_query_procperf();
test_query_module();
test_query_handle();
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c
index e216d2b2aa5..c37fc360f3e 100644
--- a/dlls/ntdll/unix/system.c
+++ b/dlls/ntdll/unix/system.c
@@ -2359,9 +2359,10 @@ static void read_dev_urandom( void *buf, ULONG len )
else WARN( "can't open /dev/urandom\n" );
}
-static NTSTATUS get_system_process_info( void *info, ULONG size, ULONG *len )
+static NTSTATUS get_system_process_info( SYSTEM_INFORMATION_CLASS class, void *info, ULONG size, ULONG *len )
{
unsigned int process_count, total_thread_count, total_name_len, i, j;
+ unsigned int thread_info_size;
unsigned int pos = 0;
char *buffer = NULL;
NTSTATUS ret;
@@ -2369,6 +2370,11 @@ static NTSTATUS get_system_process_info( void *info, ULONG size, ULONG *len )
C_ASSERT( sizeof(struct thread_info) <= sizeof(SYSTEM_THREAD_INFORMATION) );
C_ASSERT( sizeof(struct process_info) <= sizeof(SYSTEM_PROCESS_INFORMATION) );
+ if (class == SystemExtendedProcessInformation)
+ thread_info_size = sizeof(SYSTEM_EXTENDED_THREAD_INFORMATION);
+ else
+ thread_info_size = sizeof(SYSTEM_THREAD_INFORMATION);
+
*len = 0;
if (size && !(buffer = malloc( size ))) return STATUS_NO_MEMORY;
@@ -2387,7 +2393,7 @@ C_ASSERT( sizeof(struct process_info) <= sizeof(SYSTEM_PROCESS_INFORMATION) );
if (ret == STATUS_INFO_LENGTH_MISMATCH)
*len = sizeof(SYSTEM_PROCESS_INFORMATION) * process_count
+ (total_name_len + process_count) * sizeof(WCHAR)
- + total_thread_count * sizeof(SYSTEM_THREAD_INFORMATION);
+ + total_thread_count * thread_info_size;
free( buffer );
return ret;
@@ -2414,13 +2420,13 @@ C_ASSERT( sizeof(struct process_info) <= sizeof(SYSTEM_PROCESS_INFORMATION) );
name_len++;
}
- proc_len = sizeof(*nt_process) + server_process->thread_count * sizeof(SYSTEM_THREAD_INFORMATION)
+ proc_len = sizeof(*nt_process) + server_process->thread_count * thread_info_size
+ (name_len + 1) * sizeof(WCHAR);
*len += proc_len;
if (*len <= size)
{
- memset(nt_process, 0, sizeof(*nt_process));
+ memset(nt_process, 0, proc_len);
if (i < process_count - 1)
nt_process->NextEntryOffset = proc_len;
nt_process->CreationTime.QuadPart = server_process->start_time;
@@ -2438,16 +2444,23 @@ C_ASSERT( sizeof(struct process_info) <= sizeof(SYSTEM_PROCESS_INFORMATION) );
for (j = 0; j < server_process->thread_count; j++)
{
const struct thread_info *server_thread = (const struct thread_info *)(buffer + pos);
+ SYSTEM_EXTENDED_THREAD_INFORMATION *ti;
if (*len <= size)
{
- nt_process->ti[j].CreateTime.QuadPart = server_thread->start_time;
- nt_process->ti[j].ClientId.UniqueProcess = UlongToHandle(server_process->pid);
- nt_process->ti[j].ClientId.UniqueThread = UlongToHandle(server_thread->tid);
- nt_process->ti[j].dwCurrentPriority = server_thread->current_priority;
- nt_process->ti[j].dwBasePriority = server_thread->base_priority;
+ ti = (SYSTEM_EXTENDED_THREAD_INFORMATION *)((BYTE *)nt_process->ti + j * thread_info_size);
+ ti->ThreadInfo.CreateTime.QuadPart = server_thread->start_time;
+ ti->ThreadInfo.ClientId.UniqueProcess = UlongToHandle(server_process->pid);
+ ti->ThreadInfo.ClientId.UniqueThread = UlongToHandle(server_thread->tid);
+ ti->ThreadInfo.dwCurrentPriority = server_thread->current_priority;
+ ti->ThreadInfo.dwBasePriority = server_thread->base_priority;
get_thread_times( server_process->unix_pid, server_thread->unix_tid,
- &nt_process->ti[j].KernelTime, &nt_process->ti[j].UserTime );
+ &ti->ThreadInfo.KernelTime, &ti->ThreadInfo.UserTime );
+ if (class == SystemExtendedProcessInformation)
+ {
+ ti->Win32StartAddress = wine_server_get_ptr( server_thread->entry_point );
+ ti->TebBase = wine_server_get_ptr( server_thread->teb );
+ }
}
pos += sizeof(*server_thread);
@@ -2455,7 +2468,8 @@ C_ASSERT( sizeof(struct process_info) <= sizeof(SYSTEM_PROCESS_INFORMATION) );
if (*len <= size)
{
- nt_process->ProcessName.Buffer = (WCHAR *)&nt_process->ti[server_process->thread_count];
+ nt_process->ProcessName.Buffer = (WCHAR *)((BYTE *)nt_process->ti
+ + server_process->thread_count * thread_info_size);
nt_process->ProcessName.Length = name_len * sizeof(WCHAR);
nt_process->ProcessName.MaximumLength = (name_len + 1) * sizeof(WCHAR);
memcpy(nt_process->ProcessName.Buffer, file_part, name_len * sizeof(WCHAR));
@@ -2554,7 +2568,7 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
}
case SystemProcessInformation: /* 5 */
- ret = get_system_process_info( info, size, &len );
+ ret = get_system_process_info( class, info, size, &len );
break;
case SystemProcessorPerformanceInformation: /* 8 */
@@ -2858,9 +2872,7 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
}
case SystemExtendedProcessInformation: /* 57 */
- FIXME("SystemExtendedProcessInformation, size %u, info %p, stub!\n", size, info);
- memset( info, 0, size );
- ret = STATUS_SUCCESS;
+ ret = get_system_process_info( class, info, size, &len );
break;
case SystemRecommendedSharedDataAlignment: /* 58 */
diff --git a/include/winternl.h b/include/winternl.h
index 13bfc40e482..a209d1a7df9 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -2005,6 +2005,18 @@ typedef struct _SYSTEM_THREAD_INFORMATION
DWORD dwUnknown; /* 3c/4c */
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
+typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION
+{
+ SYSTEM_THREAD_INFORMATION ThreadInfo; /* 00/00 */
+ void *StackBase; /* 40/50 */
+ void *StackLimit; /* 44/58 */
+ void *Win32StartAddress; /* 48/60 */
+ void *TebBase; /* 4c/68 */
+ ULONG_PTR Reserved2; /* 50/70 */
+ ULONG_PTR Reserved3; /* 54/78 */
+ ULONG_PTR Reserved4; /* 58/80 */
+} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;
+
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
diff --git a/server/process.c b/server/process.c
index b6ad4e47bd4..6eda0bb0191 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1920,6 +1920,8 @@ DECL_HANDLER(list_processes)
thread_info->base_priority = thread->priority;
thread_info->current_priority = thread->priority; /* FIXME */
thread_info->unix_tid = thread->unix_tid;
+ thread_info->entry_point = thread->entry_point;
+ thread_info->teb = thread->teb;
pos += sizeof(*thread_info);
}
}
diff --git a/server/protocol.def b/server/protocol.def
index 7d27fa382d2..6a25db0326f 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1602,6 +1602,8 @@ struct thread_info
int base_priority;
int current_priority;
int unix_tid;
+ client_ptr_t teb;
+ client_ptr_t entry_point;
};
struct process_info
--
2.31.1
More information about the wine-devel
mailing list