From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Andrew Wesie awesie@gmail.com --- dlls/ntdll/virtual.c | 65 +++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 28 deletions(-)
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 5890344f7a..ad91cffd8f 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -3011,40 +3011,16 @@ static int get_free_mem_state_callback( void *start, size_t size, void *arg ) return 1; }
-#define UNIMPLEMENTED_INFO_CLASS(c) \ - case c: \ - FIXME("(process=%p,addr=%p) Unimplemented information class: " #c "\n", process, addr); \ - return STATUS_INVALID_INFO_CLASS - -/*********************************************************************** - * NtQueryVirtualMemory (NTDLL.@) - * ZwQueryVirtualMemory (NTDLL.@) - */ -NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, - MEMORY_INFORMATION_CLASS info_class, PVOID buffer, - SIZE_T len, SIZE_T *res_len ) +/* get basic information about a memory block */ +static NTSTATUS get_basic_memory_info( HANDLE process, LPCVOID addr, + MEMORY_BASIC_INFORMATION *info, + SIZE_T len, SIZE_T *res_len ) { struct file_view *view; char *base, *alloc_base = 0, *alloc_end = working_set_limit; struct wine_rb_entry *ptr; - MEMORY_BASIC_INFORMATION *info = buffer; sigset_t sigset;
- if (info_class != MemoryBasicInformation) - { - switch(info_class) - { - UNIMPLEMENTED_INFO_CLASS(MemoryWorkingSetList); - UNIMPLEMENTED_INFO_CLASS(MemorySectionName); - UNIMPLEMENTED_INFO_CLASS(MemoryBasicVlmInformation); - - default: - FIXME("(%p,%p,info_class=%d,%p,%ld,%p) Unknown information class\n", - process, addr, info_class, buffer, len, res_len); - return STATUS_INVALID_INFO_CLASS; - } - } - if (len < sizeof(MEMORY_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
@@ -3159,6 +3135,39 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, }
+#define UNIMPLEMENTED_INFO_CLASS(c) \ + case c: \ + FIXME("(process=%p,addr=%p) Unimplemented information class: " #c "\n", process, addr); \ + return STATUS_INVALID_INFO_CLASS + +/*********************************************************************** + * NtQueryVirtualMemory (NTDLL.@) + * ZwQueryVirtualMemory (NTDLL.@) + */ +NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, + MEMORY_INFORMATION_CLASS info_class, + PVOID buffer, SIZE_T len, SIZE_T *res_len ) +{ + TRACE("(%p, %p, info_class=%d, %p, %ld, %p)\n", + process, addr, info_class, buffer, len, res_len); + + switch(info_class) + { + case MemoryBasicInformation: + return get_basic_memory_info( process, addr, buffer, len, res_len ); + + UNIMPLEMENTED_INFO_CLASS(MemoryWorkingSetList); + UNIMPLEMENTED_INFO_CLASS(MemorySectionName); + UNIMPLEMENTED_INFO_CLASS(MemoryBasicVlmInformation); + + default: + FIXME("(%p,%p,info_class=%d,%p,%ld,%p) Unknown information class\n", + process, addr, info_class, buffer, len, res_len); + return STATUS_INVALID_INFO_CLASS; + } +} + + /*********************************************************************** * NtLockVirtualMemory (NTDLL.@) * ZwLockVirtualMemory (NTDLL.@)
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45667 Signed-off-by: Andrew Wesie awesie@gmail.com --- dlls/ntdll/virtual.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ include/winternl.h | 21 ++++++++++++++- 2 files changed, 82 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index ad91cffd8f..477dd805b2 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -3134,6 +3134,65 @@ static NTSTATUS get_basic_memory_info( HANDLE process, LPCVOID addr, return STATUS_SUCCESS; }
+static NTSTATUS get_working_set_ex( HANDLE process, LPCVOID addr, + MEMORY_WORKING_SET_EX_INFORMATION *info, + SIZE_T len, SIZE_T *res_len ) +{ + char pagemap_path[32]; + FILE *f; + MEMORY_WORKING_SET_EX_INFORMATION *p; + sigset_t sigset; + + if (process != NtCurrentProcess()) + { + FIXME( "(process=%p,addr=%p) Unimplemented information class: MemoryWorkingSetExInformation\n", process, addr ); + return STATUS_INVALID_INFO_CLASS; + } + + snprintf( pagemap_path, sizeof(pagemap_path), "/proc/%u/pagemap", getpid() ); + f = fopen( pagemap_path, "rb" ); + if (!f) + { + static int once; + if (!once++) WARN( "unable to open %s for MemoryWorkingSetExInformation\n", pagemap_path ); + } + + server_enter_uninterrupted_section( &csVirtual, &sigset ); + for (p = info; (UINT_PTR)(p + 1) <= (UINT_PTR)info + len; p++) + { + BYTE vprot; + UINT64 pagemap; + struct file_view *view; + + memset( &p->VirtualAttributes, 0, sizeof(p->VirtualAttributes) ); + + /* If we don't have pagemap information, default to invalid. */ + if (!f || fseek( f, ((UINT_PTR)p->VirtualAddress >> 12) * sizeof(pagemap), SEEK_SET ) == -1 || + fread( &pagemap, sizeof(pagemap), 1, f ) != 1) + { + pagemap = 0; + } + + if ((view = VIRTUAL_FindView( p->VirtualAddress, 0 )) && + get_committed_size( view, p->VirtualAddress, &vprot ) && + (vprot & VPROT_COMMITTED)) + { + p->VirtualAttributes.Valid = !(vprot & VPROT_GUARD) && (vprot & 0x0f) && (pagemap >> 63); + p->VirtualAttributes.Shared = !is_view_valloc( view ) && ((pagemap >> 61) & 1); + if (p->VirtualAttributes.Shared && p->VirtualAttributes.Valid) + p->VirtualAttributes.ShareCount = 1; /* FIXME */ + if (p->VirtualAttributes.Valid) + p->VirtualAttributes.Win32Protection = VIRTUAL_GetWin32Prot( vprot, view->protect ); + } + } + server_leave_uninterrupted_section( &csVirtual, &sigset ); + + if (f) + fclose( f ); + if (res_len) + *res_len = (UINT_PTR)p - (UINT_PTR)info; + return STATUS_SUCCESS; +}
#define UNIMPLEMENTED_INFO_CLASS(c) \ case c: \ @@ -3156,6 +3215,9 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, case MemoryBasicInformation: return get_basic_memory_info( process, addr, buffer, len, res_len );
+ case MemoryWorkingSetExInformation: + return get_working_set_ex( process, addr, buffer, len, res_len ); + UNIMPLEMENTED_INFO_CLASS(MemoryWorkingSetList); UNIMPLEMENTED_INFO_CLASS(MemorySectionName); UNIMPLEMENTED_INFO_CLASS(MemoryBasicVlmInformation); diff --git a/include/winternl.h b/include/winternl.h index e5aed5acb1..ea6707714d 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1051,7 +1051,8 @@ typedef enum _MEMORY_INFORMATION_CLASS { MemoryBasicInformation, MemoryWorkingSetList, MemorySectionName, - MemoryBasicVlmInformation + MemoryBasicVlmInformation, + MemoryWorkingSetExInformation } MEMORY_INFORMATION_CLASS;
typedef struct _MEMORY_SECTION_NAME @@ -1059,6 +1060,24 @@ typedef struct _MEMORY_SECTION_NAME UNICODE_STRING SectionFileName; } MEMORY_SECTION_NAME, *PMEMORY_SECTION_NAME;
+typedef union _MEMORY_WORKING_SET_EX_BLOCK { + ULONG_PTR Flags; + struct { + ULONG_PTR Valid : 1; + ULONG_PTR ShareCount : 3; + ULONG_PTR Win32Protection : 11; + ULONG_PTR Shared : 1; + ULONG_PTR Node : 6; + ULONG_PTR Locked : 1; + ULONG_PTR LargePage : 1; + } DUMMYSTRUCTNAME; +} MEMORY_WORKING_SET_EX_BLOCK, *PMEMORY_WORKING_SET_EX_BLOCK; + +typedef struct _MEMORY_WORKING_SET_EX_INFORMATION { + PVOID VirtualAddress; + MEMORY_WORKING_SET_EX_BLOCK VirtualAttributes; +} MEMORY_WORKING_SET_EX_INFORMATION, *PMEMORY_WORKING_SET_EX_INFORMATION; + typedef enum _MUTANT_INFORMATION_CLASS { MutantBasicInformation
Signed-off-by: Andrew Wesie awesie@gmail.com --- dlls/kernel32/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index 7875f3469a..5146622230 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -722,7 +722,7 @@ BOOL WINAPI K32QueryWorkingSetEx( HANDLE process, LPVOID buffer, DWORD size ) { TRACE( "(%p, %p, %d)\n", process, buffer, size );
- return set_ntstatus( NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL )); + return set_ntstatus( NtQueryVirtualMemory( process, NULL, MemoryWorkingSetExInformation, buffer, size, NULL )); }
/***********************************************************************
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=63813
Your paranoid android.
=== debian10 (32 bit WoW report) ===
kernel32: debugger: Timeout
=== debian10 (64 bit WoW report) ===
kernel32: debugger: Timeout
Signed-off-by: Andrew Wesie awesie@gmail.com --- dlls/psapi/tests/psapi_main.c | 91 +++++++++++++++++++++++++++++++++++ include/psapi.h | 18 +++++++ 2 files changed, 109 insertions(+)
diff --git a/dlls/psapi/tests/psapi_main.c b/dlls/psapi/tests/psapi_main.c index 9799d2ffae..0df247e9bf 100644 --- a/dlls/psapi/tests/psapi_main.c +++ b/dlls/psapi/tests/psapi_main.c @@ -43,6 +43,7 @@ static NTSTATUS (WINAPI *pNtQueryVirtualMemory)(HANDLE, LPCVOID, ULONG, PVOID, S static BOOL (WINAPI *pIsWow64Process)(HANDLE, BOOL *); static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(void **); static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(void *); +static BOOL (WINAPI *pQueryWorkingSetEx)(HANDLE, PVOID, DWORD);
static BOOL wow64;
@@ -53,6 +54,7 @@ static BOOL init_func_ptrs(void) pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); pWow64DisableWow64FsRedirection = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "Wow64DisableWow64FsRedirection"); pWow64RevertWow64FsRedirection = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "Wow64RevertWow64FsRedirection"); + pQueryWorkingSetEx = (void *)GetProcAddress(GetModuleHandleA("psapi.dll"), "QueryWorkingSetEx"); return TRUE; }
@@ -791,6 +793,94 @@ free_page: VirtualFree(addr, 0, MEM_RELEASE); }
+static void check_QueryWorkingSetEx(PVOID addr, const char *desc, DWORD expected_valid, + DWORD expected_protection, DWORD expected_shared, BOOL todo, BOOL todo_shared) +{ + PSAPI_WORKING_SET_EX_INFORMATION info; + BOOL ret; + + memset(&info, 0x41, sizeof(info)); + info.VirtualAddress = addr; + ret = pQueryWorkingSetEx(GetCurrentProcess(), &info, sizeof(info)); + ok(ret, "QueryWorkingSetEx failed with %d\n", GetLastError()); + + todo_wine_if(todo) + ok(info.VirtualAttributes.Valid == expected_valid, "%s expected Valid=%u but got %u\n", + desc, expected_valid, info.VirtualAttributes.Valid); + + todo_wine_if(todo) + ok(info.VirtualAttributes.Win32Protection == expected_protection, "%s expected Win32Protection=%u but got %u\n", + desc, expected_protection, info.VirtualAttributes.Win32Protection); + + ok(info.VirtualAttributes.Node == 0, "%s expected Node=0 but got %u\n", + desc, info.VirtualAttributes.Node); + ok(info.VirtualAttributes.LargePage == 0, "%s expected LargePage=0 but got %u\n", + desc, info.VirtualAttributes.LargePage); + + todo_wine_if(todo_shared) + ok(info.VirtualAttributes.Shared == expected_shared || broken(!info.VirtualAttributes.Valid) /* w2003 */, + "%s expected Shared=%u but got %u\n", desc, expected_shared, info.VirtualAttributes.Shared); + if (info.VirtualAttributes.Valid && info.VirtualAttributes.Shared) + ok(info.VirtualAttributes.ShareCount > 0, "%s expected ShareCount > 0 but got %u\n", + desc, info.VirtualAttributes.ShareCount); + else + ok(info.VirtualAttributes.ShareCount == 0, "%s expected ShareCount == 0 but got %u\n", + desc, info.VirtualAttributes.ShareCount); +} + +static void test_QueryWorkingSetEx(void) +{ + PVOID addr; + DWORD prot; + BOOL ret; + + if (pQueryWorkingSetEx == NULL) + { + win_skip("QueryWorkingSetEx not found, skipping tests\n"); + return; + } + + addr = GetModuleHandleA(NULL); + check_QueryWorkingSetEx(addr, "exe", 1, PAGE_READONLY, 1, FALSE, TRUE); + + ret = VirtualProtect(addr, 0x1000, PAGE_NOACCESS, &prot); + ok(ret, "VirtualProtect failed with %d\n", GetLastError()); + check_QueryWorkingSetEx(addr, "exe,noaccess", 0, 0, 1, FALSE, TRUE); + + ret = VirtualProtect(addr, 0x1000, prot, &prot); + ok(ret, "VirtualProtect failed with %d\n", GetLastError()); + check_QueryWorkingSetEx(addr, "exe,readonly1", 0, 0, 1, TRUE, TRUE); + + *(volatile char *)addr; + ok(ret, "VirtualProtect failed with %d\n", GetLastError()); + check_QueryWorkingSetEx(addr, "exe,readonly2", 1, PAGE_READONLY, 1, FALSE, TRUE); + + addr = VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + ok(addr != NULL, "VirtualAlloc failed with %d\n", GetLastError()); + check_QueryWorkingSetEx(addr, "valloc", 0, 0, 0, FALSE, FALSE); + + *(volatile char *)addr; + check_QueryWorkingSetEx(addr, "valloc,read", 1, PAGE_READWRITE, 0, FALSE, FALSE); + + *(volatile char *)addr = 0x42; + check_QueryWorkingSetEx(addr, "valloc,write", 1, PAGE_READWRITE, 0, FALSE, FALSE); + + ret = VirtualProtect(addr, 0x1000, PAGE_NOACCESS, &prot); + ok(ret, "VirtualProtect failed with %d\n", GetLastError()); + check_QueryWorkingSetEx(addr, "valloc,noaccess", 0, 0, 0, FALSE, FALSE); + + ret = VirtualProtect(addr, 0x1000, prot, &prot); + ok(ret, "VirtualProtect failed with %d\n", GetLastError()); + check_QueryWorkingSetEx(addr, "valloc,readwrite1", 0, 0, 0, TRUE, FALSE); + + *(volatile char *)addr; + check_QueryWorkingSetEx(addr, "valloc,readwrite2", 1, PAGE_READWRITE, 0, FALSE, FALSE); + + ret = VirtualFree(addr, 0, MEM_RELEASE); + ok(ret, "VirtualFree failed with %d\n", GetLastError()); + check_QueryWorkingSetEx(addr, "valloc,free", FALSE, 0, 0, FALSE, FALSE); +} + START_TEST(psapi_main) { DWORD pid = GetCurrentProcessId(); @@ -818,6 +908,7 @@ START_TEST(psapi_main) test_GetProcessImageFileName(); test_GetModuleFileNameEx(); test_GetModuleBaseName(); + test_QueryWorkingSetEx(); test_ws_functions();
CloseHandle(hpSR); diff --git a/include/psapi.h b/include/psapi.h index 742bf7b574..66e660b243 100644 --- a/include/psapi.h +++ b/include/psapi.h @@ -45,6 +45,24 @@ typedef struct _PROCESS_MEMORY_COUNTERS { } PROCESS_MEMORY_COUNTERS; typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS;
+typedef union _PSAPI_WORKING_SET_EX_BLOCK { + ULONG_PTR Flags; + struct { + ULONG_PTR Valid :1; + ULONG_PTR ShareCount :3; + ULONG_PTR Win32Protection :11; + ULONG_PTR Shared :1; + ULONG_PTR Node :6; + ULONG_PTR Locked :1; + ULONG_PTR LargePage :1; + } DUMMYSTRUCTNAME; +} PSAPI_WORKING_SET_EX_BLOCK, *PPSAPI_WORKING_SET_EX_BLOCK; + +typedef struct _PSAPI_WORKING_SET_EX_INFORMATION { + PVOID VirtualAddress; + PSAPI_WORKING_SET_EX_BLOCK VirtualAttributes; +} PSAPI_WORKING_SET_EX_INFORMATION, *PPSAPI_WORKING_SET_EX_INFORMATION; + typedef struct _PSAPI_WS_WATCH_INFORMATION { LPVOID FaultingPc; LPVOID FaultingVa;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=63814
Your paranoid android.
=== debian10 (32 bit report) ===
kernel32: debugger.c:305: Test failed: GetThreadContext failed: 5