From: Rémi Bernon rbernon@codeweavers.com
And debugger interface as described in https://sourceware.org/git/?p=glibc.git;a=blob;f=elf/rtld-debugger-interface... --- loader/main.c | 19 +++++++++++++++++ loader/preloader.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+)
diff --git a/loader/main.c b/loader/main.c index c258e025183..214343ea26f 100644 --- a/loader/main.c +++ b/loader/main.c @@ -33,6 +33,12 @@ #ifdef HAVE_SYS_SYSCTL_H # include <sys/sysctl.h> #endif +#ifdef HAVE_LINK_H +# include <link.h> +#endif +#ifdef HAVE_SYS_LINK_H +# include <sys/link.h> +#endif
#include "main.h"
@@ -41,6 +47,16 @@ extern char **environ; /* the preloader will set this variable */ const __attribute((visibility("default"))) struct wine_preload_info *wine_main_preload_info = NULL;
+#ifdef __linux__ + +/* the preloader will set this variable */ +typedef void (*rtld_init_func)( struct link_map *map ); +__attribute((visibility("default"))) rtld_init_func wine_rtld_init = NULL; + +static struct link_map link_map = {0}; + +#endif /* __linux__ */ + /* canonicalize path and return its directory name */ static char *realpath_dirname( const char *name ) { @@ -176,6 +192,9 @@ static void *load_ntdll( char *argv0 ) int main( int argc, char *argv[] ) { void *handle; +#ifdef __linux__ + if (wine_rtld_init) wine_rtld_init( &link_map ); +#endif /* __linux__ */
if ((handle = load_ntdll( argv[0] ))) { diff --git a/loader/preloader.c b/loader/preloader.c index d0551bae63a..49c4f0db9ad 100644 --- a/loader/preloader.c +++ b/loader/preloader.c @@ -85,12 +85,20 @@ #ifdef HAVE_SYS_LINK_H # include <sys/link.h> #endif +#ifdef HAVE_SYS_SDT_H +# include <sys/sdt.h> +#else +# define STAP_PROBE2(a,b,c,d) +# define STAP_PROBE3(a,b,c,d,e) +#endif
#include "wine/asm.h" #include "main.h"
#pragma GCC visibility push(hidden)
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + /* ELF definitions */ #define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref) #define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0) @@ -1387,6 +1395,42 @@ static void set_process_name( int argc, char *argv[] ) for (i = 1; i < argc; i++) argv[i] -= off; }
+/* GDB integration */ +extern char __executable_start; +__attribute((visibility("default"))) void _dl_debug_state(void) {} +__attribute((visibility("default"))) struct r_debug _r_debug = +{ + .r_version = 1, /* no support for r_next */ + .r_state = RT_CONSISTENT, + .r_brk = (ElfW(Addr))(uintptr_t)_dl_debug_state, +}; + +/* sets the preloader r_debug address into DT_DEBUG */ +static void init_r_debug( struct wld_auxv *av ) +{ + const char *l_addr = &__executable_start; + ElfW(Phdr) *phdr, *ph; + ElfW(Dyn) *dyn = NULL; + int phnum; + + if (!(phnum = get_auxiliary( av, AT_PHNUM, 0 ))) return; + if (!(phdr = (void *)get_auxiliary( av, AT_PHDR, 0 ))) return; + + for (ph = phdr; ph < &phdr[phnum]; ++ph) if (ph->p_type == PT_DYNAMIC) break; + if (ph >= &phdr[phnum]) return; + + dyn = (void *)(ph->p_vaddr + l_addr); + while (dyn->d_tag != DT_DEBUG) dyn++; + + if (dyn->d_tag == DT_DEBUG) dyn->d_un.d_ptr = (uintptr_t)&_r_debug; +} + +static void rtld_init( struct link_map *map ) +{ + STAP_PROBE2( rtld, init_start, LM_ID_BASE, &_r_debug ); + _r_debug.r_map = map; + STAP_PROBE2( rtld, init_complete, LM_ID_BASE, &_r_debug ); +}
/* * wld_start @@ -1403,6 +1447,7 @@ void* wld_start( void **stack ) struct wld_auxv new_av[8], delete_av[3], *av; struct wld_link_map main_binary_map, ld_so_map; struct wine_preload_info **wine_main_preload_info; + void **rtld_probe;
pargc = *stack; argv = (char **)pargc + 1; @@ -1432,6 +1477,8 @@ void* wld_start( void **stack ) dump_auxiliary( av ); #endif
+ init_r_debug( av ); + /* reserve memory that Wine needs */ if (reserve) preload_reserve( reserve ); for (i = 0; preload_info[i].size; i++) @@ -1475,6 +1522,10 @@ void* wld_start( void **stack ) if (wine_main_preload_info) *wine_main_preload_info = preload_info; else wld_printf( "wine_main_preload_info not found\n" );
+ rtld_probe = find_symbol( &main_binary_map, "wine_rtld_init", STT_OBJECT ); + if (rtld_probe) *rtld_probe = rtld_init; + else wld_printf( "wine_rtld_init not found\n" ); + #define SET_NEW_AV(n,type,val) new_av[n].a_type = (type); new_av[n].a_un.a_val = (val); SET_NEW_AV( 0, AT_PHDR, (unsigned long)main_binary_map.l_phdr ); SET_NEW_AV( 1, AT_PHENT, sizeof(ElfW(Phdr)) );