(linenum→info "unix/slp.c:2238")

glibc/2.7/elf/dl-version.c

    1: /* Handle symbol and library versioning.
    2:    Copyright (C) 1997-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4:    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
    5: 
    6:    The GNU C Library is free software; you can redistribute it and/or
    7:    modify it under the terms of the GNU Lesser General Public
    8:    License as published by the Free Software Foundation; either
    9:    version 2.1 of the License, or (at your option) any later version.
   10: 
   11:    The GNU C Library is distributed in the hope that it will be useful,
   12:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14:    Lesser General Public License for more details.
   15: 
   16:    You should have received a copy of the GNU Lesser General Public
   17:    License along with the GNU C Library; if not, write to the Free
   18:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   19:    02111-1307 USA.  */
   20: 
   21: #include <elf.h>
   22: #include <errno.h>
   23: #include <libintl.h>
   24: #include <stdlib.h>
   25: #include <string.h>
   26: #include <ldsodefs.h>
   27: #include <stdio-common/_itoa.h>
   28: 
   29: #include <assert.h>
   30: 
   31: 
   32: #ifndef VERSYMIDX
   33: # define VERSYMIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
   34: #endif
   35: 
   36: 
   37: #define make_string(string, rest...) \
   38:   ({                                                                          \
   39:     const char *all[] = { string, ## rest };                                  \
   40:     size_t len, cnt;                                                          \
   41:     char *result, *cp;                                                        \
   42:                                                                               \
   43:     len = 1;                                                                  \
   44:     for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)                \
   45:       len += strlen (all[cnt]);                                               \
   46:                                                                               \
   47:     cp = result = alloca (len);                                               \
   48:     for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)                \
   49:       cp = __stpcpy (cp, all[cnt]);                                           \
   50:                                                                               \
   51:     result;                                                                   \
   52:   })
   53: 
   54: 
   55: static inline struct link_map *
   56: __attribute ((always_inline))
   57: find_needed (const char *name, struct link_map *map)
   58: {
   59:   struct link_map *tmap;
   60:   unsigned int n;
   61: 
   62:   for (tmap = GL(dl_ns)[map->l_ns]._ns_loaded; tmap != NULL;
   63:        tmap = tmap->l_next)
   64:     if (_dl_name_match_p (name, tmap))
   65:       return tmap;
   66: 
   67:   /* The required object is not in the global scope, look to see if it is
   68:      a dependency of the current object.  */
   69:   for (n = 0; n < map->l_searchlist.r_nlist; n++)
   70:     if (_dl_name_match_p (name, map->l_searchlist.r_list[n]))
   71:       return map->l_searchlist.r_list[n];
   72: 
   73:   /* Should never happen.  */
   74:   return NULL;
   75: }
   76: 
   77: 
   78: static int
   79: internal_function
   80: match_symbol (const char *name, Lmid_t ns, ElfW(Word) hash, const char *string,
   81:               struct link_map *map, int verbose, int weak)
   82: {
   83:   const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
   84:   ElfW(Addr) def_offset;
   85:   ElfW(Verdef) *def;
   86:   /* Initialize to make the compiler happy.  */
   87:   const char *errstring = NULL;
   88:   int result = 0;
   89: 
   90:   /* Display information about what we are doing while debugging.  */
   91:   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS, 0))
   92:     _dl_debug_printf ("\
   93: checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
   94:                       string, map->l_name[0] ? map->l_name : rtld_progname,
   95:                       map->l_ns, name, ns);
   96: 
   97:   if (__builtin_expect (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL, 0))
   98:     {
   99:       /* The file has no symbol versioning.  I.e., the dependent
  100:          object was linked against another version of this file.  We
  101:          only print a message if verbose output is requested.  */
  102:       if (verbose)
  103:         {
  104:           /* XXX We cannot translate the messages.  */
  105:           errstring = make_string ("\
  106: no version information available (required by ", name, ")");
  107:           goto call_cerror;
  108:         }
  109:       return 0;
  110:     }
  111: 
  112:   def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
  113:   assert (def_offset != 0);
  114: 
  115:   def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
  116:   while (1)
  117:     {
  118:       /* Currently the version number of the definition entry is 1.
  119:          Make sure all we see is this version.  */
  120:       if (__builtin_expect (def->vd_version, 1) != 1)
  121:         {
  122:           char buf[20];
  123:           buf[sizeof (buf) - 1] = '\0';
  124:           /* XXX We cannot translate the message.  */
  125:           errstring = make_string ("unsupported version ",
  126:                                    _itoa (def->vd_version,
  127:                                           &buf[sizeof (buf) - 1], 10, 0),
  128:                                    " of Verdef record");
  129:           result = 1;
  130:           goto call_cerror;
  131:         }
  132: 
  133:       /* Compare the hash values.  */
  134:       if (hash == def->vd_hash)
  135:         {
  136:           ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
  137: 
  138:           /* To be safe, compare the string as well.  */
  139:           if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0)
  140:               == 0)
  141:             /* Bingo!  */
  142:             return 0;
  143:         }
  144: 
  145:       /* If no more definitions we failed to find what we want.  */
  146:       if (def->vd_next == 0)
  147:         break;
  148: 
  149:       /* Next definition.  */
  150:       def = (ElfW(Verdef) *) ((char *) def + def->vd_next);
  151:     }
  152: 
  153:   /* Symbol not found.  If it was a weak reference it is not fatal.  */
  154:   if (__builtin_expect (weak, 1))
  155:     {
  156:       if (verbose)
  157:         {
  158:           /* XXX We cannot translate the message.  */
  159:           errstring = make_string ("weak version `", string,
  160:                                    "' not found (required by ", name, ")");
  161:           goto call_cerror;
  162:         }
  163:       return 0;
  164:     }
  165: 
  166:   /* XXX We cannot translate the message.  */
  167:   errstring = make_string ("version `", string, "' not found (required by ",
  168:                            name, ")");
  169:   result = 1;
  170:  call_cerror:
  171:   _dl_signal_cerror (0, map->l_name[0] ? map->l_name : rtld_progname,
  172:                      NULL, errstring);
  173:   return result;
  174: }
  175: 
  176: 
  177: int
  178: internal_function
  179: _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
  180: {
  181:   int result = 0;
  182:   const char *strtab;
  183:   /* Pointer to section with needed versions.  */
  184:   ElfW(Dyn) *dyn;
  185:   /* Pointer to dynamic section with definitions.  */
  186:   ElfW(Dyn) *def;
  187:   /* We need to find out which is the highest version index used
  188:     in a dependecy.  */
  189:   unsigned int ndx_high = 0;
  190:   /* Initialize to make the compiler happy.  */
  191:   const char *errstring = NULL;
  192:   int errval = 0;
  193: 
  194:   /* If we don't have a string table, we must be ok.  */
  195:   if (map->l_info[DT_STRTAB] == NULL)
  196:     return 0;
  197:   strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
  198: 
  199:   dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
  200:   def = map->l_info[VERSYMIDX (DT_VERDEF)];
  201: 
  202:   if (dyn != NULL)
  203:     {
  204:       /* This file requires special versions from its dependencies.  */
  205:       ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
  206: 
  207:       /* Currently the version number of the needed entry is 1.
  208:          Make sure all we see is this version.  */
  209:       if (__builtin_expect (ent->vn_version, 1) != 1)
  210:         {
  211:           char buf[20];
  212:           buf[sizeof (buf) - 1] = '\0';
  213:           /* XXX We cannot translate the message.  */
  214:           errstring = make_string ("unsupported version ",
  215:                                    _itoa (ent->vn_version,
  216:                                           &buf[sizeof (buf) - 1], 10, 0),
  217:                                    " of Verneed record\n");
  218:         call_error:
  219:           _dl_signal_error (errval, *map->l_name ? map->l_name : rtld_progname,
  220:                             NULL, errstring);
  221:         }
  222: 
  223:       while (1)
  224:         {
  225:           ElfW(Vernaux) *aux;
  226:           struct link_map *needed = find_needed (strtab + ent->vn_file, map);
  227: 
  228:           /* If NEEDED is NULL this means a dependency was not found
  229:              and no stub entry was created.  This should never happen.  */
  230:           assert (needed != NULL);
  231: 
  232:           /* Make sure this is no stub we created because of a missing
  233:              dependency.  */
  234:           if (__builtin_expect (! trace_mode, 1)
  235:               || ! __builtin_expect (needed->l_faked, 0))
  236:             {
  237:               /* NEEDED is the map for the file we need.  Now look for the
  238:                  dependency symbols.  */
  239:               aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
  240:               while (1)
  241:                 {
  242:                   /* Match the symbol.  */
  243:                   result |= match_symbol ((*map->l_name
  244:                                            ? map->l_name : rtld_progname),
  245:                                           map->l_ns, aux->vna_hash,
  246:                                           strtab + aux->vna_name,
  247:                                           needed->l_real, verbose,
  248:                                           aux->vna_flags & VER_FLG_WEAK);
  249: 
  250:                   /* Compare the version index.  */
  251:                   if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
  252:                     ndx_high = aux->vna_other & 0x7fff;
  253: 
  254:                   if (aux->vna_next == 0)
  255:                     /* No more symbols.  */
  256:                     break;
  257: 
  258:                   /* Next symbol.  */
  259:                   aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
  260:                 }
  261:             }
  262: 
  263:           if (ent->vn_next == 0)
  264:             /* No more dependencies.  */
  265:             break;
  266: 
  267:           /* Next dependency.  */
  268:           ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
  269:         }
  270:     }
  271: 
  272:   /* We also must store the names of the defined versions.  Determine
  273:      the maximum index here as well.
  274: 
  275:      XXX We could avoid the loop by just taking the number of definitions
  276:      as an upper bound of new indeces.  */
  277:   if (def != NULL)
  278:     {
  279:       ElfW(Verdef) *ent;
  280:       ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
  281:       while (1)
  282:         {
  283:           if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
  284:             ndx_high = ent->vd_ndx & 0x7fff;
  285: 
  286:           if (ent->vd_next == 0)
  287:             /* No more definitions.  */
  288:             break;
  289: 
  290:           ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
  291:         }
  292:     }
  293: 
  294:   if (ndx_high > 0)
  295:     {
  296:       /* Now we are ready to build the array with the version names
  297:          which can be indexed by the version index in the VERSYM
  298:          section.  */
  299:       map->l_versions = (struct r_found_version *)
  300:         calloc (ndx_high + 1, sizeof (*map->l_versions));
  301:       if (__builtin_expect (map->l_versions == NULL, 0))
  302:         {
  303:           errstring = N_("cannot allocate version reference table");
  304:           errval = ENOMEM;
  305:           goto call_error;
  306:         }
  307: 
  308:       /* Store the number of available symbols.  */
  309:       map->l_nversions = ndx_high + 1;
  310: 
  311:       /* Compute the pointer to the version symbols.  */
  312:       map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
  313: 
  314:       if (dyn != NULL)
  315:         {
  316:           ElfW(Verneed) *ent;
  317:           ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
  318:           while (1)
  319:             {
  320:               ElfW(Vernaux) *aux;
  321:               aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
  322:               while (1)
  323:                 {
  324:                   ElfW(Half) ndx = aux->vna_other & 0x7fff;
  325:                   map->l_versions[ndx].hash = aux->vna_hash;
  326:                   map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
  327:                   map->l_versions[ndx].name = &strtab[aux->vna_name];
  328:                   map->l_versions[ndx].filename = &strtab[ent->vn_file];
  329: 
  330:                   if (aux->vna_next == 0)
  331:                     /* No more symbols.  */
  332:                     break;
  333: 
  334:                   /* Advance to next symbol.  */
  335:                   aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
  336:                 }
  337: 
  338:               if (ent->vn_next == 0)
  339:                 /* No more dependencies.  */
  340:                 break;
  341: 
  342:               /* Advance to next dependency.  */
  343:               ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
  344:             }
  345:         }
  346: 
  347:       /* And insert the defined versions.  */
  348:       if (def != NULL)
  349:         {
  350:           ElfW(Verdef) *ent;
  351:           ent = (ElfW(Verdef)  *) (map->l_addr + def->d_un.d_ptr);
  352:           while (1)
  353:             {
  354:               ElfW(Verdaux) *aux;
  355:               aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux);
  356: 
  357:               if ((ent->vd_flags & VER_FLG_BASE) == 0)
  358:                 {
  359:                   /* The name of the base version should not be
  360:                      available for matching a versioned symbol.  */
  361:                   ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
  362:                   map->l_versions[ndx].hash = ent->vd_hash;
  363:                   map->l_versions[ndx].name = &strtab[aux->vda_name];
  364:                   map->l_versions[ndx].filename = NULL;
  365:                 }
  366: 
  367:               if (ent->vd_next == 0)
  368:                 /* No more definitions.  */
  369:                 break;
  370: 
  371:               ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
  372:             }
  373:         }
  374:     }
  375: 
  376:   return result;
  377: }
  378: 
  379: 
  380: int
  381: internal_function
  382: _dl_check_all_versions (struct link_map *map, int verbose, int trace_mode)
  383: {
  384:   struct link_map *l;
  385:   int result = 0;
  386: 
  387:   for (l = map; l != NULL; l = l->l_next)
  388:     result |= (! l->l_faked
  389:                && _dl_check_map_versions (l, verbose, trace_mode));
  390: 
  391:   return result;
  392: }
Syntax (Markdown)