Back to index

glibc  2.9
dl-version.c
Go to the documentation of this file.
00001 /* Handle symbol and library versioning.
00002    Copyright (C) 1997-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <elf.h>
00022 #include <errno.h>
00023 #include <libintl.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <ldsodefs.h>
00027 #include <stdio-common/_itoa.h>
00028 
00029 #include <assert.h>
00030 
00031 
00032 #ifndef VERSYMIDX
00033 # define VERSYMIDX(tag)     (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
00034 #endif
00035 
00036 
00037 #define make_string(string, rest...) \
00038   ({                                                                 \
00039     const char *all[] = { string, ## rest };                                \
00040     size_t len, cnt;                                                 \
00041     char *result, *cp;                                                      \
00042                                                                      \
00043     len = 1;                                                         \
00044     for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)              \
00045       len += strlen (all[cnt]);                                             \
00046                                                                      \
00047     cp = result = alloca (len);                                             \
00048     for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)              \
00049       cp = __stpcpy (cp, all[cnt]);                                         \
00050                                                                      \
00051     result;                                                          \
00052   })
00053 
00054 
00055 static inline struct link_map *
00056 __attribute ((always_inline))
00057 find_needed (const char *name, struct link_map *map)
00058 {
00059   struct link_map *tmap;
00060   unsigned int n;
00061 
00062   for (tmap = GL(dl_ns)[map->l_ns]._ns_loaded; tmap != NULL;
00063        tmap = tmap->l_next)
00064     if (_dl_name_match_p (name, tmap))
00065       return tmap;
00066 
00067   /* The required object is not in the global scope, look to see if it is
00068      a dependency of the current object.  */
00069   for (n = 0; n < map->l_searchlist.r_nlist; n++)
00070     if (_dl_name_match_p (name, map->l_searchlist.r_list[n]))
00071       return map->l_searchlist.r_list[n];
00072 
00073   /* Should never happen.  */
00074   return NULL;
00075 }
00076 
00077 
00078 static int
00079 internal_function
00080 match_symbol (const char *name, Lmid_t ns, ElfW(Word) hash, const char *string,
00081              struct link_map *map, int verbose, int weak)
00082 {
00083   const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00084   ElfW(Addr) def_offset;
00085   ElfW(Verdef) *def;
00086   /* Initialize to make the compiler happy.  */
00087   const char *errstring = NULL;
00088   int result = 0;
00089 
00090   /* Display information about what we are doing while debugging.  */
00091   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS, 0))
00092     _dl_debug_printf ("\
00093 checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
00094                     string, map->l_name[0] ? map->l_name : rtld_progname,
00095                     map->l_ns, name, ns);
00096 
00097   if (__builtin_expect (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL, 0))
00098     {
00099       /* The file has no symbol versioning.  I.e., the dependent
00100         object was linked against another version of this file.  We
00101         only print a message if verbose output is requested.  */
00102       if (verbose)
00103        {
00104          /* XXX We cannot translate the messages.  */
00105          errstring = make_string ("\
00106 no version information available (required by ", name, ")");
00107          goto call_cerror;
00108        }
00109       return 0;
00110     }
00111 
00112   def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
00113   assert (def_offset != 0);
00114 
00115   def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
00116   while (1)
00117     {
00118       /* Currently the version number of the definition entry is 1.
00119         Make sure all we see is this version.  */
00120       if (__builtin_expect (def->vd_version, 1) != 1)
00121        {
00122          char buf[20];
00123          buf[sizeof (buf) - 1] = '\0';
00124          /* XXX We cannot translate the message.  */
00125          errstring = make_string ("unsupported version ",
00126                                _itoa (def->vd_version,
00127                                      &buf[sizeof (buf) - 1], 10, 0),
00128                                " of Verdef record");
00129          result = 1;
00130          goto call_cerror;
00131        }
00132 
00133       /* Compare the hash values.  */
00134       if (hash == def->vd_hash)
00135        {
00136          ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
00137 
00138          /* To be safe, compare the string as well.  */
00139          if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0)
00140              == 0)
00141            /* Bingo!  */
00142            return 0;
00143        }
00144 
00145       /* If no more definitions we failed to find what we want.  */
00146       if (def->vd_next == 0)
00147        break;
00148 
00149       /* Next definition.  */
00150       def = (ElfW(Verdef) *) ((char *) def + def->vd_next);
00151     }
00152 
00153   /* Symbol not found.  If it was a weak reference it is not fatal.  */
00154   if (__builtin_expect (weak, 1))
00155     {
00156       if (verbose)
00157        {
00158          /* XXX We cannot translate the message.  */
00159          errstring = make_string ("weak version `", string,
00160                                "' not found (required by ", name, ")");
00161          goto call_cerror;
00162        }
00163       return 0;
00164     }
00165 
00166   /* XXX We cannot translate the message.  */
00167   errstring = make_string ("version `", string, "' not found (required by ",
00168                         name, ")");
00169   result = 1;
00170  call_cerror:
00171   _dl_signal_cerror (0, map->l_name[0] ? map->l_name : rtld_progname,
00172                    NULL, errstring);
00173   return result;
00174 }
00175 
00176 
00177 int
00178 internal_function
00179 _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
00180 {
00181   int result = 0;
00182   const char *strtab;
00183   /* Pointer to section with needed versions.  */
00184   ElfW(Dyn) *dyn;
00185   /* Pointer to dynamic section with definitions.  */
00186   ElfW(Dyn) *def;
00187   /* We need to find out which is the highest version index used
00188     in a dependecy.  */
00189   unsigned int ndx_high = 0;
00190   /* Initialize to make the compiler happy.  */
00191   const char *errstring = NULL;
00192   int errval = 0;
00193 
00194   /* If we don't have a string table, we must be ok.  */
00195   if (map->l_info[DT_STRTAB] == NULL)
00196     return 0;
00197   strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00198 
00199   dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
00200   def = map->l_info[VERSYMIDX (DT_VERDEF)];
00201 
00202   if (dyn != NULL)
00203     {
00204       /* This file requires special versions from its dependencies.  */
00205       ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
00206 
00207       /* Currently the version number of the needed entry is 1.
00208         Make sure all we see is this version.  */
00209       if (__builtin_expect (ent->vn_version, 1) != 1)
00210        {
00211          char buf[20];
00212          buf[sizeof (buf) - 1] = '\0';
00213          /* XXX We cannot translate the message.  */
00214          errstring = make_string ("unsupported version ",
00215                                _itoa (ent->vn_version,
00216                                      &buf[sizeof (buf) - 1], 10, 0),
00217                                " of Verneed record\n");
00218        call_error:
00219          _dl_signal_error (errval, *map->l_name ? map->l_name : rtld_progname,
00220                          NULL, errstring);
00221        }
00222 
00223       while (1)
00224        {
00225          ElfW(Vernaux) *aux;
00226          struct link_map *needed = find_needed (strtab + ent->vn_file, map);
00227 
00228          /* If NEEDED is NULL this means a dependency was not found
00229             and no stub entry was created.  This should never happen.  */
00230          assert (needed != NULL);
00231 
00232          /* Make sure this is no stub we created because of a missing
00233             dependency.  */
00234          if (__builtin_expect (! trace_mode, 1)
00235              || ! __builtin_expect (needed->l_faked, 0))
00236            {
00237              /* NEEDED is the map for the file we need.  Now look for the
00238                dependency symbols.  */
00239              aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
00240              while (1)
00241               {
00242                 /* Match the symbol.  */
00243                 result |= match_symbol ((*map->l_name
00244                                       ? map->l_name : rtld_progname),
00245                                      map->l_ns, aux->vna_hash,
00246                                      strtab + aux->vna_name,
00247                                      needed->l_real, verbose,
00248                                      aux->vna_flags & VER_FLG_WEAK);
00249 
00250                 /* Compare the version index.  */
00251                 if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
00252                   ndx_high = aux->vna_other & 0x7fff;
00253 
00254                 if (aux->vna_next == 0)
00255                   /* No more symbols.  */
00256                   break;
00257 
00258                 /* Next symbol.  */
00259                 aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
00260               }
00261            }
00262 
00263          if (ent->vn_next == 0)
00264            /* No more dependencies.  */
00265            break;
00266 
00267          /* Next dependency.  */
00268          ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
00269        }
00270     }
00271 
00272   /* We also must store the names of the defined versions.  Determine
00273      the maximum index here as well.
00274 
00275      XXX We could avoid the loop by just taking the number of definitions
00276      as an upper bound of new indeces.  */
00277   if (def != NULL)
00278     {
00279       ElfW(Verdef) *ent;
00280       ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
00281       while (1)
00282        {
00283          if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
00284            ndx_high = ent->vd_ndx & 0x7fff;
00285 
00286          if (ent->vd_next == 0)
00287            /* No more definitions.  */
00288            break;
00289 
00290          ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
00291        }
00292     }
00293 
00294   if (ndx_high > 0)
00295     {
00296       /* Now we are ready to build the array with the version names
00297         which can be indexed by the version index in the VERSYM
00298         section.  */
00299       map->l_versions = (struct r_found_version *)
00300        calloc (ndx_high + 1, sizeof (*map->l_versions));
00301       if (__builtin_expect (map->l_versions == NULL, 0))
00302        {
00303          errstring = N_("cannot allocate version reference table");
00304          errval = ENOMEM;
00305          goto call_error;
00306        }
00307 
00308       /* Store the number of available symbols.  */
00309       map->l_nversions = ndx_high + 1;
00310 
00311       /* Compute the pointer to the version symbols.  */
00312       map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
00313 
00314       if (dyn != NULL)
00315        {
00316          ElfW(Verneed) *ent;
00317          ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
00318          while (1)
00319            {
00320              ElfW(Vernaux) *aux;
00321              aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
00322              while (1)
00323               {
00324                 ElfW(Half) ndx = aux->vna_other & 0x7fff;
00325                 map->l_versions[ndx].hash = aux->vna_hash;
00326                 map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
00327                 map->l_versions[ndx].name = &strtab[aux->vna_name];
00328                 map->l_versions[ndx].filename = &strtab[ent->vn_file];
00329 
00330                 if (aux->vna_next == 0)
00331                   /* No more symbols.  */
00332                   break;
00333 
00334                 /* Advance to next symbol.  */
00335                 aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
00336               }
00337 
00338              if (ent->vn_next == 0)
00339               /* No more dependencies.  */
00340               break;
00341 
00342              /* Advance to next dependency.  */
00343              ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
00344            }
00345        }
00346 
00347       /* And insert the defined versions.  */
00348       if (def != NULL)
00349        {
00350          ElfW(Verdef) *ent;
00351          ent = (ElfW(Verdef)  *) (map->l_addr + def->d_un.d_ptr);
00352          while (1)
00353            {
00354              ElfW(Verdaux) *aux;
00355              aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux);
00356 
00357              if ((ent->vd_flags & VER_FLG_BASE) == 0)
00358               {
00359                 /* The name of the base version should not be
00360                    available for matching a versioned symbol.  */
00361                 ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
00362                 map->l_versions[ndx].hash = ent->vd_hash;
00363                 map->l_versions[ndx].name = &strtab[aux->vda_name];
00364                 map->l_versions[ndx].filename = NULL;
00365               }
00366 
00367              if (ent->vd_next == 0)
00368               /* No more definitions.  */
00369               break;
00370 
00371              ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
00372            }
00373        }
00374     }
00375 
00376   return result;
00377 }
00378 
00379 
00380 int
00381 internal_function
00382 _dl_check_all_versions (struct link_map *map, int verbose, int trace_mode)
00383 {
00384   struct link_map *l;
00385   int result = 0;
00386 
00387   for (l = map; l != NULL; l = l->l_next)
00388     result |= (! l->l_faked
00389               && _dl_check_map_versions (l, verbose, trace_mode));
00390 
00391   return result;
00392 }