* elf/dl-lookup.c (_dl_debug_bindings): Remove unised symbol_scope
[glibc.git] / elf / dl-sym.c
blob8bb564c2fe385b26b62812bdd25291151a3e4b76
1 /* Look up a symbol in a shared object loaded by `dlopen'.
2 Copyright (C) 1999,2000,2001,2002,2004,2006 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <assert.h>
21 #include <stddef.h>
22 #include <setjmp.h>
23 #include <libintl.h>
25 #include <dlfcn.h>
26 #include <ldsodefs.h>
27 #include <dl-hash.h>
28 #include <sysdep-cancel.h>
29 #ifdef USE_TLS
30 # include <dl-tls.h>
31 #endif
34 #if defined USE_TLS && defined SHARED
35 /* Systems which do not have tls_index also probably have to define
36 DONT_USE_TLS_INDEX. */
38 # ifndef __TLS_GET_ADDR
39 # define __TLS_GET_ADDR __tls_get_addr
40 # endif
42 /* Return the symbol address given the map of the module it is in and
43 the symbol record. This is used in dl-sym.c. */
44 static void *
45 internal_function
46 _dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
48 # ifndef DONT_USE_TLS_INDEX
49 tls_index tmp =
51 .ti_module = map->l_tls_modid,
52 .ti_offset = ref->st_value
55 return __TLS_GET_ADDR (&tmp);
56 # else
57 return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
58 # endif
60 #endif
63 struct call_dl_lookup_args
65 /* Arguments to do_dlsym. */
66 struct link_map *map;
67 const char *name;
68 struct r_found_version *vers;
69 int flags;
71 /* Return values of do_dlsym. */
72 lookup_t loadbase;
73 const ElfW(Sym) **refp;
76 static void
77 call_dl_lookup (void *ptr)
79 struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr;
80 args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp,
81 args->map->l_scope, args->vers, 0,
82 args->flags, NULL);
86 static void *
87 internal_function
88 do_sym (void *handle, const char *name, void *who,
89 struct r_found_version *vers, int flags)
91 const ElfW(Sym) *ref = NULL;
92 lookup_t result;
93 ElfW(Addr) caller = (ElfW(Addr)) who;
95 /* If the address is not recognized the call comes from the main
96 program (we hope). */
97 struct link_map *match = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
99 /* Find the highest-addressed object that CALLER is not below. */
100 for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
101 for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
102 l = l->l_next)
103 if (caller >= l->l_map_start && caller < l->l_map_end)
105 /* There must be exactly one DSO for the range of the virtual
106 memory. Otherwise something is really broken. */
107 match = l;
108 break;
111 if (handle == RTLD_DEFAULT)
113 /* Search the global scope. We have the simple case where
114 we look up in the scope of an object which was part of
115 the initial binary. And then the more complex part
116 where the object is dynamically loaded and the scope
117 array can change. */
118 if (match->l_type != lt_loaded || SINGLE_THREAD_P)
119 result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
120 match->l_scope, vers, 0,
121 flags | DL_LOOKUP_ADD_DEPENDENCY,
122 NULL);
123 else
125 __rtld_mrlock_lock (match->l_scope_lock);
127 struct call_dl_lookup_args args;
128 args.name = name;
129 args.map = match;
130 args.vers = vers;
131 args.flags = flags | DL_LOOKUP_ADD_DEPENDENCY;
132 args.refp = &ref;
134 const char *objname;
135 const char *errstring = NULL;
136 bool malloced;
137 int err = GLRO(dl_catch_error) (&objname, &errstring, &malloced,
138 call_dl_lookup, &args);
140 __rtld_mrlock_unlock (match->l_scope_lock);
142 if (__builtin_expect (errstring != NULL, 0))
144 /* The lookup was unsuccessful. Rethrow the error. */
145 char *errstring_dup = strdupa (errstring);
146 char *objname_dup = strdupa (objname);
147 if (malloced)
148 free ((char *) errstring);
150 GLRO(dl_signal_error) (err, objname_dup, NULL, errstring_dup);
151 /* NOTREACHED */
154 result = args.map;
157 else if (handle == RTLD_NEXT)
159 if (__builtin_expect (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded, 0))
161 if (match == NULL
162 || caller < match->l_map_start
163 || caller >= match->l_map_end)
164 GLRO(dl_signal_error) (0, NULL, NULL, N_("\
165 RTLD_NEXT used in code not dynamically loaded"));
168 struct link_map *l = match;
169 while (l->l_loader != NULL)
170 l = l->l_loader;
172 result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
173 vers, 0, 0, match);
175 else
177 /* Search the scope of the given object. */
178 struct link_map *map = handle;
179 result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
180 vers, 0, flags, NULL);
183 if (ref != NULL)
185 void *value;
187 #if defined USE_TLS && defined SHARED
188 if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
189 /* The found symbol is a thread-local storage variable.
190 Return the address for to the current thread. */
191 value = _dl_tls_symaddr (result, ref);
192 else
193 #endif
194 value = DL_SYMBOL_ADDRESS (result, ref);
196 #ifdef SHARED
197 /* Auditing checkpoint: we have a new binding. Provide the
198 auditing libraries the possibility to change the value and
199 tell us whether further auditing is wanted. */
200 if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
202 const char *strtab = (const char *) D_PTR (result,
203 l_info[DT_STRTAB]);
204 /* Compute index of the symbol entry in the symbol table of
205 the DSO with the definition. */
206 unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
207 l_info[DT_SYMTAB]));
209 if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
211 unsigned int altvalue = 0;
212 struct audit_ifaces *afct = GLRO(dl_audit);
213 /* Synthesize a symbol record where the st_value field is
214 the result. */
215 ElfW(Sym) sym = *ref;
216 sym.st_value = (ElfW(Addr)) value;
218 for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
220 if (afct->symbind != NULL
221 && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
222 != 0
223 || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
224 != 0)))
226 unsigned int flags = altvalue | LA_SYMB_DLSYM;
227 uintptr_t new_value
228 = afct->symbind (&sym, ndx,
229 &match->l_audit[cnt].cookie,
230 &result->l_audit[cnt].cookie,
231 &flags, strtab + ref->st_name);
232 if (new_value != (uintptr_t) sym.st_value)
234 altvalue = LA_SYMB_ALTVALUE;
235 sym.st_value = new_value;
239 afct = afct->next;
242 value = (void *) sym.st_value;
245 #endif
247 return value;
250 return NULL;
254 void *
255 internal_function
256 _dl_vsym (void *handle, const char *name, const char *version, void *who)
258 struct r_found_version vers;
260 /* Compute hash value to the version string. */
261 vers.name = version;
262 vers.hidden = 1;
263 vers.hash = _dl_elf_hash (version);
264 /* We don't have a specific file where the symbol can be found. */
265 vers.filename = NULL;
267 return do_sym (handle, name, who, &vers, 0);
271 void *
272 internal_function
273 _dl_sym (void *handle, const char *name, void *who)
275 return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);