Blame elf/dl-addr.c

Packit 6c4009
/* Locate the shared object symbol nearest a given address.
Packit 6c4009
   Copyright (C) 1996-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 <dlfcn.h>
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
Packit 6c4009
		struct link_map **mapp, const ElfW(Sym) **symbolp)
Packit 6c4009
{
Packit 6c4009
  /* Now we know what object the address lies in.  */
Packit 6c4009
  info->dli_fname = match->l_name;
Packit 6c4009
  info->dli_fbase = (void *) match->l_map_start;
Packit 6c4009
Packit 6c4009
  /* If this is the main program the information is incomplete.  */
Packit 6c4009
  if (__builtin_expect (match->l_name[0], 'a') == '\0'
Packit 6c4009
      && match->l_type == lt_executable)
Packit 6c4009
    info->dli_fname = _dl_argv[0];
Packit 6c4009
Packit 6c4009
  const ElfW(Sym) *symtab
Packit 6c4009
    = (const ElfW(Sym) *) D_PTR (match, l_info[DT_SYMTAB]);
Packit 6c4009
  const char *strtab = (const char *) D_PTR (match, l_info[DT_STRTAB]);
Packit 6c4009
Packit 6c4009
  ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val;
Packit 6c4009
Packit 6c4009
  const ElfW(Sym) *matchsym = NULL;
Packit Service b4e251
  if (match->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL)
Packit 6c4009
    {
Packit 6c4009
      /* We look at all symbol table entries referenced by the hash
Packit 6c4009
	 table.  */
Packit 6c4009
      for (Elf_Symndx bucket = 0; bucket < match->l_nbuckets; ++bucket)
Packit 6c4009
	{
Packit 6c4009
	  Elf32_Word symndx = match->l_gnu_buckets[bucket];
Packit 6c4009
	  if (symndx != 0)
Packit 6c4009
	    {
Packit 6c4009
	      const Elf32_Word *hasharr = &match->l_gnu_chain_zero[symndx];
Packit 6c4009
Packit 6c4009
	      do
Packit 6c4009
		{
Packit 6c4009
		  /* The hash table never references local symbols so
Packit 6c4009
		     we can omit that test here.  */
Packit Service b4e251
		  symndx = ELF_MACHINE_HASH_SYMIDX (match, hasharr);
Packit 6c4009
		  if ((symtab[symndx].st_shndx != SHN_UNDEF
Packit 6c4009
		       || symtab[symndx].st_value != 0)
Packit 6c4009
		      && symtab[symndx].st_shndx != SHN_ABS
Packit 6c4009
		      && ELFW(ST_TYPE) (symtab[symndx].st_info) != STT_TLS
Packit 6c4009
		      && DL_ADDR_SYM_MATCH (match, &symtab[symndx],
Packit 6c4009
					    matchsym, addr)
Packit 6c4009
		      && symtab[symndx].st_name < strtabsize)
Packit 6c4009
		    matchsym = (ElfW(Sym) *) &symtab[symndx];
Packit 6c4009
		}
Packit 6c4009
	      while ((*hasharr++ & 1u) == 0);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      const ElfW(Sym) *symtabend;
Packit 6c4009
      if (match->l_info[DT_HASH] != NULL)
Packit 6c4009
	symtabend = (symtab
Packit 6c4009
		     + ((Elf_Symndx *) D_PTR (match, l_info[DT_HASH]))[1]);
Packit 6c4009
      else
Packit 6c4009
	/* There is no direct way to determine the number of symbols in the
Packit 6c4009
	   dynamic symbol table and no hash table is present.  The ELF
Packit 6c4009
	   binary is ill-formed but what shall we do?  Use the beginning of
Packit 6c4009
	   the string table which generally follows the symbol table.  */
Packit 6c4009
	symtabend = (const ElfW(Sym) *) strtab;
Packit 6c4009
Packit 6c4009
      for (; (void *) symtab < (void *) symtabend; ++symtab)
Packit 6c4009
	if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
Packit 6c4009
	     || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)
Packit 6c4009
	    && __glibc_likely (!dl_symbol_visibility_binds_local_p (symtab))
Packit 6c4009
	    && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS
Packit 6c4009
	    && (symtab->st_shndx != SHN_UNDEF
Packit 6c4009
		|| symtab->st_value != 0)
Packit 6c4009
	    && symtab->st_shndx != SHN_ABS
Packit 6c4009
	    && DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr)
Packit 6c4009
	    && symtab->st_name < strtabsize)
Packit 6c4009
	  matchsym = (ElfW(Sym) *) symtab;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (mapp)
Packit 6c4009
    *mapp = match;
Packit 6c4009
  if (symbolp)
Packit 6c4009
    *symbolp = matchsym;
Packit 6c4009
Packit 6c4009
  if (matchsym)
Packit 6c4009
    {
Packit 6c4009
      /* We found a symbol close by.  Fill in its name and exact
Packit 6c4009
	 address.  */
Packit 6c4009
      lookup_t matchl = LOOKUP_VALUE (match);
Packit 6c4009
Packit 6c4009
      info->dli_sname = strtab + matchsym->st_name;
Packit 6c4009
      info->dli_saddr = DL_SYMBOL_ADDRESS (matchl, matchsym);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* No symbol matches.  We return only the containing object.  */
Packit 6c4009
      info->dli_sname = NULL;
Packit 6c4009
      info->dli_saddr = NULL;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_dl_addr (const void *address, Dl_info *info,
Packit 6c4009
	  struct link_map **mapp, const ElfW(Sym) **symbolp)
Packit 6c4009
{
Packit 6c4009
  const ElfW(Addr) addr = DL_LOOKUP_ADDRESS (address);
Packit 6c4009
  int result = 0;
Packit 6c4009
Packit 6c4009
  /* Protect against concurrent loads and unloads.  */
Packit 6c4009
  __rtld_lock_lock_recursive (GL(dl_load_lock));
Packit 6c4009
Packit 6c4009
  struct link_map *l = _dl_find_dso_for_object (addr);
Packit 6c4009
Packit 6c4009
  if (l)
Packit 6c4009
    {
Packit 6c4009
      determine_info (addr, l, info, mapp, symbolp);
Packit 6c4009
      result = 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_dl_addr)