Home | History | Annotate | Download | only in libdwfl
      1 /* Find debugging and symbol information for a module in libdwfl.
      2    Copyright (C) 2006-2014 Red Hat, Inc.
      3    This file is part of elfutils.
      4 
      5    This file is free software; you can redistribute it and/or modify
      6    it under the terms of either
      7 
      8      * the GNU Lesser General Public License as published by the Free
      9        Software Foundation; either version 3 of the License, or (at
     10        your option) any later version
     11 
     12    or
     13 
     14      * the GNU General Public License as published by the Free
     15        Software Foundation; either version 2 of the License, or (at
     16        your option) any later version
     17 
     18    or both in parallel, as here.
     19 
     20    elfutils is distributed in the hope that it will be useful, but
     21    WITHOUT ANY WARRANTY; without even the implied warranty of
     22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     23    General Public License for more details.
     24 
     25    You should have received copies of the GNU General Public License and
     26    the GNU Lesser General Public License along with this program.  If
     27    not, see <http://www.gnu.org/licenses/>.  */
     28 
     29 #include "libdwflP.h"
     30 
     31 const char *
     32 internal_function
     33 __libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, GElf_Addr *addr,
     34 		  GElf_Word *shndxp, Elf **elfp, Dwarf_Addr *biasp,
     35 		  bool *resolved, bool adjust_st_value)
     36 {
     37   if (unlikely (mod == NULL))
     38     return NULL;
     39 
     40   if (unlikely (mod->symdata == NULL))
     41     {
     42       int result = INTUSE(dwfl_module_getsymtab) (mod);
     43       if (result < 0)
     44 	return NULL;
     45     }
     46 
     47   /* All local symbols should come before all global symbols.  If we
     48      have an auxiliary table make sure all the main locals come first,
     49      then all aux locals, then all main globals and finally all aux globals.
     50      And skip the auxiliary table zero undefined entry.  */
     51   GElf_Word shndx;
     52   int tndx = ndx;
     53   int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0;
     54   Elf *elf;
     55   Elf_Data *symdata;
     56   Elf_Data *symxndxdata;
     57   Elf_Data *symstrdata;
     58   if (mod->aux_symdata == NULL
     59       || ndx < mod->first_global)
     60     {
     61       /* main symbol table (locals).  */
     62       tndx = ndx;
     63       elf = mod->symfile->elf;
     64       symdata = mod->symdata;
     65       symxndxdata = mod->symxndxdata;
     66       symstrdata = mod->symstrdata;
     67     }
     68   else if (ndx < mod->first_global + mod->aux_first_global - skip_aux_zero)
     69     {
     70       /* aux symbol table (locals).  */
     71       tndx = ndx - mod->first_global + skip_aux_zero;
     72       elf = mod->aux_sym.elf;
     73       symdata = mod->aux_symdata;
     74       symxndxdata = mod->aux_symxndxdata;
     75       symstrdata = mod->aux_symstrdata;
     76     }
     77   else if ((size_t) ndx < mod->syments + mod->aux_first_global - skip_aux_zero)
     78     {
     79       /* main symbol table (globals).  */
     80       tndx = ndx - mod->aux_first_global + skip_aux_zero;
     81       elf = mod->symfile->elf;
     82       symdata = mod->symdata;
     83       symxndxdata = mod->symxndxdata;
     84       symstrdata = mod->symstrdata;
     85     }
     86   else
     87     {
     88       /* aux symbol table (globals).  */
     89       tndx = ndx - mod->syments + skip_aux_zero;
     90       elf = mod->aux_sym.elf;
     91       symdata = mod->aux_symdata;
     92       symxndxdata = mod->aux_symxndxdata;
     93       symstrdata = mod->aux_symstrdata;
     94     }
     95   sym = gelf_getsymshndx (symdata, symxndxdata, tndx, sym, &shndx);
     96 
     97   if (unlikely (sym == NULL))
     98     {
     99       __libdwfl_seterrno (DWFL_E_LIBELF);
    100       return NULL;
    101     }
    102 
    103   if (sym->st_shndx != SHN_XINDEX)
    104     shndx = sym->st_shndx;
    105 
    106   /* Figure out whether this symbol points into an SHF_ALLOC section.  */
    107   bool alloc = true;
    108   if ((shndxp != NULL || mod->e_type != ET_REL)
    109       && (sym->st_shndx == SHN_XINDEX
    110 	  || (sym->st_shndx < SHN_LORESERVE && sym->st_shndx != SHN_UNDEF)))
    111     {
    112       GElf_Shdr shdr_mem;
    113       GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, shndx), &shdr_mem);
    114       alloc = unlikely (shdr == NULL) || (shdr->sh_flags & SHF_ALLOC);
    115     }
    116 
    117   /* In case of an value in an allocated section the main Elf Ebl
    118      might know where the real value is (e.g. for function
    119      descriptors).  */
    120 
    121   char *ident;
    122   GElf_Addr st_value = sym->st_value & ebl_func_addr_mask (mod->ebl);
    123   *resolved = false;
    124   if (! adjust_st_value && mod->e_type != ET_REL && alloc
    125       && (GELF_ST_TYPE (sym->st_info) == STT_FUNC
    126 	  || (GELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
    127 	      && (ident = elf_getident (elf, NULL)) != NULL
    128 	      && ident[EI_OSABI] == ELFOSABI_LINUX)))
    129     {
    130       if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR))
    131 	{
    132 	  if (elf != mod->main.elf)
    133 	    {
    134 	      st_value = dwfl_adjusted_st_value (mod, elf, st_value);
    135 	      st_value = dwfl_deadjust_st_value (mod, mod->main.elf, st_value);
    136 	    }
    137 
    138 	  *resolved = ebl_resolve_sym_value (mod->ebl, &st_value);
    139 	  if (! *resolved)
    140 	    st_value = sym->st_value;
    141 	}
    142     }
    143 
    144   if (shndxp != NULL)
    145     /* Yield -1 in case of a non-SHF_ALLOC section.  */
    146     *shndxp = alloc ? shndx : (GElf_Word) -1;
    147 
    148   switch (sym->st_shndx)
    149     {
    150     case SHN_ABS:		/* XXX sometimes should use bias?? */
    151     case SHN_UNDEF:
    152     case SHN_COMMON:
    153       break;
    154 
    155     default:
    156       if (mod->e_type == ET_REL)
    157 	{
    158 	  /* In an ET_REL file, the symbol table values are relative
    159 	     to the section, not to the module's load base.  */
    160 	  size_t symshstrndx = SHN_UNDEF;
    161 	  Dwfl_Error result = __libdwfl_relocate_value (mod, elf,
    162 							&symshstrndx,
    163 							shndx, &st_value);
    164 	  if (unlikely (result != DWFL_E_NOERROR))
    165 	    {
    166 	      __libdwfl_seterrno (result);
    167 	      return NULL;
    168 	    }
    169 	}
    170       else if (alloc)
    171 	/* Apply the bias to the symbol value.  */
    172 	st_value = dwfl_adjusted_st_value (mod,
    173 					   *resolved ? mod->main.elf : elf,
    174 					   st_value);
    175       break;
    176     }
    177 
    178   if (adjust_st_value)
    179     sym->st_value = st_value;
    180 
    181   if (addr != NULL)
    182     *addr = st_value;
    183 
    184   if (unlikely (sym->st_name >= symstrdata->d_size))
    185     {
    186       __libdwfl_seterrno (DWFL_E_BADSTROFF);
    187       return NULL;
    188     }
    189   if (elfp)
    190     *elfp = elf;
    191   if (biasp)
    192     *biasp = dwfl_adjusted_st_value (mod, elf, 0);
    193   return (const char *) symstrdata->d_buf + sym->st_name;
    194 }
    195 
    196 const char *
    197 dwfl_module_getsym_info (Dwfl_Module *mod, int ndx,
    198 			 GElf_Sym *sym, GElf_Addr *addr,
    199 			 GElf_Word *shndxp,
    200 			 Elf **elfp, Dwarf_Addr *bias)
    201 {
    202   bool resolved;
    203   return __libdwfl_getsym (mod, ndx, sym, addr, shndxp, elfp, bias,
    204 			   &resolved, false);
    205 }
    206 INTDEF (dwfl_module_getsym_info)
    207 
    208 const char *
    209 dwfl_module_getsym (Dwfl_Module *mod, int ndx,
    210 		    GElf_Sym *sym, GElf_Word *shndxp)
    211 {
    212   bool resolved;
    213   return __libdwfl_getsym (mod, ndx, sym, NULL, shndxp, NULL, NULL,
    214 			   &resolved, true);
    215 }
    216 INTDEF (dwfl_module_getsym)
    217