fgetws implementation.
[kopensolaris-gnu/glibc.git] / elf / dl-version.c
index d06fd5c..8d59fe2 100644 (file)
@@ -1,5 +1,5 @@
 /* Handle symbol and library versioning.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
 
 #include <elf.h>
 #include <errno.h>
-#include <link.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
-
+#include <elf/ldsodefs.h>
 #include <stdio-common/_itoa.h>
 
+#include <assert.h>
 
-/* Set in rtld.c at startup.  */
-extern char **_dl_argv;
 
-#define VERSTAG(tag)   (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
+#ifndef VERSYMIDX
+# define VERSYMIDX(tag)        (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
+#endif
 
 
 #define make_string(string, rest...) \
@@ -46,20 +45,27 @@ extern char **_dl_argv;
                                                                              \
     cp = result = alloca (len);                                                      \
     for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)               \
-      cp = stpcpy (cp, all[cnt]);                                            \
+      cp = __stpcpy (cp, all[cnt]);                                          \
                                                                              \
     result;                                                                  \
   })
 
 
 static inline struct link_map *
-find_needed (const char *name)
+find_needed (const char *name, struct link_map *map)
 {
+  struct link_map *tmap;
   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];
+  for (tmap = _dl_loaded; tmap != NULL; tmap = tmap->l_next)
+    if (_dl_name_match_p (name, tmap))
+      return tmap;
+
+  /* The required object is not in the global scope, look to see if it is
+     a dependency of the current object.  */
+  for (n = 0; n < map->l_searchlist.r_nlist; n++)
+    if (_dl_name_match_p (name, map->l_searchlist.r_list[n]))
+      return map->l_searchlist.r_list[n];
 
   /* Should never happen.  */
   return NULL;
@@ -67,27 +73,34 @@ find_needed (const char *name)
 
 
 static int
+internal_function
 match_symbol (const char *name, ElfW(Word) hash, const char *string,
              struct link_map *map, int verbose, int weak)
 {
-  const char *strtab = (const char *) (map->l_addr
-                                      + map->l_info[DT_STRTAB]->d_un.d_ptr);
+  const char *strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
   ElfW(Addr) def_offset;
   ElfW(Verdef) *def;
 
-  if (map->l_info[VERSTAG (DT_VERDEF)] == NULL)
+  /* Display information about what we are doing while debugging.  */
+  if (_dl_debug_versions)
+    _dl_debug_message (1, "checking for version `", string, "' in file ",
+                      map->l_name[0] ? map->l_name : _dl_argv[0],
+                      " required by file ", name, "\n", NULL);
+
+  if (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL)
     {
       /* The file has no symbol versioning.  I.e., the dependent
         object was linked against another version of this file.  We
         only print a message if verbose output is requested.  */
       if (verbose)
-       _dl_signal_error (0, map->l_name, make_string ("\
+       _dl_signal_cerror (0, map->l_name,
+                          make_string ("\
 no version information available (required by ",
-                                                      name, ")"));
+                                       name, ")"));
       return 0;
     }
 
-  def_offset = map->l_info[VERSTAG (DT_VERDEF)]->d_un.d_ptr;
+  def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
   assert (def_offset != 0);
 
   def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
@@ -131,34 +144,42 @@ no version information available (required by ",
   if (weak)
     {
       if (verbose)
-       _dl_signal_error (0, map->l_name,
-                         make_string ("weak version `", string,
-                                      "' not found (required by ", name,
-                                      ")"));
+       _dl_signal_cerror (0, map->l_name,
+                          make_string ("weak version `", string,
+                                       "' not found (required by ", name,
+                                       ")"));
       return 0;
     }
 
-  _dl_signal_error (0, map->l_name,
-                   make_string ("version `", string,
-                                "' not found (required by ", name, ")"));
+  _dl_signal_cerror (0, map->l_name,
+                    make_string ("version `", string,
+                                 "' not found (required by ", name, ")"));
   return 1;
 }
 
 
 int
+internal_function
 _dl_check_map_versions (struct link_map *map, int verbose)
 {
   int result = 0;
-  const char *strtab = (const char *) (map->l_addr
-                                      + map->l_info[DT_STRTAB]->d_un.d_ptr);
+  const char *strtab;
   /* Pointer to section with needed versions.  */
-  ElfW(Dyn) *dyn = map->l_info[VERSTAG (DT_VERNEED)];
+  ElfW(Dyn) *dyn;
   /* Pointer to dynamic section with definitions.  */
-  ElfW(Dyn) *def = map->l_info[VERSTAG (DT_VERDEF)];
+  ElfW(Dyn) *def;
   /* We need to find out which is the highest version index used
     in a dependecy.  */
   unsigned int ndx_high = 0;
 
+  /* If we don't have a string table, we must be ok.  */
+  if (map->l_info[DT_STRTAB] == NULL)
+    return 0;
+  strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
+
+  dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
+  def = map->l_info[VERSYMIDX (DT_VERDEF)];
+
   if (dyn != NULL)
     {
       /* This file requires special versions from its dependencies.  */
@@ -182,7 +203,7 @@ _dl_check_map_versions (struct link_map *map, int verbose)
       while (1)
        {
          ElfW(Vernaux) *aux;
-         struct link_map *needed = find_needed (strtab + ent->vn_file);
+         struct link_map *needed = find_needed (strtab + ent->vn_file, map);
 
          /* If NEEDED is NULL this means a dependency was not found
             and no stub entry was created.  This should never happen.  */
@@ -262,6 +283,10 @@ _dl_check_map_versions (struct link_map *map, int verbose)
          /* Store the number of available symbols.  */
          map->l_nversions = ndx_high + 1;
 
+         /* Compute the pointer to the version symbols.  */
+         map->l_versyms =
+           (void *) map->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
+
          if (dyn != NULL)
            {
              ElfW(Verneed) *ent;
@@ -330,6 +355,7 @@ _dl_check_map_versions (struct link_map *map, int verbose)
 
 
 int
+internal_function
 _dl_check_all_versions (struct link_map *map, int verbose)
 {
   struct link_map *l;