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(a)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(a)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(a)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(a)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(a)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(a)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