From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ntdll/tests/virtual.c | 97 +++++++++++++++++++++++++++++++ dlls/ntdll/unix/virtual.c | 115 +++++++++++++++++++++++++------------ dlls/wow64/struct32.h | 11 ++++ dlls/wow64/virtual.c | 23 ++++++++ include/winternl.h | 24 ++++++++ 5 files changed, 233 insertions(+), 37 deletions(-)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 24c87c46d26..221b1d252ee 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -1434,6 +1434,102 @@ static void test_NtFreeVirtualMemory(void) ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); }
+static void test_query_region_information(void) +{ + MEMORY_REGION_INFORMATION info; + LARGE_INTEGER offset; + SIZE_T len, size; + NTSTATUS status; + HANDLE mapping; + void *ptr; + + size = 0x10000; + ptr = NULL; + status = NtAllocateVirtualMemory(NtCurrentProcess(), &ptr, 0, &size, MEM_RESERVE, PAGE_READWRITE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + +#if _WIN64 + status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, + FIELD_OFFSET(MEMORY_REGION_INFORMATION, PartitionId), &len); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, + FIELD_OFFSET(MEMORY_REGION_INFORMATION, CommitSize), &len); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, + FIELD_OFFSET(MEMORY_REGION_INFORMATION, RegionSize), &len); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "Unexpected status %08lx.\n", status); +#endif + + len = 0; + memset(&info, 0x11, sizeof(info)); + status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, sizeof(info), &len); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(info.AllocationBase == ptr, "Unexpected base %p.\n", info.AllocationBase); + ok(info.AllocationProtect == PAGE_READWRITE, "Unexpected protection %lu.\n", info.AllocationProtect); + ok(!info.Private, "Unexpected flag %d.\n", info.Private); + ok(!info.MappedDataFile, "Unexpected flag %d.\n", info.MappedDataFile); + ok(!info.MappedImage, "Unexpected flag %d.\n", info.MappedImage); + ok(!info.MappedPageFile, "Unexpected flag %d.\n", info.MappedPageFile); + ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); + ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); + ok(info.RegionSize == size, "Unexpected region size.\n"); + + size = 0; + status = NtFreeVirtualMemory(NtCurrentProcess(), &ptr, &size, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + /* Committed size */ + size = 0x10000; + ptr = NULL; + status = NtAllocateVirtualMemory(NtCurrentProcess(), &ptr, 0, &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + memset(&info, 0x11, sizeof(info)); + status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, sizeof(info), &len); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(info.AllocationBase == ptr, "Unexpected base %p.\n", info.AllocationBase); + ok(info.AllocationProtect == PAGE_READWRITE, "Unexpected protection %lu.\n", info.AllocationProtect); + ok(!info.Private, "Unexpected flag %d.\n", info.Private); + ok(!info.MappedDataFile, "Unexpected flag %d.\n", info.MappedDataFile); + ok(!info.MappedImage, "Unexpected flag %d.\n", info.MappedImage); + ok(!info.MappedPageFile, "Unexpected flag %d.\n", info.MappedPageFile); + ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); + ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); + ok(info.RegionSize == size, "Unexpected region size.\n"); + + size = 0; + status = NtFreeVirtualMemory(NtCurrentProcess(), &ptr, &size, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + /* Pagefile mapping */ + mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL); + ok(mapping != 0, "CreateFileMapping failed\n"); + + ptr = NULL; + size = 0; + offset.QuadPart = 0; + status = NtMapViewOfSection(mapping, NtCurrentProcess(), &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READONLY); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + memset(&info, 0x11, sizeof(info)); + status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, sizeof(info), &len); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(info.AllocationBase == ptr, "Unexpected base %p.\n", info.AllocationBase); + ok(info.AllocationProtect == PAGE_READONLY, "Unexpected protection %lu.\n", info.AllocationProtect); + ok(!info.Private, "Unexpected flag %d.\n", info.Private); + ok(!info.MappedDataFile, "Unexpected flag %d.\n", info.MappedDataFile); + ok(!info.MappedImage, "Unexpected flag %d.\n", info.MappedImage); + ok(!info.MappedPageFile, "Unexpected flag %d.\n", info.MappedPageFile); + ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); + ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); + ok(info.RegionSize == 4096, "Unexpected region size.\n"); + + status = NtUnmapViewOfSection(NtCurrentProcess(), ptr); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + NtClose(mapping); +} + START_TEST(virtual) { HMODULE mod; @@ -1477,4 +1573,5 @@ START_TEST(virtual) test_NtMapViewOfSectionEx(); test_user_shared_data(); test_syscalls(); + test_query_region_information(); } diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index a93d5b4174a..ad9955d35fb 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4080,48 +4080,13 @@ static int get_free_mem_state_callback( void *start, SIZE_T size, void *arg ) return 1; }
-/* 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 ) +static NTSTATUS fill_basic_memory_info( const void *addr, MEMORY_BASIC_INFORMATION *info ) { - struct file_view *view; char *base, *alloc_base = 0, *alloc_end = working_set_limit; struct wine_rb_entry *ptr; + struct file_view *view; sigset_t sigset;
- if (len < sizeof(MEMORY_BASIC_INFORMATION)) - return STATUS_INFO_LENGTH_MISMATCH; - - if (process != NtCurrentProcess()) - { - NTSTATUS status; - apc_call_t call; - apc_result_t result; - - memset( &call, 0, sizeof(call) ); - - call.virtual_query.type = APC_VIRTUAL_QUERY; - call.virtual_query.addr = wine_server_client_ptr( addr ); - status = server_queue_process_apc( process, &call, &result ); - if (status != STATUS_SUCCESS) return status; - - if (result.virtual_query.status == STATUS_SUCCESS) - { - info->BaseAddress = wine_server_get_ptr( result.virtual_query.base ); - info->AllocationBase = wine_server_get_ptr( result.virtual_query.alloc_base ); - info->RegionSize = result.virtual_query.size; - info->Protect = result.virtual_query.prot; - info->AllocationProtect = result.virtual_query.alloc_prot; - info->State = (DWORD)result.virtual_query.state << 12; - info->Type = (DWORD)result.virtual_query.alloc_type << 16; - if (info->RegionSize != result.virtual_query.size) /* truncated */ - return STATUS_INVALID_PARAMETER; /* FIXME */ - if (res_len) *res_len = sizeof(*info); - } - return result.virtual_query.status; - } - base = ROUND_ADDR( addr, page_mask );
if (is_beyond_limit( base, 1, working_set_limit )) return STATUS_INVALID_PARAMETER; @@ -4195,6 +4160,79 @@ static NTSTATUS get_basic_memory_info( HANDLE process, LPCVOID addr, } server_leave_uninterrupted_section( &virtual_mutex, &sigset );
+ return STATUS_SUCCESS; +} + +/* 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 ) +{ + NTSTATUS status; + + if (len < sizeof(*info)) + return STATUS_INFO_LENGTH_MISMATCH; + + if (process != NtCurrentProcess()) + { + NTSTATUS status; + apc_call_t call; + apc_result_t result; + + memset( &call, 0, sizeof(call) ); + + call.virtual_query.type = APC_VIRTUAL_QUERY; + call.virtual_query.addr = wine_server_client_ptr( addr ); + status = server_queue_process_apc( process, &call, &result ); + if (status != STATUS_SUCCESS) return status; + + if (result.virtual_query.status == STATUS_SUCCESS) + { + info->BaseAddress = wine_server_get_ptr( result.virtual_query.base ); + info->AllocationBase = wine_server_get_ptr( result.virtual_query.alloc_base ); + info->RegionSize = result.virtual_query.size; + info->Protect = result.virtual_query.prot; + info->AllocationProtect = result.virtual_query.alloc_prot; + info->State = (DWORD)result.virtual_query.state << 12; + info->Type = (DWORD)result.virtual_query.alloc_type << 16; + if (info->RegionSize != result.virtual_query.size) /* truncated */ + return STATUS_INVALID_PARAMETER; /* FIXME */ + if (res_len) *res_len = sizeof(*info); + } + return result.virtual_query.status; + } + + if ((status = fill_basic_memory_info( addr, info ))) return status; + + if (res_len) *res_len = sizeof(*info); + return STATUS_SUCCESS; +} + +static NTSTATUS get_memory_region_info( HANDLE process, LPCVOID addr, MEMORY_REGION_INFORMATION *info, + SIZE_T len, SIZE_T *res_len ) +{ + MEMORY_BASIC_INFORMATION basic_info; + NTSTATUS status; + + if (len < FIELD_OFFSET(MEMORY_REGION_INFORMATION, CommitSize)) + return STATUS_INFO_LENGTH_MISMATCH; + + if (process != NtCurrentProcess()) + { + FIXME("Unimplemented for other processes.\n"); + return STATUS_NOT_IMPLEMENTED; + } + + if ((status = fill_basic_memory_info( addr, &basic_info ))) return status; + + info->AllocationBase = basic_info.AllocationBase; + info->AllocationProtect = basic_info.AllocationProtect; + info->RegionType = 0; /* FIXME */ + if (len >= FIELD_OFFSET(MEMORY_REGION_INFORMATION, CommitSize)) + info->RegionSize = basic_info.RegionSize; + if (len >= FIELD_OFFSET(MEMORY_REGION_INFORMATION, PartitionId)) + info->CommitSize = basic_info.State == MEM_COMMIT ? basic_info.RegionSize : 0; + if (res_len) *res_len = sizeof(*info); return STATUS_SUCCESS; } @@ -4366,6 +4404,9 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, case MemoryMappedFilenameInformation: return get_memory_section_name( process, addr, buffer, len, res_len );
+ case MemoryRegionInformation: + return get_memory_region_info( process, addr, buffer, len, res_len ); + case MemoryWineUnixFuncs: case MemoryWineUnixWow64Funcs: if (len != sizeof(unixlib_handle_t)) return STATUS_INFO_LENGTH_MISMATCH; diff --git a/dlls/wow64/struct32.h b/dlls/wow64/struct32.h index b096c8d587b..b4762c1c5ee 100644 --- a/dlls/wow64/struct32.h +++ b/dlls/wow64/struct32.h @@ -156,6 +156,17 @@ typedef struct DWORD Type; } MEMORY_BASIC_INFORMATION32;
+typedef struct +{ + ULONG AllocationBase; + ULONG AllocationProtect; + ULONG RegionType; + ULONG RegionSize; + ULONG CommitSize; + ULONG PartitionId; + ULONG NodePreference; +} MEMORY_REGION_INFORMATION32; + typedef struct { UNICODE_STRING32 SectionFileName; diff --git a/dlls/wow64/virtual.c b/dlls/wow64/virtual.c index c21464857fa..2aed0fc854a 100644 --- a/dlls/wow64/virtual.c +++ b/dlls/wow64/virtual.c @@ -404,6 +404,29 @@ NTSTATUS WINAPI wow64_NtQueryVirtualMemory( UINT *args ) break; }
+ case MemoryRegionInformation: /* MEMORY_REGION_INFORMATION */ + { + if (len >= sizeof(MEMORY_REGION_INFORMATION32)) + { + MEMORY_REGION_INFORMATION info; + MEMORY_REGION_INFORMATION32 *info32 = ptr; + + if (!(status = NtQueryVirtualMemory( handle, addr, class, &info, sizeof(info), &res_len ))) + { + info32->AllocationBase = PtrToUlong( info.AllocationBase ); + info32->AllocationProtect = info.AllocationProtect; + info32->RegionType = info.RegionType; + info32->RegionSize = info.RegionSize; + info32->CommitSize = info.CommitSize; + info32->PartitionId = info.PartitionId; + info32->NodePreference = info.NodePreference; + } + } + else status = STATUS_INFO_LENGTH_MISMATCH; + res_len = sizeof(MEMORY_REGION_INFORMATION32); + break; + } + case MemoryWorkingSetExInformation: /* MEMORY_WORKING_SET_EX_INFORMATION */ { MEMORY_WORKING_SET_EX_INFORMATION32 *info32 = ptr; diff --git a/include/winternl.h b/include/winternl.h index 85aac653a21..ece7a998ba7 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1971,6 +1971,30 @@ typedef struct _MEMORY_WORKING_SET_EX_INFORMATION { MEMORY_WORKING_SET_EX_BLOCK VirtualAttributes; } MEMORY_WORKING_SET_EX_INFORMATION, *PMEMORY_WORKING_SET_EX_INFORMATION;
+typedef struct _MEMORY_REGION_INFORMATION +{ + PVOID AllocationBase; + ULONG AllocationProtect; + union + { + ULONG RegionType; + struct + { + ULONG Private : 1; + ULONG MappedDataFile : 1; + ULONG MappedImage : 1; + ULONG MappedPageFile : 1; + ULONG MappedPhysical : 1; + ULONG DirectMapped : 1; + ULONG Reserved : 26; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + SIZE_T RegionSize; + SIZE_T CommitSize; + ULONG_PTR PartitionId; + ULONG_PTR NodePreference; +} MEMORY_REGION_INFORMATION, *PMEMORY_REGION_INFORMATION; + typedef enum _MUTANT_INFORMATION_CLASS { MutantBasicInformation
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/memory.c | 17 +++++++++++++ include/memoryapi.h | 45 +++++++++++++++++++++++++++++++++ include/winbase.h | 1 + 4 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 include/memoryapi.h
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 1296757b29a..07664646983 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1248,7 +1248,7 @@ @ stdcall QueryThreadpoolStackInformation(ptr ptr) @ stdcall QueryUnbiasedInterruptTime(ptr) ntdll.RtlQueryUnbiasedInterruptTime # @ stub QueryUnbiasedInterruptTimePrecise -# @ stub QueryVirtualMemoryInformation +@ stdcall QueryVirtualMemoryInformation(long ptr long ptr long ptr) @ stdcall QueryWorkingSet(long ptr long) @ stdcall QueryWorkingSetEx(long ptr long) @ stdcall QueueUserAPC(ptr long long) diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index e24a6f9aad0..09ab8fdc895 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -1390,6 +1390,23 @@ LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAllocExNuma( HANDLE process, void *addr, }
+/*********************************************************************** + * QueryVirtualMemoryInformation (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryVirtualMemoryInformation( HANDLE process, const void *addr, + WIN32_MEMORY_INFORMATION_CLASS info_class, void *info, SIZE_T size, SIZE_T *ret_size) +{ + switch (info_class) + { + case MemoryRegionInfo: + return set_ntstatus( NtQueryVirtualMemory( process, addr, MemoryRegionInformation, info, size, ret_size )); + default: + FIXME("Unsupported info class %u.\n", info_class); + return FALSE; + } +} + + /*********************************************************************** * CPU functions ***********************************************************************/ diff --git a/include/memoryapi.h b/include/memoryapi.h new file mode 100644 index 00000000000..8743e67927c --- /dev/null +++ b/include/memoryapi.h @@ -0,0 +1,45 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +typedef enum WIN32_MEMORY_INFORMATION_CLASS +{ + MemoryRegionInfo +} WIN32_MEMORY_INFORMATION_CLASS; + +typedef struct WIN32_MEMORY_REGION_INFORMATION +{ + PVOID AllocationBase; + ULONG AllocationProtect; + union + { + ULONG Flags; + struct + { + ULONG Private : 1; + ULONG MappedDataFile : 1; + ULONG MappedImage : 1; + ULONG MappedPageFile : 1; + ULONG MappedPhysical : 1; + ULONG DirectMapped : 1; + ULONG Reserved : 26; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + SIZE_T RegionSize; + SIZE_T CommitSize; +} WIN32_MEMORY_REGION_INFORMATION; + +BOOL WINAPI QueryVirtualMemoryInformation(HANDLE process,const void *addr, + WIN32_MEMORY_INFORMATION_CLASS info_class, void *info, SIZE_T size, SIZE_T *ret_size); diff --git a/include/winbase.h b/include/winbase.h index bf191153ddc..1c83a5350d4 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -43,6 +43,7 @@ extern "C" { #include <processthreadsapi.h> #include <synchapi.h> #include <threadpoolapiset.h> +#include <memoryapi.h>
/* Windows Exit Procedure flag values */ #define WEP_FREE_DLL 0