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