Signed-off-by: Paul Gofman pgofman@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