Blame elf/dl-addr.c

Packit Service 82fcde
/* Locate the shared object symbol nearest a given address.
Packit Service 82fcde
   Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <dlfcn.h>
Packit Service 82fcde
#include <stddef.h>
Packit Service 82fcde
#include <ldsodefs.h>
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static inline void
Packit Service 82fcde
__attribute ((always_inline))
Packit Service 82fcde
determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
Packit Service 82fcde
		struct link_map **mapp, const ElfW(Sym) **symbolp)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Now we know what object the address lies in.  */
Packit Service 82fcde
  info->dli_fname = match->l_name;
Packit Service 82fcde
  info->dli_fbase = (void *) match->l_map_start;
Packit Service 82fcde
Packit Service 82fcde
  /* If this is the main program the information is incomplete.  */
Packit Service 82fcde
  if (__builtin_expect (match->l_name[0], 'a') == '\0'
Packit Service 82fcde
      && match->l_type == lt_executable)
Packit Service 82fcde
    info->dli_fname = _dl_argv[0];
Packit Service 82fcde
Packit Service 82fcde
  const ElfW(Sym) *symtab
Packit Service 82fcde
    = (const ElfW(Sym) *) D_PTR (match, l_info[DT_SYMTAB]);
Packit Service 82fcde
  const char *strtab = (const char *) D_PTR (match, l_info[DT_STRTAB]);
Packit Service 82fcde
Packit Service 82fcde
  ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val;
Packit Service 82fcde
Packit Service 82fcde
  const ElfW(Sym) *matchsym = NULL;
Packit Service 82fcde
  if (match->l_info[ADDRIDX (DT_GNU_HASH)] != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We look at all symbol table entries referenced by the hash
Packit Service 82fcde
	 table.  */
Packit Service 82fcde
      for (Elf_Symndx bucket = 0; bucket < match->l_nbuckets; ++bucket)
Packit Service 82fcde
	{
Packit Service 82fcde
	  Elf32_Word symndx = match->l_gnu_buckets[bucket];
Packit Service 82fcde
	  if (symndx != 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      const Elf32_Word *hasharr = &match->l_gnu_chain_zero[symndx];
Packit Service 82fcde
Packit Service 82fcde
	      do
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* The hash table never references local symbols so
Packit Service 82fcde
		     we can omit that test here.  */
Packit Service 82fcde
		  if ((symtab[symndx].st_shndx != SHN_UNDEF
Packit Service 82fcde
		       || symtab[symndx].st_value != 0)
Packit Service 82fcde
		      && symtab[symndx].st_shndx != SHN_ABS
Packit Service 82fcde
		      && ELFW(ST_TYPE) (symtab[symndx].st_info) != STT_TLS
Packit Service 82fcde
		      && DL_ADDR_SYM_MATCH (match, &symtab[symndx],
Packit Service 82fcde
					    matchsym, addr)
Packit Service 82fcde
		      && symtab[symndx].st_name < strtabsize)
Packit Service 82fcde
		    matchsym = (ElfW(Sym) *) &symtab[symndx];
Packit Service 82fcde
Packit Service 82fcde
		  ++symndx;
Packit Service 82fcde
		}
Packit Service 82fcde
	      while ((*hasharr++ & 1u) == 0);
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      const ElfW(Sym) *symtabend;
Packit Service 82fcde
      if (match->l_info[DT_HASH] != NULL)
Packit Service 82fcde
	symtabend = (symtab
Packit Service 82fcde
		     + ((Elf_Symndx *) D_PTR (match, l_info[DT_HASH]))[1]);
Packit Service 82fcde
      else
Packit Service 82fcde
	/* There is no direct way to determine the number of symbols in the
Packit Service 82fcde
	   dynamic symbol table and no hash table is present.  The ELF
Packit Service 82fcde
	   binary is ill-formed but what shall we do?  Use the beginning of
Packit Service 82fcde
	   the string table which generally follows the symbol table.  */
Packit Service 82fcde
	symtabend = (const ElfW(Sym) *) strtab;
Packit Service 82fcde
Packit Service 82fcde
      for (; (void *) symtab < (void *) symtabend; ++symtab)
Packit Service 82fcde
	if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
Packit Service 82fcde
	     || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)
Packit Service 82fcde
	    && __glibc_likely (!dl_symbol_visibility_binds_local_p (symtab))
Packit Service 82fcde
	    && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS
Packit Service 82fcde
	    && (symtab->st_shndx != SHN_UNDEF
Packit Service 82fcde
		|| symtab->st_value != 0)
Packit Service 82fcde
	    && symtab->st_shndx != SHN_ABS
Packit Service 82fcde
	    && DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr)
Packit Service 82fcde
	    && symtab->st_name < strtabsize)
Packit Service 82fcde
	  matchsym = (ElfW(Sym) *) symtab;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (mapp)
Packit Service 82fcde
    *mapp = match;
Packit Service 82fcde
  if (symbolp)
Packit Service 82fcde
    *symbolp = matchsym;
Packit Service 82fcde
Packit Service 82fcde
  if (matchsym)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We found a symbol close by.  Fill in its name and exact
Packit Service 82fcde
	 address.  */
Packit Service 82fcde
      lookup_t matchl = LOOKUP_VALUE (match);
Packit Service 82fcde
Packit Service 82fcde
      info->dli_sname = strtab + matchsym->st_name;
Packit Service 82fcde
      info->dli_saddr = DL_SYMBOL_ADDRESS (matchl, matchsym);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      /* No symbol matches.  We return only the containing object.  */
Packit Service 82fcde
      info->dli_sname = NULL;
Packit Service 82fcde
      info->dli_saddr = NULL;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
_dl_addr (const void *address, Dl_info *info,
Packit Service 82fcde
	  struct link_map **mapp, const ElfW(Sym) **symbolp)
Packit Service 82fcde
{
Packit Service 82fcde
  const ElfW(Addr) addr = DL_LOOKUP_ADDRESS (address);
Packit Service 82fcde
  int result = 0;
Packit Service 82fcde
Packit Service 82fcde
  /* Protect against concurrent loads and unloads.  */
Packit Service 82fcde
  __rtld_lock_lock_recursive (GL(dl_load_lock));
Packit Service 82fcde
Packit Service 82fcde
  struct link_map *l = _dl_find_dso_for_object (addr);
Packit Service 82fcde
Packit Service 82fcde
  if (l)
Packit Service 82fcde
    {
Packit Service 82fcde
      determine_info (addr, l, info, mapp, symbolp);
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
libc_hidden_def (_dl_addr)