about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/ldd.bash.in14
-rw-r--r--elf/ldd.sh.in13
-rw-r--r--elf/libdl.map2
-rw-r--r--elf/rtld.c166
4 files changed, 174 insertions, 21 deletions
diff --git a/elf/ldd.bash.in b/elf/ldd.bash.in
index c433a72679..809c2717da 100644
--- a/elf/ldd.bash.in
+++ b/elf/ldd.bash.in
@@ -31,14 +31,16 @@ TEXTDOMAINDIR=@TEXTDOMAINDIR@
 RTLD=@RTLD@
 warn=
 bind_now=
+verbose=
 
 while test $# -gt 0; do
   case "$1" in
-  --v | --ve | --ver | --vers | --versi | --versio | --version)
+  --vers | --versi | --versio | --version)
     echo 'ldd (GNU libc) @VERSION@'
     echo $"Copyright (C) 1996, 1997 Free Software Foundation, Inc.
 This is free software; see the source for copying conditions.  There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+Written by Roland McGrath and Ulrich Drepper."
     exit 0 ;;
   --h | --he | --hel | --help)
     echo $"ldd [OPTION]... FILE...
@@ -46,6 +48,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
       --version           print version information and exit
   -d, --data-relocs       process data relocations
   -r, --function-relocs   process data and function relocations
+  -v, --verbose           print all information
 Report bugs using the \`glibcbug' script to <bugs@gnu.ai.mit.edu>."
     exit 0 ;;
   -d | --d | --da | --dat | --data | --data- | --data-r | --data-re | \
@@ -58,6 +61,12 @@ Report bugs using the \`glibcbug' script to <bugs@gnu.ai.mit.edu>."
     warn=yes
     bind_now=yes
     shift ;;
+  -v | --verb | --verbo | --verbos | --verbose)
+    verbose=yes
+    shift ;;
+  --v | --ve | --ver)
+    echo >&2 $"ldd: option \`" $1 $"' is ambiguous"
+    exit 1 ;;
   --)		# Stop option processing.
     shift; break ;;
   -*)
@@ -70,6 +79,7 @@ Report bugs using the \`glibcbug' script to <bugs@gnu.ai.mit.edu>."
 done
 
 add_env="LD_TRACE_LOADED_OBJECTS=1 LD_WARN=$warn LD_BIND_NOW=$bind_now"
+add_env="$add_env LD_VERBOSE=$verbose"
 case $# in
 0)
   echo >&2 'ldd:' $"missing file arguments"
diff --git a/elf/ldd.sh.in b/elf/ldd.sh.in
index d5dd54a536..908a26e269 100644
--- a/elf/ldd.sh.in
+++ b/elf/ldd.sh.in
@@ -30,11 +30,12 @@ bind_now=
 
 while test $# -gt 0; do
   case "$1" in
-  --v | --ve | --ver | --vers | --versi | --versio | --version)
+  --vers | --versi | --versio | --version)
     echo 'ldd (GNU libc) @VERSION@
 Copyright (C) 1996, 1997 Free Software Foundation, Inc.
 This is free software; see the source for copying conditions.  There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.'
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+Written by Roland McGrath and Ulrich Drepper.'
     exit 0 ;;
   --h | --he | --hel | --help)
     echo "ldd [OPTION]... FILE...
@@ -42,6 +43,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.'
       --version           print version information and exit
   -d, --data-relocs       process data relocations
   -r, --function-relocs   process data and function relocations
+  -v, --verbose           print all information
 Report bugs using the \`glibcbug' script to <bugs@gnu.ai.mit.edu>."
     exit 0 ;;
   -d | --d | --da | --dat | --data | --data- | --data-r | --data-re | \
@@ -54,6 +56,12 @@ Report bugs using the \`glibcbug' script to <bugs@gnu.ai.mit.edu>."
     warn=yes
     bind_now=yes
     shift ;;
+  -v | --verb | --verbo | --verbos | --verbose)
+    verbose=yes
+    shift ;;
+  --v | --ve | --ver)
+    echo >&2 "ldd: option \`$1' is ambiguous"
+    exit 1 ;;
   --)		# Stop option processing.
     shift; break ;;
   -*)
@@ -67,6 +75,7 @@ Try \`ldd --help' for more information."
 done
 
 add_env="LD_TRACE_LOADED_OBJECTS=1 LD_WARN=$warn LD_BIND_NOW=$bind_now"
+add_env="$add_env LD_VERBOSE=$verbose"
 case $# in
 0)
   echo >&2 "\
diff --git a/elf/libdl.map b/elf/libdl.map
index d950382346..4bd2145a47 100644
--- a/elf/libdl.map
+++ b/elf/libdl.map
@@ -4,4 +4,4 @@ GLIBC_2.0 {
 
   local:
     *;
-};
\ No newline at end of file
+};
diff --git a/elf/rtld.c b/elf/rtld.c
index ffa569e729..78ca490447 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -23,7 +23,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/mman.h>		/* Check if MAP_ANON is defined.  */
-#include "../stdio-common/_itoa.h"
+#include <stdio-common/_itoa.h>
 #include <assert.h>
 #include "dynamic-link.h"
 
@@ -188,6 +188,54 @@ version_check_doit (void *a)
     _exit (1);
 }
 
+
+static inline struct link_map *
+find_needed (const char *name)
+{
+  unsigned int n;
+
+  for (n = 0; n < _dl_loaded->l_nsearchlist; ++n)
+    if (_dl_name_match_p (name, _dl_loaded->l_searchlist[n]))
+      return _dl_loaded->l_searchlist[n];
+
+  /* Should never happen.  */
+  return NULL;
+}
+
+static int
+match_version (const char *string, struct link_map *map)
+{
+  const char *strtab = (const char *) (map->l_addr
+				       + map->l_info[DT_STRTAB]->d_un.d_ptr);
+  ElfW(Verdef) *def;
+
+#define VERDEFTAG (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (DT_VERDEF))
+  if (map->l_info[VERDEFTAG] == NULL)
+    /* The file has no symbol versioning.  */
+    return 0;
+
+  def = (ElfW(Verdef) *) ((char *) map->l_addr
+			  + map->l_info[VERDEFTAG]->d_un.d_ptr);
+  while (1)
+    {
+      ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
+
+      /* Compare the version strings.  */
+      if (strcmp (string, strtab + aux->vda_name) == 0)
+	/* Bingo!  */
+	return 1;
+
+      /* If no more definitions we failed to find what we want.  */
+      if (def->vd_next == 0)
+	break;
+
+      /* Next definition.  */
+      def = (ElfW(Verdef) *) ((char *) def + def->vd_next);
+    }
+
+  return 0;
+}
+
 unsigned int _dl_skip_args;	/* Nonzero if we were run directly.  */
 
 static void
@@ -576,27 +624,113 @@ of this helper program; chances are you did not intend to run this program.\n",
 	      *--bp = '0';
 	    _dl_sysdep_message (" in object at 0x", bp, "\n", NULL);
 	  }
-      else if (lazy >= 0)
+      else
 	{
-	  /* We have to do symbol dependency testing.  */
-	  struct relocate_args args;
-	  struct link_map *l;
+	  if (lazy >= 0)
+	    {
+	      /* We have to do symbol dependency testing.  */
+	      struct relocate_args args;
+	      struct link_map *l;
 
-	  args.lazy = lazy;
+	      args.lazy = lazy;
 
-	  l = _dl_loaded;
-	  while (l->l_next)
-	    l = l->l_next;
-	  do
+	      l = _dl_loaded;
+	      while (l->l_next)
+		l = l->l_next;
+	      do
+		{
+		  if (l != &_dl_rtld_map && l->l_opencount > 0)
+		    {
+		      args.l = l;
+		      _dl_receive_error (print_unresolved, relocate_doit,
+					 &args);
+		      *_dl_global_scope_end = NULL;
+		    }
+		  l = l->l_prev;
+		} while (l);
+	    }
+
+#define VERNEEDTAG (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (DT_VERNEED))
+	  if (*(getenv ("LD_VERBOSE") ?: "") != '\0')
 	    {
-	      if (l != &_dl_rtld_map && l->l_opencount > 0)
+	      /* Print more information.  This means here, print information
+		 about the versions needed.  */
+	      int first = 1;
+	      struct link_map *map = _dl_loaded;
+
+	      for (map = _dl_loaded; map != NULL; map = map->l_next)
 		{
-		  args.l = l;
-		  _dl_receive_error (print_unresolved, relocate_doit, &args);
-		  *_dl_global_scope_end = NULL;
+		  const char *strtab =
+		    (const char *) (map->l_addr
+				    + map->l_info[DT_STRTAB]->d_un.d_ptr);
+		  ElfW(Dyn) *dyn = map->l_info[VERNEEDTAG];
+
+		  if (dyn != NULL)
+		    {
+		      ElfW(Verneed) *ent =
+			(ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
+
+		      if (first)
+			{
+			  _dl_sysdep_message ("\n\tVersion information:\n",
+					      NULL);
+			  first = 0;
+			}
+
+		      _dl_sysdep_message ("\t", (map->l_name[0]
+						 ? map->l_name
+						 : _dl_argv[0]), ":\n",
+					  NULL);
+
+		      while (1)
+			{
+			  ElfW(Vernaux) *aux;
+			  struct link_map *needed;
+
+			  needed = find_needed (strtab + ent->vn_file);
+			  aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
+
+			  while (1)
+			    {
+			      const char *fname = NULL;
+
+			      _dl_sysdep_message ("\t\t",
+						  strtab + ent->vn_file,
+						  " (", strtab + aux->vna_name,
+						  ") ",
+						  (aux->vna_flags
+						   & VER_FLG_WEAK
+						   ? "[WEAK] " : ""),
+						  "=> ", NULL);
+
+			      if (needed != NULL
+				  && match_version (strtab + aux->vna_name,
+						    needed))
+				fname = needed->l_name;
+
+			      _dl_sysdep_message (fname ?: "not found", "\n",
+						  NULL);
+
+			      if (aux->vna_next == 0)
+				/* No more symbols.  */
+				break;
+
+			      /* Next symbol.  */
+			      aux = (ElfW(Vernaux) *) ((char *) aux
+						   + aux->vna_next);
+			    }
+
+			  if (ent->vn_next == 0)
+			    /* No more dependencies.  */
+			    break;
+
+			  /* Next dependency.  */
+			  ent = (ElfW(Verneed) *) ((char *) ent
+						   + ent->vn_next);
+			}
+		    }
 		}
-	      l = l->l_prev;
-	    } while (l);
+	    }
 	}
 
       _exit (0);