diff options
Diffstat (limited to 'newlib/libc/sys/linux/dl/dl-sym.c')
-rw-r--r-- | newlib/libc/sys/linux/dl/dl-sym.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/newlib/libc/sys/linux/dl/dl-sym.c b/newlib/libc/sys/linux/dl/dl-sym.c new file mode 100644 index 000000000..85d084f7f --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-sym.c @@ -0,0 +1,158 @@ +/* Look up a symbol in a shared object loaded by `dlopen'. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> +#include <setjmp.h> +#include <libintl.h> + +#include <dlfcn.h> +#include <ldsodefs.h> +#include <dl-hash.h> + +void * +internal_function +_dl_sym (void *handle, const char *name, void *who) +{ + const ElfW(Sym) *ref = NULL; + lookup_t result; + ElfW(Addr) caller = (ElfW(Addr)) who; + struct link_map *match; + struct link_map *l; + + /* If the address is not recognized the call comes from the main + program (we hope). */ + match = _dl_loaded; + + /* Find the highest-addressed object that CALLER is not below. */ + for (l = _dl_loaded; l != NULL; l = l->l_next) + if (caller >= l->l_map_start && caller < l->l_map_end) + { + /* There must be exactly one DSO for the range of the virtual + memory. Otherwise something is really broken. */ + match = l; + break; + } + + if (handle == RTLD_DEFAULT) + /* Search the global scope as seen in the caller object. */ + result = _dl_lookup_symbol (name, match, &ref, match->l_scope, 0, 0); + else + { + if (handle != RTLD_NEXT) + { + /* Search the scope of the given object. */ + struct link_map *map = handle; + + result = _dl_lookup_symbol (name, match, &ref, map->l_local_scope, + 0, 1); + } + else + { + if (__builtin_expect (match == _dl_loaded, 0)) + { + if (! _dl_loaded + || caller < _dl_loaded->l_map_start + || caller >= _dl_loaded->l_map_end) + _dl_signal_error (0, NULL, NULL, N_("\ +RTLD_NEXT used in code not dynamically loaded")); + } + + l = match; + while (l->l_loader != NULL) + l = l->l_loader; + + result = _dl_lookup_symbol_skip (name, l, &ref, l->l_local_scope, + match); + } + } + + if (ref != NULL) + return DL_SYMBOL_ADDRESS (result, ref); + + return NULL; +} + +void * +internal_function +_dl_vsym (void *handle, const char *name, const char *version, void *who) +{ + const ElfW(Sym) *ref = NULL; + struct r_found_version vers; + lookup_t result; + ElfW(Addr) caller = (ElfW(Addr)) who; + struct link_map *match; + struct link_map *l; + + /* Compute hash value to the version string. */ + vers.name = version; + vers.hidden = 1; + vers.hash = _dl_elf_hash (version); + /* We don't have a specific file where the symbol can be found. */ + vers.filename = NULL; + + /* If the address is not recognized the call comes from the main + program (we hope). */ + match = _dl_loaded; + + /* Find the highest-addressed object that CALLER is not below. */ + for (l = _dl_loaded; l != NULL; l = l->l_next) + if (caller >= l->l_map_start && caller < l->l_map_end) + { + /* There must be exactly one DSO for the range of the virtual + memory. Otherwise something is really broken. */ + match = l; + break; + } + + if (handle == RTLD_DEFAULT) + /* Search the global scope. */ + result = _dl_lookup_versioned_symbol (name, match, &ref, match->l_scope, + &vers, 0, 0); + else if (handle == RTLD_NEXT) + { + if (__builtin_expect (match == _dl_loaded, 0)) + { + if (! _dl_loaded + || caller < _dl_loaded->l_map_start + || caller >= _dl_loaded->l_map_end) + _dl_signal_error (0, NULL, NULL, N_("\ +RTLD_NEXT used in code not dynamically loaded")); + } + + l = match; + while (l->l_loader != NULL) + l = l->l_loader; + + result = _dl_lookup_versioned_symbol_skip (name, l, &ref, + l->l_local_scope, + &vers, match); + } + else + { + /* Search the scope of the given object. */ + struct link_map *map = handle; + result = _dl_lookup_versioned_symbol (name, map, &ref, + map->l_local_scope, &vers, 0, 1); + } + + if (ref != NULL) + return DL_SYMBOL_ADDRESS (result, ref); + + return NULL; +} |