diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index d20ff8a043d..fc7dca2c71f 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -2483,7 +2483,6 @@ static void test_query_image_information(void) &info, sizeof(info), &len ); if (status == STATUS_INVALID_INFO_CLASS) { - todo_wine win_skip( "MemoryImageInformation not supported\n" ); NtUnmapViewOfSection( NtCurrentProcess(), ptr ); return; @@ -2578,6 +2577,7 @@ static void test_query_image_information(void) offset.QuadPart = 0; status = NtMapViewOfSection( mapping, NtCurrentProcess(), &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READONLY ); ok( status == STATUS_IMAGE_NOT_AT_BASE, "Unexpected status %08lx\n", status ); + todo_wine ok( size == 0x4000, "wrong size %Ix\n", size ); NtClose( mapping ); @@ -2589,6 +2589,7 @@ static void test_query_image_information(void) ok( info.ImageBase == ptr, "wrong image base %p/%p\n", info.ImageBase, ptr ); ok( info.SizeOfImage == nt->OptionalHeader.SizeOfImage, "wrong size %Ix/%x\n", info.SizeOfImage, (UINT)nt->OptionalHeader.SizeOfImage ); + todo_wine ok( info.ImagePartialMap, "wrong partial map\n" ); ok( !info.ImageNotExecutable, "wrong not executable\n" ); ok( info.ImageSigningLevel == 0 || info.ImageSigningLevel == 12, @@ -2606,6 +2607,7 @@ static void test_query_image_information(void) offset.QuadPart = 0; status = NtMapViewOfSection( mapping, NtCurrentProcess(), &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READONLY ); ok( status == STATUS_IMAGE_NOT_AT_BASE, "Unexpected status %08lx\n", status ); + todo_wine ok( size == 0x5000, "wrong size %Ix\n", size ); NtClose( mapping ); @@ -2617,6 +2619,7 @@ static void test_query_image_information(void) ok( info.ImageBase == ptr, "wrong image base %p/%p\n", info.ImageBase, ptr ); ok( info.SizeOfImage == nt->OptionalHeader.SizeOfImage, "wrong size %Ix/%x\n", info.SizeOfImage, (UINT)nt->OptionalHeader.SizeOfImage ); + todo_wine ok( info.ImagePartialMap, "wrong partial map\n" ); ok( !info.ImageNotExecutable, "wrong not executable\n" ); ok( info.ImageSigningLevel == 0 || info.ImageSigningLevel == 12, diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 8621b2ac6aa..21b4e9b4dba 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4967,6 +4967,40 @@ static unsigned int get_memory_section_name( HANDLE process, LPCVOID addr, return status; } +static unsigned int get_memory_image_info( HANDLE process, LPCVOID addr, MEMORY_IMAGE_INFORMATION *info, + SIZE_T len, SIZE_T *res_len ) +{ + unsigned int status; + + if (len < sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH; + memset( info, 0, sizeof(*info) ); + + SERVER_START_REQ( get_image_view_info ) + { + req->process = wine_server_obj_handle( process ); + req->addr = wine_server_client_ptr( addr ); + status = wine_server_call( req ); + if (!status && reply->base) + { + info->ImageBase = wine_server_get_ptr( reply->base ); + info->SizeOfImage = reply->size; + info->ImageSigningLevel = 12; + } + } + SERVER_END_REQ; + + if (status == STATUS_NOT_MAPPED_VIEW) + { + MEMORY_BASIC_INFORMATION basic_info; + + status = get_basic_memory_info( process, addr, &basic_info, sizeof(basic_info), NULL ); + if (status || basic_info.State == MEM_FREE) status = STATUS_INVALID_ADDRESS; + } + + if (!status && res_len) *res_len = sizeof(*info); + return status; +} + /*********************************************************************** * NtQueryVirtualMemory (NTDLL.@) @@ -4995,6 +5029,9 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, case MemoryRegionInformation: return get_memory_region_info( process, addr, buffer, len, res_len ); + case MemoryImageInformation: + return get_memory_image_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 0a560ac0f92..7dc12b75271 100644 --- a/dlls/wow64/struct32.h +++ b/dlls/wow64/struct32.h @@ -190,6 +190,23 @@ typedef struct MEMORY_WORKING_SET_EX_BLOCK32 VirtualAttributes; } MEMORY_WORKING_SET_EX_INFORMATION32; +typedef struct +{ + ULONG ImageBase; + ULONG SizeOfImage; + union + { + ULONG ImageFlags; + struct + { + ULONG ImagePartialMap : 1; + ULONG ImageNotExecutable : 1; + ULONG ImageSigningLevel : 4; + ULONG Reserved : 26; + }; + }; +} MEMORY_IMAGE_INFORMATION32; + typedef struct { NTSTATUS ExitStatus; diff --git a/dlls/wow64/virtual.c b/dlls/wow64/virtual.c index 21ce0905654..c171fe39cb2 100644 --- a/dlls/wow64/virtual.c +++ b/dlls/wow64/virtual.c @@ -493,7 +493,7 @@ NTSTATUS WINAPI wow64_NtQueryVirtualMemory( UINT *args ) { if (len < sizeof(MEMORY_REGION_INFORMATION32)) status = STATUS_INFO_LENGTH_MISMATCH; - if ((ULONG_PTR)addr > highest_user_address) + else if ((ULONG_PTR)addr > highest_user_address) status = STATUS_INVALID_PARAMETER; else { @@ -534,6 +534,27 @@ NTSTATUS WINAPI wow64_NtQueryVirtualMemory( UINT *args ) break; } + case MemoryImageInformation: /* MEMORY_IMAEG_INFORMATION */ + { + if (len < sizeof(MEMORY_IMAGE_INFORMATION32)) return STATUS_INFO_LENGTH_MISMATCH; + + if ((ULONG_PTR)addr > highest_user_address) status = STATUS_INVALID_PARAMETER; + else + { + MEMORY_IMAGE_INFORMATION info; + MEMORY_IMAGE_INFORMATION32 *info32 = ptr; + + if (!(status = NtQueryVirtualMemory( handle, addr, class, &info, sizeof(info), &res_len ))) + { + info32->ImageBase = PtrToUlong( info.ImageBase ); + info32->SizeOfImage = info.SizeOfImage; + info32->ImageFlags = info.ImageFlags; + } + } + res_len = sizeof(MEMORY_IMAGE_INFORMATION32); + break; + } + case MemoryWineUnixWow64Funcs: return STATUS_INVALID_INFO_CLASS; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 1701a3e0420..51ac86b935e 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2027,6 +2027,21 @@ struct map_builtin_view_reply +struct get_image_view_info_request +{ + struct request_header __header; + obj_handle_t process; + client_ptr_t addr; +}; +struct get_image_view_info_reply +{ + struct reply_header __header; + client_ptr_t base; + mem_size_t size; +}; + + + struct unmap_view_request { struct request_header __header; @@ -5629,6 +5644,7 @@ enum request REQ_map_view, REQ_map_image_view, REQ_map_builtin_view, + REQ_get_image_view_info, REQ_unmap_view, REQ_get_mapping_committed_range, REQ_add_mapping_committed_range, @@ -5916,6 +5932,7 @@ union generic_request struct map_view_request map_view_request; struct map_image_view_request map_image_view_request; struct map_builtin_view_request map_builtin_view_request; + struct get_image_view_info_request get_image_view_info_request; struct unmap_view_request unmap_view_request; struct get_mapping_committed_range_request get_mapping_committed_range_request; struct add_mapping_committed_range_request add_mapping_committed_range_request; @@ -6201,6 +6218,7 @@ union generic_reply struct map_view_reply map_view_reply; struct map_image_view_reply map_image_view_reply; struct map_builtin_view_reply map_builtin_view_reply; + struct get_image_view_info_reply get_image_view_info_reply; struct unmap_view_reply unmap_view_reply; struct get_mapping_committed_range_reply get_mapping_committed_range_reply; struct add_mapping_committed_range_reply add_mapping_committed_range_reply; @@ -6418,7 +6436,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 778 +#define SERVER_PROTOCOL_VERSION 779 /* ### protocol_version end ### */ diff --git a/server/mapping.c b/server/mapping.c index e730486ac77..5d4df2050e4 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -1325,6 +1325,23 @@ DECL_HANDLER(unmap_view) free_memory_view( view ); } +/* get information about a mapped image view */ +DECL_HANDLER(get_image_view_info) +{ + struct process *process; + struct memory_view *view; + + if (!(process = get_process_from_handle( req->process, PROCESS_QUERY_INFORMATION ))) return; + + if ((view = find_mapped_addr( process, req->addr )) && (view->flags & SEC_IMAGE)) + { + reply->base = view->base; + reply->size = view->size; + } + + release_object( process ); +} + /* get a range of committed pages in a file mapping */ DECL_HANDLER(get_mapping_committed_range) { diff --git a/server/protocol.def b/server/protocol.def index b690817ef1d..41c857f5cb9 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1628,6 +1628,16 @@ enum server_fd_type @END +/* Get information about a mapped image view */ +@REQ(get_image_view_info) + obj_handle_t process; /* process handle */ + client_ptr_t addr; /* address inside mapped view (in process address space) */ +@REPLY + client_ptr_t base; /* view base address */ + mem_size_t size; /* view size */ +@END + + /* Unmap a memory view from the current process */ @REQ(unmap_view) client_ptr_t base; /* view base address */ diff --git a/server/request.h b/server/request.h index 0e54dc30b85..efc4eede9a2 100644 --- a/server/request.h +++ b/server/request.h @@ -186,6 +186,7 @@ DECL_HANDLER(get_mapping_info); DECL_HANDLER(map_view); DECL_HANDLER(map_image_view); DECL_HANDLER(map_builtin_view); +DECL_HANDLER(get_image_view_info); DECL_HANDLER(unmap_view); DECL_HANDLER(get_mapping_committed_range); DECL_HANDLER(add_mapping_committed_range); @@ -472,6 +473,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_map_view, (req_handler)req_map_image_view, (req_handler)req_map_builtin_view, + (req_handler)req_get_image_view_info, (req_handler)req_unmap_view, (req_handler)req_get_mapping_committed_range, (req_handler)req_add_mapping_committed_range, @@ -1145,6 +1147,12 @@ C_ASSERT( FIELD_OFFSET(struct map_image_view_request, entry) == 32 ); C_ASSERT( FIELD_OFFSET(struct map_image_view_request, machine) == 36 ); C_ASSERT( sizeof(struct map_image_view_request) == 40 ); C_ASSERT( sizeof(struct map_builtin_view_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_image_view_info_request, process) == 12 ); +C_ASSERT( FIELD_OFFSET(struct get_image_view_info_request, addr) == 16 ); +C_ASSERT( sizeof(struct get_image_view_info_request) == 24 ); +C_ASSERT( FIELD_OFFSET(struct get_image_view_info_reply, base) == 8 ); +C_ASSERT( FIELD_OFFSET(struct get_image_view_info_reply, size) == 16 ); +C_ASSERT( sizeof(struct get_image_view_info_reply) == 24 ); C_ASSERT( FIELD_OFFSET(struct unmap_view_request, base) == 16 ); C_ASSERT( sizeof(struct unmap_view_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct get_mapping_committed_range_request, base) == 16 ); diff --git a/server/trace.c b/server/trace.c index 4242e70a835..bb26608ad66 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2210,6 +2210,18 @@ static void dump_map_builtin_view_request( const struct map_builtin_view_request dump_varargs_unicode_str( ", name=", cur_size ); } +static void dump_get_image_view_info_request( const struct get_image_view_info_request *req ) +{ + fprintf( stderr, " process=%04x", req->process ); + dump_uint64( ", addr=", &req->addr ); +} + +static void dump_get_image_view_info_reply( const struct get_image_view_info_reply *req ) +{ + dump_uint64( " base=", &req->base ); + dump_uint64( ", size=", &req->size ); +} + static void dump_unmap_view_request( const struct unmap_view_request *req ) { dump_uint64( " base=", &req->base ); @@ -4622,6 +4634,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_map_view_request, (dump_func)dump_map_image_view_request, (dump_func)dump_map_builtin_view_request, + (dump_func)dump_get_image_view_info_request, (dump_func)dump_unmap_view_request, (dump_func)dump_get_mapping_committed_range_request, (dump_func)dump_add_mapping_committed_range_request, @@ -4905,6 +4918,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { NULL, NULL, NULL, + (dump_func)dump_get_image_view_info_reply, NULL, (dump_func)dump_get_mapping_committed_range_reply, NULL, @@ -5188,6 +5202,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "map_view", "map_image_view", "map_builtin_view", + "get_image_view_info", "unmap_view", "get_mapping_committed_range", "add_mapping_committed_range",