From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/loader.c | 26 +++++++++ dlls/ntdll/unix/virtual.c | 4 ++ loader/main.c | 113 +++++++++++++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 7243be49489..c718acb5382 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1439,6 +1439,30 @@ static inline char *prepend_build_dir_path( char *ptr, const char *ext, const ch }
+static void notify_gdb_dll_loaded( void *module, const char *unix_path ) +{ + static void (*wine_gdb_dll_loaded)( const void *module, const char *unix_path ); + if (!wine_gdb_dll_loaded) wine_gdb_dll_loaded = dlsym( RTLD_DEFAULT, "wine_gdb_dll_loaded" ); + if (wine_gdb_dll_loaded) wine_gdb_dll_loaded( module, unix_path ); +} + +static void notify_gdb_native_dll_loaded( void *module, UNICODE_STRING *nt_name ) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING redir; + char *unix_path; + + InitializeObjectAttributes( &attr, (void *)nt_name, OBJ_CASE_INSENSITIVE, 0, 0 ); + get_redirect( &attr, &redir ); + + if (!nt_to_unix_file_name( &attr, &unix_path, FILE_OPEN )) + notify_gdb_dll_loaded( module, unix_path ); + + free( redir.Buffer ); + free( unix_path ); +} + + /*********************************************************************** * open_dll_file * @@ -1489,6 +1513,7 @@ static NTSTATUS open_builtin_pe_file( const char *name, OBJECT_ATTRIBUTES *attr, { status = virtual_map_builtin_module( mapping, module, size, image_info, zero_bits, machine, prefer_native ); NtClose( mapping ); + if (!status) notify_gdb_dll_loaded( *module, name ); } return status; } @@ -1619,6 +1644,7 @@ static NTSTATUS find_builtin_dll( UNICODE_STRING *nt_name, void **module, SIZE_T
if (found_image) status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH; WARN( "cannot find builtin library for %s\n", debugstr_us(nt_name) ); + notify_gdb_native_dll_loaded( *module, nt_name ); done: if (status >= 0 && ext) { diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 2a00ac52811..75245885781 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4774,6 +4774,10 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) SERVER_END_REQ; if (!status) { + static void (*wine_gdb_dll_unload)( const void *module ); + if (!wine_gdb_dll_unload) wine_gdb_dll_unload = dlsym( RTLD_DEFAULT, "wine_gdb_dll_unload" ); + if (wine_gdb_dll_unload) wine_gdb_dll_unload( view->base ); + if (view->protect & SEC_IMAGE) release_builtin_module( view->base ); delete_view( view ); } diff --git a/loader/main.c b/loader/main.c index b7805473da8..adbe952e96c 100644 --- a/loader/main.c +++ b/loader/main.c @@ -20,6 +20,13 @@
#include "config.h"
+#include <stdarg.h> +#include <stddef.h> + +#include "windef.h" +#include "winbase.h" +#include "winnt.h" + #include <fcntl.h> #include <pthread.h> #include <stdio.h> @@ -40,6 +47,8 @@ # include <sys/link.h> #endif
+#include "wine/list.h" + #include "main.h"
extern char **environ; @@ -51,13 +60,23 @@ struct r_debug *wine_r_debug = NULL;
#ifdef __linux__
+struct link_map_entry +{ + struct link_map map; + const void *module; + struct list entry; +}; + +static struct list pe_link_map_entries = LIST_INIT( pe_link_map_entries ); +static struct link_map so_link_map; +static struct link_map pe_link_map = {.l_prev = &so_link_map, .l_name = (char *)""}; static struct link_map so_link_map = {.l_name = (char *)""}; static pthread_mutex_t link_map_lock = PTHREAD_MUTEX_INITIALIZER;
static void sync_wine_link_map(void) { static struct r_debug *_r_debug; - struct link_map *next = &so_link_map, *prev = NULL, **rtld_map, **wine_map; + struct link_map *next = &so_link_map, **rtld_map, **wine_map;
if (!_r_debug) _r_debug = dlsym( RTLD_NEXT, "_r_debug" ); rtld_map = &_r_debug->r_map; @@ -65,15 +84,18 @@ static void sync_wine_link_map(void)
pthread_mutex_lock( &link_map_lock );
+ /* unlink PE link map */ + pe_link_map.l_prev->l_next = NULL; + while (*rtld_map) { if (!*wine_map) { if (!(*wine_map = calloc( 1, sizeof(struct link_map) ))) break; - (*wine_map)->l_prev = prev; + (*wine_map)->l_prev = pe_link_map.l_prev; }
- prev = *wine_map; + pe_link_map.l_prev = *wine_map; (*wine_map)->l_addr = (*rtld_map)->l_addr; (*wine_map)->l_name = strdup( (*rtld_map)->l_name ); (*wine_map)->l_ld = (*rtld_map)->l_ld; @@ -95,12 +117,97 @@ static void sync_wine_link_map(void) free( prev ); }
+ /* link PE link map back */ + pe_link_map.l_prev->l_next = &pe_link_map; + pthread_mutex_unlock( &link_map_lock );
if (wine_r_debug) wine_r_debug->r_map = &so_link_map; if (wine_dl_debug_state) wine_dl_debug_state(); }
+static void add_dll_to_pe_link_map( const void *module, const char *unix_path ) +{ + const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)module; + const IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((const BYTE *)dos + dos->e_lfanew); + struct link_map_entry *entry; + struct link_map *map_end; + struct list *tail; + + if (!(entry = calloc( 1, sizeof(*entry) ))) return; + + entry->module = module; + entry->map.l_addr = (char *)module - (char *)nt->OptionalHeader.ImageBase; + entry->map.l_name = strdup( unix_path ); + + if ((tail = list_tail( &pe_link_map_entries ))) + { + entry->map.l_prev = &LIST_ENTRY( tail, struct link_map_entry, entry )->map; + entry->map.l_prev->l_next = &entry->map; + } + else + { + map_end = &pe_link_map; + while (map_end->l_next) map_end = map_end->l_next; + + map_end->l_next = &entry->map; + map_end->l_next->l_prev = map_end; + } + + list_add_tail( &pe_link_map_entries, &entry->entry ); +} + +void wine_gdb_dll_loaded( const void *module, const char *unix_path ) +{ + struct link_map_entry *entry; + + pthread_mutex_lock( &link_map_lock ); + + LIST_FOR_EACH_ENTRY( entry, &pe_link_map_entries, struct link_map_entry, entry ) + if (entry->module == module) break; + + if (&entry->entry == &pe_link_map_entries) + add_dll_to_pe_link_map( module, unix_path ); + else + { + const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)module; + const IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((const BYTE *)dos + dos->e_lfanew); + entry->map.l_addr = (char *)module - (char *)nt->OptionalHeader.ImageBase; + } + + pthread_mutex_unlock( &link_map_lock ); + + sync_wine_link_map(); +} + +void wine_gdb_dll_unload( const void *module ) +{ + struct link_map_entry *entry; + + pthread_mutex_lock( &link_map_lock ); + + LIST_FOR_EACH_ENTRY( entry, &pe_link_map_entries, struct link_map_entry, entry ) + if (entry->module == module) break; + + if (&entry->entry == &pe_link_map_entries) + { + pthread_mutex_unlock( &link_map_lock ); + return; + } + + list_remove( &entry->entry ); + + if (entry->map.l_prev) entry->map.l_prev->l_next = entry->map.l_next; + if (entry->map.l_next) entry->map.l_next->l_prev = entry->map.l_prev; + + pthread_mutex_unlock( &link_map_lock ); + + sync_wine_link_map(); + + free( entry->map.l_name ); + free( entry ); +} + void *dlopen( const char *file, int mode ) { static typeof(dlopen) *rtld_dlopen;