]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dl-sym.c
Update copyright notices with scripts/update-copyrights.
[thirdparty/glibc.git] / elf / dl-sym.c
CommitLineData
94e365c6 1/* Look up a symbol in a shared object loaded by `dlopen'.
568035b7 2 Copyright (C) 1999-2013 Free Software Foundation, Inc.
94e365c6
UD
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
41bdb6e2
AJ
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.
94e365c6
UD
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
41bdb6e2 13 Lesser General Public License for more details.
94e365c6 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
94e365c6 18
1100f849 19#include <assert.h>
94e365c6
UD
20#include <stddef.h>
21#include <setjmp.h>
176790a7 22#include <stdlib.h>
94e365c6
UD
23#include <libintl.h>
24
25#include <dlfcn.h>
26#include <ldsodefs.h>
27#include <dl-hash.h>
609cf614 28#include <sysdep-cancel.h>
11bf311e 29#include <dl-tls.h>
42675c6f 30#include <dl-irel.h>
154d10bd
UD
31
32
11bf311e 33#ifdef SHARED
154d10bd
UD
34/* Systems which do not have tls_index also probably have to define
35 DONT_USE_TLS_INDEX. */
36
37# ifndef __TLS_GET_ADDR
38# define __TLS_GET_ADDR __tls_get_addr
39# endif
40
41/* Return the symbol address given the map of the module it is in and
42 the symbol record. This is used in dl-sym.c. */
43static void *
44internal_function
45_dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
46{
47# ifndef DONT_USE_TLS_INDEX
48 tls_index tmp =
49 {
50 .ti_module = map->l_tls_modid,
51 .ti_offset = ref->st_value
52 };
53
54 return __TLS_GET_ADDR (&tmp);
55# else
56 return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
57# endif
58}
59#endif
60
94e365c6 61
1100f849
UD
62struct call_dl_lookup_args
63{
64 /* Arguments to do_dlsym. */
65 struct link_map *map;
66 const char *name;
1100f849
UD
67 struct r_found_version *vers;
68 int flags;
69
70 /* Return values of do_dlsym. */
71 lookup_t loadbase;
72 const ElfW(Sym) **refp;
73};
74
75static void
76call_dl_lookup (void *ptr)
77{
78 struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr;
79 args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp,
c0a777e8 80 args->map->l_scope, args->vers, 0,
1100f849
UD
81 args->flags, NULL);
82}
83
84
53761a8b 85static void *
94e365c6 86internal_function
f0323886
UD
87do_sym (void *handle, const char *name, void *who,
88 struct r_found_version *vers, int flags)
94e365c6 89{
94e365c6 90 const ElfW(Sym) *ref = NULL;
c0282c06 91 lookup_t result;
2b7238dd 92 ElfW(Addr) caller = (ElfW(Addr)) who;
94e365c6 93
f92338be
UD
94 /* If the address is not recognized the call comes from the main
95 program (we hope). */
c0f62c56 96 struct link_map *match = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
f92338be 97
2b7238dd 98 /* Find the highest-addressed object that CALLER is not below. */
22c83193 99 for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
c0f62c56
UD
100 for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
101 l = l->l_next)
9be09e06
UD
102 if (caller >= l->l_map_start && caller < l->l_map_end
103 && (l->l_contiguous || _dl_addr_inside_object (l, caller)))
c0f62c56 104 {
c0f62c56
UD
105 match = l;
106 break;
107 }
2b7238dd 108
94e365c6 109 if (handle == RTLD_DEFAULT)
1100f849
UD
110 {
111 /* Search the global scope. We have the simple case where
112 we look up in the scope of an object which was part of
113 the initial binary. And then the more complex part
114 where the object is dynamically loaded and the scope
115 array can change. */
e4eb675d 116 if (RTLD_SINGLE_THREAD_P)
1100f849 117 result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
c0a777e8 118 match->l_scope, vers, 0,
1100f849
UD
119 flags | DL_LOOKUP_ADD_DEPENDENCY,
120 NULL);
121 else
122 {
1100f849
UD
123 struct call_dl_lookup_args args;
124 args.name = name;
125 args.map = match;
1100f849 126 args.vers = vers;
b90395e6
UD
127 args.flags
128 = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
1100f849
UD
129 args.refp = &ref;
130
e4eb675d
UD
131 THREAD_GSCOPE_SET_FLAG ();
132
1100f849
UD
133 const char *objname;
134 const char *errstring = NULL;
135 bool malloced;
136 int err = GLRO(dl_catch_error) (&objname, &errstring, &malloced,
137 call_dl_lookup, &args);
138
e4eb675d 139 THREAD_GSCOPE_RESET_FLAG ();
1100f849
UD
140
141 if (__builtin_expect (errstring != NULL, 0))
142 {
143 /* The lookup was unsuccessful. Rethrow the error. */
144 char *errstring_dup = strdupa (errstring);
145 char *objname_dup = strdupa (objname);
146 if (malloced)
147 free ((char *) errstring);
148
149 GLRO(dl_signal_error) (err, objname_dup, NULL, errstring_dup);
150 /* NOTREACHED */
151 }
152
153 result = args.map;
154 }
155 }
94e365c6
UD
156 else if (handle == RTLD_NEXT)
157 {
c0f62c56 158 if (__builtin_expect (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded, 0))
2373b30e 159 {
173a06ec
UD
160 if (match == NULL
161 || caller < match->l_map_start
162 || caller >= match->l_map_end)
154d10bd 163 GLRO(dl_signal_error) (0, NULL, NULL, N_("\
94e365c6 164RTLD_NEXT used in code not dynamically loaded"));
2373b30e 165 }
94e365c6 166
53761a8b 167 struct link_map *l = match;
f92338be 168 while (l->l_loader != NULL)
94e365c6
UD
169 l = l->l_loader;
170
74c5693b 171 result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
53761a8b 172 vers, 0, 0, match);
94e365c6
UD
173 }
174 else
175 {
176 /* Search the scope of the given object. */
177 struct link_map *map = handle;
021723ab 178 result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
53761a8b 179 vers, 0, flags, NULL);
94e365c6
UD
180 }
181
f92338be 182 if (ref != NULL)
aed283dd 183 {
9dcafc55
UD
184 void *value;
185
11bf311e 186#ifdef SHARED
aed283dd
UD
187 if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
188 /* The found symbol is a thread-local storage variable.
189 Return the address for to the current thread. */
9dcafc55
UD
190 value = _dl_tls_symaddr (result, ref);
191 else
192#endif
193 value = DL_SYMBOL_ADDRESS (result, ref);
194
bc5e8462
AS
195 /* Resolve indirect function address. */
196 if (__builtin_expect (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC, 0))
8608ae1f
L
197 {
198 DL_FIXUP_VALUE_TYPE fixup
199 = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
42675c6f 200 fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
8608ae1f
L
201 value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
202 }
bc5e8462 203
9dcafc55
UD
204#ifdef SHARED
205 /* Auditing checkpoint: we have a new binding. Provide the
206 auditing libraries the possibility to change the value and
207 tell us whether further auditing is wanted. */
208 if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
209 {
210 const char *strtab = (const char *) D_PTR (result,
211 l_info[DT_STRTAB]);
212 /* Compute index of the symbol entry in the symbol table of
213 the DSO with the definition. */
214 unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
215 l_info[DT_SYMTAB]));
216
217 if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
218 {
219 unsigned int altvalue = 0;
220 struct audit_ifaces *afct = GLRO(dl_audit);
221 /* Synthesize a symbol record where the st_value field is
222 the result. */
223 ElfW(Sym) sym = *ref;
224 sym.st_value = (ElfW(Addr)) value;
225
226 for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
227 {
228 if (afct->symbind != NULL
229 && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
230 != 0
231 || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
232 != 0)))
233 {
234 unsigned int flags = altvalue | LA_SYMB_DLSYM;
235 uintptr_t new_value
236 = afct->symbind (&sym, ndx,
237 &match->l_audit[cnt].cookie,
238 &result->l_audit[cnt].cookie,
239 &flags, strtab + ref->st_name);
240 if (new_value != (uintptr_t) sym.st_value)
241 {
242 altvalue = LA_SYMB_ALTVALUE;
243 sym.st_value = new_value;
244 }
245 }
246
247 afct = afct->next;
248 }
249
250 value = (void *) sym.st_value;
251 }
252 }
aed283dd
UD
253#endif
254
9dcafc55 255 return value;
aed283dd 256 }
5e76a346 257
94e365c6
UD
258 return NULL;
259}
53761a8b
UD
260
261
53761a8b
UD
262void *
263internal_function
264_dl_vsym (void *handle, const char *name, const char *version, void *who)
265{
266 struct r_found_version vers;
267
268 /* Compute hash value to the version string. */
269 vers.name = version;
270 vers.hidden = 1;
271 vers.hash = _dl_elf_hash (version);
272 /* We don't have a specific file where the symbol can be found. */
273 vers.filename = NULL;
274
f0323886 275 return do_sym (handle, name, who, &vers, 0);
53761a8b
UD
276}
277
278
279void *
280internal_function
281_dl_sym (void *handle, const char *name, void *who)
282{
f0323886 283 return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
53761a8b 284}