[PATCH 1/2] ntdll: Partially implement MemoryRegionInformation query.
Nikolay Sivov
wine at gitlab.winehq.org
Tue Jun 28 10:15:19 CDT 2022
From: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Nikolay Sivov <nsivov at 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
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/333
More information about the wine-devel
mailing list