From 4d6acc61fa6892b40eaf94de4ff506ff83e37490 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 13 Jun 1996 04:06:45 +0000 Subject: Thu Jun 13 00:02:25 1996 Roland McGrath * elf/dl-lookup.c (_dl_lookup_symbol): If no value and *REF is null, consider it a strong reference and give the error. Wed Jun 12 15:52:46 1996 Roland McGrath * elf/dl-open.c (_dl_open): Correctly terminate relocating loop after relocating NEW when it's the only new object. * elf/dl-init.c (_dl_init_next): When out of initializers, set _r_debug.r_state to RT_CONSISTENT and call _dl_debug_state just before return. * elf/rtld.c (dl_main): Move _dl_debug_initialize call after relocation. Call it unconditionally and only fill in DT_DEBUG if it's present. Then call _dl_debug_state with r_state RT_ADD before running initializers. * elf/dl-open.c (_dl_open): Call _dl_debug_initialize and then call _dl_debug_state with r_state RT_ADD before running initializers * elf/dl-close.c (_dl_close): Call _dl_debug_state with r_state RT_DELETE before running finalizers and with RT_CONSISTENT just before return. * elf/Makefile (dl-routines): Add dl-debug. * elf/dl-debug.c: New file. * elf/rtld.c (_dl_r_debug): Rename to _r_debug and move to dl-debug.c. (_dl_r_debug_state): Rename to _dl_debug_state and likewise move. (dl_main): Use _dl_debug_initialize. * elf/link.h: Fix name to _dl_debug_state in decl. (_dl_debug_initialize): Declare new function from dl-debug.c. (_r_debug): Declare it. * Makerules (distinfo-vars): Add install-{lib,data,bin,sbin,others}. In distinfo set $(subdir)-VAR and then set VAR to $($(subdir)-VAR). * Makeconfig (rpath-link): New variable; add $(elfobjdir). (default-rpath): Use it. (built-program-cmd): Use it in LD_LIBRARY_PATH. * Makeconfig (sysdep-configures): Prepend $(sysdep_dir) to names tried. * sysdeps/unix/Dist: Add make-syscalls.sh. * misc/Makefile (headers): Add sys/swap.h. * posix/unistd.h: Remove decls for swapon, swapoff. * sysdeps/generic/sys/swap.h: New file. * sysdeps/unix/sysv/linux/sys/swap.h: New file. * sysdeps/unix/sysv/linux/gnu/types.h: Remove temporary hack #define of __kernel_fsid_t. It is correctly defines in now. --- elf/Makefile | 2 +- elf/dl-close.c | 8 ++++++++ elf/dl-debug.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ elf/dl-init.c | 5 +++++ elf/dl-lookup.c | 3 ++- elf/dl-open.c | 15 +++++++++++++-- elf/link.h | 10 +++++++++- elf/rtld.c | 34 ++++++++++++++-------------------- 8 files changed, 108 insertions(+), 25 deletions(-) create mode 100644 elf/dl-debug.c (limited to 'elf') diff --git a/elf/Makefile b/elf/Makefile index 07ffbd8788..be7604de8e 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -26,7 +26,7 @@ routines = $(dl-routines) dl-open dl-close dl-symbol dl-support # The core dynamic linking functions are in libc for the static and # profiled libraries. dl-routines = $(addprefix dl-,load lookup object reloc deps \ - runtime error init fini) + runtime error init fini debug) # But they are absent from the shared libc, because that code is in ld.so. elide-routines.so = $(dl-routines) dl-support diff --git a/elf/dl-close.c b/elf/dl-close.c index 70d7ab4083..184d38298e 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -41,6 +41,10 @@ _dl_close (struct link_map *map) /* There are still references to this object. Do nothing more. */ return; + /* Notify the debugger we are about to remove some loaded objects. */ + _r_debug.r_state = RT_DELETE; + _dl_debug_state (); + list = map->l_searchlist; /* The search list contains a counted reference to each object it @@ -105,4 +109,8 @@ _dl_close (struct link_map *map) } free (list); + + /* Notify the debugger those objects are finalized and gone. */ + _r_debug.r_state = RT_CONSISTENT; + _dl_debug_state (); } diff --git a/elf/dl-debug.c b/elf/dl-debug.c new file mode 100644 index 0000000000..861e0019e8 --- /dev/null +++ b/elf/dl-debug.c @@ -0,0 +1,56 @@ +/* Communicate dynamic linker state to the debugger at runtime. +Copyright (C) 1996 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include + +/* This structure communicates dl state to the debugger. The debugger + normally finds it via the DT_DEBUG entry in the dynamic section, but in + a statically-linked program there is no dynamic section for the debugger + to examine and it looks for this particular symbol name. */ +struct r_debug _r_debug; + + +/* Initialize _r_debug if it has not already been done. The argument is + the run-time load address of the dynamic linker, to be put in + _r_debug.r_ldbase. Returns the address of _r_debug. */ + +struct r_debug * +_dl_debug_initialize (ElfW(Addr) ldbase) +{ + if (_r_debug.r_brk == 0) + { + /* Tell the debugger where to find the map of loaded objects. */ + _r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */; + _r_debug.r_ldbase = _dl_rtld_map.l_addr; /* Record our load address. */ + _r_debug.r_map = _dl_loaded; + _r_debug.r_brk = (ElfW(Addr)) &_dl_debug_state; + } + + return &_r_debug; +} + + +/* This function exists solely to have a breakpoint set on it by the + debugger. The debugger is supposed to find this function's address by + examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks + for this particular symbol name in the PT_INTERP file. */ +void +_dl_debug_state (void) +{ +} diff --git a/elf/dl-init.c b/elf/dl-init.c index 66ef83e28b..6259c35235 100644 --- a/elf/dl-init.c +++ b/elf/dl-init.c @@ -65,5 +65,10 @@ _dl_init_next (struct link_map *map) l->l_init_called = 1; } + + /* Notify the debugger all new objects are now ready to go. */ + _r_debug.r_state = RT_CONSISTENT; + _dl_debug_state (); + return 0; } diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index bbccbc01ef..7ceffa23e1 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -129,7 +129,8 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref, } } - if (weak_value.s == NULL && ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) + if (weak_value.s == NULL && + !*ref || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) { /* We could find no value for a strong reference. */ const char msg[] = "undefined symbol: "; diff --git a/elf/dl-open.c b/elf/dl-open.c index 9389303b90..373d32dd79 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -29,6 +29,7 @@ _dl_open (struct link_map *parent, const char *file, int mode) { struct link_map *new, *l; ElfW(Addr) init; + struct r_debug *r; /* Load the named object. */ @@ -47,7 +48,7 @@ _dl_open (struct link_map *parent, const char *file, int mode) l = new; while (l->l_next) l = l->l_next; - do + while (1) { if (! l->l_relocated) { @@ -56,8 +57,10 @@ _dl_open (struct link_map *parent, const char *file, int mode) *_dl_global_scope_end = NULL; } + if (l == new) + break; l = l->l_prev; - } while (l != new); + } new->l_global = (mode & RTLD_GLOBAL); if (new->l_global) @@ -108,6 +111,14 @@ _dl_open (struct link_map *parent, const char *file, int mode) } } + + /* Notify the debugger we have added some objects. We need to call + _dl_debug_initialize in a static program in case dynamic linking has + not been used before. */ + r = _dl_debug_initialize (0); + r->r_state = RT_ADD; + _dl_debug_state (); + /* Run the initializer functions of new objects. */ while (init = _dl_init_next (new)) (*(void (*) (void)) init) (); diff --git a/elf/link.h b/elf/link.h index 6910445095..f43ec411f8 100644 --- a/elf/link.h +++ b/elf/link.h @@ -62,6 +62,9 @@ struct r_debug ElfW(Addr) r_ldbase; /* Base address the linker is loaded at. */ }; +/* This is the instance of that structure used by the dynamic linker. */ +extern struct r_debug _r_debug; + /* This symbol refers to the "dynamic structure" in the `.dynamic' section of whatever module refers to `_DYNAMIC'. So, to find its own `struct r_debug', a program could do: @@ -291,7 +294,12 @@ extern void _dl_fini (void); any shared object mappings. The `r_state' member of `struct r_debug' says what change is taking place. This function's address is the value of the `r_brk' member. */ -extern void _dl_r_debug_state (void); +extern void _dl_debug_state (void); + +/* Initialize `struct r_debug' if it has not already been done. The + argument is the run-time load address of the dynamic linker, to be put + in the `r_ldbase' member. Returns the address of the structure. */ +extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase); #endif /* link.h */ diff --git a/elf/rtld.c b/elf/rtld.c index c9ddfb5c63..7befc0a82f 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -46,8 +46,6 @@ int _dl_argc; char **_dl_argv; const char *_dl_rpath; -struct r_debug _dl_r_debug; - static void dl_main (const ElfW(Phdr) *phdr, ElfW(Half) phent, ElfW(Addr) *user_entry); @@ -229,12 +227,6 @@ of this helper program; chances are you did not intend to run this program.\n", /* Set up our cache of pointers into the hash table. */ _dl_setup_hash (l); - if (l->l_info[DT_DEBUG]) - /* There is a DT_DEBUG entry in the dynamic section. Fill it in - with the run-time address of the r_debug structure, which we - will set up later to communicate with the debugger. */ - l->l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) &_dl_r_debug; - /* Put the link_map for ourselves on the chain so it can be found by name. */ _dl_rtld_map.l_name = (char *) _dl_rtld_map.l_libname = interpreter_name; @@ -343,11 +335,20 @@ of this helper program; chances are you did not intend to run this program.\n", _dl_relocate_object (&_dl_rtld_map, &_dl_default_scope[2], 0); } - /* Tell the debugger where to find the map of loaded objects. */ - _dl_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */; - _dl_r_debug.r_ldbase = _dl_rtld_map.l_addr; /* Record our load address. */ - _dl_r_debug.r_map = _dl_loaded; - _dl_r_debug.r_brk = (ElfW(Addr)) &_dl_r_debug_state; + { + /* Initialize _r_debug. */ + struct r_debug *r = _dl_debug_initialize (_dl_rtld_map.l_addr); + + l = _dl_loaded; + if (l->l_info[DT_DEBUG]) + /* There is a DT_DEBUG entry in the dynamic section. Fill it in + with the run-time address of the r_debug structure */ + l->l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) r; + + /* Notify the debugger that all objects are now mapped in. */ + r->r_state = RT_ADD; + _dl_debug_state (); + } if (_dl_rtld_map.l_info[DT_INIT]) { @@ -365,10 +366,3 @@ of this helper program; chances are you did not intend to run this program.\n", /* Once we return, _dl_sysdep_start will invoke the DT_INIT functions and then *USER_ENTRY. */ } - -/* This function exists solely to have a breakpoint set on it by the - debugger. */ -void -_dl_r_debug_state (void) -{ -} -- cgit 1.4.1