[PATCH v2 3/3] ntdll: Implement SystemExtendedProcessInformation system info class.

Paul Gofman pgofman at codeweavers.com
Mon Oct 25 13:46:21 CDT 2021


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
v2:
    - fix a random test failure.

 dlls/ntdll/tests/info.c  | 90 +++++++++++++++++++++++++++++++++++-----
 dlls/ntdll/unix/system.c | 42 ++++++++++++-------
 include/winternl.h       | 12 ++++++
 server/process.c         |  2 +
 server/protocol.def      |  2 +
 5 files changed, 123 insertions(+), 25 deletions(-)

diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index 635c551383c..6c01ee092d4 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,67 @@ 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;
+                    if (!is_wow64 && !is_process_wow64 && !tbi.TebBaseAddress)
+                        win_skip( "Could not get TebBaseAddress, thread %u.\n", j );
+                    else
+                        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 +645,7 @@ static void test_query_process(void)
 
         NtClose( handle );
     }
+    winetest_pop_context();
 }
 
 static void test_query_procperf(void)
@@ -3317,7 +3386,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