mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 18:37:17 +00:00
ntdll: Partially implement MemoryRegionInformation query.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
This commit is contained in:
parent
0d21e1cbcf
commit
fc5cb9b577
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue