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