]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dl-version.c
Update.
[thirdparty/glibc.git] / elf / dl-version.c
CommitLineData
c84142e8 1/* Handle symbol and library versioning.
7dea968e 2 Copyright (C) 1997, 1998 Free Software Foundation, Inc.
c84142e8
UD
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
714a562f 28#include <stdio-common/_itoa.h>
c84142e8
UD
29
30
c84142e8
UD
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) \
26b4d766 46 cp = __stpcpy (cp, all[cnt]); \
c84142e8
UD
47 \
48 result; \
49 })
50
51
52static inline struct link_map *
762a2918 53find_needed (const char *name, struct link_map *map)
c84142e8 54{
26b4d766 55 struct link_map *tmap;
c84142e8
UD
56 unsigned int n;
57
26b4d766
UD
58 for (tmap = _dl_loaded; tmap != NULL; tmap = tmap->l_next)
59 if (_dl_name_match_p (name, tmap))
60 return tmap;
c84142e8 61
762a2918
UD
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
c84142e8
UD
68 /* Should never happen. */
69 return NULL;
70}
71
72
73static int
74match_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);
714a562f 79 ElfW(Addr) def_offset;
c84142e8
UD
80 ElfW(Verdef) *def;
81
8193034b
UD
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
714a562f 88 if (map->l_info[VERSTAG (DT_VERDEF)] == NULL)
c84142e8
UD
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 ("\
95no version information available (required by ",
96 name, ")"));
97 return 0;
98 }
99
714a562f
UD
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);
c84142e8
UD
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
158int
159_dl_check_map_versions (struct link_map *map, int verbose)
160{
161 int result = 0;
f41c8091 162 const char *strtab;
c84142e8 163 /* Pointer to section with needed versions. */
f41c8091 164 ElfW(Dyn) *dyn;
c84142e8 165 /* Pointer to dynamic section with definitions. */
f41c8091 166 ElfW(Dyn) *def;
c84142e8
UD
167 /* We need to find out which is the highest version index used
168 in a dependecy. */
169 unsigned int ndx_high = 0;
170
f41c8091
UD
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
c84142e8
UD
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;
762a2918 202 struct link_map *needed = find_needed (strtab + ent->vn_file, map);
c84142e8
UD
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. */
c131718c 222 if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
c84142e8
UD
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;
714a562f 250 ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
c84142e8
UD
251 while (1)
252 {
c131718c 253 if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
c84142e8
UD
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. */
1fb05e3d 269 map->l_versions = (struct r_found_version *)
c131718c 270 calloc (ndx_high + 1, sizeof (*map->l_versions));
c84142e8
UD
271 if (map->l_versions == NULL)
272 {
273 _dl_signal_error (ENOMEM, (*map->l_name ? map->l_name : _dl_argv[0]),
1fb05e3d 274 "cannot allocate version reference table");
c84142e8
UD
275 result = 1;
276 }
277 else
278 {
279 /* Store the number of available symbols. */
280 map->l_nversions = ndx_high + 1;
281
0c367d92
UD
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
c84142e8
UD
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;
f9a73ae1 298 map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
c84142e8 299 map->l_versions[ndx].name = &strtab[aux->vna_name];
1fb05e3d 300 map->l_versions[ndx].filename = &strtab[ent->vn_file];
c84142e8
UD
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];
1fb05e3d 336 map->l_versions[ndx].filename = NULL;
c84142e8
UD
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
353int
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)
ceb2d9aa 360 result |= l->l_opencount != 0 && _dl_check_map_versions (l, verbose);
c84142e8
UD
361
362 return result;
363}