(find_needed): Look for needed objects also in the dependency list of
[kopensolaris-gnu/glibc.git] / elf / dl-version.c
1 /* Handle symbol and library versioning.
2    Copyright (C) 1997 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 Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    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    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include <elf.h>
22 #include <errno.h>
23 #include <link.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include <stdio-common/_itoa.h>
29
30
31 /* Set in rtld.c at startup.  */
32 extern char **_dl_argv;
33
34 #define VERSTAG(tag)    (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
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 find_needed (const char *name, struct link_map *map)
57 {
58   unsigned int n;
59
60   for (n = 0; n < _dl_loaded->l_nsearchlist; ++n)
61     if (_dl_name_match_p (name, _dl_loaded->l_searchlist[n]))
62       return _dl_loaded->l_searchlist[n];
63
64   /* The required object is not in the global scope, look to see if it is
65      a dependency of the current object.  */
66   for (n = 0; n < map->l_nsearchlist; n++)
67     if (_dl_name_match_p (name, map->l_searchlist[n]))
68       return map->l_searchlist[n];
69
70   /* Should never happen.  */
71   return NULL;
72 }
73
74
75 static int
76 match_symbol (const char *name, ElfW(Word) hash, const char *string,
77               struct link_map *map, int verbose, int weak)
78 {
79   const char *strtab = (const char *) (map->l_addr
80                                        + map->l_info[DT_STRTAB]->d_un.d_ptr);
81   ElfW(Addr) def_offset;
82   ElfW(Verdef) *def;
83
84   if (map->l_info[VERSTAG (DT_VERDEF)] == NULL)
85     {
86       /* The file has no symbol versioning.  I.e., the dependent
87          object was linked against another version of this file.  We
88          only print a message if verbose output is requested.  */
89       if (verbose)
90         _dl_signal_error (0, map->l_name, make_string ("\
91 no version information available (required by ",
92                                                        name, ")"));
93       return 0;
94     }
95
96   def_offset = map->l_info[VERSTAG (DT_VERDEF)]->d_un.d_ptr;
97   assert (def_offset != 0);
98
99   def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
100   while (1)
101     {
102       /* Currently the version number of the definition entry is 1.
103          Make sure all we see is this version.  */
104       if (def->vd_version  != 1)
105         {
106           char buf[20];
107           buf[sizeof (buf) - 1] = '\0';
108           _dl_signal_error (0, map->l_name,
109                             make_string ("unsupported version ",
110                                          _itoa_word (def->vd_version,
111                                                      &buf[sizeof (buf) - 1],
112                                                      10, 0),
113                                          " of Verdef record"));
114           return 1;
115         }
116
117       /* Compare the hash values.  */
118       if (hash == def->vd_hash)
119         {
120           ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
121
122           /* To be safe, compare the string as well.  */
123           if (strcmp (string, strtab + aux->vda_name) == 0)
124             /* Bingo!  */
125             return 0;
126         }
127
128       /* If no more definitions we failed to find what we want.  */
129       if (def->vd_next == 0)
130         break;
131
132       /* Next definition.  */
133       def = (ElfW(Verdef) *) ((char *) def + def->vd_next);
134     }
135
136   /* Symbol not found.  If it was a weak reference it is not fatal.  */
137   if (weak)
138     {
139       if (verbose)
140         _dl_signal_error (0, map->l_name,
141                           make_string ("weak version `", string,
142                                        "' not found (required by ", name,
143                                        ")"));
144       return 0;
145     }
146
147   _dl_signal_error (0, map->l_name,
148                     make_string ("version `", string,
149                                  "' not found (required by ", name, ")"));
150   return 1;
151 }
152
153
154 int
155 _dl_check_map_versions (struct link_map *map, int verbose)
156 {
157   int result = 0;
158   const char *strtab = (const char *) (map->l_addr
159                                        + map->l_info[DT_STRTAB]->d_un.d_ptr);
160   /* Pointer to section with needed versions.  */
161   ElfW(Dyn) *dyn = map->l_info[VERSTAG (DT_VERNEED)];
162   /* Pointer to dynamic section with definitions.  */
163   ElfW(Dyn) *def = map->l_info[VERSTAG (DT_VERDEF)];
164   /* We need to find out which is the highest version index used
165     in a dependecy.  */
166   unsigned int ndx_high = 0;
167
168   if (dyn != NULL)
169     {
170       /* This file requires special versions from its dependencies.  */
171       ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
172
173       /* Currently the version number of the needed entry is 1.
174          Make sure all we see is this version.  */
175       if (ent->vn_version  != 1)
176         {
177           char buf[20];
178           buf[sizeof (buf) - 1] = '\0';
179           _dl_signal_error (0, (*map->l_name ? map->l_name : _dl_argv[0]),
180                             make_string ("unsupported version ",
181                                          _itoa_word (ent->vn_version,
182                                                      &buf[sizeof (buf) - 1],
183                                                      10, 0),
184                                          " of Verneed record\n"));
185           return 1;
186         }
187
188       while (1)
189         {
190           ElfW(Vernaux) *aux;
191           struct link_map *needed = find_needed (strtab + ent->vn_file, map);
192
193           /* If NEEDED is NULL this means a dependency was not found
194              and no stub entry was created.  This should never happen.  */
195           assert (needed != NULL);
196
197           /* NEEDED is the map for the file we need.  Now look for the
198              dependency symbols.  */
199           aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
200           while (1)
201             {
202               /* Match the symbol.  */
203               result |= match_symbol ((*map->l_name
204                                        ? map->l_name : _dl_argv[0]),
205                                       aux->vna_hash,
206                                       strtab + aux->vna_name,
207                                       needed, verbose,
208                                       aux->vna_flags & VER_FLG_WEAK);
209
210               /* Compare the version index.  */
211               if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
212                 ndx_high = aux->vna_other & 0x7fff;
213
214               if (aux->vna_next == 0)
215                 /* No more symbols.  */
216                 break;
217
218               /* Next symbol.  */
219               aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
220             }
221
222           if (ent->vn_next == 0)
223             /* No more dependencies.  */
224             break;
225
226           /* Next dependency.  */
227           ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
228         }
229     }
230
231   /* We also must store the names of the defined versions.  Determine
232      the maximum index here as well.
233
234      XXX We could avoid the loop by just taking the number of definitions
235      as an upper bound of new indeces.  */
236   if (def != NULL)
237     {
238       ElfW(Verdef) *ent;
239       ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
240       while (1)
241         {
242           if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
243             ndx_high = ent->vd_ndx & 0x7fff;
244
245           if (ent->vd_next == 0)
246             /* No more definitions.  */
247             break;
248
249           ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
250         }
251     }
252
253   if (ndx_high > 0)
254     {
255       /* Now we are ready to build the array with the version names
256          which can be indexed by the version index in the VERSYM
257          section.  */
258       map->l_versions = (struct r_found_version *)
259         calloc (ndx_high + 1, sizeof (*map->l_versions));
260       if (map->l_versions == NULL)
261         {
262           _dl_signal_error (ENOMEM, (*map->l_name ? map->l_name : _dl_argv[0]),
263                             "cannot allocate version reference table");
264           result = 1;
265         }
266       else
267         {
268           /* Store the number of available symbols.  */
269           map->l_nversions = ndx_high + 1;
270
271           if (dyn != NULL)
272             {
273               ElfW(Verneed) *ent;
274               ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
275               while (1)
276                 {
277                   ElfW(Vernaux) *aux;
278                   aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
279                   while (1)
280                     {
281                       ElfW(Half) ndx = aux->vna_other & 0x7fff;
282                       map->l_versions[ndx].hash = aux->vna_hash;
283                       map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
284                       map->l_versions[ndx].name = &strtab[aux->vna_name];
285                       map->l_versions[ndx].filename = &strtab[ent->vn_file];
286
287                       if (aux->vna_next == 0)
288                         /* No more symbols.  */
289                         break;
290
291                       /* Advance to next symbol.  */
292                       aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
293                     }
294
295                   if (ent->vn_next == 0)
296                     /* No more dependencies.  */
297                     break;
298
299                   /* Advance to next dependency.  */
300                   ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
301                 }
302             }
303
304           /* And insert the defined versions.  */
305           if (def != NULL)
306             {
307               ElfW(Verdef) *ent;
308               ent = (ElfW(Verdef)  *) (map->l_addr + def->d_un.d_ptr);
309               while (1)
310                 {
311                   ElfW(Verdaux) *aux;
312                   aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux);
313
314                   if ((ent->vd_flags & VER_FLG_BASE) == 0)
315                     {
316                       /* The name of the base version should not be
317                          available for matching a versioned symbol.  */
318                       ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
319                       map->l_versions[ndx].hash = ent->vd_hash;
320                       map->l_versions[ndx].name = &strtab[aux->vda_name];
321                       map->l_versions[ndx].filename = NULL;
322                     }
323
324                   if (ent->vd_next == 0)
325                     /* No more definitions.  */
326                     break;
327
328                   ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
329                 }
330             }
331         }
332     }
333
334   return result;
335 }
336
337
338 int
339 _dl_check_all_versions (struct link_map *map, int verbose)
340 {
341   struct link_map *l;
342   int result = 0;
343
344   for (l = map; l != NULL; l = l->l_next)
345     result |= l->l_opencount != 0 && _dl_check_map_versions (l, verbose);
346
347   return result;
348 }