Blame libdwfl/dwfl_module_getsym.c

Packit 032894
/* Find debugging and symbol information for a module in libdwfl.
Packit 032894
   Copyright (C) 2006-2014 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include "libdwflP.h"
Packit 032894
Packit 032894
const char *
Packit 032894
internal_function
Packit 032894
__libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, GElf_Addr *addr,
Packit 032894
		  GElf_Word *shndxp, Elf **elfp, Dwarf_Addr *biasp,
Packit 032894
		  bool *resolved, bool adjust_st_value)
Packit 032894
{
Packit 032894
  if (unlikely (mod == NULL))
Packit 032894
    return NULL;
Packit 032894
Packit 032894
  if (unlikely (mod->symdata == NULL))
Packit 032894
    {
Packit 032894
      int result = INTUSE(dwfl_module_getsymtab) (mod);
Packit 032894
      if (result < 0)
Packit 032894
	return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  /* All local symbols should come before all global symbols.  If we
Packit 032894
     have an auxiliary table make sure all the main locals come first,
Packit 032894
     then all aux locals, then all main globals and finally all aux globals.
Packit 032894
     And skip the auxiliary table zero undefined entry.  */
Packit 032894
  GElf_Word shndx;
Packit 032894
  int tndx = ndx;
Packit 032894
  int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0;
Packit 032894
  Elf *elf;
Packit 032894
  Elf_Data *symdata;
Packit 032894
  Elf_Data *symxndxdata;
Packit 032894
  Elf_Data *symstrdata;
Packit 032894
  if (mod->aux_symdata == NULL
Packit 032894
      || ndx < mod->first_global)
Packit 032894
    {
Packit 032894
      /* main symbol table (locals).  */
Packit 032894
      tndx = ndx;
Packit 032894
      elf = mod->symfile->elf;
Packit 032894
      symdata = mod->symdata;
Packit 032894
      symxndxdata = mod->symxndxdata;
Packit 032894
      symstrdata = mod->symstrdata;
Packit 032894
    }
Packit 032894
  else if (ndx < mod->first_global + mod->aux_first_global - skip_aux_zero)
Packit 032894
    {
Packit 032894
      /* aux symbol table (locals).  */
Packit 032894
      tndx = ndx - mod->first_global + skip_aux_zero;
Packit 032894
      elf = mod->aux_sym.elf;
Packit 032894
      symdata = mod->aux_symdata;
Packit 032894
      symxndxdata = mod->aux_symxndxdata;
Packit 032894
      symstrdata = mod->aux_symstrdata;
Packit 032894
    }
Packit 032894
  else if ((size_t) ndx < mod->syments + mod->aux_first_global - skip_aux_zero)
Packit 032894
    {
Packit 032894
      /* main symbol table (globals).  */
Packit 032894
      tndx = ndx - mod->aux_first_global + skip_aux_zero;
Packit 032894
      elf = mod->symfile->elf;
Packit 032894
      symdata = mod->symdata;
Packit 032894
      symxndxdata = mod->symxndxdata;
Packit 032894
      symstrdata = mod->symstrdata;
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      /* aux symbol table (globals).  */
Packit 032894
      tndx = ndx - mod->syments + skip_aux_zero;
Packit 032894
      elf = mod->aux_sym.elf;
Packit 032894
      symdata = mod->aux_symdata;
Packit 032894
      symxndxdata = mod->aux_symxndxdata;
Packit 032894
      symstrdata = mod->aux_symstrdata;
Packit 032894
    }
Packit 032894
  sym = gelf_getsymshndx (symdata, symxndxdata, tndx, sym, &shndx);
Packit 032894
Packit 032894
  if (unlikely (sym == NULL))
Packit 032894
    {
Packit 032894
      __libdwfl_seterrno (DWFL_E_LIBELF);
Packit 032894
      return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  if (sym->st_shndx != SHN_XINDEX)
Packit 032894
    shndx = sym->st_shndx;
Packit 032894
Packit 032894
  /* Figure out whether this symbol points into an SHF_ALLOC section.  */
Packit 032894
  bool alloc = true;
Packit 032894
  if ((shndxp != NULL || mod->e_type != ET_REL)
Packit 032894
      && (sym->st_shndx == SHN_XINDEX
Packit 032894
	  || (sym->st_shndx < SHN_LORESERVE && sym->st_shndx != SHN_UNDEF)))
Packit 032894
    {
Packit 032894
      GElf_Shdr shdr_mem;
Packit 032894
      GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, shndx), &shdr_mem);
Packit 032894
      alloc = unlikely (shdr == NULL) || (shdr->sh_flags & SHF_ALLOC);
Packit 032894
    }
Packit 032894
Packit 032894
  /* In case of an value in an allocated section the main Elf Ebl
Packit 032894
     might know where the real value is (e.g. for function
Packit 032894
     descriptors).  */
Packit 032894
Packit 032894
  char *ident;
Packit 032894
  GElf_Addr st_value = sym->st_value & ebl_func_addr_mask (mod->ebl);
Packit 032894
  *resolved = false;
Packit 032894
  if (! adjust_st_value && mod->e_type != ET_REL && alloc
Packit 032894
      && (GELF_ST_TYPE (sym->st_info) == STT_FUNC
Packit 032894
	  || (GELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
Packit 032894
	      && (ident = elf_getident (elf, NULL)) != NULL
Packit 032894
	      && ident[EI_OSABI] == ELFOSABI_LINUX)))
Packit 032894
    {
Packit 032894
      if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR))
Packit 032894
	{
Packit 032894
	  if (elf != mod->main.elf)
Packit 032894
	    {
Packit 032894
	      st_value = dwfl_adjusted_st_value (mod, elf, st_value);
Packit 032894
	      st_value = dwfl_deadjust_st_value (mod, mod->main.elf, st_value);
Packit 032894
	    }
Packit 032894
Packit 032894
	  *resolved = ebl_resolve_sym_value (mod->ebl, &st_value);
Packit 032894
	  if (! *resolved)
Packit 032894
	    st_value = sym->st_value;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  if (shndxp != NULL)
Packit 032894
    /* Yield -1 in case of a non-SHF_ALLOC section.  */
Packit 032894
    *shndxp = alloc ? shndx : (GElf_Word) -1;
Packit 032894
Packit 032894
  switch (sym->st_shndx)
Packit 032894
    {
Packit 032894
    case SHN_ABS:		/* XXX sometimes should use bias?? */
Packit 032894
    case SHN_UNDEF:
Packit 032894
    case SHN_COMMON:
Packit 032894
      break;
Packit 032894
Packit 032894
    default:
Packit 032894
      if (mod->e_type == ET_REL)
Packit 032894
	{
Packit 032894
	  /* In an ET_REL file, the symbol table values are relative
Packit 032894
	     to the section, not to the module's load base.  */
Packit 032894
	  size_t symshstrndx = SHN_UNDEF;
Packit 032894
	  Dwfl_Error result = __libdwfl_relocate_value (mod, elf,
Packit 032894
							&symshstrndx,
Packit 032894
							shndx, &st_value);
Packit 032894
	  if (unlikely (result != DWFL_E_NOERROR))
Packit 032894
	    {
Packit 032894
	      __libdwfl_seterrno (result);
Packit 032894
	      return NULL;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
      else if (alloc)
Packit 032894
	/* Apply the bias to the symbol value.  */
Packit 032894
	st_value = dwfl_adjusted_st_value (mod,
Packit 032894
					   *resolved ? mod->main.elf : elf,
Packit 032894
					   st_value);
Packit 032894
      break;
Packit 032894
    }
Packit 032894
Packit 032894
  if (adjust_st_value)
Packit 032894
    sym->st_value = st_value;
Packit 032894
Packit 032894
  if (addr != NULL)
Packit 032894
    *addr = st_value;
Packit 032894
Packit 032894
  if (unlikely (sym->st_name >= symstrdata->d_size))
Packit 032894
    {
Packit 032894
      __libdwfl_seterrno (DWFL_E_BADSTROFF);
Packit 032894
      return NULL;
Packit 032894
    }
Packit 032894
  if (elfp)
Packit 032894
    *elfp = elf;
Packit 032894
  if (biasp)
Packit 032894
    *biasp = dwfl_adjusted_st_value (mod, elf, 0);
Packit 032894
  return (const char *) symstrdata->d_buf + sym->st_name;
Packit 032894
}
Packit 032894
Packit 032894
const char *
Packit 032894
dwfl_module_getsym_info (Dwfl_Module *mod, int ndx,
Packit 032894
			 GElf_Sym *sym, GElf_Addr *addr,
Packit 032894
			 GElf_Word *shndxp,
Packit 032894
			 Elf **elfp, Dwarf_Addr *bias)
Packit 032894
{
Packit 032894
  bool resolved;
Packit 032894
  return __libdwfl_getsym (mod, ndx, sym, addr, shndxp, elfp, bias,
Packit 032894
			   &resolved, false);
Packit 032894
}
Packit 032894
INTDEF (dwfl_module_getsym_info)
Packit 032894
Packit 032894
const char *
Packit 032894
dwfl_module_getsym (Dwfl_Module *mod, int ndx,
Packit 032894
		    GElf_Sym *sym, GElf_Word *shndxp)
Packit 032894
{
Packit 032894
  bool resolved;
Packit 032894
  return __libdwfl_getsym (mod, ndx, sym, NULL, shndxp, NULL, NULL,
Packit 032894
			   &resolved, true);
Packit 032894
}
Packit 032894
INTDEF (dwfl_module_getsym)