Update copyright dates with scripts/update-copyrights.
[external/glibc.git] / elf / dl-sym.c
1 /* Look up a symbol in a shared object loaded by `dlopen'.
2    Copyright (C) 1999-2015 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 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.
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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <assert.h>
20 #include <stddef.h>
21 #include <setjmp.h>
22 #include <stdlib.h>
23 #include <libintl.h>
24
25 #include <dlfcn.h>
26 #include <ldsodefs.h>
27 #include <dl-hash.h>
28 #include <sysdep-cancel.h>
29 #include <dl-tls.h>
30 #include <dl-irel.h>
31
32
33 #ifdef SHARED
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.  */
43 static void *
44 internal_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
61
62 struct call_dl_lookup_args
63 {
64   /* Arguments to do_dlsym.  */
65   struct link_map *map;
66   const char *name;
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
75 static void
76 call_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,
80                                         args->map->l_scope, args->vers, 0,
81                                         args->flags, NULL);
82 }
83
84
85 static void *
86 internal_function
87 do_sym (void *handle, const char *name, void *who,
88         struct r_found_version *vers, int flags)
89 {
90   const ElfW(Sym) *ref = NULL;
91   lookup_t result;
92   ElfW(Addr) caller = (ElfW(Addr)) who;
93
94   struct link_map *l = _dl_find_dso_for_object (caller);
95   /* If the address is not recognized the call comes from the main
96      program (we hope).  */
97   struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
98
99   if (handle == RTLD_DEFAULT)
100     {
101       /* Search the global scope.  We have the simple case where
102          we look up in the scope of an object which was part of
103          the initial binary.  And then the more complex part
104          where the object is dynamically loaded and the scope
105          array can change.  */
106       if (RTLD_SINGLE_THREAD_P)
107         result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
108                                            match->l_scope, vers, 0,
109                                            flags | DL_LOOKUP_ADD_DEPENDENCY,
110                                            NULL);
111       else
112         {
113           struct call_dl_lookup_args args;
114           args.name = name;
115           args.map = match;
116           args.vers = vers;
117           args.flags
118             = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
119           args.refp = &ref;
120
121           THREAD_GSCOPE_SET_FLAG ();
122
123           const char *objname;
124           const char *errstring = NULL;
125           bool malloced;
126           int err = GLRO(dl_catch_error) (&objname, &errstring, &malloced,
127                                           call_dl_lookup, &args);
128
129           THREAD_GSCOPE_RESET_FLAG ();
130
131           if (__glibc_unlikely (errstring != NULL))
132             {
133               /* The lookup was unsuccessful.  Rethrow the error.  */
134               char *errstring_dup = strdupa (errstring);
135               char *objname_dup = strdupa (objname);
136               if (malloced)
137                 free ((char *) errstring);
138
139               GLRO(dl_signal_error) (err, objname_dup, NULL, errstring_dup);
140               /* NOTREACHED */
141             }
142
143           result = args.map;
144         }
145     }
146   else if (handle == RTLD_NEXT)
147     {
148       if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
149         {
150           if (match == NULL
151               || caller < match->l_map_start
152               || caller >= match->l_map_end)
153             GLRO(dl_signal_error) (0, NULL, NULL, N_("\
154 RTLD_NEXT used in code not dynamically loaded"));
155         }
156
157       struct link_map *l = match;
158       while (l->l_loader != NULL)
159         l = l->l_loader;
160
161       result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
162                                          vers, 0, 0, match);
163     }
164   else
165     {
166       /* Search the scope of the given object.  */
167       struct link_map *map = handle;
168       result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
169                                          vers, 0, flags, NULL);
170     }
171
172   if (ref != NULL)
173     {
174       void *value;
175
176 #ifdef SHARED
177       if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
178         /* The found symbol is a thread-local storage variable.
179            Return the address for to the current thread.  */
180         value = _dl_tls_symaddr (result, ref);
181       else
182 #endif
183         value = DL_SYMBOL_ADDRESS (result, ref);
184
185       /* Resolve indirect function address.  */
186       if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
187         {
188           DL_FIXUP_VALUE_TYPE fixup
189             = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
190           fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
191           value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
192         }
193
194 #ifdef SHARED
195       /* Auditing checkpoint: we have a new binding.  Provide the
196          auditing libraries the possibility to change the value and
197          tell us whether further auditing is wanted.  */
198       if (__glibc_unlikely (GLRO(dl_naudit) > 0))
199         {
200           const char *strtab = (const char *) D_PTR (result,
201                                                      l_info[DT_STRTAB]);
202           /* Compute index of the symbol entry in the symbol table of
203              the DSO with the definition.  */
204           unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
205                                                          l_info[DT_SYMTAB]));
206
207           if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
208             {
209               unsigned int altvalue = 0;
210               struct audit_ifaces *afct = GLRO(dl_audit);
211               /* Synthesize a symbol record where the st_value field is
212                  the result.  */
213               ElfW(Sym) sym = *ref;
214               sym.st_value = (ElfW(Addr)) value;
215
216               for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
217                 {
218                   if (afct->symbind != NULL
219                       && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
220                           != 0
221                           || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
222                               != 0)))
223                     {
224                       unsigned int flags = altvalue | LA_SYMB_DLSYM;
225                       uintptr_t new_value
226                         = afct->symbind (&sym, ndx,
227                                          &match->l_audit[cnt].cookie,
228                                          &result->l_audit[cnt].cookie,
229                                          &flags, strtab + ref->st_name);
230                       if (new_value != (uintptr_t) sym.st_value)
231                         {
232                           altvalue = LA_SYMB_ALTVALUE;
233                           sym.st_value = new_value;
234                         }
235                     }
236
237                   afct = afct->next;
238                 }
239
240               value = (void *) sym.st_value;
241             }
242         }
243 #endif
244
245       return value;
246     }
247
248   return NULL;
249 }
250
251
252 void *
253 internal_function
254 _dl_vsym (void *handle, const char *name, const char *version, void *who)
255 {
256   struct r_found_version vers;
257
258   /* Compute hash value to the version string.  */
259   vers.name = version;
260   vers.hidden = 1;
261   vers.hash = _dl_elf_hash (version);
262   /* We don't have a specific file where the symbol can be found.  */
263   vers.filename = NULL;
264
265   return do_sym (handle, name, who, &vers, 0);
266 }
267
268
269 void *
270 internal_function
271 _dl_sym (void *handle, const char *name, void *who)
272 {
273   return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
274 }