Update.
[platform/upstream/glibc.git] / elf / dl-lookup.c
1 /* Look up a symbol in the loaded objects.
2    Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <alloca.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <elf/ldsodefs.h>
24 #include "dl-hash.h"
25 #include <dl-machine.h>
26
27 #include <assert.h>
28
29 #define VERSTAG(tag)    (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
30
31 /* We need this string more than once.  */
32 static const char undefined_msg[] = "undefined symbol: ";
33
34
35 struct sym_val
36   {
37     const ElfW(Sym) *s;
38     struct link_map *m;
39   };
40
41
42 #define make_string(string, rest...) \
43   ({                                                                          \
44     const char *all[] = { string, ## rest };                                  \
45     size_t len, cnt;                                                          \
46     char *result, *cp;                                                        \
47                                                                               \
48     len = 1;                                                                  \
49     for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)                \
50       len += strlen (all[cnt]);                                               \
51                                                                               \
52     cp = result = alloca (len);                                               \
53     for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)                \
54       cp = __stpcpy (cp, all[cnt]);                                           \
55                                                                               \
56     result;                                                                   \
57   })
58
59
60 /* Inner part of the lookup functions.  We return a value > 0 if we
61    found the symbol, the value 0 if nothing is found and < 0 if
62    something bad happened.  */
63 static inline int
64 do_lookup (const char *undef_name, unsigned long int hash,
65            const ElfW(Sym) *ref, struct sym_val *result,
66            struct link_map *scope, size_t i, const char *reference_name,
67            const struct r_found_version *version, struct link_map *skip,
68            int reloc_type)
69 {
70   struct link_map **list = scope->l_searchlist;
71   size_t n = scope->l_nsearchlist;
72   struct link_map *map;
73
74   for (; i < n; ++i)
75     {
76       const ElfW(Sym) *symtab;
77       const char *strtab;
78       const ElfW(Half) *verstab;
79       ElfW(Symndx) symidx;
80
81       map = list[i];
82
83       /* Here come the extra test needed for `_dl_lookup_symbol_skip'.  */
84       if (skip != NULL && map == skip)
85         continue;
86
87       /* Skip objects that could not be opened, which can occur in trace
88          mode.  */
89       if (map->l_opencount == 0)
90         continue;
91
92       /* Don't search the executable when resolving a copy reloc.  */
93       if (elf_machine_lookup_noexec_p (reloc_type)
94           && map->l_type == lt_executable)
95         continue;
96
97       /* Skip objects without symbol tables.  */
98       if (map->l_info[DT_SYMTAB] == NULL)
99         continue;
100
101       /* Print some debugging info if wanted.  */
102       if (_dl_debug_symbols)
103         _dl_debug_message (1, "symbol=", undef_name, ";  lookup in file=",
104                            map->l_name[0] ? map->l_name : _dl_argv[0],
105                            "\n", NULL);
106
107       symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
108       strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
109       verstab = map->l_versyms;
110
111       /* Search the appropriate hash bucket in this object's symbol table
112          for a definition for the same symbol name.  */
113       for (symidx = map->l_buckets[hash % map->l_nbuckets];
114            symidx != STN_UNDEF;
115            symidx = map->l_chain[symidx])
116         {
117           const ElfW(Sym) *sym = &symtab[symidx];
118
119           if (sym->st_value == 0 || /* No value.  */
120               (elf_machine_lookup_noplt_p (reloc_type) /* Reject PLT entry.  */
121                && sym->st_shndx == SHN_UNDEF))
122             continue;
123
124           if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC)
125             /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC entries
126                since these are no code/data definitions.  */
127             continue;
128
129           if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
130             /* Not the symbol we are looking for.  */
131             continue;
132
133           if (version == NULL)
134             {
135               /* No specific version is selected.  When the object
136                  file also does not define a version we have a match.
137                  Otherwise we only accept the default version, i.e.,
138                  the version which name is "".  */
139               if (verstab != NULL)
140                 {
141                   ElfW(Half) ndx = verstab[symidx] & 0x7fff;
142                   if (ndx > 2) /* map->l_versions[ndx].hash != 0) */
143                     continue;
144                 }
145             }
146           else
147             {
148               if (verstab == NULL)
149                 {
150                   /* We need a versioned system but haven't found any.
151                      If this is the object which is referenced in the
152                      verneed entry it is a bug in the library since a
153                      symbol must not simply disappear.  */
154                   if (version->filename != NULL
155                       && _dl_name_match_p (version->filename, map))
156                     return -2;
157                   /* Otherwise we accept the symbol.  */
158                 }
159               else
160                 {
161                   /* We can match the version information or use the
162                      default one if it is not hidden.  */
163                   ElfW(Half) ndx = verstab[symidx] & 0x7fff;
164                   if ((map->l_versions[ndx].hash != version->hash
165                        || strcmp (map->l_versions[ndx].name, version->name))
166                       && (version->hidden || map->l_versions[ndx].hash
167                           || (verstab[symidx] & 0x8000)))
168                     /* It's not the version we want.  */
169                     continue;
170                 }
171             }
172
173           switch (ELFW(ST_BIND) (sym->st_info))
174             {
175             case STB_GLOBAL:
176               /* Global definition.  Just what we need.  */
177               result->s = sym;
178               result->m = map;
179               return 1;
180             case STB_WEAK:
181               /* Weak definition.  Use this value if we don't find
182                  another.  */
183               if (! result->s)
184                 {
185                   result->s = sym;
186                   result->m = map;
187                 }
188               break;
189             default:
190               /* Local symbols are ignored.  */
191               break;
192             }
193
194           /* There cannot be another entry for this symbol so stop here.  */
195           break;
196         }
197
198       /* If this current map is the one mentioned in the verneed entry
199          and we have not found a weak entry, it is a bug.  */
200       if (symidx == STN_UNDEF && version != NULL && version->filename != NULL
201           && _dl_name_match_p (version->filename, map))
202         return -1;
203     }
204
205   /* We have not found anything until now.  */
206   return 0;
207 }
208
209 /* Search loaded objects' symbol tables for a definition of the symbol
210    UNDEF_NAME.  */
211
212 ElfW(Addr)
213 internal_function
214 _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
215                    struct link_map *symbol_scope[],
216                    const char *reference_name,
217                    int reloc_type)
218 {
219   const unsigned long int hash = _dl_elf_hash (undef_name);
220   struct sym_val current_value = { NULL, NULL };
221   struct link_map **scope;
222
223   /* Search the relevant loaded objects for a definition.  */
224   for (scope = symbol_scope; *scope; ++scope)
225     if (do_lookup (undef_name, hash, *ref, &current_value,
226                    *scope, 0, reference_name, NULL, NULL, reloc_type))
227       break;
228
229   if (current_value.s == NULL)
230     {
231       if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
232         /* We could find no value for a strong reference.  */
233         _dl_signal_error (0, (reference_name  && reference_name[0]
234                               ? reference_name
235                               : (_dl_argv[0] ?: "<main program>")),
236                           make_string (undefined_msg, undef_name));
237       *ref = NULL;
238       return 0;
239     }
240
241   if (_dl_debug_bindings)
242     _dl_debug_message (1, "binding file ",
243                        (reference_name && reference_name[0]
244                         ? reference_name
245                         : (_dl_argv[0] ?: "<main program>")),
246                        " to ", current_value.m->l_name[0]
247                        ? current_value.m->l_name : _dl_argv[0],
248                        ": symbol `", undef_name, "'\n", NULL);
249
250   *ref = current_value.s;
251   return current_value.m->l_addr;
252 }
253
254
255 /* This function is nearly the same as `_dl_lookup_symbol' but it
256    skips in the first list all objects until SKIP_MAP is found.  I.e.,
257    it only considers objects which were loaded after the described
258    object.  If there are more search lists the object described by
259    SKIP_MAP is only skipped.  */
260 ElfW(Addr)
261 internal_function
262 _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
263                         struct link_map *symbol_scope[],
264                         const char *reference_name,
265                         struct link_map *skip_map)
266 {
267   const unsigned long int hash = _dl_elf_hash (undef_name);
268   struct sym_val current_value = { NULL, NULL };
269   struct link_map **scope;
270   size_t i;
271
272   /* Search the relevant loaded objects for a definition.  */
273   scope = symbol_scope;
274   for (i = 0; (*scope)->l_dupsearchlist[i] != skip_map; ++i)
275     assert (i < (*scope)->l_ndupsearchlist);
276
277   if (! do_lookup (undef_name, hash, *ref, &current_value,
278                    *scope, i, reference_name, NULL, skip_map, 0))
279     while (*++scope)
280       if (do_lookup (undef_name, hash, *ref, &current_value,
281                      *scope, 0, reference_name, NULL, skip_map, 0))
282         break;
283
284   if (current_value.s == NULL)
285     {
286       *ref = NULL;
287       return 0;
288     }
289
290   if (_dl_debug_bindings)
291     _dl_debug_message (1, "binding file ",
292                        (reference_name && reference_name[0]
293                         ? reference_name
294                         : (_dl_argv[0] ?: "<main program>")),
295                        " to ", current_value.m->l_name[0]
296                        ? current_value.m->l_name : _dl_argv[0],
297                        ": symbol `", undef_name, "' (skip)\n", NULL);
298
299   *ref = current_value.s;
300   return current_value.m->l_addr;
301 }
302
303
304 /* This function works like _dl_lookup_symbol but it takes an
305    additional arguement with the version number of the requested
306    symbol.
307
308    XXX We'll see whether we need this separate function.  */
309 ElfW(Addr)
310 internal_function
311 _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
312                              struct link_map *symbol_scope[],
313                              const char *reference_name,
314                              const struct r_found_version *version,
315                              int reloc_type)
316 {
317   const unsigned long int hash = _dl_elf_hash (undef_name);
318   struct sym_val current_value = { NULL, NULL };
319   struct link_map **scope;
320
321   /* Search the relevant loaded objects for a definition.  */
322   for (scope = symbol_scope; *scope; ++scope)
323     {
324       int res = do_lookup (undef_name, hash, *ref, &current_value,
325                            *scope, 0, reference_name, version, NULL, reloc_type);
326       if (res > 0)
327         break;
328
329       if (res < 0)
330         /* Oh, oh.  The file named in the relocation entry does not
331            contain the needed symbol.  */
332         _dl_signal_error (0, (reference_name && reference_name[0]
333                               ? reference_name
334                               : (_dl_argv[0] ?: "<main program>")),
335                           make_string ("symbol ", undef_name, ", version ",
336                                        version->name,
337                                        " not defined in file ",
338                                        version->filename,
339                                        " with link time reference",
340                                        res == -2
341                                        ? " (no version symbols)" : ""));
342     }
343
344   if (current_value.s == NULL)
345     {
346       if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
347         /* We could find no value for a strong reference.  */
348         _dl_signal_error (0, (reference_name && reference_name[0]
349                               ? reference_name
350                               : (_dl_argv[0] ?: "<main program>")),
351                           make_string (undefined_msg, undef_name,
352                                        ", version ", version->name ?: NULL));
353       *ref = NULL;
354       return 0;
355     }
356
357   if (_dl_debug_bindings)
358     _dl_debug_message (1, "binding file ",
359                        (reference_name && reference_name[0]
360                         ? reference_name
361                         : (_dl_argv[0] ?: "<main program>")),
362                        " to ", current_value.m->l_name[0]
363                        ? current_value.m->l_name : _dl_argv[0],
364                        ": symbol `", undef_name, "' [", version->name,
365                        "]\n", NULL);
366
367   *ref = current_value.s;
368   return current_value.m->l_addr;
369 }
370
371
372 /* Similar to _dl_lookup_symbol_skip but takes an additional argument
373    with the version we are looking for.  */
374 ElfW(Addr)
375 internal_function
376 _dl_lookup_versioned_symbol_skip (const char *undef_name,
377                                   const ElfW(Sym) **ref,
378                                   struct link_map *symbol_scope[],
379                                   const char *reference_name,
380                                   const struct r_found_version *version,
381                                   struct link_map *skip_map)
382 {
383   const unsigned long int hash = _dl_elf_hash (undef_name);
384   struct sym_val current_value = { NULL, NULL };
385   struct link_map **scope;
386   size_t i;
387
388   /* Search the relevant loaded objects for a definition.  */
389   scope = symbol_scope;
390   for (i = 0; (*scope)->l_dupsearchlist[i] != skip_map; ++i)
391     assert (i < (*scope)->l_ndupsearchlist);
392
393   if (! do_lookup (undef_name, hash, *ref, &current_value,
394                    *scope, i, reference_name, version, skip_map, 0))
395     while (*++scope)
396       if (do_lookup (undef_name, hash, *ref, &current_value,
397                      *scope, 0, reference_name, version, skip_map, 0))
398         break;
399
400   if (current_value.s == NULL)
401     {
402       if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
403         {
404           /* We could find no value for a strong reference.  */
405           const size_t len = strlen (undef_name);
406           char buf[sizeof undefined_msg + len];
407           __mempcpy (__mempcpy (buf, undefined_msg, sizeof undefined_msg - 1),
408                      undef_name, len + 1);
409           _dl_signal_error (0, (reference_name && reference_name[0]
410                                 ? reference_name
411                                 : (_dl_argv[0] ?: "<main program>")), buf);
412         }
413       *ref = NULL;
414       return 0;
415     }
416
417   if (_dl_debug_bindings)
418     _dl_debug_message (1, "binding file ",
419                        (reference_name && reference_name[0]
420                         ? reference_name
421                         : (_dl_argv[0] ?: "<main program>")),
422                        " to ",
423                        current_value.m->l_name[0]
424                        ? current_value.m->l_name : _dl_argv[0],
425                        ": symbol `", undef_name, "' [", version->name,
426                        "] (skip)\n", NULL);
427
428   *ref = current_value.s;
429   return current_value.m->l_addr;
430 }
431
432
433 /* Cache the location of MAP's hash table.  */
434
435 void
436 internal_function
437 _dl_setup_hash (struct link_map *map)
438 {
439   ElfW(Symndx) *hash;
440   ElfW(Symndx) nchain;
441
442   if (!map->l_info[DT_HASH])
443     return;
444   hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr);
445
446   map->l_nbuckets = *hash++;
447   nchain = *hash++;
448   map->l_buckets = hash;
449   hash += map->l_nbuckets;
450   map->l_chain = hash;
451 }