[PATCH] Introduce dwfl_module_getsym_info and dwfl_module_addrinfo.

Jan Kratochvil jan.kratochvil at redhat.com
Thu Dec 12 21:11:27 UTC 2013


On Thu, 12 Dec 2013 11:51:37 +0100, Mark Wielaard wrote:
> --- /dev/null
> +++ b/backends/ppc64_resolve_sym.c
> @@ -0,0 +1,63 @@
> +/* Resolve symbol values through .opd function descriptors.
> +   Copyright (C) 2013 Red Hat, Inc.
> +   This file is part of elfutils.
> +
> +   This file is free software; you can redistribute it and/or modify
> +   it under the terms of either
> +
> +     * the GNU Lesser General Public License as published by the Free
> +       Software Foundation; either version 3 of the License, or (at
> +       your option) any later version
> +
> +   or
> +
> +     * the GNU General Public License as published by the Free
> +       Software Foundation; either version 2 of the License, or (at
> +       your option) any later version
> +
> +   or both in parallel, as here.
> +
> +   elfutils is distributed in the hope that it will be useful, but
> +   WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   General Public License for more details.
> +
> +   You should have received copies of the GNU General Public License and
> +   the GNU Lesser General Public License along with this program.  If
> +   not, see <http://www.gnu.org/licenses/>.  */
> +
> +#ifdef HAVE_CONFIG_H
> +# include <config.h>
> +#endif
> +
> +#define BACKEND ppc64_
> +#include "libebl_CPU.h"
> +
> +/* Resolve a function descriptor if addr points into the .odp section.
> +   The .odp section contains function descriptors consisting of 3 addresses.
> +   function, toc and chain. We are just interested in the first.
> +   http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#FUNC-DES
> +
> +   Returns true if the given address could be resolved, false otherwise.
> +*/
> +bool
> +ppc64_resolve_sym_value (Ebl *ebl, GElf_Addr *addr)
> +{
> +  if (ebl->fd_data != NULL && *addr >= ebl->fd_addr

> +      && *addr < ebl->fd_addr + ebl->fd_data->d_size)

         && *addr + sizeof (Elf64_Addr) <= ebl->fd_addr + ebl->fd_data->d_size)

> +    {
> +      GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (ebl->elf, &ehdr_mem);
> +      if (ehdr != NULL)
> +	{
> +	  Elf_Data opd_in, opd_out;
> +	  opd_in.d_buf = ebl->fd_data->d_buf + (*addr - ebl->fd_addr);
> +	  opd_out.d_buf = addr;
> +	  opd_out.d_size = opd_in.d_size = sizeof (Elf64_Addr);
> +	  opd_out.d_type = opd_in.d_type = ELF_T_ADDR;
> +	  if (elf64_xlatetom (&opd_out, &opd_in,
> +			      ehdr->e_ident[EI_DATA]) != NULL)
> +	    return true;
> +	}
> +    }
> +  return false;
> +}
> diff --git a/libdw/ChangeLog b/libdw/ChangeLog
> index 91e1083..1efe0dc 100644
> --- a/libdw/ChangeLog
> +++ b/libdw/ChangeLog
> @@ -1,3 +1,10 @@
> +2013-12-11  Mark Wielaard  <mjw at redhat.com>
> +
> +	* libdw.map (ELFUTILS_0.158): Remove dwfl_module_addrsym_elf and
> +	dwfl_module_getsym_elf. Add dwfl_module_addrinfo,
> +	dwfl_module_addrinfo_elf, dwfl_module_getsym_info and
> +	dwfl_module_getsym_info_elf.
> +
>  2013-11-27  Mark Wielaard  <mjw at redhat.com>
>  
>  	* libdw.map (ELFUTILS_0.158): Add dwfl_module_addrsym_elf and
> diff --git a/libdw/libdw.map b/libdw/libdw.map
> index 0438e24..6d21101 100644
> --- a/libdw/libdw.map
> +++ b/libdw/libdw.map
> @@ -284,6 +284,8 @@ ELFUTILS_0.158 {
>      dwfl_thread_getframes;
>      dwfl_frame_pc;
>  
> -    dwfl_module_addrsym_elf;
> -    dwfl_module_getsym_elf;
> +    dwfl_module_addrinfo;
> +    dwfl_module_addrinfo_elf;
> +    dwfl_module_getsym_info;
> +    dwfl_module_getsym_info_elf;

FYI my opinion is that there is no benefit to have the functions
dwfl_module_addrinfo and dwfl_module_getsym_info.  One can use just the *_elf
ones.


>  } ELFUTILS_0.157;
> diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
> index 7e87e17..51027e4 100644
> --- a/libdwfl/ChangeLog
> +++ b/libdwfl/ChangeLog
> @@ -1,3 +1,39 @@
> +2013-12-11  Mark Wielaard  <mjw at redhat.com>
> +
> +	* derelocate.c (__libdwfl_find_section_ndx): New internal function.
> +	* dwfl_module_addrname.c (dwfl_module_addrname): Use
> +	dwfl_module_addrinfo.
> +	* dwfl_module_addrsym.c (dwfl_module_addrsym_elf): Replace with...
> +	(__libdwfl_addrsym): ...this. Use __libdwfl_getsym, use value
> +	for comparisons, not st_value. Fill in off.
> +	(dwfl_module_addrsym): Implement using __libdwfl_addrsym.
> +	(dwfl_module_addrinfo): New function.
> +	(dwfl_module_addrinfo_elf): Likewise.
> +	* dwfl_module_getsym.c (dwfl_module_getsym_elf): Replace with...
> +	(__libdwfl_getsym): ...this. Use ebl_resolve_sym_value if requested
> +	and possible. Adjust sym->st_value only when requested. Fill in addr
> +	if available.
> +	(dwfl_module_getsym_info): New function.
> +	(dwfl_module_getsym_info_elf): New function.
> +	(dwfl_module_getsym): Use __libdwfl_getsym.
> +	* libdwfl.h (dwfl_module_getsym_elf): Removed.
> +	(dwfl_module_getsym_info): New function declaration.
> +	(dwfl_module_getsym_info_elf): Likewise.
> +	(dwfl_module_addrinfo): Likewise.
> +	(dwfl_module_addrinfo_elf): Likewise.
> +	(dwfl_module_addrsym): Add documentation describing differences
> +	with addrinfo variants.
> +	(dwfl_module_addrsym_elf): Removed.
> +	* libdwflP.h (__libdwfl_getsym): New internal function declaration.
> +	(__libdwfl_addrsym): Likewise.
> +	(__libdwfl_find_section_ndx): Likewise.
> +	(dwfl_module_addrinfo): New internal declaration.
> +	(dwfl_module_addrinfo_elf): Likewise.
> +	(dwfl_module_addrsym_elf): Removed.
> +	(dwfl_module_getsym_elf): Likewise.
> +	(dwfl_module_getsym_info): New internal declaration.
> +	(dwfl_module_getsym_info_elf): Likewise.
> +
>  2013-11-30  Jan Kratochvil  <jan.kratochvil at redhat.com>
>  
>  	Introduce process_attach_error.
> diff --git a/libdwfl/derelocate.c b/libdwfl/derelocate.c
> index 56f998c..da67908 100644
> --- a/libdwfl/derelocate.c
> +++ b/libdwfl/derelocate.c
> @@ -1,5 +1,5 @@
>  /* Recover relocatibility for addresses computed from debug information.
> -   Copyright (C) 2005-2010 Red Hat, Inc.
> +   Copyright (C) 2005-2010, 2013 Red Hat, Inc.
>     This file is part of elfutils.
>  
>     This file is free software; you can redistribute it and/or modify
> @@ -330,6 +330,17 @@ find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
>    return -1;
>  }
>  
> +size_t
> +internal_function
> +__libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr)
> +{
> +  int idx = find_section (mod, addr);

I see I did not know there is find_section ().


> +  if (unlikely (idx == -1))
> +    return SHN_UNDEF;
> +
> +  return elf_ndxscn (mod->reloc_info->refs[idx].scn);
> +}
> +
>  int
>  dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
>  {
[...]
> --- a/libdwfl/libdwfl.h
> +++ b/libdwfl/libdwfl.h
> @@ -445,34 +445,75 @@ extern const char *dwfl_module_getsym (Dwfl_Module *mod, int ndx,
>  				       GElf_Sym *sym, GElf_Word *shndxp)
>    __nonnull_attribute__ (3);
>  
> -/* Same as dwfl_module_getsym but also returns the ELF file, if not NULL,
> -   that the symbol came from so the section index can be reliably used.
> -   Fills in *BIAS, if not NULL, with the difference between addresses
> -   within the loaded module and those in symbol tables of the ELF file. */
> -extern const char *dwfl_module_getsym_elf (Dwfl_Module *mod, int ndx,
> -				           GElf_Sym *sym, GElf_Word *shndxp,
> -					   Elf **elfp, Dwarf_Addr *bias)
> -  __nonnull_attribute__ (3);
> +/* Fetch one entry from the module's symbol table and the associated
> +   address value. On errors, returns NULL.  If successful, fills in
> +   *SYM, *ADDR and returns the string for st_name.  This works like
> +   gelf_getsym. *ADDR is set to the st_value adjusted to an absolute
> +   value based on the module's location, when the symbol is in an
> +   SHF_ALLOC section. For non-ET_REL files, if the arch uses function
> +   descriptors, and the st_value points to one, the value will be
> +   resolved to the actual function address. Note that since symbols
> +   can come from either the main, debug or auxiliary ELF symbol file
> +   (either dynsym or symtab) and the st_value itself isn't adjusted in
> +   any way (this is different from dwfl_module_getsym).  */

The sentence is unfinished.


> +extern const char *dwfl_module_getsym_info (Dwfl_Module *mod, int ndx,
> +					    GElf_Sym *sym, GElf_Addr *addr)
> +  __nonnull_attribute__ (3, 4);
> +
> +/* Same as dwfl_module_getsym_info but also returns the section index,
> +   the ELF file and bias. If SHNDXP is non-null, it's set with the
> +   section index (whether from st_shndx or extended index table); in
> +   case of a symbol in a non-allocated section, *SHNDXP is instead set
> +   to -1.  Fills in BIAS, if not NULL, with the difference between

It is uint32_t so maybe the doc could say s/-1/0xffffffff/.  But maybe it was
intentional.

> +   addresses within the loaded module and those in symbol tables of
> +   the ELF file.  Note that the address associated with the symbol
> +   might be a different section (and ELF file) than the returned
> +   symbol.  That section, in the main elf file, can be found with
> +   dwfl_module_address_section. */
> +extern const char *dwfl_module_getsym_info_elf (Dwfl_Module *mod, int ndx,
> +						GElf_Sym *sym, GElf_Addr *addr,
> +						GElf_Word *shndxp,
> +						Elf **elfp, Dwarf_Addr *bias)
> +  __nonnull_attribute__ (3, 4);
>  
>  /* Find the symbol that ADDRESS lies inside, and return its name.  */
>  extern const char *dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr address);
>  
> +/* Find the symbol associated with ADDRESS, return its name, the
> +   OFFSET that ADDRESS is from the start and optionally the originally

I cannot parse the sentence.
s/from the start/from the address of returned SYM/ ?
s/originally// ?

> +   SYM associated with the ADDRESS.  Note that the address is matched
> +   against the, possibly resolved (for function descriptor symbols),
> +   and adjusted st_value for the Dwfl_Module location. The SYM->st_value
> +   itself isn't changed.  */
> +extern const char *dwfl_module_addrinfo (Dwfl_Module *mod, GElf_Addr address,
> +					 GElf_Off *offset, GElf_Sym *sym)
> +  __nonnull_attribute__ (3, 4);
> +
> +/* Same as dwfl_module_addrinfo but also returns the ELF file, if not
> +   NULL, that the symbol originally came from. If SHNDXP is non-null,
> +   it's set with the section index (whether from st_shndx or extended
> +   index table); in case of a symbol in a non-allocated section,
> +   *SHNDXP is instead set to -1.  Fills in *BIAS, if not NULL, with

It is uint32_t so maybe the doc could say s/-1/0xffffffff/.  But maybe it was
intentional.

> +   the difference between addresses within the loaded module and those
> +   in the symbol table of the ELF file. */
> +extern const char *dwfl_module_addrinfo_elf (Dwfl_Module *mod,
> +					     GElf_Addr address,
> +					     GElf_Off *offset,
> +					     GElf_Sym *sym,
> +					     GElf_Word *shndxp,
> +					     Elf **elfp, Dwarf_Addr *bias)
> +  __nonnull_attribute__ (3);
> +
>  /* Find the symbol that ADDRESS lies inside, and return detailed
> -   information as for dwfl_module_getsym (above).  */
> +   information as for dwfl_module_getsym (above).  Note that unlike
> +   dwfl_module_addrname and dwfl_module_addrinfo this matches ADDRESS
> +   against the adjusted SYM->ST_VALUE directly, so might depending on
> +   whether the architecture uses indirections like function descriptors,
> +   not match against actual function addresses.  */

I cannot parse the sentence, I hope it is clear it is formed incorrectly.
It would be good to know whether it finds function entry addresses and whether
it finds function descriptor addresses.

>  extern const char *dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr address,
>  					GElf_Sym *sym, GElf_Word *shndxp)
>    __nonnull_attribute__ (3);
>  
> -/* Same as dwfl_module_addrsym but also returns the ELF file, if not NULL,
> -   that the symbol came from so the section index can be reliably used.
> -   Fills in *BIAS, if not NULL, with the difference between addresses
> -   within the loaded module and those in symbol tables of the ELF file. */
> -extern const char *dwfl_module_addrsym_elf (Dwfl_Module *mod,
> -					    GElf_Addr address, GElf_Sym *sym,
> -					    GElf_Word *shndxp, Elf **elfp,
> -					    Dwarf_Addr *bias)
> -  __nonnull_attribute__ (3);
> -
>  /* Find the ELF section that *ADDRESS lies inside and return it.
>     On success, adjusts *ADDRESS to be relative to the section,
>     and sets *BIAS to the difference between addresses used in
> diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
> index ba1c758..d931eac 100644
> --- a/libdwfl/libdwflP.h
> +++ b/libdwfl/libdwflP.h
> @@ -388,6 +388,22 @@ struct dwfl_arange
>  };
>  
>  
> +/* Internal wrapper for old dwfl_module_getsym and new dwfl_module_getsym_info.
> +   adjust_st_value set to true returns adjusted SYM st_value, set to false
> +   it will not adjust SYM at all, but does match against resolved *ADDR. */
> +extern const char *__libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym,
> +				     GElf_Addr *addr, GElf_Word *shndxp,
> +				     Elf **elfp, Dwarf_Addr *biasp,
> +				     bool adjust_st_value) internal_function;
> +
> +/* Internal wrapper for old dwfl_module_addrsym and new dwfl_module_addrinfo.
> +   adjust_st_value set to true returns adjusted SYM st_value, set to false
> +   it will not adjust SYM at all, but does match against resolved values. */
> +extern const char *__libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr,
> +				      GElf_Off *off, GElf_Sym *sym,
> +				      GElf_Word *shndxp, Elf **elfp,
> +				      Dwarf_Addr *bias,
> +				      bool adjust_st_value) internal_function;
>  
>  extern void __libdwfl_module_free (Dwfl_Module *mod) internal_function;
>  
> @@ -404,6 +420,12 @@ extern void __libdwfl_getelf (Dwfl_Module *mod) internal_function;
>  extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *mod, Elf *file, bool debug)
>    internal_function;
>  
> +/* Find the section index in mod->main.elf that contains the given
> +   *ADDR.  Adjusts *ADDR to be section relative on success, returns
> +   SHN_UNDEF on failure.  */
> +extern size_t __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr)
> +  internal_function;
> +
>  /* Process (simple) relocations in arbitrary section TSCN of an ET_REL file.
>     RELOCSCN is SHT_REL or SHT_RELA and TSCN is its sh_info target section.  */
>  extern Dwfl_Error __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
> @@ -638,13 +660,15 @@ INTDECL (dwfl_core_file_report)
>  INTDECL (dwfl_getmodules)
>  INTDECL (dwfl_module_addrdie)
>  INTDECL (dwfl_module_address_section)
> +INTDECL (dwfl_module_addrinfo)
> +INTDECL (dwfl_module_addrinfo_elf)
>  INTDECL (dwfl_module_addrsym)
> -INTDECL (dwfl_module_addrsym_elf)
>  INTDECL (dwfl_module_build_id)
>  INTDECL (dwfl_module_getdwarf)
>  INTDECL (dwfl_module_getelf)
>  INTDECL (dwfl_module_getsym)
> -INTDECL (dwfl_module_getsym_elf)
> +INTDECL (dwfl_module_getsym_info)
> +INTDECL (dwfl_module_getsym_info_elf)
>  INTDECL (dwfl_module_getsymtab)
>  INTDECL (dwfl_module_getsrc)
>  INTDECL (dwfl_module_report_build_id)
> diff --git a/libebl/ChangeLog b/libebl/ChangeLog
> index a5c9dae..0144c4e 100644
> --- a/libebl/ChangeLog
> +++ b/libebl/ChangeLog
> @@ -1,3 +1,12 @@
> +2013-12-11  Mark Wielaard  <mjw at redhat.com>
> +
> +	* Makefile.am (gen_SOURCES): Add eblresolvesym.c.
> +	* ebl-hooks.h (resolve_sym_value): New entry.
> +	* eblresolvesym.c: New file.
> +	* libebl.h (ebl_resolve_sym_value): New definition.
> +	* libeblP.h (fd_addr): New field.
> +	(fd_data): Likewise.
> +
>  2013-11-25  Petr Machata  <pmachata at redhat.com>
>  
>  	* eblopenbackend.c (machines): Add entry for AArch64.
> diff --git a/libebl/Makefile.am b/libebl/Makefile.am
> index 4487c5f..5322315 100644
> --- a/libebl/Makefile.am
> +++ b/libebl/Makefile.am
> @@ -54,7 +54,7 @@ gen_SOURCES = eblopenbackend.c eblclosebackend.c eblstrtab.c \
>  	      eblreginfo.c eblnonerelocp.c eblrelativerelocp.c \
>  	      eblsysvhashentrysize.c eblauxvinfo.c eblcheckobjattr.c \
>  	      ebl_check_special_section.c ebl_syscall_abi.c eblabicfi.c \
> -	      eblstother.c eblinitreg.c
> +	      eblstother.c eblinitreg.c eblresolvesym.c
>  
>  libebl_a_SOURCES = $(gen_SOURCES)
>  
> diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h
> index cb52fee..7cbbb8f 100644
> --- a/libebl/ebl-hooks.h
> +++ b/libebl/ebl-hooks.h
> @@ -162,5 +162,10 @@ bool EBLHOOK(set_initial_registers_tid) (pid_t tid,
>  					 ebl_tid_registers_t *setfunc,
>  					 void *arg);
>  
> +/* Returns true if the value can be resolved to an address in an
> +   allocated section, which will be returned in *SHNDXP.
> +   (e.g. function descriptor resolving).  */
                                          |
probably an excessive dot                 ^

> +bool EBLHOOK(resolve_sym_value) (Ebl *ebl, GElf_Addr *addr);
> +
>  /* Destructor for ELF backend handle.  */
>  void EBLHOOK(destr) (struct ebl *);
> diff --git a/libdwfl/dwfl_module_addrname.c b/libebl/eblresolvesym.c
> similarity index 72%
> copy from libdwfl/dwfl_module_addrname.c
> copy to libebl/eblresolvesym.c
> index 6ae0123..470f6f0 100644
> --- a/libdwfl/dwfl_module_addrname.c
> +++ b/libebl/eblresolvesym.c
> @@ -1,5 +1,5 @@
> -/* Find debugging and symbol information for a module in libdwfl.
> -   Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
> +/* Resolve a symbol value to an allocated section of the Elf file.
> +   Copyright (C) 2013 Red Hat, Inc.
>     This file is part of elfutils.
>  
>     This file is free software; you can redistribute it and/or modify
> @@ -26,11 +26,18 @@
>     the GNU Lesser General Public License along with this program.  If
>     not, see <http://www.gnu.org/licenses/>.  */
>  
> -#include "libdwflP.h"
> +#ifdef HAVE_CONFIG_H
> +# include <config.h>
> +#endif
>  
> -const char *
> -dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr addr)
> +#include <libeblP.h>
> +#include <assert.h>
> +
> +bool
> +ebl_resolve_sym_value (Ebl *ebl, GElf_Addr *addr)
>  {
> -  GElf_Sym sym;
> -  return INTUSE(dwfl_module_addrsym) (mod, addr, &sym, NULL);
> +  if (ebl == NULL || ebl->resolve_sym_value == NULL)
> +    return false;
> +
> +  return ebl->resolve_sym_value (ebl, addr);
>  }
> diff --git a/libebl/libebl.h b/libebl/libebl.h
> index 045a198..eea6700 100644
> --- a/libebl/libebl.h
> +++ b/libebl/libebl.h
> @@ -402,6 +402,12 @@ extern bool ebl_set_initial_registers_tid (Ebl *ebl,
>  extern size_t ebl_frame_nregs (Ebl *ebl)
>    __nonnull_attribute__ (1);
>  
> +/* Returns true if the value can be resolved to an address in an
> +   allocated section, which will be returned in *ADDR
> +   (e.g. function descriptor resolving).  */
                                          |
probably an excessive dot                 ^

> +extern bool ebl_resolve_sym_value (Ebl *ebl, GElf_Addr *addr)
> +   __nonnull_attribute__ (2);
> +
>  #ifdef __cplusplus
>  }
>  #endif
[...]


Thanks,
Jan


More information about the elfutils-devel mailing list