Blame elf/dl-sym.c

Packit 6c4009
/* Look up a symbol in a shared object loaded by `dlopen'.
Packit 6c4009
   Copyright (C) 1999-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <setjmp.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
Packit 6c4009
#include <dlfcn.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <dl-hash.h>
Packit 6c4009
#include <sysdep-cancel.h>
Packit 6c4009
#include <dl-tls.h>
Packit 6c4009
#include <dl-irel.h>
Packit Bot d2f69c
#include <dl-sym-post.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
/* Systems which do not have tls_index also probably have to define
Packit 6c4009
   DONT_USE_TLS_INDEX.  */
Packit 6c4009
Packit 6c4009
# ifndef __TLS_GET_ADDR
Packit 6c4009
#  define __TLS_GET_ADDR __tls_get_addr
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
/* Return the symbol address given the map of the module it is in and
Packit 6c4009
   the symbol record.  This is used in dl-sym.c.  */
Packit 6c4009
static void *
Packit 6c4009
_dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
Packit 6c4009
{
Packit 6c4009
# ifndef DONT_USE_TLS_INDEX
Packit 6c4009
  tls_index tmp =
Packit 6c4009
    {
Packit 6c4009
      .ti_module = map->l_tls_modid,
Packit 6c4009
      .ti_offset = ref->st_value
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  return __TLS_GET_ADDR (&tmp);
Packit 6c4009
# else
Packit 6c4009
  return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
Packit 6c4009
# endif
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct call_dl_lookup_args
Packit 6c4009
{
Packit 6c4009
  /* Arguments to do_dlsym.  */
Packit 6c4009
  struct link_map *map;
Packit 6c4009
  const char *name;
Packit 6c4009
  struct r_found_version *vers;
Packit 6c4009
  int flags;
Packit 6c4009
Packit 6c4009
  /* Return values of do_dlsym.  */
Packit 6c4009
  lookup_t loadbase;
Packit 6c4009
  const ElfW(Sym) **refp;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
call_dl_lookup (void *ptr)
Packit 6c4009
{
Packit 6c4009
  struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr;
Packit 6c4009
  args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp,
Packit 6c4009
					args->map->l_scope, args->vers, 0,
Packit 6c4009
					args->flags, NULL);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
do_sym (void *handle, const char *name, void *who,
Packit 6c4009
	struct r_found_version *vers, int flags)
Packit 6c4009
{
Packit 6c4009
  const ElfW(Sym) *ref = NULL;
Packit 6c4009
  lookup_t result;
Packit 6c4009
  ElfW(Addr) caller = (ElfW(Addr)) who;
Packit 6c4009
Packit Bot ff96d8
  /* Link map of the caller if needed.  */
Packit Bot ff96d8
  struct link_map *match = NULL;
Packit 6c4009
Packit 6c4009
  if (handle == RTLD_DEFAULT)
Packit 6c4009
    {
Packit Bot d2f69c
      match = _dl_sym_find_caller_link_map (caller);
Packit Bot ff96d8
Packit 6c4009
      /* Search the global scope.  We have the simple case where
Packit 6c4009
	 we look up in the scope of an object which was part of
Packit 6c4009
	 the initial binary.  And then the more complex part
Packit 6c4009
	 where the object is dynamically loaded and the scope
Packit 6c4009
	 array can change.  */
Packit 6c4009
      if (RTLD_SINGLE_THREAD_P)
Packit 6c4009
	result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
Packit 6c4009
					   match->l_scope, vers, 0,
Packit 6c4009
					   flags | DL_LOOKUP_ADD_DEPENDENCY,
Packit 6c4009
					   NULL);
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  struct call_dl_lookup_args args;
Packit 6c4009
	  args.name = name;
Packit 6c4009
	  args.map = match;
Packit 6c4009
	  args.vers = vers;
Packit 6c4009
	  args.flags
Packit 6c4009
	    = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
Packit 6c4009
	  args.refp = &ref;
Packit 6c4009
Packit 6c4009
	  THREAD_GSCOPE_SET_FLAG ();
Packit 6c4009
	  struct dl_exception exception;
Packit 6c4009
	  int err = _dl_catch_exception (&exception, call_dl_lookup, &args);
Packit 6c4009
	  THREAD_GSCOPE_RESET_FLAG ();
Packit 6c4009
	  if (__glibc_unlikely (exception.errstring != NULL))
Packit 6c4009
	    _dl_signal_exception (err, &exception, NULL);
Packit 6c4009
Packit 6c4009
	  result = args.map;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else if (handle == RTLD_NEXT)
Packit 6c4009
    {
Packit Bot d2f69c
      match = _dl_sym_find_caller_link_map (caller);
Packit Bot ff96d8
Packit 6c4009
      if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
Packit 6c4009
	{
Packit 6c4009
	  if (match == NULL
Packit 6c4009
	      || caller < match->l_map_start
Packit 6c4009
	      || caller >= match->l_map_end)
Packit 6c4009
	    _dl_signal_error (0, NULL, NULL, N_("\
Packit 6c4009
RTLD_NEXT used in code not dynamically loaded"));
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      struct link_map *l = match;
Packit 6c4009
      while (l->l_loader != NULL)
Packit 6c4009
	l = l->l_loader;
Packit 6c4009
Packit 6c4009
      result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
Packit 6c4009
					 vers, 0, 0, match);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* Search the scope of the given object.  */
Packit 6c4009
      struct link_map *map = handle;
Packit 6c4009
      result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
Packit 6c4009
					 vers, 0, flags, NULL);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (ref != NULL)
Packit 6c4009
    {
Packit 6c4009
      void *value;
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
      if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
Packit 6c4009
	/* The found symbol is a thread-local storage variable.
Packit 6c4009
	   Return the address for to the current thread.  */
Packit 6c4009
	value = _dl_tls_symaddr (result, ref);
Packit 6c4009
      else
Packit 6c4009
#endif
Packit 6c4009
	value = DL_SYMBOL_ADDRESS (result, ref);
Packit 6c4009
Packit Bot d2f69c
      return _dl_sym_post (result, ref, value, caller, match);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
_dl_vsym (void *handle, const char *name, const char *version, void *who)
Packit 6c4009
{
Packit 6c4009
  struct r_found_version vers;
Packit 6c4009
Packit 6c4009
  /* Compute hash value to the version string.  */
Packit 6c4009
  vers.name = version;
Packit 6c4009
  vers.hidden = 1;
Packit 6c4009
  vers.hash = _dl_elf_hash (version);
Packit 6c4009
  /* We don't have a specific file where the symbol can be found.  */
Packit 6c4009
  vers.filename = NULL;
Packit 6c4009
Packit 6c4009
  return do_sym (handle, name, who, &vers, 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
_dl_sym (void *handle, const char *name, void *who)
Packit 6c4009
{
Packit 6c4009
  return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
Packit 6c4009
}