ntdll: Partially implement MemoryRegionInformation query.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
This commit is contained in:
Nikolay Sivov 2022-06-28 17:13:47 +03:00 committed by Alexandre Julliard
parent 0d21e1cbcf
commit fc5cb9b577
5 changed files with 233 additions and 37 deletions

View file

@ -1574,6 +1574,102 @@ static void test_prefetch(void)
"NtSetInformationVirtualMemory unexpected status on 2 page-aligned entries: %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);
#ifdef _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;
@ -1619,4 +1715,5 @@ START_TEST(virtual)
test_prefetch();
test_user_shared_data();
test_syscalls();
test_query_region_information();
}

View file

@ -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;
}
@ -4371,6 +4409,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;

View file

@ -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;

View file

@ -422,6 +422,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;

View file

@ -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