From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/virtual.c | 35 +++++++++++- loader/main.c | 114 +++++++++++++++++++++++++++++++++++++- 2 files changed, 147 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 75e6319c007..dc46026f094 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -79,6 +79,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(virtual); WINE_DECLARE_DEBUG_CHANNEL(module); WINE_DECLARE_DEBUG_CHANNEL(virtual_ranges);
+/* Gdb integration, in loader/main.c */ +static void (*wine_gdb_dll_loaded)( const void *module, const char *unix_path, INT_PTR offset ); +static void (*wine_gdb_dll_unload)( const void *module ); + struct preload_info { void *addr; @@ -2670,6 +2674,27 @@ static IMAGE_BASE_RELOCATION *process_relocation_block( char *page, IMAGE_BASE_R }
+/*********************************************************************** + * notify_gdb_dll_loaded + */ +static void notify_gdb_dll_loaded( void *module, const WCHAR *filename, INT_PTR offset ) +{ + UNICODE_STRING redir, nt_name; + OBJECT_ATTRIBUTES attr; + char *unix_path = NULL; + + RtlInitUnicodeString( &nt_name, filename ); + InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, 0 ); + get_redirect( &attr, &redir ); + + if (!nt_to_unix_file_name( &attr, &unix_path, FILE_OPEN )) + wine_gdb_dll_loaded( module, unix_path, offset ); + + free( redir.Buffer ); + free( unix_path ); +} + + /*********************************************************************** * map_image_into_view * @@ -2900,6 +2925,7 @@ static NTSTATUS map_image_into_view( struct file_view *view, const WCHAR *filena #ifdef VALGRIND_LOAD_PDB_DEBUGINFO VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, ptr - (char *)wine_server_get_ptr( image_info->base )); #endif + if (wine_gdb_dll_loaded) notify_gdb_dll_loaded( ptr, filename, ptr - (char *)wine_server_get_ptr( image_info->base ) ); return STATUS_SUCCESS; }
@@ -3256,6 +3282,9 @@ void virtual_init(void) int i; pthread_mutexattr_t attr;
+ wine_gdb_dll_loaded = dlsym( RTLD_DEFAULT, "wine_gdb_dll_loaded" ); + wine_gdb_dll_unload = dlsym( RTLD_DEFAULT, "wine_gdb_dll_unload" ); + pthread_mutexattr_init( &attr ); pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); pthread_mutex_init( &virtual_mutex, &attr ); @@ -5598,7 +5627,11 @@ static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr, ULONG flags ) SERVER_END_REQ; if (!status) { - if (view->protect & SEC_IMAGE) release_builtin_module( view->base ); + if (view->protect & SEC_IMAGE) + { + if (wine_gdb_dll_unload) wine_gdb_dll_unload( view->base ); + release_builtin_module( view->base ); + } if (flags & MEM_PRESERVE_PLACEHOLDER) free_pages_preserve_placeholder( view, view->base, view->size ); else delete_view( view ); } diff --git a/loader/main.c b/loader/main.c index 8667823de4a..ad4a8f4c6bf 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; @@ -58,18 +67,43 @@ __attribute((visibility("default"))) rtld_notify_func wine_rtld_map_complete = N __attribute((visibility("default"))) rtld_notify_func wine_rtld_unmap_start = NULL; __attribute((visibility("default"))) rtld_notify_func wine_rtld_unmap_complete = NULL;
+struct link_map_entry +{ + struct link_map map; + const void *module; + struct list entry; +}; + static pthread_mutex_t link_map_lock; static struct link_map link_map = {0}; +static struct list dll_map_entries = LIST_INIT( dll_map_entries ); + +static char *link_realpath( const char *path ) +{ + char *real; + if (!path) return NULL; + if (!(real = realpath( path, NULL ))) return strdup( path ); + return real; +}
static void sync_wine_link_map(void) { static struct r_debug *_r_debug; struct link_map *next = &link_map, *last = NULL, **rtld_map, **wine_map; + struct link_map_entry *pe_entry = NULL; + struct list *ptr;
if (!_r_debug) _r_debug = dlsym( RTLD_NEXT, "_r_debug" ); rtld_map = &_r_debug->r_map; wine_map = &next;
+ /* detach the PE link map */ + if ((ptr = list_head( &dll_map_entries ))) + { + pe_entry = LIST_ENTRY( ptr, struct link_map_entry, entry ); + if (pe_entry->map.l_prev) pe_entry->map.l_prev->l_next = NULL; + } + while (*rtld_map) { if (!*wine_map) @@ -81,7 +115,7 @@ static void sync_wine_link_map(void) last = *wine_map; free( (*wine_map)->l_name ); (*wine_map)->l_addr = (*rtld_map)->l_addr; - (*wine_map)->l_name = strdup( (*rtld_map)->l_name ); + (*wine_map)->l_name = link_realpath( (*rtld_map)->l_name ); (*wine_map)->l_ld = (*rtld_map)->l_ld; rtld_map = &(*rtld_map)->l_next; wine_map = &(*wine_map)->l_next; @@ -100,6 +134,84 @@ static void sync_wine_link_map(void) free( tmp->l_name ); free( tmp ); } + + if (pe_entry) + { + /* attach PE link map back */ + pe_entry->map.l_prev = last; + last->l_next = &pe_entry->map; + } +} + +static void add_dll_to_pe_link_map( const void *module, const char *unix_path, INT_PTR offset ) +{ + struct link_map_entry *entry, *last_entry; + struct list *ptr; + + if (!(entry = calloc( 1, sizeof(*entry) ))) return; + + entry->module = module; + entry->map.l_addr = offset; + entry->map.l_name = link_realpath( unix_path ); + + if ((ptr = list_tail( &dll_map_entries ))) + { + last_entry = LIST_ENTRY( ptr, struct link_map_entry, entry ); + entry->map.l_prev = &last_entry->map; + last_entry->map.l_next = &entry->map; + } + + list_add_tail( &dll_map_entries, &entry->entry ); + if (!entry->map.l_prev) sync_wine_link_map(); +} + +__attribute((visibility("default"))) void wine_gdb_dll_loaded( const void *module, const char *unix_path, INT_PTR offset ) +{ + struct link_map_entry *entry; + + pthread_mutex_lock( &link_map_lock ); + + LIST_FOR_EACH_ENTRY( entry, &dll_map_entries, struct link_map_entry, entry ) + if (entry->module == module) break; + + if (&entry->entry == &dll_map_entries) + add_dll_to_pe_link_map( module, unix_path, offset ); + else + entry->map.l_addr = offset; + + if (wine_rtld_map_start) wine_rtld_map_start(); + if (wine_rtld_map_complete) wine_rtld_map_complete(); + + pthread_mutex_unlock( &link_map_lock ); +} + +__attribute((visibility("default"))) void wine_gdb_dll_unload( const void *module ) +{ + struct link_map *prev, *next; + struct link_map_entry *entry; + + pthread_mutex_lock( &link_map_lock ); + + LIST_FOR_EACH_ENTRY( entry, &dll_map_entries, struct link_map_entry, entry ) + if (entry->module == module) break; + + if (&entry->entry == &dll_map_entries) + { + pthread_mutex_unlock( &link_map_lock ); + return; + } + + list_remove( &entry->entry ); + if ((prev = entry->map.l_prev)) prev->l_next = entry->map.l_next; + if ((next = entry->map.l_next)) next->l_prev = entry->map.l_prev; + + if (wine_rtld_unmap_start) wine_rtld_unmap_start(); + if (wine_rtld_unmap_complete) wine_rtld_unmap_complete(); + + pthread_mutex_unlock( &link_map_lock ); + + free( entry->map.l_name ); + free( entry ); }
__attribute((visibility("default"))) void *dlopen( const char *file, int mode )