OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [newlib-1.18.0/] [newlib/] [libc/] [sys/] [linux/] [dl/] [dl-version.c] - Blame information for rev 301

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 207 jeremybenn
/* Handle symbol and library versioning.
2
   Copyright (C) 1997, 1998, 1999, 2000, 2001 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
 
28
#include <assert.h>
29
 
30
 
31
#ifndef VERSYMIDX
32
# define VERSYMIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
33
#endif
34
 
35
 
36
#define make_string(string, rest...) \
37
  ({                                                                          \
38
    const char *all[] = { string, ## rest };                                  \
39
    size_t len, cnt;                                                          \
40
    char *result, *cp;                                                        \
41
                                                                              \
42
    len = 1;                                                                  \
43
    for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)                  \
44
      len += strlen (all[cnt]);                                               \
45
                                                                              \
46
    cp = result = alloca (len);                                               \
47
    for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)                  \
48
    {                                                                         \
49
      cp = strcpy (cp, all[cnt]);                                             \
50
      cp += strlen (all[cnt]);                                                \
51
    }                                                                         \
52
                                                                              \
53
    result;                                                                   \
54
  })
55
 
56
 
57
static inline struct link_map *
58
find_needed (const char *name, struct link_map *map)
59
{
60
  struct link_map *tmap;
61
  unsigned int n;
62
 
63
  for (tmap = _dl_loaded; tmap != NULL; 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, 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 (_dl_debug_mask & DL_DEBUG_VERSIONS, 0))
92
    _dl_debug_printf ("\
93
checking for version `%s' in file %s required by file %s\n",
94
                      string, map->l_name[0] ? map->l_name : _dl_argv[0],
95
                      name);
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 of Verdef record");
126
          result = 1;
127
          goto call_cerror;
128
        }
129
 
130
      /* Compare the hash values.  */
131
      if (hash == def->vd_hash)
132
        {
133
          ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
134
 
135
          /* To be safe, compare the string as well.  */
136
          if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0)
137
              == 0)
138
            /* Bingo!  */
139
            return 0;
140
        }
141
 
142
      /* If no more definitions we failed to find what we want.  */
143
      if (def->vd_next == 0)
144
        break;
145
 
146
      /* Next definition.  */
147
      def = (ElfW(Verdef) *) ((char *) def + def->vd_next);
148
    }
149
 
150
  /* Symbol not found.  If it was a weak reference it is not fatal.  */
151
  if (__builtin_expect (weak, 1))
152
    {
153
      if (verbose)
154
        {
155
          /* XXX We cannot translate the message.  */
156
          errstring = make_string ("weak version `", string,
157
                                   "' not found (required by ", name, ")");
158
          goto call_cerror;
159
        }
160
      return 0;
161
    }
162
 
163
  /* XXX We cannot translate the message.  */
164
  errstring = make_string ("version `", string, "' not found (required by ",
165
                           name, ")");
166
  result = 1;
167
 call_cerror:
168
  _dl_signal_cerror (0, map->l_name[0] ? map->l_name : _dl_argv[0], NULL,
169
                     errstring);
170
  return result;
171
}
172
 
173
 
174
int
175
internal_function
176
_dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
177
{
178
  int result = 0;
179
  const char *strtab;
180
  /* Pointer to section with needed versions.  */
181
  ElfW(Dyn) *dyn;
182
  /* Pointer to dynamic section with definitions.  */
183
  ElfW(Dyn) *def;
184
  /* We need to find out which is the highest version index used
185
    in a dependecy.  */
186
  unsigned int ndx_high = 0;
187
  /* Initialize to make the compiler happy.  */
188
  const char *errstring = NULL;
189
  int errval = 0;
190
 
191
  /* If we don't have a string table, we must be ok.  */
192
  if (map->l_info[DT_STRTAB] == NULL)
193
    return 0;
194
  strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
195
 
196
  dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
197
  def = map->l_info[VERSYMIDX (DT_VERDEF)];
198
 
199
  if (dyn != NULL)
200
    {
201
      /* This file requires special versions from its dependencies.  */
202
      ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
203
 
204
      /* Currently the version number of the needed entry is 1.
205
         Make sure all we see is this version.  */
206
      if (__builtin_expect (ent->vn_version, 1) != 1)
207
        {
208
          char buf[20];
209
          buf[sizeof (buf) - 1] = '\0';
210
          /* XXX We cannot translate the message.  */
211
          errstring = make_string ("unsupported version of Verneed record\n");
212
        call_error:
213
          _dl_signal_error (errval, (*map->l_name ? map->l_name : _dl_argv[0]),
214
                            NULL, errstring);
215
        }
216
 
217
      while (1)
218
        {
219
          ElfW(Vernaux) *aux;
220
          struct link_map *needed = find_needed (strtab + ent->vn_file, map);
221
 
222
          /* If NEEDED is NULL this means a dependency was not found
223
             and no stub entry was created.  This should never happen.  */
224
          assert (needed != NULL);
225
 
226
          /* Make sure this is no stub we created because of a missing
227
             dependency.  */
228
          if (__builtin_expect (! trace_mode, 1)
229
              || ! __builtin_expect (needed->l_faked, 0))
230
            {
231
              /* NEEDED is the map for the file we need.  Now look for the
232
                 dependency symbols.  */
233
              aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
234
              while (1)
235
                {
236
                  /* Match the symbol.  */
237
                  result |= match_symbol ((*map->l_name
238
                                           ? map->l_name : _dl_argv[0]),
239
                                          aux->vna_hash,
240
                                          strtab + aux->vna_name,
241
                                          needed, verbose,
242
                                          aux->vna_flags & VER_FLG_WEAK);
243
 
244
                  /* Compare the version index.  */
245
                  if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
246
                    ndx_high = aux->vna_other & 0x7fff;
247
 
248
                  if (aux->vna_next == 0)
249
                    /* No more symbols.  */
250
                    break;
251
 
252
                  /* Next symbol.  */
253
                  aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
254
                }
255
            }
256
 
257
          if (ent->vn_next == 0)
258
            /* No more dependencies.  */
259
            break;
260
 
261
          /* Next dependency.  */
262
          ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
263
        }
264
    }
265
 
266
  /* We also must store the names of the defined versions.  Determine
267
     the maximum index here as well.
268
 
269
     XXX We could avoid the loop by just taking the number of definitions
270
     as an upper bound of new indeces.  */
271
  if (def != NULL)
272
    {
273
      ElfW(Verdef) *ent;
274
      ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
275
      while (1)
276
        {
277
          if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
278
            ndx_high = ent->vd_ndx & 0x7fff;
279
 
280
          if (ent->vd_next == 0)
281
            /* No more definitions.  */
282
            break;
283
 
284
          ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
285
        }
286
    }
287
 
288
  if (ndx_high > 0)
289
    {
290
      /* Now we are ready to build the array with the version names
291
         which can be indexed by the version index in the VERSYM
292
         section.  */
293
      map->l_versions = (struct r_found_version *)
294
        calloc (ndx_high + 1, sizeof (*map->l_versions));
295
      if (__builtin_expect (map->l_versions == NULL, 0))
296
        {
297
          errstring = N_("cannot allocate version reference table");
298
          errval = ENOMEM;
299
          goto call_error;
300
        }
301
 
302
      /* Store the number of available symbols.  */
303
      map->l_nversions = ndx_high + 1;
304
 
305
      /* Compute the pointer to the version symbols.  */
306
      map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
307
 
308
      if (dyn != NULL)
309
        {
310
          ElfW(Verneed) *ent;
311
          ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
312
          while (1)
313
            {
314
              ElfW(Vernaux) *aux;
315
              aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
316
              while (1)
317
                {
318
                  ElfW(Half) ndx = aux->vna_other & 0x7fff;
319
                  map->l_versions[ndx].hash = aux->vna_hash;
320
                  map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
321
                  map->l_versions[ndx].name = &strtab[aux->vna_name];
322
                  map->l_versions[ndx].filename = &strtab[ent->vn_file];
323
 
324
                  if (aux->vna_next == 0)
325
                    /* No more symbols.  */
326
                    break;
327
 
328
                  /* Advance to next symbol.  */
329
                  aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
330
                }
331
 
332
              if (ent->vn_next == 0)
333
                /* No more dependencies.  */
334
                break;
335
 
336
              /* Advance to next dependency.  */
337
              ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
338
            }
339
        }
340
 
341
      /* And insert the defined versions.  */
342
      if (def != NULL)
343
        {
344
          ElfW(Verdef) *ent;
345
          ent = (ElfW(Verdef)  *) (map->l_addr + def->d_un.d_ptr);
346
          while (1)
347
            {
348
              ElfW(Verdaux) *aux;
349
              aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux);
350
 
351
              if ((ent->vd_flags & VER_FLG_BASE) == 0)
352
                {
353
                  /* The name of the base version should not be
354
                     available for matching a versioned symbol.  */
355
                  ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
356
                  map->l_versions[ndx].hash = ent->vd_hash;
357
                  map->l_versions[ndx].name = &strtab[aux->vda_name];
358
                  map->l_versions[ndx].filename = NULL;
359
                }
360
 
361
              if (ent->vd_next == 0)
362
                /* No more definitions.  */
363
                break;
364
 
365
              ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
366
            }
367
        }
368
    }
369
 
370
  return result;
371
}
372
 
373
 
374
int
375
internal_function
376
_dl_check_all_versions (struct link_map *map, int verbose, int trace_mode)
377
{
378
  struct link_map *l;
379
  int result = 0;
380
 
381
  for (l = map; l != NULL; l = l->l_next)
382
    result |= ! l->l_faked && _dl_check_map_versions (l, verbose, trace_mode);
383
 
384
  return result;
385
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.