fdwalk should return 0 on an empty directory
[kopensolaris-gnu/glibc.git] / 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 }