[PATCH] Fix sig8_hash memory leak in libdw/dwarf_begin_elf.c if not valid_p.
by Mark Wielaard
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdw/ChangeLog | 4 ++++
libdw/dwarf_begin_elf.c | 1 +
2 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 0d35ca9..f3ba224 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,7 @@
+2012-12-18 Mark Wielaard <mjw(a)redhat.com>
+
+ * dwarf_begin_elf.c (valid_p): Call Dwarf_Sig8_Hash_free.
+
2012-10-09 Petr Machata <pmachata(a)redhat.com>
* dwarf_getlocation.c (__libdw_intern_expression): Handle
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index a9c826c..65a59cd 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -344,6 +344,7 @@ valid_p (Dwarf *result)
&& unlikely (result->sectiondata[IDX_debug_info] == NULL))
{
__libdw_free_zdata (result);
+ Dwarf_Sig8_Hash_free (&result->sig8_hash);
__libdw_seterrno (DWARF_E_NO_DWARF);
free (result);
result = NULL;
--
1.7.1
11 years, 4 months
[patch 3/3] ppc64 .opd: Bidirectional provider
by Jan Kratochvil
Hi,
jankratochvil/symrefactor-scnfindvma-ppc64opdbidir
this time the ppc64 code entry points are provided as first class ELF symbols.
That means dwfl_module_addrsym need to be no longer modified (almost) at all.
I was thinking about the discussion with Mark and I believe there have been
mixed the "user display form" and "ELF symbol name". It was also said that
for example C++ demangling could be used for the "user display form" together
with the leading dot removal.
I believe such "user display form" should be completely outside of the scope
of the current patches. These patches are about ELF symbols and ELF symbol
names. As is probably clear no C++ demangling should take place here it IMO
clarifies why also no dot removals should be done here.
Thanks,
Jan
commit 3847e9414281a1c94bb6b6aa5111fbfb19a3eb56
Author: Jan Kratochvil <jan.kratochvil(a)redhat.com>
Date: Fri Dec 14 20:09:53 2012 +0100
backends/
* Makefile.am (INCLUDES): Add libdwfl.
(ppc64_SRCS): Add ppc64_getsym.c.
* ppc64_getsym.c: New file.
* ppc64_init.c (ppc64_init): Install getsym and destr.
libdwfl/
* dwfl_module_addrsym.c (dwfl_module_addrsym): Search also
Dwfl_Module->ebllocals.
* dwfl_module_getdwarf.c (find_symtab): Assert also
Dwfl_Module->ebllocals and Dwfl_Module->eblglobals. Call
__libdwfl_module_getebl and ebl_getsym.
(dwfl_module_getsymtab): Return also the sum of Dwfl_Module->ebllocals
and Dwfl_Module->eblglobals.
* dwfl_module_getsym.c (dwfl_module_getsym): Rename parameter ndx to
ndxi. New variables ndx and name. Call ebl_getsym for the matching
range. Prefer to return NAME if set.
* libdwflP.h (struct Dwfl_Module): New fields ebllocals and eblglobals.
libebl/
* Makefile.am (gen_SOURCES): Add eblgetsym.c.
* ebl-hooks.h (getsym): New entry.
* eblgetsym.c: New file.
* libebl.h (struct Dwfl_Module): New declaration.
(ebl_getsym): New declaration.
* libeblP.h (struct ebl): New field backend.
tests/
* run-addrname-test.sh: New testcase for ppc64 function descriptors.
* testfile66.bz2: New file.
* Makefile.am (EXTRA_DIST): Add testfile66.bz2.
Signed-off-by: Jan Kratochvil <jan.kratochvil(a)redhat.com>
diff --git a/backends/ChangeLog b/backends/ChangeLog
index cca7113..8cc5275 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,3 +1,10 @@
+2012-12-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * Makefile.am (INCLUDES): Add libdwfl.
+ (ppc64_SRCS): Add ppc64_getsym.c.
+ * ppc64_getsym.c: New file.
+ * ppc64_init.c (ppc64_init): Install getsym and destr.
+
2012-10-12 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* linux-core-note.c (prstatus_items): Rename groups of sigpend and
diff --git a/backends/Makefile.am b/backends/Makefile.am
index 982ff2a..62fee35 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -29,7 +29,7 @@
## not, see <http://www.gnu.org/licenses/>.
include $(top_srcdir)/config/eu.am
INCLUDES += -I$(top_srcdir)/libebl -I$(top_srcdir)/libasm \
- -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw
+ -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw -I$(top_srcdir)/libdwfl
modules = i386 sh x86_64 ia64 alpha arm sparc ppc ppc64 s390 tilegx
@@ -90,7 +90,8 @@ libebl_ppc_pic_a_SOURCES = $(ppc_SRCS)
am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os)
ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c \
- ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c ppc_syscall.c
+ ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \
+ ppc64_getsym.c
libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS)
am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os)
diff --git a/backends/ppc64_getsym.c b/backends/ppc64_getsym.c
new file mode 100644
index 0000000..14902fd
--- /dev/null
+++ b/backends/ppc64_getsym.c
@@ -0,0 +1,196 @@
+/* Return NDXth backend symbol from MOD.
+ Copyright (C) 2012 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
+
+#include <assert.h>
+#include "libdwflP.h"
+#include <endian.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define BACKEND ppc64_
+#include "libebl_CPU.h"
+
+/* Pointer to the first entry is stored into ebl->backend.
+ It has Dwfl_Module->eblsyments entries and follow it strings for the NAME
+ entries. */
+
+struct sym_entry
+{
+ GElf_Sym sym;
+ GElf_Word shndx;
+ const char *name;
+};
+
+static void
+init (Dwfl_Module *mod)
+{
+ assert (mod->ebllocals == 0);
+ assert (mod->eblglobals == 0);
+ Ebl *ebl = mod->ebl;
+ Elf *elf = ebl->elf;
+ if (elf == NULL)
+ return;
+ GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
+ if (ehdr == NULL)
+ return;
+ GElf_Word opd_shndx = 0;
+ GElf_Shdr opd_shdr_mem, *opd_shdr;
+ Elf_Data *opd_data;
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
+ {
+ opd_shdr = gelf_getshdr (scn, &opd_shdr_mem);
+ if (opd_shdr == NULL)
+ continue;
+ if (strcmp (elf_strptr (elf, ehdr->e_shstrndx, opd_shdr->sh_name), ".opd")
+ != 0)
+ continue;
+ opd_data = elf_getdata (scn, NULL);
+ /* SHT_NOBITS will produce NULL D_BUF. */
+ if (opd_data == NULL || opd_data->d_buf == NULL)
+ return;
+ assert (opd_data->d_size == opd_shdr->sh_size);
+ opd_shndx = elf_ndxscn (scn);
+ break;
+ }
+ if (opd_shndx == 0)
+ return;
+ Dwarf_Addr symbias;
+ dwfl_module_info (mod, NULL, NULL, NULL, NULL, &symbias, NULL, NULL);
+ size_t names_size = 0, ebllocals = 0, eblglobals = 0;
+ for (int symi = 1; symi < dwfl_module_getsymtab (mod); symi++)
+ {
+ GElf_Sym sym;
+ GElf_Word shndx;
+ const char *symname = dwfl_module_getsym (mod, symi, &sym, &shndx);
+ if (symname == NULL || shndx != opd_shndx)
+ continue;
+ Elf64_Addr val;
+ if (sym.st_value < opd_shdr->sh_addr + symbias
+ || sym.st_value > (opd_shdr->sh_addr + symbias
+ + opd_shdr->sh_size - sizeof (val)))
+ continue;
+ if ((size_t) symi < mod->symlocals)
+ ebllocals++;
+ else
+ eblglobals++;
+ names_size += 1 + strlen (symname) + 1;
+ }
+ if (ebllocals + eblglobals == 0)
+ return;
+ struct sym_entry *sym_table;
+ sym_table = malloc ((ebllocals + eblglobals) * sizeof (*sym_table)
+ + names_size);
+ if (sym_table == NULL)
+ return;
+ ebl->backend = sym_table;
+ struct sym_entry *dest = sym_table;
+ char *names = (void *) &sym_table[ebllocals + eblglobals];
+ char *names_dest = names;
+ for (int symi = 1; symi < dwfl_module_getsymtab (mod); symi++)
+ {
+ GElf_Sym sym;
+ GElf_Word shndx;
+ const char *symname = dwfl_module_getsym (mod, symi, &sym, &shndx);
+ if (symname == NULL || shndx != opd_shndx)
+ continue;
+ uint64_t val64;
+ if (sym.st_value < opd_shdr->sh_addr + symbias
+ || sym.st_value > (opd_shdr->sh_addr + symbias
+ + opd_shdr->sh_size - sizeof (val64)))
+ continue;
+ val64 = *(const uint64_t *) (opd_data->d_buf + sym.st_value
+ - (opd_shdr->sh_addr + symbias));
+ val64 = (elf_getident (elf, NULL)[EI_DATA] == ELFDATA2MSB
+ ? be64toh (val64) : le64toh (val64));
+ assert ((char *) dest < names);
+ dest->sym = sym;
+ dest->sym.st_value = val64; // + symbias;
+ Elf_Scn *sym_scn = elf_scnfindvma (elf, val64);
+ dest->shndx = sym_scn == NULL ? SHN_ABS : elf_ndxscn (sym_scn);
+ dest->sym.st_shndx = SHN_XINDEX;
+ dest->name = names_dest;
+ *names_dest++ = '.';
+ names_dest = stpcpy (names_dest, symname) + 1;
+ dest++;
+ }
+ assert ((char *) dest == names);
+ assert (names_dest == names + names_size);
+ mod->ebllocals = ebllocals;
+ mod->eblglobals = eblglobals;
+}
+
+const char *
+ppc64_getsym (Dwfl_Module *mod, int ndxi, GElf_Sym *sym, GElf_Word *shndxp)
+{
+ Ebl *ebl = mod->ebl;
+ assert (ebl != NULL);
+ if (ebl->backend == NULL)
+ init (mod);
+ if (ebl->backend == NULL)
+ {
+ assert (mod->ebllocals + mod->eblglobals == 0);
+ ebl->backend = malloc (1);
+ return NULL;
+ }
+ struct sym_entry *sym_table = ebl->backend;
+ const struct sym_entry *found;
+ if (ndxi < 0)
+ return NULL;
+ size_t ndx = ndxi;
+ if (ndx < mod->symlocals)
+ return NULL;
+ else if (ndx < mod->symlocals + mod->ebllocals)
+ found = &sym_table[ndx - mod->symlocals];
+ else if (ndx < mod->symlocals + mod->ebllocals + mod->symglobals)
+ return NULL;
+ else if (ndx < (mod->symlocals + mod->ebllocals + mod->symglobals
+ + mod->eblglobals))
+ found = &sym_table[ndx - mod->symlocals - mod->symglobals];
+ else
+ return NULL;
+ if (sym)
+ *sym = found->sym;
+ if (shndxp)
+ *shndxp = found->shndx;
+ return found->name;
+}
+
+void
+ppc64_destr (Ebl *ebl)
+{
+ if (ebl->backend == NULL)
+ return;
+ struct sym_entry *sym_table = ebl->backend;
+ free (sym_table);
+ ebl->backend = NULL;
+}
diff --git a/backends/ppc64_init.c b/backends/ppc64_init.c
index 90d4f2b..c64a903 100644
--- a/backends/ppc64_init.c
+++ b/backends/ppc64_init.c
@@ -64,6 +64,8 @@ ppc64_init (elf, machine, eh, ehlen)
HOOK (eh, syscall_abi);
HOOK (eh, core_note);
HOOK (eh, auxv_info);
+ HOOK (eh, getsym);
+ HOOK (eh, destr);
return MODVERSION;
}
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 8caf083..b9d0e66 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,5 +1,19 @@
2012-12-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+ * dwfl_module_addrsym.c (dwfl_module_addrsym): Search also
+ Dwfl_Module->ebllocals.
+ * dwfl_module_getdwarf.c (find_symtab): Assert also
+ Dwfl_Module->ebllocals and Dwfl_Module->eblglobals. Call
+ __libdwfl_module_getebl and ebl_getsym.
+ (dwfl_module_getsymtab): Return also the sum of Dwfl_Module->ebllocals
+ and Dwfl_Module->eblglobals.
+ * dwfl_module_getsym.c (dwfl_module_getsym): Rename parameter ndx to
+ ndxi. New variables ndx and name. Call ebl_getsym for the matching
+ range. Prefer to return NAME if set.
+ * libdwflP.h (struct Dwfl_Module): New fields ebllocals and eblglobals.
+
+2012-12-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
* dwfl_module_addrsym.c (dwfl_module_addrsym): Call elf_scnfindvma
where is the code from here moved out.
diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c
index d2316c6..b2db68e 100644
--- a/libdwfl/dwfl_module_addrsym.c
+++ b/libdwfl/dwfl_module_addrsym.c
@@ -157,13 +157,13 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
}
/* First go through global symbols. */
- search_table (mod->symlocals, syments);
+ search_table (mod->symlocals + mod->ebllocals, syments);
/* If we found nothing searching the global symbols, then try the locals.
Unless we have a global sizeless symbol that matches exactly. */
- if (closest_name == NULL && mod->symlocals > 1
+ if (closest_name == NULL && mod->symlocals + mod->ebllocals > 1
&& (sizeless_name == NULL || sizeless_sym.st_value != addr))
- search_table (1, mod->symlocals);
+ search_table (1, mod->symlocals + mod->ebllocals);
/* If we found no proper sized symbol to use, fall back to the best
candidate sizeless symbol we found, if any. */
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index f816f2c..8e30671 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -828,7 +828,9 @@ find_symtab (Dwfl_Module *mod)
return;
assert (mod->symlocals == 0);
+ assert (mod->ebllocals == 0);
assert (mod->symglobals == 0);
+ assert (mod->eblglobals == 0);
/* First see if the main ELF file has the debugging information. */
Elf_Scn *symscn = NULL, *xndxscn = NULL;
@@ -913,6 +915,10 @@ find_symtab (Dwfl_Module *mod)
mod->symdata = elf_getdata (symscn, NULL);
if (mod->symdata == NULL)
goto elferr;
+
+ Dwfl_Error error = __libdwfl_module_getebl (mod);
+ if (error == DWFL_E_NOERROR)
+ ebl_getsym (mod->ebl, mod, -1, NULL, NULL);
}
@@ -1068,7 +1074,7 @@ dwfl_module_getsymtab (Dwfl_Module *mod)
find_symtab (mod);
if (mod->symerr == DWFL_E_NOERROR)
- return mod->symlocals + mod->symglobals;
+ return mod->symlocals + mod->ebllocals + mod->symglobals + mod->eblglobals;
__libdwfl_seterrno (mod->symerr);
return -1;
diff --git a/libdwfl/dwfl_module_getsym.c b/libdwfl/dwfl_module_getsym.c
index 9103380..537bc59 100644
--- a/libdwfl/dwfl_module_getsym.c
+++ b/libdwfl/dwfl_module_getsym.c
@@ -29,7 +29,7 @@
#include "libdwflP.h"
const char *
-dwfl_module_getsym (Dwfl_Module *mod, int ndx,
+dwfl_module_getsym (Dwfl_Module *mod, int ndxi,
GElf_Sym *sym, GElf_Word *shndxp)
{
if (unlikely (mod == NULL))
@@ -42,12 +42,32 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
return NULL;
}
+ size_t ndx = ndxi;
+ const char *name = NULL;
GElf_Word shndx;
- sym = gelf_getsymshndx (mod->symdata, mod->symxndxdata, ndx, sym, &shndx);
- if (unlikely (sym == NULL))
+ if (unlikely ((ndx >= mod->symlocals && ndx < mod->symlocals + mod->ebllocals)
+ || (ndx >= mod->symlocals + mod->ebllocals + mod->symglobals
+ && ndx < (mod->symlocals + mod->ebllocals + mod->symglobals
+ + mod->eblglobals))))
{
- __libdwfl_seterrno (DWFL_E_LIBELF);
- return NULL;
+ name = ebl_getsym (mod->ebl, mod, ndx, sym, &shndx);
+ if (unlikely (name == NULL))
+ {
+ __libdwfl_seterrno (DWFL_E_LIBEBL);
+ return NULL;
+ }
+ }
+ else
+ {
+ if (ndx >= mod->symlocals)
+ ndx -= mod->ebllocals;
+
+ sym = gelf_getsymshndx (mod->symdata, mod->symxndxdata, ndx, sym, &shndx);
+ if (unlikely (sym == NULL))
+ {
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return NULL;
+ }
}
if (sym->st_shndx != SHN_XINDEX)
@@ -97,6 +117,9 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
break;
}
+ if (name)
+ return name;
+
if (unlikely (sym->st_name >= mod->symstrdata->d_size))
{
__libdwfl_seterrno (DWFL_E_BADSTROFF);
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 360e1ef..bd04128 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -157,7 +157,9 @@ struct Dwfl_Module
/* All symbols with local binding come first in the symbol table,
then all globals. */
size_t symlocals; /* Local symbols in SYMDATA. */
+ size_t ebllocals; /* Local symbols via ebl_getsym. */
size_t symglobals; /* Global symbols in SYMDATA. */
+ size_t eblglobals; /* Global symbols via ebl_getsym. */
Dwarf *dw; /* libdw handle for its debugging info. */
diff --git a/libebl/ChangeLog b/libebl/ChangeLog
index e881ce7..5d3c015 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,12 @@
+2012-12-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * Makefile.am (gen_SOURCES): Add eblgetsym.c.
+ * ebl-hooks.h (getsym): New entry.
+ * eblgetsym.c: New file.
+ * libebl.h (struct Dwfl_Module): New declaration.
+ (ebl_getsym): New declaration.
+ * libeblP.h (struct ebl): New field backend.
+
2012-10-12 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* ebl-hooks.h (abi_cfi): Extend its comment for return value.
diff --git a/libebl/Makefile.am b/libebl/Makefile.am
index 65e6b5b..08fe5b6 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
+ eblstother.c eblgetsym.c
libebl_a_SOURCES = $(gen_SOURCES)
diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h
index d3cf3e6..30bd0a2 100644
--- a/libebl/ebl-hooks.h
+++ b/libebl/ebl-hooks.h
@@ -155,5 +155,12 @@ int EBLHOOK(disasm) (const uint8_t **startp, const uint8_t *end,
Function returns 0 on success and -1 on error. */
int EBLHOOK(abi_cfi) (Ebl *ebl, Dwarf_CIE *abi_info);
+/* Return NDXth backend symbol from MOD, store it to *SYM and *SHNDX and return
+ its new name. If NDX is -1 then only initialize MOD's EBLSYMENTS (and
+ associated fields) and return NULL (SYM and SHNDXP are ignored in such
+ case). Returned name is valid as long as EBL is valid. */
+const char *EBLHOOK(getsym) (struct Dwfl_Module *mod, int ndx, GElf_Sym *sym,
+ GElf_Word *shndxp);
+
/* Destructor for ELF backend handle. */
void EBLHOOK(destr) (struct ebl *);
diff --git a/libebl/eblgetsym.c b/libebl/eblgetsym.c
new file mode 100644
index 0000000..af20ea6
--- /dev/null
+++ b/libebl/eblgetsym.c
@@ -0,0 +1,45 @@
+/* Return NDXth backend symbol from MOD.
+ Copyright (C) 2012 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
+
+#include <libeblP.h>
+#include <assert.h>
+
+const char *
+ebl_getsym (Ebl *ebl, struct Dwfl_Module *mod, int ndx, GElf_Sym *sym,
+ GElf_Word *shndxp)
+{
+ if (ebl == NULL)
+ return NULL;
+ if (ebl->getsym == NULL)
+ return NULL;
+ return ebl->getsym (mod, ndx, sym, shndxp);
+}
diff --git a/libebl/libebl.h b/libebl/libebl.h
index cae31c9..a9314c3 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -378,6 +378,15 @@ extern int ebl_auxv_info (Ebl *ebl, GElf_Xword a_type,
const char **name, const char **format)
__nonnull_attribute__ (1, 3, 4);
+/* Return NDXth backend symbol from MOD, store it to *SYM and *SHNDX and return
+ its new name. If NDX is -1 then only initialize MOD's EBLSYMENTS (and
+ associated fields) and return NULL (SYM and SHNDXP are ignored in such
+ case). Returned name is valid as long as EBL is valid. */
+struct Dwfl_Module;
+extern const char * ebl_getsym (Ebl *ebl, struct Dwfl_Module *mod, int ndx,
+ GElf_Sym *sym, GElf_Word *shndxp)
+ __nonnull_attribute__ (1, 2);
+
#ifdef __cplusplus
}
diff --git a/libebl/libeblP.h b/libebl/libeblP.h
index 5ec26a4..c8196bd 100644
--- a/libebl/libeblP.h
+++ b/libebl/libeblP.h
@@ -62,6 +62,9 @@ struct ebl
/* Internal data. */
void *dlhandle;
+
+ /* Data specific to the backend. */
+ void *backend;
};
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 0289148..02adf94 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2012-12-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * run-addrname-test.sh: New testcase for ppc64 function descriptors.
+ * testfile66.bz2: New file.
+ * Makefile.am (EXTRA_DIST): Add testfile66.bz2.
+
2012-12-03 Mark Wielaard <mjw(a)redhat.com>
* Makefile.am (valgrind_cmd): Add --run-libc-freeres=no.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8b7b751..bb442ae 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -181,7 +181,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
run-readelf-vmcoreinfo.sh testfile62.bz2 \
run-readelf-mixed-corenote.sh testfile63.bz2 testfile64.bz2 \
testfile65.bz2 testfile69.core.bz2 testfile69.so.bz2 \
- testfile70.core.bz2 testfile70.exec.bz2
+ testfile70.core.bz2 testfile70.exec.bz2 testfile66.bz2
if USE_VALGRIND
valgrind_cmd="valgrind -q --trace-children=yes --error-exitcode=1 --run-libc-freeres=no"
diff --git a/tests/run-addrname-test.sh b/tests/run-addrname-test.sh
index 99abf9d..06dd151 100755
--- a/tests/run-addrname-test.sh
+++ b/tests/run-addrname-test.sh
@@ -298,6 +298,18 @@ __vdso_time
??:0
EOF
+testfiles testfile66
+testrun_compare ../src/addr2line -S -e testfile66 func 0x10340 .func 0x250 <<\EOF
+func
+??:0
+func
+??:0
+.func
+??:0
+.func
+??:0
+EOF
+
testfiles testfile69.core testfile69.so
testrun_compare ../src/addr2line --core=./testfile69.core -S 0x7f0bc6a33535 0x7f0bc6a33546 <<\EOF
libstatic+0x9
diff --git a/tests/testfile66.bz2 b/tests/testfile66.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..db07f25415729927f4e2b4985c5668c8e2ee10a2
GIT binary patch
literal 569
zcmV-90>=G9T4*^jL0KkKSrloeYybi*|NH;`Q+Gmd_t9I$azOv*{$$8R5dZ){00;sg
zN(3VzzyZ?W%~)z`O*V<ChK5r#X)zd>fu;fm0WvhiG}9)JQGyXYL8JhU5NHRe007X?
z$Qoh*0BMi_;L)Q%&}a;pfXL9u01Y(A003Zs0!0dH8USbj00000000000H3&^h5+h?
zHGH8oS#&k;tR%<0nFK6&-#1i4RnYl;-bpN9k2InZwNKHPIa5z$l?D9dtf^2;aFZ>;
z6H2`TaFp50B|IFU9;meM2nk4CXKdt!?6iqh`+DOs7204JFHHaexzT9oele)vNXcO|
z&aXz&bgUpHL5Q+$&J@iFQZPa%v>5P$Ld;?WwHgw?W$OZSUT)aw=i|cU?V{^+uO+T&
zsc1>77*MKpaR&z&l3<3FBTF`AA*kg!f+LXQdlF0z1|<OGVw|;E3MDuVYg}lF1kIB*
z2MO?2(vv|()kGjFhM>|aV;0;9Y&kKvJQ6|?q76u^Sl}`<LIO+NDfU1C1=+J>CXwR7
zvQ|1@iR(qMOPC<M!U)iAS_QSrP$be&teWK@Xh4y??kxH~E_K((z?!P4lv4z@9Y0sD
zK?cn^FLD~401iNn#iXf~Yy5H5(sqZpp=+#)n|DQ6r81NSyLB;KQD(6uE>?9m>Ok-8
z(YXp^O0BHJBpo)oV3bgUCvFNTfZoo@a?O8}_!iyT909f+z2<0!_i&kLzs1~<P81{s
H8flvV7_Id;
literal 0
HcmV?d00001
11 years, 4 months
[patch 2/3] ppc64 .opd: Provide elf_scnfindvma
by Jan Kratochvil
Hi,
jankratochvil/symrefactor-scnfindvma
it just provides a part of existing code as a public function called
in [patch 3/3]. I understand it has no meaning on its own.
Thanks,
Jan
commit 4299e5860e94c012cadfc6af7ae10facc9c5b6ed
Author: Jan Kratochvil <jan.kratochvil(a)redhat.com>
Date: Fri Dec 14 20:07:14 2012 +0100
libdwfl/
* dwfl_module_addrsym.c (dwfl_module_addrsym): Call elf_scnfindvma
where is the code from here moved out.
libelf/
* Makefile.am (libelf_a_SOURCES): Add elf_scnfindvma.c.
* elf_scnfindvma.c: New file.
* libelf.h (elf_scnfindvma): New declaration.
* libelf.map (ELFUTILS_1.156): New with elf_scnfindvma.
Signed-off-by: Jan Kratochvil <jan.kratochvil(a)redhat.com>
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index bbe2255..8caf083 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,5 +1,10 @@
2012-12-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+ * dwfl_module_addrsym.c (dwfl_module_addrsym): Call elf_scnfindvma
+ where is the code from here moved out.
+
+2012-12-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
* dwfl_module_addrsym.c (dwfl_module_addrsym): Replace the usse of
Dwfl_Module->first_global by Dwfl_Module->symlocals. Delete the
first_global comment, move part of it to struct Dwfl_Module.
diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c
index e7c42da..d2316c6 100644
--- a/libdwfl/dwfl_module_addrsym.c
+++ b/libdwfl/dwfl_module_addrsym.c
@@ -51,20 +51,8 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
if (addr_shndx == SHN_UNDEF)
{
GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, addr);
- Elf_Scn *scn = NULL;
- addr_shndx = SHN_ABS;
- while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
- {
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- if (likely (shdr != NULL)
- && mod_addr >= shdr->sh_addr
- && mod_addr < shdr->sh_addr + shdr->sh_size)
- {
- addr_shndx = elf_ndxscn (scn);
- break;
- }
- }
+ Elf_Scn *scn = elf_scnfindvma (mod->symfile->elf, mod_addr);
+ addr_shndx = scn == NULL ? SHN_ABS : elf_ndxscn (scn);
}
return shndx == addr_shndx;
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 4a9e358..4ff36f5 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,10 @@
+2012-12-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * Makefile.am (libelf_a_SOURCES): Add elf_scnfindvma.c.
+ * elf_scnfindvma.c: New file.
+ * libelf.h (elf_scnfindvma): New declaration.
+ * libelf.map (ELFUTILS_1.156): New with elf_scnfindvma.
+
2012-09-17 Petr Machata <pmachata(a)redhat.com>
* elf.h: Update from glibc.
diff --git a/libelf/Makefile.am b/libelf/Makefile.am
index 5903ea8..4b83e23 100644
--- a/libelf/Makefile.am
+++ b/libelf/Makefile.am
@@ -90,7 +90,7 @@ libelf_a_SOURCES = elf_version.c elf_hash.c elf_error.c elf_fill.c \
elf32_offscn.c elf64_offscn.c gelf_offscn.c \
elf_getaroff.c \
elf_gnu_hash.c \
- elf_scnshndx.c
+ elf_scnshndx.c elf_scnfindvma.c
if !MUDFLAP
libelf_pic_a_SOURCES =
diff --git a/libelf/elf_scnfindvma.c b/libelf/elf_scnfindvma.c
new file mode 100644
index 0000000..b543819
--- /dev/null
+++ b/libelf/elf_scnfindvma.c
@@ -0,0 +1,52 @@
+/* Get section containing VMA address. Return NULL otherwise.
+ Copyright (C) 2012 Red Hat, Inc.
+ This file is part of elfutils.
+ Contributed by Ulrich Drepper <drepper(a)redhat.com>, 1998.
+
+ 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
+
+#include "libelfP.h"
+
+
+Elf_Scn *
+elf_scnfindvma (Elf *__elf, GElf_Addr __vma)
+{
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (__elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (likely (shdr != NULL)
+ && __vma >= shdr->sh_addr
+ && __vma < shdr->sh_addr + shdr->sh_size)
+ break;
+ }
+ return scn;
+}
+INTDEF(elf_scnfindvma)
diff --git a/libelf/libelf.h b/libelf/libelf.h
index 5a2b3af..1dd5d2f 100644
--- a/libelf/libelf.h
+++ b/libelf/libelf.h
@@ -219,6 +219,11 @@ extern Elf64_Phdr *elf64_newphdr (Elf *__elf, size_t __cnt);
/* Get section at INDEX. */
extern Elf_Scn *elf_getscn (Elf *__elf, size_t __index);
+/* Get section containing VMA address. Return NULL otherwise.
+ GElf_Addr type cannot be used here for __vma due to include
+ interdependencies. */
+extern Elf_Scn *elf_scnfindvma (Elf *__elf, Elf64_Addr __vma);
+
/* Get section at OFFSET. */
extern Elf_Scn *elf32_offscn (Elf *__elf, Elf32_Off __offset);
/* Similar bug this time the binary calls is ELFCLASS64. */
diff --git a/libelf/libelf.map b/libelf/libelf.map
index de6d912..ec288fe 100644
--- a/libelf/libelf.map
+++ b/libelf/libelf.map
@@ -138,3 +138,8 @@ ELFUTILS_1.6 {
global:
elf_getphdrnum;
} ELFUTILS_1.5;
+
+ELFUTILS_1.156 {
+ global:
+ elf_scnfindvma;
+} ELFUTILS_1.6;
11 years, 4 months
[patch 1/3] ppc64 .opd: Refactor syments/first_global
by Jan Kratochvil
Hi,
jankratochvil/symrefactor
currently SYMENTS is the total number of symbols and FIRST_GLOBAL is somehow
the first half of local symbols from SYMENTS.
But it is difficult to extend it so that there can be multiple providers of
local and global symbols, for both ppc64 .opd resolver and possible
"minidebuginfo" provider.
This patch should not change any behavior.
Thanks,
Jan
commit d40e96c75d838215863f96d91f851e45c046b5d3
Author: Jan Kratochvil <jan.kratochvil(a)redhat.com>
Date: Fri Dec 14 19:45:32 2012 +0100
libdwfl/
* dwfl_module_addrsym.c (dwfl_module_addrsym): Replace the usse of
Dwfl_Module->first_global by Dwfl_Module->symlocals. Delete the
first_global comment, move part of it to struct Dwfl_Module.
* dwfl_module_getdwarf.c (load_symtab): Replace parameters syments and
first_global by symlocals and symglobals. Update their use therein.
(find_dynsym): Replace the use of Dwfl_Module->syments by
Dwfl_Module->symglobals.
(find_symtab): Replace first_global initialization by two asserts on
symlocals and symglobals. Update the load_symtab caller.
(dwfl_module_getsymtab): Replace the usse of Dwfl_Module->syments by
Dwfl_Module->symlocals and Dwfl_Module->symglobals.
* libdwflP.h (struct Dwfl_Module): Replace fields syments and
first_global by symlocals and symglobals. Add here a part of comment
from dwfl_module_addrsym.
* relocate.c (resolve_symbol): Replace Dwfl_Module->syments by a call
to dwfl_module_getsymtab. Change ndx variable type to signed int.
Signed-off-by: Jan Kratochvil <jan.kratochvil(a)redhat.com>
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 896ae39..bbe2255 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,22 @@
+2012-12-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * dwfl_module_addrsym.c (dwfl_module_addrsym): Replace the usse of
+ Dwfl_Module->first_global by Dwfl_Module->symlocals. Delete the
+ first_global comment, move part of it to struct Dwfl_Module.
+ * dwfl_module_getdwarf.c (load_symtab): Replace parameters syments and
+ first_global by symlocals and symglobals. Update their use therein.
+ (find_dynsym): Replace the use of Dwfl_Module->syments by
+ Dwfl_Module->symglobals.
+ (find_symtab): Replace first_global initialization by two asserts on
+ symlocals and symglobals. Update the load_symtab caller.
+ (dwfl_module_getsymtab): Replace the usse of Dwfl_Module->syments by
+ Dwfl_Module->symlocals and Dwfl_Module->symglobals.
+ * libdwflP.h (struct Dwfl_Module): Replace fields syments and
+ first_global by symlocals and symglobals. Add here a part of comment
+ from dwfl_module_addrsym.
+ * relocate.c (resolve_symbol): Replace Dwfl_Module->syments by a call
+ to dwfl_module_getsymtab. Change ndx variable type to signed int.
+
2012-12-11 Mark Wielaard <mjw(a)redhat.com>
* linux-kernel-modules.c (report_kernel): Only free fname if
diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c
index fdc95fc..e7c42da 100644
--- a/libdwfl/dwfl_module_addrsym.c
+++ b/libdwfl/dwfl_module_addrsym.c
@@ -168,17 +168,14 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
}
}
- /* First go through global symbols. mod->first_global is setup by
- dwfl_module_getsymtab to the index of the first global symbol in
- the module's symbol table, or -1 when unknown. All symbols with
- local binding come first in the symbol table, then all globals. */
- search_table (mod->first_global < 0 ? 1 : mod->first_global, syments);
+ /* First go through global symbols. */
+ search_table (mod->symlocals, syments);
/* If we found nothing searching the global symbols, then try the locals.
Unless we have a global sizeless symbol that matches exactly. */
- if (closest_name == NULL && mod->first_global > 1
+ if (closest_name == NULL && mod->symlocals > 1
&& (sizeless_name == NULL || sizeless_sym.st_value != addr))
- search_table (1, mod->first_global);
+ search_table (1, mod->symlocals);
/* If we found no proper sized symbol to use, fall back to the best
candidate sizeless symbol we found, if any. */
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index 025cb8a..f816f2c 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -550,7 +550,7 @@ find_debuginfo (Dwfl_Module *mod)
static Dwfl_Error
load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
Elf_Scn **symscn, Elf_Scn **xndxscn,
- size_t *syments, int *first_global, GElf_Word *strshndx)
+ size_t *symlocals, size_t *symglobals, GElf_Word *strshndx)
{
bool symtab = false;
Elf_Scn *scn = NULL;
@@ -565,8 +565,8 @@ load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
*symscn = scn;
*symfile = file;
*strshndx = shdr->sh_link;
- *syments = shdr->sh_size / shdr->sh_entsize;
- *first_global = shdr->sh_info;
+ *symlocals = shdr->sh_info;
+ *symglobals = (shdr->sh_size / shdr->sh_entsize) - *symlocals;
if (*xndxscn != NULL)
return DWFL_E_NOERROR;
break;
@@ -578,7 +578,7 @@ load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
*symscn = scn;
*symfile = file;
*strshndx = shdr->sh_link;
- *syments = shdr->sh_size / shdr->sh_entsize;
+ *symglobals = shdr->sh_size / shdr->sh_entsize;
break;
case SHT_SYMTAB_SHNDX:
@@ -718,11 +718,11 @@ find_dynsym (Dwfl_Module *mod)
entsz == 4 ? ELF_T_WORD
: ELF_T_XWORD);
if (data != NULL)
- mod->syments = (entsz == 4
- ? *(const GElf_Word *) data->d_buf
- : *(const GElf_Xword *) data->d_buf);
+ mod->symglobals = (entsz == 4
+ ? *(const GElf_Word *) data->d_buf
+ : *(const GElf_Xword *) data->d_buf);
}
- if (offs[i_gnu_hash] != 0 && mod->syments == 0)
+ if (offs[i_gnu_hash] != 0 && mod->symglobals == 0)
{
/* In the new format, we can derive it with some work. */
@@ -769,7 +769,7 @@ find_dynsym (Dwfl_Module *mod)
if (data != NULL
&& (*(const Elf32_Word *) data->d_buf & 1u))
{
- mod->syments = maxndx + 1;
+ mod->symglobals = maxndx + 1;
break;
}
++maxndx;
@@ -778,18 +778,18 @@ find_dynsym (Dwfl_Module *mod)
}
}
}
- if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0)
- mod->syments = ((offs[i_strtab] - offs[i_symtab])
- / gelf_fsize (mod->main.elf,
- ELF_T_SYM, 1, EV_CURRENT));
+ if (offs[i_strtab] > offs[i_symtab] && mod->symglobals == 0)
+ mod->symglobals = ((offs[i_strtab] - offs[i_symtab])
+ / gelf_fsize (mod->main.elf,
+ ELF_T_SYM, 1, EV_CURRENT));
- if (mod->syments > 0)
+ if (mod->symglobals > 0)
{
mod->symdata = elf_getdata_rawchunk (mod->main.elf,
offs[i_symtab],
gelf_fsize (mod->main.elf,
ELF_T_SYM,
- mod->syments,
+ mod->symglobals,
EV_CURRENT),
ELF_T_SYM);
if (mod->symdata != NULL)
@@ -827,13 +827,14 @@ find_symtab (Dwfl_Module *mod)
if (mod->symerr != DWFL_E_NOERROR)
return;
- mod->first_global = -1; /* Unknown, unless explicitly set by load_symtab. */
+ assert (mod->symlocals == 0);
+ assert (mod->symglobals == 0);
/* First see if the main ELF file has the debugging information. */
Elf_Scn *symscn = NULL, *xndxscn = NULL;
GElf_Word strshndx;
mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn,
- &xndxscn, &mod->syments, &mod->first_global,
+ &xndxscn, &mod->symlocals, &mod->symglobals,
&strshndx);
switch (mod->symerr)
{
@@ -853,8 +854,8 @@ find_symtab (Dwfl_Module *mod)
case DWFL_E_NOERROR:
mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn,
- &xndxscn, &mod->syments,
- &mod->first_global, &strshndx);
+ &xndxscn, &mod->symlocals,
+ &mod->symglobals, &strshndx);
break;
case DWFL_E_CB: /* The find_debuginfo hook failed. */
@@ -1067,7 +1068,7 @@ dwfl_module_getsymtab (Dwfl_Module *mod)
find_symtab (mod);
if (mod->symerr == DWFL_E_NOERROR)
- return mod->syments;
+ return mod->symlocals + mod->symglobals;
__libdwfl_seterrno (mod->symerr);
return -1;
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 806ebcd..360e1ef 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -152,10 +152,12 @@ struct Dwfl_Module
struct dwfl_file *symfile; /* Either main or debug. */
Elf_Data *symdata; /* Data in the ELF symbol table section. */
- size_t syments; /* sh_size / sh_entsize of that section. */
- int first_global; /* Index of first global symbol of table. */
Elf_Data *symstrdata; /* Data for its string table. */
Elf_Data *symxndxdata; /* Data in the extended section index table. */
+ /* All symbols with local binding come first in the symbol table,
+ then all globals. */
+ size_t symlocals; /* Local symbols in SYMDATA. */
+ size_t symglobals; /* Global symbols in SYMDATA. */
Dwarf *dw; /* libdw handle for its debugging info. */
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index 2c24bd5..70715cc 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -223,7 +223,7 @@ resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
&& m->symerr != DWFL_E_NO_SYMTAB)
return m->symerr;
- for (size_t ndx = 1; ndx < m->syments; ++ndx)
+ for (int ndx = 1; ndx < INTUSE(dwfl_module_getsymtab) (m); ++ndx)
{
sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
ndx, sym, &shndx);
11 years, 4 months
[patch] Resolve ppc64 func descriptors as .func (via .opd)
by Jan Kratochvil
Hi,
patch has dependency on:
Re: [patch] Fix bias for vDSOs from core files
https://lists.fedorahosted.org/pipermail/elfutils-devel/2012-October/0026...
(gdb) info addr main
Symbol "main" is at 0x10556708 in a file compiled without debugging.
(gdb) info addr .main
Symbol ".main" is at 0x100562d0 in a file compiled without debugging.
Entry point address: 0x105566b8
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[26] .opd PROGBITS 00000000105566b8 5566b8 024458 00 WA 0 0 8
[13] .text PROGBITS 00000000100526a8 0526a8 36c258 00 AX 0 0 8
$ eu-addr2line -e /usr/bin/gdb -S 0x10556708 0x100562d0
FAIL:
main
??:0
??
??:0
PASS:
main
??:0
.main
??:0
So far elfutils resolves addresses from function descriptors but not the real
code addresses.
It does not work universally like bfd artificial ELF symbols do, only
dwfl_module_addrsym is patched; but I find it good enough as I could not find
some easy enough way for elfutils first-class artificial ELF symbols.
I had to add all the INCLUDES entries because ebl-hooks.h declaration depends
on Dwfl_Module now.
In backends/ppc64_get_func_pc.c I was considering fixedsizehash.h instead of
qsort + bsearch but one needs to search by a block of bytes but
fixedsizehash.h can search only by strings.
Use there conversion by
+ val64 = (elf_getident (elf, NULL)[EI_DATA] == ELFDATA2MSB
+ ? be64toh (val64) : le64toh (val64));
While I used first src/readelf.c function "convert" I do not much understand
its purpose, it does not handle properly different sizes of indata / valuedata
anyway and it is more complicated than to just convert it by hand as above.
Thanks,
Jan
backends/
2012-10-09 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* Makefile.am (INCLUDES): Add libdwfl.
(ppc64_SRCS): Add ppc64_get_func_pc.c.
* ppc64_get_func_pc.c: New file.
* ppc64_init.c (ppc64_init): Install get_func_pc and destr.
libasm/
2012-10-09 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* Makefile.am (INCLUDES): Add libdwfl.
libcpu/
2012-10-09 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* Makefile.am (INCLUDES): Add libdwfl.
libdw/
2012-10-09 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* Makefile.am (INCLUDES): Add libdwfl.
libdwfl/
2012-10-09 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* dwfl_module_addrsym.c (dwfl_module_addrsym) (get_section): New
function from ...
(dwfl_module_addrsym) (same_section): ... here. Call it.
(dwfl_module_addrsym) (found_sym): New function from ...
(dwfl_module_addrsym) (search_table): ... here. Call it. Try second
time with ebl_get_func_pc.
libebl/
2012-10-09 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* Makefile.am (INCLUDES): Add libdwfl.
(gen_SOURCES): Add eblgetfuncpc.c.
* ebl-hooks.h (get_func_pc): New entry.
* eblgetfuncpc.c: New file.
* libebl.h: Include libdwfl.h.
(ebl_get_func_pc): New declaration.
* libeblP.h (struct ebl): New field backend.
tests/
2012-10-09 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* run-addrname-test.sh: New testcase for ppc64 function descriptors.
* testfile66.bz2: New file.
diff --git a/backends/Makefile.am b/backends/Makefile.am
index 982ff2a..f52c493 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -29,7 +29,7 @@
## not, see <http://www.gnu.org/licenses/>.
include $(top_srcdir)/config/eu.am
INCLUDES += -I$(top_srcdir)/libebl -I$(top_srcdir)/libasm \
- -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw
+ -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw -I$(top_srcdir)/libdwfl
modules = i386 sh x86_64 ia64 alpha arm sparc ppc ppc64 s390 tilegx
@@ -90,7 +90,8 @@ libebl_ppc_pic_a_SOURCES = $(ppc_SRCS)
am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os)
ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c \
- ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c ppc_syscall.c
+ ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \
+ ppc64_get_func_pc.c
libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS)
am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os)
diff --git a/backends/ppc64_get_func_pc.c b/backends/ppc64_get_func_pc.c
new file mode 100644
index 0000000..f6df6e2
--- /dev/null
+++ b/backends/ppc64_get_func_pc.c
@@ -0,0 +1,195 @@
+/* Convert function descriptor SYM to the function PC value in-place.
+ Copyright (C) 2005-2010 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
+
+#include <assert.h>
+#include "../libdwfl/libdwflP.h"
+#include <endian.h>
+
+#define BACKEND ppc64_
+#include "libebl_CPU.h"
+
+struct pc_entry
+{
+ /* sym_from must be the very first element for the use in bsearch below. */
+ GElf_Sym sym_from;
+ Elf64_Addr st_value_to;
+ const char *name_to;
+};
+
+struct pc_table
+{
+ size_t nelem;
+ struct pc_entry a[];
+ /* Here follow strings allocated for pc_entry->name_to. */
+};
+
+static int
+compar (const void *a_voidp, const void *b_voidp)
+{
+ const struct pc_entry *a = a_voidp;
+ const struct pc_entry *b = b_voidp;
+
+ return memcmp (&a->sym_from, &b->sym_from, sizeof (a->sym_from));
+}
+
+static void
+init (Ebl *ebl, Dwfl_Module *mod)
+{
+ int syments = dwfl_module_getsymtab (mod);
+ assert (syments >= 0);
+ GElf_Sym sym;
+ size_t funcs = 0;
+ size_t names_size = 0;
+ Elf *elf = ebl->elf;
+ if (elf == NULL)
+ return;
+ GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
+ if (ehdr == NULL)
+ return;
+ GElf_Word shndx, opd_shndx = 0;
+ /* Needless initialization for old GCCs. */
+ Elf_Data *opd_data = NULL;
+ /* Needless initialization for old GCCs. */
+ GElf_Shdr opd_shdr_mem, *opd_shdr = NULL;
+ for (int symi = 1; symi < syments; symi++)
+ {
+ if (dwfl_module_getsym (mod, symi, &sym, &shndx) == NULL
+ || GELF_ST_TYPE (sym.st_info) != STT_FUNC)
+ continue;
+ if (sym.st_shndx != SHN_XINDEX)
+ shndx = sym.st_shndx;
+ /* Zero is invalid value but it could crash this code. */
+ if (shndx == 0)
+ continue;
+ if (opd_shndx == 0)
+ {
+ Elf_Scn *scn = elf_getscn (elf, shndx);
+ if (scn == NULL)
+ continue;
+ opd_shdr = gelf_getshdr (scn, &opd_shdr_mem);
+ if (opd_shdr == NULL)
+ continue;
+ if (strcmp (elf_strptr (elf, ehdr->e_shstrndx, opd_shdr->sh_name),
+ ".opd") != 0)
+ continue;
+ opd_data = elf_getdata (scn, NULL);
+ /* SHT_NOBITS will produce NULL D_BUF. */
+ if (opd_data == NULL || opd_data->d_buf == NULL)
+ return;
+ assert (opd_data->d_size == opd_shdr->sh_size);
+ opd_shndx = shndx;
+ }
+ if (shndx != opd_shndx)
+ continue;
+ Elf64_Addr val;
+ if (sym.st_value < opd_shdr->sh_addr + mod->main_bias
+ || sym.st_value > (opd_shdr->sh_addr + mod->main_bias
+ + opd_shdr->sh_size - sizeof (val)))
+ continue;
+ if (unlikely (sym.st_name >= mod->symstrdata->d_size))
+ continue;
+ funcs++;
+ const char *name = mod->symstrdata->d_buf + sym.st_name;
+ names_size += 1 + strlen (name) + 1;
+ }
+ struct pc_table *pc_table;
+ pc_table = malloc (sizeof (*pc_table) + funcs * sizeof (*pc_table->a)
+ + names_size);
+ if (pc_table == NULL)
+ return;
+ ebl->backend = pc_table;
+ pc_table->nelem = 0;
+ if (funcs == 0)
+ return;
+ struct pc_entry *dest = pc_table->a;
+ char *names = (void *) (pc_table->a + funcs), *names_dest = names;
+ for (int symi = 1; symi < syments; symi++)
+ {
+ if (dwfl_module_getsym (mod, symi, &sym, &shndx) == NULL
+ || GELF_ST_TYPE (sym.st_info) != STT_FUNC)
+ continue;
+ if (sym.st_shndx != SHN_XINDEX)
+ shndx = sym.st_shndx;
+ if (shndx != opd_shndx)
+ continue;
+ uint64_t val64;
+ if (sym.st_value < opd_shdr->sh_addr + mod->main_bias
+ || sym.st_value > (opd_shdr->sh_addr + mod->main_bias
+ + opd_shdr->sh_size - sizeof (val64)))
+ continue;
+ val64 = *(const uint64_t *) (opd_data->d_buf + sym.st_value
+ - (opd_shdr->sh_addr + mod->main_bias));
+ val64 = (elf_getident (elf, NULL)[EI_DATA] == ELFDATA2MSB
+ ? be64toh (val64) : le64toh (val64));
+ assert (dest < pc_table->a + funcs);
+ dest->sym_from = sym;
+ dest->st_value_to = val64 + mod->main_bias;
+ assert (sym.st_name < mod->symstrdata->d_size);
+ const char *name = mod->symstrdata->d_buf + sym.st_name;
+ dest->name_to = names_dest;
+ *names_dest++ = '.';
+ names_dest = stpcpy (names_dest, name) + 1;
+ dest++;
+ pc_table->nelem++;
+ }
+ assert (pc_table->nelem == funcs);
+ assert (dest == pc_table->a + pc_table->nelem);
+ assert (names_dest == names + names_size);
+ qsort (pc_table->a, pc_table->nelem, sizeof (*pc_table->a), compar);
+}
+
+const char *
+ppc64_get_func_pc (Ebl *ebl, Dwfl_Module *mod, GElf_Sym *sym)
+{
+ if (ebl->backend == NULL)
+ init (ebl, mod);
+ if (ebl->backend == NULL)
+ return NULL;
+ const struct pc_table *pc_table = ebl->backend;
+ const struct pc_entry *found;
+ found = bsearch (sym, pc_table->a, pc_table->nelem, sizeof (*pc_table->a),
+ compar);
+ if (found == NULL)
+ return NULL;
+ sym->st_value = found->st_value_to;
+ return found->name_to;
+}
+
+void
+ppc64_destr (Ebl *ebl)
+{
+ if (ebl->backend == NULL)
+ return;
+ struct pc_table *pc_table = ebl->backend;
+ free (pc_table);
+ ebl->backend = NULL;
+}
diff --git a/backends/ppc64_init.c b/backends/ppc64_init.c
index 90d4f2b..da7d02c 100644
--- a/backends/ppc64_init.c
+++ b/backends/ppc64_init.c
@@ -64,6 +64,8 @@ ppc64_init (elf, machine, eh, ehlen)
HOOK (eh, syscall_abi);
HOOK (eh, core_note);
HOOK (eh, auxv_info);
+ HOOK (eh, get_func_pc);
+ HOOK (eh, destr);
return MODVERSION;
}
diff --git a/libasm/Makefile.am b/libasm/Makefile.am
index abe5468..0552a7e 100644
--- a/libasm/Makefile.am
+++ b/libasm/Makefile.am
@@ -28,7 +28,8 @@
## not, see <http://www.gnu.org/licenses/>.
##
include $(top_srcdir)/config/eu.am
-INCLUDES += -I$(top_srcdir)/libelf -I$(top_srcdir)/libebl -I$(top_srcdir)/libdw
+INCLUDES += -I$(top_srcdir)/libelf -I$(top_srcdir)/libebl \
+ -I$(top_srcdir)/libdw -I$(top_srcdir)/libdwfl
GCC_INCLUDE = -I$(shell $(CC) -print-file-name=include)
VERSION = 1
diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am
index 8f62be2..4934c76 100644
--- a/libcpu/Makefile.am
+++ b/libcpu/Makefile.am
@@ -29,7 +29,7 @@
##
include $(top_srcdir)/config/eu.am
INCLUDES += -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
- -I$(srcdir)/../libdw -I$(srcdir)/../libasm
+ -I$(srcdir)/../libdw -I$(srcdir)/../libdwfl -I$(srcdir)/../libasm
AM_CFLAGS += -fpic -fdollars-in-identifiers
LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -P$(<F:lex.l=)
LEX_OUTPUT_ROOT = lex.$(<F:lex.l=)
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index c6ac264..7189e91 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -32,7 +32,7 @@ DEFS += -DIS_LIBDW
if BUILD_STATIC
AM_CFLAGS += -fpic
endif
-INCLUDES += -I$(srcdir)/../libelf
+INCLUDES += -I$(srcdir)/../libelf -I$(srcdir)/../libdwfl
VERSION = 1
lib_LIBRARIES = libdw.a
diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c
index dcc2a7a..272b31e 100644
--- a/libdwfl/dwfl_module_addrsym.c
+++ b/libdwfl/dwfl_module_addrsym.c
@@ -39,6 +39,23 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
if (syments < 0)
return NULL;
+ /* Return section where FIND_ADDR lies. Return SHN_ABS otherwise. */
+ inline GElf_Word get_section (GElf_Addr find_addr)
+ {
+ GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, find_addr);
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (likely (shdr != NULL)
+ && mod_addr >= shdr->sh_addr
+ && mod_addr < shdr->sh_addr + shdr->sh_size)
+ return elf_ndxscn (scn);
+ }
+ return SHN_ABS;
+ }
+
/* Return true iff we consider ADDR to lie in the same section as SYM. */
GElf_Word addr_shndx = SHN_UNDEF;
inline bool same_section (const GElf_Sym *sym, GElf_Word shndx)
@@ -49,23 +66,7 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
/* Figure out what section ADDR lies in. */
if (addr_shndx == SHN_UNDEF)
- {
- GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, addr);
- Elf_Scn *scn = NULL;
- addr_shndx = SHN_ABS;
- while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
- {
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- if (likely (shdr != NULL)
- && mod_addr >= shdr->sh_addr
- && mod_addr < shdr->sh_addr + shdr->sh_size)
- {
- addr_shndx = elf_ndxscn (scn);
- break;
- }
- }
- }
+ addr_shndx = get_section (addr);
return shndx == addr_shndx;
}
@@ -83,80 +84,95 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
/* Keep track of the lowest address a relevant sizeless symbol could have. */
GElf_Addr min_label = 0;
- /* Look through the symbol table for a matching symbol. */
- inline void search_table (int start, int end)
+ /* Consider one symbol SYM. */
+ inline void found_sym (const GElf_Sym *sym, GElf_Word shndx, const char *name)
{
- for (int i = start; i < end; ++i)
+ if (name != NULL && name[0] != '\0'
+ && sym->st_shndx != SHN_UNDEF
+ && sym->st_value <= addr
+ && GELF_ST_TYPE (sym->st_info) != STT_SECTION
+ && GELF_ST_TYPE (sym->st_info) != STT_FILE
+ && GELF_ST_TYPE (sym->st_info) != STT_TLS)
{
- GElf_Sym sym;
- GElf_Word shndx;
- const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx);
- if (name != NULL && name[0] != '\0'
- && sym.st_shndx != SHN_UNDEF
- && sym.st_value <= addr
- && GELF_ST_TYPE (sym.st_info) != STT_SECTION
- && GELF_ST_TYPE (sym.st_info) != STT_FILE
- && GELF_ST_TYPE (sym.st_info) != STT_TLS)
- {
- /* Even if we don't choose this symbol, its existence excludes
- any sizeless symbol (assembly label) that is below its upper
- bound. */
- if (sym.st_value + sym.st_size > min_label)
- min_label = sym.st_value + sym.st_size;
+ /* Even if we don't choose this symbol, its existence excludes
+ any sizeless symbol (assembly label) that is below its upper
+ bound. */
+ if (sym->st_value + sym->st_size > min_label)
+ min_label = sym->st_value + sym->st_size;
- if (sym.st_size == 0 || addr - sym.st_value < sym.st_size)
- {
+ if (sym->st_size == 0 || addr - sym->st_value < sym->st_size)
+ {
#define BIND_PREF(sym) \
- (GELF_ST_BIND ((sym).st_info) == STB_GLOBAL \
- ? 3 : (GELF_ST_BIND ((sym).st_info) == STB_WEAK \
- ? 2 : (GELF_ST_BIND ((sym).st_info) == STB_LOCAL ? 1 : 0)))
- /* This symbol is a better candidate than the current one
- if it's closer to ADDR or is global when it was local. */
- if (closest_name == NULL
- || closest_sym->st_value < sym.st_value
- || BIND_PREF (*closest_sym) < BIND_PREF (sym))
- {
- if (sym.st_size != 0)
- {
- *closest_sym = sym;
- closest_shndx = shndx;
- closest_name = name;
- }
- else if (closest_name == NULL
- && sym.st_value >= min_label
- && same_section (&sym, shndx))
- {
- /* Handwritten assembly symbols sometimes have no
- st_size. If no symbol with proper size includes
- the address, we'll use the closest one that is in
- the same section as ADDR. */
- sizeless_sym = sym;
- sizeless_shndx = shndx;
- sizeless_name = name;
- }
- }
- /* When the beginning of its range is no closer,
- the end of its range might be. Otherwise follow
- GELF_ST_BIND preference. If all are equal prefer
- the first symbol found. */
- else if (sym.st_size != 0
- && closest_sym->st_value == sym.st_value
- && ((closest_sym->st_size > sym.st_size
- && BIND_PREF (*closest_sym) <= BIND_PREF (sym))
- || (closest_sym->st_size >= sym.st_size
- && (BIND_PREF (*closest_sym)
- < BIND_PREF (sym)))))
+ (GELF_ST_BIND ((sym)->st_info) == STB_GLOBAL \
+ ? 3 : (GELF_ST_BIND ((sym)->st_info) == STB_WEAK \
+ ? 2 : (GELF_ST_BIND ((sym)->st_info) == STB_LOCAL ? 1 : 0)))
+ /* This symbol is a better candidate than the current one
+ if it's closer to ADDR or is global when it was local. */
+ if (closest_name == NULL
+ || closest_sym->st_value < sym->st_value
+ || BIND_PREF (closest_sym) < BIND_PREF (sym))
+ {
+ if (sym->st_size != 0)
{
- *closest_sym = sym;
+ *closest_sym = *sym;
closest_shndx = shndx;
closest_name = name;
}
-#undef BIND_PREF
+ else if (closest_name == NULL
+ && sym->st_value >= min_label
+ && same_section (sym, shndx))
+ {
+ /* Handwritten assembly symbols sometimes have no
+ st_size. If no symbol with proper size includes
+ the address, we'll use the closest one that is in
+ the same section as ADDR. */
+ sizeless_sym = *sym;
+ sizeless_shndx = shndx;
+ sizeless_name = name;
+ }
+ }
+ /* When the beginning of its range is no closer,
+ the end of its range might be. Otherwise follow
+ GELF_ST_BIND preference. If all are equal prefer
+ the first symbol found. */
+ else if (sym->st_size != 0
+ && closest_sym->st_value == sym->st_value
+ && ((closest_sym->st_size > sym->st_size
+ && BIND_PREF (closest_sym) <= BIND_PREF (sym))
+ || (closest_sym->st_size >= sym->st_size
+ && (BIND_PREF (closest_sym) < BIND_PREF (sym)))))
+ {
+ *closest_sym = *sym;
+ closest_shndx = shndx;
+ closest_name = name;
}
+#undef BIND_PREF
}
}
}
+ /* Look through the symbol table for a matching symbol. */
+ inline void search_table (int start, int end)
+ {
+ for (int i = start; i < end; ++i)
+ {
+ GElf_Sym sym;
+ GElf_Word shndx;
+ const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx);
+ found_sym (&sym, shndx, name);
+ if (name == NULL || GELF_ST_TYPE (sym.st_info) != STT_FUNC)
+ continue;
+ Dwfl_Error error = __libdwfl_module_getebl (mod);
+ if (error != DWFL_E_NOERROR)
+ continue;
+ name = ebl_get_func_pc (mod->ebl, mod, &sym);
+ if (name == NULL)
+ continue;
+ shndx = get_section (sym.st_value);
+ found_sym (&sym, shndx, name);
+ }
+ }
+
/* First go through global symbols. mod->first_global is setup by
dwfl_module_getsymtab to the index of the first global symbol in
the module's symbol table, or -1 when unknown. All symbols with
diff --git a/libebl/Makefile.am b/libebl/Makefile.am
index 65e6b5b..db24518 100644
--- a/libebl/Makefile.am
+++ b/libebl/Makefile.am
@@ -29,7 +29,8 @@
##
include $(top_srcdir)/config/eu.am
AM_CFLAGS += -fpic
-INCLUDES += -I$(srcdir)/../libelf -I$(srcdir)/../libdw -I$(srcdir)/../libasm
+INCLUDES += -I$(srcdir)/../libelf -I$(srcdir)/../libdw -I$(srcdir)/../libdwfl \
+ -I$(srcdir)/../libasm
VERSION = 1
LIBEBL_SUBDIR = @LIBEBL_SUBDIR@
@@ -54,7 +55,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
+ eblstother.c eblgetfuncpc.c
libebl_a_SOURCES = $(gen_SOURCES)
diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h
index f629bce..6510e98 100644
--- a/libebl/ebl-hooks.h
+++ b/libebl/ebl-hooks.h
@@ -154,5 +154,10 @@ int EBLHOOK(disasm) (const uint8_t **startp, const uint8_t *end,
/* Supply the machine-specific state of CFI before CIE initial programs. */
int EBLHOOK(abi_cfi) (Ebl *ebl, Dwarf_CIE *abi_info);
+/* *SYM must be STT_FUNC. Then if it describes a function descriptor (PPC64)
+ convert in-place its data and return a possibly different new name for it.
+ The name is valid as long as EBL is valid. */
+const char *EBLHOOK(get_func_pc) (Ebl *ebl, Dwfl_Module *mod, GElf_Sym *sym);
+
/* Destructor for ELF backend handle. */
void EBLHOOK(destr) (struct ebl *);
diff --git a/libebl/eblgetfuncpc.c b/libebl/eblgetfuncpc.c
new file mode 100644
index 0000000..f67c08f
--- /dev/null
+++ b/libebl/eblgetfuncpc.c
@@ -0,0 +1,46 @@
+/* Convert function descriptor SYM to the function PC value in-place.
+ Copyright (C) 2012 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
+
+#include <libeblP.h>
+#include <assert.h>
+
+const char *
+ebl_get_func_pc (Ebl *ebl, Dwfl_Module *mod, GElf_Sym *sym)
+{
+ if (ebl == NULL)
+ return NULL;
+ assert (sym != NULL);
+ assert (GELF_ST_TYPE (sym->st_info) == STT_FUNC);
+ if (ebl->get_func_pc == NULL)
+ return NULL;
+ return ebl->get_func_pc (ebl, mod, sym);
+}
diff --git a/libebl/libebl.h b/libebl/libebl.h
index 0d5621d..6f67451 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -31,6 +31,7 @@
#include <gelf.h>
#include "libdw.h"
+#include "libdwfl.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -375,6 +376,10 @@ extern int ebl_auxv_info (Ebl *ebl, GElf_Xword a_type,
const char **name, const char **format)
__nonnull_attribute__ (1, 3, 4);
+/* Convert function descriptor SYM to the function PC value in-place. */
+extern const char *ebl_get_func_pc (Ebl *ebl, Dwfl_Module *mod, GElf_Sym *sym)
+ __nonnull_attribute__ (1, 2, 3);
+
#ifdef __cplusplus
}
diff --git a/libebl/libeblP.h b/libebl/libeblP.h
index 5ec26a4..c8196bd 100644
--- a/libebl/libeblP.h
+++ b/libebl/libeblP.h
@@ -62,6 +62,9 @@ struct ebl
/* Internal data. */
void *dlhandle;
+
+ /* Data specific to the backend. */
+ void *backend;
};
diff --git a/tests/run-addrname-test.sh b/tests/run-addrname-test.sh
index 4feb193..4dd6018 100755
--- a/tests/run-addrname-test.sh
+++ b/tests/run-addrname-test.sh
@@ -298,4 +298,12 @@ __vdso_time
??:0
EOF
+testfiles testfile66
+testrun_compare ../src/addr2line -S -e testfile66 0x10340 0x250 <<\EOF
+func
+??:0
+.func
+??:0
+EOF
+
exit 0
diff --git a/tests/testfile66.bz2 b/tests/testfile66.bz2
new file mode 100755
index 0000000000000000000000000000000000000000..db07f25415729927f4e2b4985c5668c8e2ee10a2
GIT binary patch
literal 569
zcmV-90>=G9T4*^jL0KkKSrloeYybi*|NH;`Q+Gmd_t9I$azOv*{$$8R5dZ){00;sg
zN(3VzzyZ?W%~)z`O*V<ChK5r#X)zd>fu;fm0WvhiG}9)JQGyXYL8JhU5NHRe007X?
z$Qoh*0BMi_;L)Q%&}a;pfXL9u01Y(A003Zs0!0dH8USbj00000000000H3&^h5+h?
zHGH8oS#&k;tR%<0nFK6&-#1i4RnYl;-bpN9k2InZwNKHPIa5z$l?D9dtf^2;aFZ>;
z6H2`TaFp50B|IFU9;meM2nk4CXKdt!?6iqh`+DOs7204JFHHaexzT9oele)vNXcO|
z&aXz&bgUpHL5Q+$&J@iFQZPa%v>5P$Ld;?WwHgw?W$OZSUT)aw=i|cU?V{^+uO+T&
zsc1>77*MKpaR&z&l3<3FBTF`AA*kg!f+LXQdlF0z1|<OGVw|;E3MDuVYg}lF1kIB*
z2MO?2(vv|()kGjFhM>|aV;0;9Y&kKvJQ6|?q76u^Sl}`<LIO+NDfU1C1=+J>CXwR7
zvQ|1@iR(qMOPC<M!U)iAS_QSrP$be&teWK@Xh4y??kxH~E_K((z?!P4lv4z@9Y0sD
zK?cn^FLD~401iNn#iXf~Yy5H5(sqZpp=+#)n|DQ6r81NSyLB;KQD(6uE>?9m>Ok-8
z(YXp^O0BHJBpo)oV3bgUCvFNTfZoo@a?O8}_!iyT909f+z2<0!_i&kLzs1~<P81{s
H8flvV7_Id;
literal 0
HcmV?d00001
11 years, 4 months
[PATCH] show_symbols_sysv: Fix incorrect size in snprintf
by David Abdurachmanov
A size of a pointer is passed to snprintf forcing it [snprintf] to
truncate the output. size must be sizeof "[invalid sh_name 0x12345678]"
+ 1 (for the terminating null byte "\0").
Signed-off-by: David Abdurachmanov <David.Abdurachmanov(a)cern.ch>
---
src/nm.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/nm.c b/src/nm.c
index f50da0b..8012b2f 100644
--- a/src/nm.c
+++ b/src/nm.c
@@ -770,7 +770,7 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, const char *fullname,
if (unlikely (name == NULL))
{
name = alloca (sizeof "[invalid sh_name 0x12345678]");
- snprintf (name, sizeof name, "[invalid sh_name %#" PRIx32 "]",
+ snprintf (name, sizeof "[invalid sh_name 0x12345678]" + 1, "[invalid sh_name %#" PRIx32 "]",
gelf_getshdr (scn, &shdr_mem)->sh_name);
}
scnnames[elf_ndxscn (scn)] = name;
--
1.7.4.1
11 years, 4 months
[PATCH] Fix two failure condition checks in libdwfl/linux-kernel-modules.c.
by Mark Wielaard
In report_kernel () if find_kernel_elf () fails then fname hasn't been
allocated or already freed. Don't free it again.
Brackets around unlikely expression in report_kernel_archive were incorrect
making the check always succeed.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdwfl/ChangeLog | 6 ++++++
libdwfl/linux-kernel-modules.c | 6 +++---
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index bea55cf..896ae39 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,9 @@
+2012-12-11 Mark Wielaard <mjw(a)redhat.com>
+
+ * linux-kernel-modules.c (report_kernel): Only free fname if
+ find_kernel_elf succeeds and allocates it.
+ (report_kernel_archive): Fix brackets around unlikely expression.
+
2012-11-29 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* argp-std.c: Update Copyright year.
diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
index bafe53c..9bf5f25 100644
--- a/libdwfl/linux-kernel-modules.c
+++ b/libdwfl/linux-kernel-modules.c
@@ -225,12 +225,12 @@ report_kernel (Dwfl *dwfl, const char **release,
mod->e_type = ET_DYN;
}
+ free (fname);
+
if (!report || result < 0)
close (fd);
}
- free (fname);
-
return result;
}
@@ -247,7 +247,7 @@ report_kernel_archive (Dwfl *dwfl, const char **release,
char *archive;
if (unlikely ((*release)[0] == '/'
? asprintf (&archive, "%s/debug.a", *release)
- : asprintf (&archive, MODULEDIRFMT "/debug.a", *release)) < 0)
+ : asprintf (&archive, MODULEDIRFMT "/debug.a", *release) < 0))
return ENOMEM;
int fd = try_kernel_name (dwfl, &archive, false);
--
1.7.1
11 years, 4 months
[PATCH] Run valgrind tests with --run-libc-freeres=no.
by Mark Wielaard
By default valgrind tries to free up glibc memory at exit by running
__libc_freeres (). Unfortunately some older glibc versions have bugs
that either crash the test or make valgrind report errors. Since we
aren't interested in tracking memory leaks in glibc anyway, just
disable it.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
tests/ChangeLog | 4 ++++
tests/Makefile.am | 2 +-
2 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 5b06b85..0289148 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,7 @@
+2012-12-03 Mark Wielaard <mjw(a)redhat.com>
+
+ * Makefile.am (valgrind_cmd): Add --run-libc-freeres=no.
+
2012-11-29 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* run-addrname-test.sh: New test for PIE relocation.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6808bd1..8b7b751 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -184,7 +184,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
testfile70.core.bz2 testfile70.exec.bz2
if USE_VALGRIND
-valgrind_cmd="valgrind -q --trace-children=yes --error-exitcode=1"
+valgrind_cmd="valgrind -q --trace-children=yes --error-exitcode=1 --run-libc-freeres=no"
endif
installed_TESTS_ENVIRONMENT = libdir=$(DESTDIR)$(libdir) \
--
1.7.1
11 years, 4 months