diff options
-rw-r--r-- | elf/Makefile | 2 | ||||
-rw-r--r-- | elf/dl-load.c | 86 | ||||
-rw-r--r-- | elf/dl-support.c | 1 | ||||
-rw-r--r-- | elf/genrtldtbl.awk | 2 | ||||
-rw-r--r-- | elf/link.h | 11 | ||||
-rw-r--r-- | elf/rtld.c | 50 | ||||
-rw-r--r-- | posix/Makefile | 2 | ||||
-rw-r--r-- | posix/wordexp-test.c | 95 | ||||
-rw-r--r-- | sysdeps/generic/dl-cache.c | 9 |
9 files changed, 248 insertions, 10 deletions
diff --git a/elf/Makefile b/elf/Makefile index aff64e4b9f..fc74fa4c8e 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -142,7 +142,7 @@ $(objpfx)trusted-dirs.h: Makefile echo " \"$$dir\","; \ done;) > $@T mv -f $@T $@ -$(objpfx)rtldtbl.h: Makefile +$(objpfx)rtldtbl.h: Makefile genrtldtbl.awk $(make-target-directory) echo "$(default-rpath)" | awk -f genrtldtbl.awk > $@T mv -f $@T $@ diff --git a/elf/dl-load.c b/elf/dl-load.c index 7adb6612d0..003754bf60 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -92,6 +92,9 @@ ELF_PREFERRED_ADDRESS_DATA; size_t _dl_pagesize; +/* Arguments passed to the dynamic linker. */ +extern char **_dl_argv; + extern const char *_dl_platform; extern size_t _dl_platformlen; @@ -163,7 +166,7 @@ static size_t max_dirnamelen; static inline struct r_search_path_elem ** fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, - const char **trusted) + const char **trusted, const char *what, const char *where) { char *cp; size_t nelems = 0; @@ -268,6 +271,9 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, max_dirnamelen = dirp->dirnamelen; } + dirp->what = what; + dirp->where = where; + dirp->next = all_dirs; all_dirs = dirp; @@ -284,7 +290,8 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, static struct r_search_path_elem ** -decompose_rpath (const char *rpath, size_t additional_room) +decompose_rpath (const char *rpath, size_t additional_room, + const char *what, const char *where) { /* Make a copy we can work with. */ char *copy = strdupa (rpath); @@ -305,7 +312,7 @@ decompose_rpath (const char *rpath, size_t additional_room) if (result == NULL) _dl_signal_error (ENOMEM, NULL, "cannot create cache for search path"); - return fillin_rpath (copy, result, ":", NULL); + return fillin_rpath (copy, result, ":", NULL, what, where); } @@ -358,7 +365,7 @@ _dl_init_paths (const char *llp) decompose_rpath ((const char *) (l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr + l->l_info[DT_RPATH]->d_un.d_val), - nllp); + nllp, "RPATH", l->l_name); } else { @@ -394,7 +401,8 @@ _dl_init_paths (const char *llp) /* We need to take care that the LD_LIBRARY_PATH environment variable can contain a semicolon. */ (void) fillin_rpath (copy, result, ":;", - __libc_enable_secure ? trusted_dirs : NULL); + __libc_enable_secure ? trusted_dirs : NULL, + "LD_LIBRARY_PATH", NULL); } } else @@ -415,7 +423,8 @@ _dl_init_paths (const char *llp) "cannot create cache for search path"); (void) fillin_rpath (local_strdup (llp), fake_path_list, ":;", - __libc_enable_secure ? trusted_dirs : NULL); + __libc_enable_secure ? trusted_dirs : NULL, + "LD_LIBRARY_PATH", NULL); } } @@ -454,6 +463,9 @@ _dl_init_paths (const char *llp) if (max_dirnamelen < relem->dirnamelen) max_dirnamelen = relem->dirnamelen; } + + relem->what = "system search path"; + relem->where = NULL; } } @@ -789,6 +801,41 @@ _dl_map_object_from_fd (char *name, int fd, char *realname, return l; } +/* Print search path. */ +static void +print_search_path (struct r_search_path_elem **list, + const char *what, const char *name) +{ + int first = 1; + + _dl_sysdep_message ("\t search path=", NULL); + + while (*list != NULL && (*list)->what == what) /* Yes, ==. */ + { + char *buf = strdupa ((*list)->dirname); + + if ((*list)->machdirstatus != nonexisting) + { + buf[(*list)->machdirnamelen - 1] = '\0'; + _dl_sysdep_message (first ? "" : ":", buf, NULL); + first = 0; + } + if ((*list)->dirstatus != nonexisting) + { + buf[(*list)->dirnamelen - 1] = '\0'; + _dl_sysdep_message (first ? "" : ":", buf, NULL); + first = 0; + } + ++list; + } + + if (name != NULL) + _dl_sysdep_message ("\t\t(", what, " from file ", + name[0] ? name : _dl_argv[0], ")\n", NULL); + else + _dl_sysdep_message ("\t\t(", what, ")\n", NULL); +} + /* Try to open NAME in one of the directories in DIRS. Return the fd, or -1. If successful, fill in *REALNAME with the malloc'd full directory name. */ @@ -800,6 +847,7 @@ open_path (const char *name, size_t namelen, int preloaded, { char *buf; int fd = -1; + const char *current_what = NULL; if (dirs == NULL || *dirs == NULL) { @@ -813,6 +861,14 @@ open_path (const char *name, size_t namelen, int preloaded, struct r_search_path_elem *this_dir = *dirs; size_t buflen = 0; + /* If we are debugging the search for libraries print the path + now if it hasn't happened now. */ + if (_dl_debug_libs && current_what != this_dir->what) + { + current_what = this_dir->what; + print_search_path (dirs, current_what, this_dir->where); + } + if (this_dir->machdirstatus != nonexisting) { /* Construct the pathname to try. */ @@ -821,6 +877,10 @@ open_path (const char *name, size_t namelen, int preloaded, name, namelen) - buf); + /* Print name we try if this is wanted. */ + if (_dl_debug_libs) + _dl_sysdep_message ("\t trying file=", buf, "\n", NULL); + fd = __open (buf, O_RDONLY); if (this_dir->machdirstatus == unknown) if (fd != -1) @@ -872,6 +932,10 @@ open_path (const char *name, size_t namelen, int preloaded, name, namelen) - buf); + /* Print name we try if this is wanted. */ + if (_dl_debug_libs) + _dl_sysdep_message ("\t trying file=", buf, "\n", NULL); + fd = __open (buf, O_RDONLY); if (this_dir->dirstatus == unknown) if (fd != -1) @@ -988,6 +1052,9 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded, size_t namelen = strlen (name) + 1; + if (_dl_debug_libs) + _dl_sysdep_message ("\tfind library=", name, "; searching\n", NULL); + fd = -1; /* First try the DT_RPATH of the dependent object that caused NAME @@ -1002,7 +1069,8 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded, + l->l_info[DT_STRTAB]->d_un.d_ptr + l->l_info[DT_RPATH]->d_un.d_val); l->l_rpath_dirs = - decompose_rpath ((const char *) ptrval, 0); + decompose_rpath ((const char *) ptrval, 0, + "RPATH", l->l_name); } if (l->l_rpath_dirs != (struct r_search_path_elem **) -1l) @@ -1046,6 +1114,10 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded, /* Finally, try the default path. */ if (fd == -1) fd = open_path (name, namelen, preloaded, rtld_search_dirs, &realname); + + /* Add another newline when we a tracing the library loading. */ + if (_dl_debug_libs) + _dl_sysdep_message ("\n", NULL); } else { diff --git a/elf/dl-support.c b/elf/dl-support.c index 5868656c4e..9d28d2b640 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -35,6 +35,7 @@ const char *_dl_rpath = DEFAULT_RPATH; /* Name of the architecture. */ const char *_dl_platform; size_t _dl_platformlen; +int _dl_debug_libs; /* If nonzero print warnings about problematic situations. */ int _dl_verbose; diff --git a/elf/genrtldtbl.awk b/elf/genrtldtbl.awk index 63ada003f6..54cdc8c589 100644 --- a/elf/genrtldtbl.awk +++ b/elf/genrtldtbl.awk @@ -12,7 +12,7 @@ BEGIN { END { for (i = 0; i < count; ++i) { printf ("static struct r_search_path_elem rtld_search_dir%d =\n", i+1); - printf (" { \"%s/\", %d, unknown, 0, nonexisting, ", + printf (" { \"%s/\", %d, unknown, 0, nonexisting, NULL, NULL, ", dir[i], length (dir[i]) + 1); if (i== 0) printf ("NULL };\n"); diff --git a/elf/link.h b/elf/link.h index d056e65617..b8bce5839d 100644 --- a/elf/link.h +++ b/elf/link.h @@ -106,6 +106,10 @@ struct r_search_path_elem size_t machdirnamelen; enum r_dir_status machdirstatus; + /* Strings saying where the definition came from. */ + const char *what; + const char *where; + /* This link is only used in the `all_dirs' member of `r_search_path'. */ struct r_search_path_elem *next; }; @@ -238,6 +242,9 @@ extern const char *_dl_profile; /* Map of shared object to be profiled. */ extern struct link_map *_dl_profile_map; +/* If nonzero the appropriate debug information if printed. */ +extern int _dl_debug_libs; + /* OS-dependent function to open the zero-fill device. */ extern int _dl_sysdep_open_zero_fill (void); /* dl-sysdep.c */ @@ -461,6 +468,10 @@ extern void _dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc); /* Show the members of the auxiliary array passed up from the kernel. */ extern void _dl_show_auxv (void); +/* Return all environment variables starting with `LD_', one after the + other. */ +extern char *_dl_next_ld_env_entry (char ***position); + __END_DECLS #endif /* link.h */ diff --git a/elf/rtld.c b/elf/rtld.c index 2707da60df..72316905b4 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -73,6 +73,7 @@ struct r_search_path *_dl_search_paths; const char *_dl_profile; const char *_dl_profile_output; struct link_map *_dl_profile_map; +int _dl_debug_libs; /* Set nonzero during loading and initialization of executable and libraries, cleared before the executable's entry point runs. This @@ -906,6 +907,45 @@ print_missing_version (int errcode __attribute__ ((unused)), objname, ": ", errstring, "\n", NULL); } +/* Process the string given as the parameter which explains which debugging + options are enabled. */ +static void +process_dl_debug (char *dl_debug) +{ + do + { +#define issep(Ch) ((Ch) == ' ' || (Ch) == ',') + /* Skip separating white spaces and commas. */ + while (issep (*dl_debug)) + ++dl_debug; + if (*dl_debug != '\0') + { + if (strncmp (dl_debug, "libs", 4) == 0 + && (issep (dl_debug[4]) || dl_debug[4] == '\0')) + { + _dl_debug_libs = 1; + dl_debug += 4; + } + else if (strncmp (dl_debug, "help", 4) == 0 + && (issep (dl_debug[4]) || dl_debug[4] == '\0')) + { + _dl_sysdep_message ("\ +Valid options for the DL_DEBUG environment variable are:\n\ +\n\ + help display this help message and exit + libs display library search paths\n", NULL); + _exit (0); + } + else + /* Skip everything until next separator. */ + do + ++dl_debug; + while (*dl_debug != '\0' && !issep (*dl_debug)); + } + } + while (*dl_debug != '\0'); +} + /* Process all environments variables the dynamic linker must recognize. Since all of them start with `LD_' we are a bit smarter while finding all the entries. */ @@ -934,6 +974,16 @@ process_envvars (enum mode *modep, int *lazyp) if (result < 0) continue; + /* Debugging of the dynamic linker? */ + result = strncmp (&envline[3], "DEBUG=", 6); + if (result == 0) + { + process_dl_debug (&envline[9]); + continue; + } + if (result < 0) + continue; + /* Which shared object shall be profiled. */ result = strncmp (&envline[3], "PROFILE=", 8); if (result == 0) diff --git a/posix/Makefile b/posix/Makefile index 5927f31335..a9b78aa606 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -52,7 +52,7 @@ routines := \ pread pwrite pread64 pwrite64 aux := init-posix environ -tests := tstgetopt testfnm runtests +tests := tstgetopt testfnm runtests wordexp-test test-srcs := globtest others := getconf install-bin := getconf diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c new file mode 100644 index 0000000000..2e403caa0e --- /dev/null +++ b/posix/wordexp-test.c @@ -0,0 +1,95 @@ +/* Copyright (C) 1997, 1998 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <wordexp.h> +#include <stdio.h> +#include <stdlib.h> + +struct test_case_struct +{ + int retval; + const char *env; + const char *words; + int flags; + int wordc; + const char *wordv[10]; +} test_case[] = + { + { 0, NULL, "one", 0, 1, { "one", } }, + { 0, NULL, "one two", 0, 2, { "one", "two", } }, + { 0, NULL, "one two three", 0, 3, { "one", "two", "three", } }, + { 0, NULL, "~root", 0, 1, { "/root", } }, + { 0, "foo", "${var}", 0, 1, { "foo", } }, + { 0, "foo", "$var", 0, 1, { "foo", } }, + { 0, NULL, "\"quoted\"", 0, 1, { "quoted", } }, + { -1, NULL, NULL, 0, 0, { NULL, } }, + }; + +int +main (int argc, char * argv[]) +{ + wordexp_t we; + int test; + int fail = 0; + int retval; + int i; + + setenv ("IFS", " \t\n", 1); + for (test = 0; test_case[test].retval != -1; test++) + { + int bzzzt = 0; + + if (test_case[test].env) + setenv ("var", test_case[test].env, 1); + else + unsetenv ("var"); + + printf ("Test %d: ", test); + retval = wordexp (test_case[test].words, &we, test_case[test].flags); + + if (retval != test_case[test].retval || + we.we_wordc != test_case[test].wordc) + bzzzt = 1; + else + for (i = 0; i < we.we_wordc; i++) + if (strcmp (test_case[test].wordv[i], we.we_wordv[i]) != 0) + { + bzzzt = 1; + break; + } + + if (bzzzt) + { + ++fail; + printf ("FAILED\n"); + printf ("Test words: <%s>, need retval %d, wordc %d\n", + test_case[test].words, test_case[test].retval, + test_case[test].wordc); + printf ("Got retval %d, wordc %d: ", retval, we.we_wordc); + for (i = 0; i < we.we_wordc; i++) + printf ("<%s> ", we.we_wordv[i]); + printf ("\n"); + } + else + printf ("OK\n"); + + wordfree (&we); + } + + return fail; +} diff --git a/sysdeps/generic/dl-cache.c b/sysdeps/generic/dl-cache.c index 8eb18b79cc..43a987a1fd 100644 --- a/sysdeps/generic/dl-cache.c +++ b/sysdeps/generic/dl-cache.c @@ -55,6 +55,10 @@ _dl_load_cache_lookup (const char *name) unsigned int i; const char *best; + /* Print a message if the loading of libs is traced. */ + if (_dl_debug_libs) + _dl_sysdep_message ("\t search cache=", LD_SO_CACHE, "\n", NULL); + if (cache == NULL) { /* Read the contents of the file. */ @@ -99,5 +103,10 @@ _dl_load_cache_lookup (const char *name) break; } } + + /* Print our result if wanted. */ + if (_dl_debug_libs && best != NULL) + _dl_sysdep_message ("\t trying file=", best, "\n", NULL); + return best; } |