[PATCH] Note that .rela.debug* sections are debuginfo sections.
by Nick Alcock
Without this fix, strip -g misbehaves when stripping object files
and other ELF objects containing debuginfo relocation sections,
preserving all debuginfo sections in the output file because the
.rela.debug* sections reference them.
Signed-off-by: Nick Alcock <nick.alcock(a)oracle.com>
---
The selection of sections to RELAFY here is pretty much arbitrary,
covering everything I've seen .rela.* created for and anything else that
seems likely to need it.
Testing is trivial: try to strip -g a Linux kernel module (or any other
object file containing debug info) and observe the .debug* and
.rela.debug* sections turning up in the stripped output rather than (if
specified) the -f file. binutils behaves correctly in this area.
I haven't considered DWARF 1 sections not shared with DWARF 2+ at all
because I have no way to generate such sections for testing.
libebl/ChangeLog | 5 +++++
libebl/eblopenbackend.c | 36 +++++++++++++++++++-----------------
2 files changed, 24 insertions(+), 17 deletions(-)
diff --git a/libebl/ChangeLog b/libebl/ChangeLog
index af819a2..c6204c6 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,8 @@
+2012-09-18 Nick Alcock <nick.alcock(a)oracle.com>
+
+ * eblopenbackend.c (default_debugscn_p): Add .rela.* versions of
+ many DWARF 2+ debuginfo sections.
+
2012-08-22 Jeff Kenton <jkenton(a)tilera.com>
* eblopenbackend.c (machines): Add tilegx.
diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c
index 89e5da5..d10b0d0 100644
--- a/libebl/eblopenbackend.c
+++ b/libebl/eblopenbackend.c
@@ -619,6 +619,7 @@ default_object_note (const char *name __attribute__ ((unused)),
static bool
default_debugscn_p (const char *name)
{
+#define RELAFY(x) x, ".rela" x
/* We know by default only about the DWARF debug sections which have
fixed names. */
static const char *dwarf_scn_names[] =
@@ -630,31 +631,32 @@ default_debugscn_p (const char *name)
".debug_srcinfo",
".debug_sfnames",
/* DWARF 1.1 and DWARF 2 */
- ".debug_aranges",
- ".debug_pubnames",
+ RELAFY(".debug_aranges"),
+ RELAFY(".debug_pubnames"),
/* DWARF 2 */
- ".debug_info",
- ".debug_abbrev",
- ".debug_line",
- ".debug_frame",
- ".debug_str",
- ".debug_loc",
- ".debug_macinfo",
+ RELAFY(".debug_info"),
+ RELAFY(".debug_abbrev"),
+ RELAFY(".debug_line"),
+ RELAFY(".debug_frame"),
+ RELAFY(".debug_str"),
+ RELAFY(".debug_loc"),
+ RELAFY(".debug_macinfo"),
/* DWARF 3 */
- ".debug_ranges",
- ".debug_pubtypes",
+ RELAFY(".debug_ranges"),
+ RELAFY(".debug_pubtypes"),
/* DWARF 4 */
- ".debug_types",
+ RELAFY(".debug_types"),
/* GDB DWARF 4 extension */
".gdb_index",
/* GNU/DWARF 5 extension/proposal */
- ".debug_macro",
+ RELAFY(".debug_macro"),
/* SGI/MIPS DWARF 2 extensions */
- ".debug_weaknames",
- ".debug_funcnames",
- ".debug_typenames",
- ".debug_varnames"
+ RELAFY(".debug_weaknames"),
+ RELAFY(".debug_funcnames"),
+ RELAFY(".debug_typenames"),
+ RELAFY(".debug_varnames")
};
+#undef RELAFY
const size_t ndwarf_scn_names = (sizeof (dwarf_scn_names)
/ sizeof (dwarf_scn_names[0]));
for (size_t cnt = 0; cnt < ndwarf_scn_names; ++cnt)
--
1.7.12.156.gd7c4257
--
NULL && (void)
10 years, 2 months
[patch 5/4] unwinder: non-x86* parts of the unwinder [resent]
by Jan Kratochvil
Hi,
dependent on:
[patch 4/4] unwinder: The unwinder (x86* only)
present in:
jankratochvil/forunwind-baseaddr-hookvars-corereport-unwindx86-nonx86
but this branch is not suitable for merge as it is unclear in which form get
checked in the patches above. The branch is usable only for "git checkout",
neither diff nor merge should be done on it.
ppc* and s390* extensions with core files to test them.
The testfiles are present only in the GIT branch, not in the diff below.
Thanks,
Jan
backends/
2012-11-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* Makefile.am (ppc_SRCS, ppc64_SRCS): Add ppc_frame_state.c and
ppc_cfi.c.
(s390_SRCS): Add s390_cfi.c, s390_frame_state.c and
s390_frame_unwind.c.
(noinst_HEADERS): Add core-get-pc.c.
* core-get-pc.c: New file.
* ppc64_init.c (ppc64_init): Initialize frame_state_nregs, frame_state,
abi_cfi, frame_dwarf_to_regno, get_func_pc and destr.
* ppc_cfi.c: New file.
* ppc_frame_state.c: New file.
* ppc_init.c (ppc_init): Initialize frame_state_nregs, frame_state,
abi_cfi and frame_dwarf_to_regno.
* s390_cfi.c: New file.
* s390_frame_state.c: New file.
* s390_frame_unwind.c: New file.
* s390_init.c (s390_init): Initialize abi_cfi, frame_state_nregs,
frame_state, optionally normalize_pc and also frame_unwind.
libdwfl/
2012-11-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* dwfl_frame_state_pc.c (dwfl_frame_state_pc): Call ebl_normalize_pc.
* dwfl_frame_unwind.c (handle_cfi): Call ebl_frame_dwarf_to_regno.
(dwfl_frame_unwind): Reinitialzie *STATEP, call ebl_frame_unwind,
handle its return value.
* libdwflP.h (dwfl_frame_state_reg_get, dwfl_frame_state_reg_set): Call
frame_dwarf_to_regno.
libebl/
2012-11-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* Makefile.am (gen_SOURCES): Add eblnormalizepc.c, eblframeunwind.c and
eblframedwarftoregno.c.
* ebl-hooks.h (frame_dwarf_to_regno, normalize_pc, frame_unwind): New
entries.
* eblframedwarftoregno.c: New file.
* eblframeunwind.c: New file.
* eblnormalizepc.c: New file.
* libebl.h (ebl_normalize_pc, struct Dwfl_Frame_State_Process)
(ebl_frame_unwind, ebl_frame_dwarf_to_regno): New declarations.
tests/
2012-11-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* backtrace.ppc.core.bz2: New file.
* backtrace.ppc.exec.bz2: New file.
* backtrace.ppc64.core.bz2: New file.
* backtrace.ppc64.exec.bz2: New file.
* backtrace.s390.core.bz2: New file.
* backtrace.s390.exec.bz2: New file.
* backtrace.s390x.core.bz2: New file.
* backtrace.s390x.exec.bz2: New file.
* run-backtrace.sh: Add tests for the core files above.
diff --git a/backends/Makefile.am b/backends/Makefile.am
index 6f99758..ad909da 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -87,18 +87,20 @@ libebl_sparc_pic_a_SOURCES = $(sparc_SRCS)
am_libebl_sparc_pic_a_OBJECTS = $(sparc_SRCS:.c=.os)
ppc_SRCS = ppc_init.c ppc_symbol.c ppc_retval.c ppc_regs.c \
- ppc_corenote.c ppc_auxv.c ppc_attrs.c ppc_syscall.c
+ ppc_corenote.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \
+ ppc_frame_state.c ppc_cfi.c
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_get_func_pc.c
+ ppc64_get_func_pc.c ppc_frame_state.c ppc_cfi.c
libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS)
am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os)
s390_SRCS = s390_init.c s390_symbol.c s390_regs.c s390_retval.c \
- s390_corenote.c s390x_corenote.c
+ s390_corenote.c s390x_corenote.c s390_cfi.c s390_frame_state.c \
+ s390_frame_unwind.c
libebl_s390_pic_a_SOURCES = $(s390_SRCS)
am_libebl_s390_pic_a_OBJECTS = $(s390_SRCS:.c=.os)
@@ -136,7 +138,8 @@ uninstall: uninstall-am
done
rmdir --ignore-fail-on-non-empty $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)
-noinst_HEADERS = libebl_CPU.h common-reloc.c linux-core-note.c x86_corenote.c
+noinst_HEADERS = libebl_CPU.h common-reloc.c linux-core-note.c x86_corenote.c \
+ core-get-pc.c
EXTRA_DIST = $(foreach m,$(modules),$($(m)_SRCS)) $(modules:=_reloc.def)
CLEANFILES += $(foreach m,$(modules),\
diff --git a/backends/core-get-pc.c b/backends/core-get-pc.c
new file mode 100644
index 0000000..4d1b92e
--- /dev/null
+++ b/backends/core-get-pc.c
@@ -0,0 +1,86 @@
+/* Common core note PC address extraction.
+ 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/>. */
+
+#include <stdlib.h>
+
+static bool
+core_get_pc (Elf *core, Dwarf_Addr *core_pc, unsigned pc_offset)
+{
+ size_t phnum;
+ if (elf_getphdrnum (core, &phnum) < 0)
+ return NULL;
+ unsigned bits = gelf_getclass (core) == ELFCLASS32 ? 32 : 64;
+ for (size_t cnt = 0; cnt < phnum; ++cnt)
+ {
+ GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
+ if (phdr == NULL || phdr->p_type != PT_NOTE)
+ continue;
+ Elf_Data *data = elf_getdata_rawchunk (core, phdr->p_offset,
+ phdr->p_filesz, ELF_T_NHDR);
+ if (data == NULL)
+ return NULL;
+ size_t offset = 0;
+ GElf_Nhdr nhdr;
+ size_t name_offset;
+ size_t desc_offset;
+ while (offset < data->d_size
+ && (offset = gelf_getnote (data, offset,
+ &nhdr, &name_offset, &desc_offset)) > 0)
+ {
+ if (nhdr.n_type != NT_PRSTATUS)
+ continue;
+ const char *reg_desc = data->d_buf + desc_offset + pc_offset;
+ if (reg_desc + bits / 8 > (const char *) data->d_buf + nhdr.n_descsz)
+ continue;
+ Dwarf_Addr val;
+ switch (bits)
+ {
+ case 32:;
+ uint32_t val32 = *(const uint32_t *) reg_desc;
+ reg_desc += sizeof val32;
+ val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
+ ? be32toh (val32) : le32toh (val32));
+ /* Do a host width conversion. */
+ val = val32;
+ break;
+ case 64:;
+ uint64_t val64 = *(const uint64_t *) reg_desc;
+ reg_desc += sizeof val64;
+ val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
+ ? be64toh (val64) : le64toh (val64));
+ val = val64;
+ break;
+ default:
+ abort ();
+ }
+ *core_pc = val;
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/backends/ppc64_init.c b/backends/ppc64_init.c
index da7d02c..32ca876 100644
--- a/backends/ppc64_init.c
+++ b/backends/ppc64_init.c
@@ -66,6 +66,13 @@ ppc64_init (elf, machine, eh, ehlen)
HOOK (eh, auxv_info);
HOOK (eh, get_func_pc);
HOOK (eh, destr);
+ /* gcc/config/ #define DWARF_FRAME_REGISTERS. */
+ eh->frame_state_nregs = (114 - 1) + 32;
+ HOOK (eh, frame_state);
+ HOOK (eh, abi_cfi);
+ HOOK (eh, frame_dwarf_to_regno);
+ HOOK (eh, get_func_pc);
+ HOOK (eh, destr);
return MODVERSION;
}
diff --git a/backends/ppc_cfi.c b/backends/ppc_cfi.c
new file mode 100644
index 0000000..2c7091f
--- /dev/null
+++ b/backends/ppc_cfi.c
@@ -0,0 +1,77 @@
+/* ppc ABI-specified defaults for DWARF CFI.
+ 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 <dwarf.h>
+
+#define BACKEND ppc_
+#include "libebl_CPU.h"
+
+int
+ppc_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info)
+{
+ static const uint8_t abi_cfi[] =
+ {
+ /* This instruction is provided in every CIE. It is not repeated here:
+ DW_CFA_def_cfa, ULEB128_7 (1), ULEB128_7 (0) */
+ /* r1 is assumed to be restored from cfa adress,
+ r1 acts as a stack frame pointer. */
+ DW_CFA_val_expression, ULEB128_7 (1), ULEB128_7 (1), DW_OP_nop,
+ /* lr is not callee-saved but it needs to be preserved as it is pre-set
+ by the caller. */
+ DW_CFA_same_value, ULEB128_7 (65), /* lr */
+
+ /* Callee-saved regs. */
+#define SV(n) DW_CFA_same_value, ULEB128_7 (n)
+ SV (2), /* r2 is TOC pointer. */
+ SV (13), /* Reserved as system thread id (is it for CFI?). */
+ /* r14-r31 are non-volatile registers. */
+ SV (14), SV (15), SV (16), SV (17), SV (18), SV (19), SV (20), SV (21),
+ SV (22), SV (23), SV (24), SV (25), SV (26), SV (27), SV (28), SV (29),
+ SV (30), SV (31)
+ /* VMX registers v20-v31 and vrsave are non-volatile but they are
+ assigned DWARF registers 1144-1156 (v20-v31) which is outside of the
+ CFI supported range. */
+#undef SV
+ };
+
+ abi_info->initial_instructions = abi_cfi;
+ abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi];
+ abi_info->data_alignment_factor = ebl->class == ELFCLASS64 ? 8 : 4;
+
+ abi_info->return_address_register = 65;
+
+ return 0;
+}
+
+__typeof (ppc_abi_cfi)
+ ppc64_abi_cfi
+ __attribute__ ((alias ("ppc_abi_cfi")));
diff --git a/backends/ppc_frame_state.c b/backends/ppc_frame_state.c
new file mode 100644
index 0000000..0965e23
--- /dev/null
+++ b/backends/ppc_frame_state.c
@@ -0,0 +1,122 @@
+/* Fetch live process Dwfl_Frame_State from PID.
+ 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
+
+#ifdef __powerpc__
+# include <sys/user.h>
+# include <sys/ptrace.h>
+#endif
+#include "libdwflP.h"
+
+#define BACKEND ppc_
+#include "libebl_CPU.h"
+
+#include "core-get-pc.c"
+
+bool
+ppc_frame_dwarf_to_regno (Ebl *ebl __attribute__ ((unused)), unsigned *regno)
+{
+ switch (*regno)
+ {
+ case 108:
+ *regno = 65;
+ return true;
+ case 0 ... 107:
+ case 109 ... (114 - 1) -1:
+ return true;
+ case 1200 ... 1231:
+ *regno = *regno - 1200 + (114 - 1);
+ return true;
+ default:
+ return false;
+ }
+ abort ();
+}
+
+__typeof (ppc_frame_dwarf_to_regno)
+ ppc64_frame_dwarf_to_regno
+ __attribute__ ((alias ("ppc_frame_dwarf_to_regno")));
+
+bool
+ppc_frame_state (Dwfl_Frame_State *state)
+{
+ Dwfl_Frame_State_Thread *thread = state->thread;
+ Dwfl_Frame_State_Process *process = thread->process;
+ Ebl *ebl = process->ebl;
+ Elf *core = process->core;
+ pid_t tid = thread->tid;
+ if (core == NULL && tid)
+ {
+#ifndef __powerpc__
+ return false;
+#else /* __powerpc__ */
+ union
+ {
+ struct pt_regs r;
+ long l[sizeof (struct pt_regs) / sizeof (long)];
+ }
+ user_regs;
+ eu_static_assert (sizeof (struct pt_regs) % sizeof (long) == 0);
+ /* PTRACE_GETREGS is EIO on kernel-2.6.18-308.el5.ppc64. */
+ errno = 0;
+ for (unsigned regno = 0; regno < sizeof (user_regs) / sizeof (long);
+ regno++)
+ {
+ user_regs.l[regno] = ptrace (PTRACE_PEEKUSER, tid,
+ (void *) (uintptr_t) (regno
+ * sizeof (long)),
+ NULL);
+ if (errno != 0)
+ return false;
+ }
+ for (unsigned gpr = 0;
+ gpr < sizeof (user_regs.r.gpr) / sizeof (*user_regs.r.gpr); gpr++)
+ dwfl_frame_state_reg_set (state, gpr, user_regs.r.gpr[gpr]);
+ state->pc = user_regs.r.nip;
+ state->pc_state = DWFL_FRAME_STATE_PC_SET;
+ dwfl_frame_state_reg_set (state, 65, user_regs.r.link); // or 108
+ /* Registers like msr, ctr, xer, dar, dsisr etc. are probably irrelevant
+ for CFI. */
+#endif /* __powerpc__ */
+ }
+ else if (core)
+ {
+ if (! core_get_pc (core, &state->pc,
+ ebl->class == ELFCLASS64 ? 0x170 : 0xc8))
+ return false;
+ state->pc_state = DWFL_FRAME_STATE_PC_SET;
+ }
+ return true;
+}
+
+__typeof (ppc_frame_state)
+ ppc64_frame_state
+ __attribute__ ((alias ("ppc_frame_state")));
diff --git a/backends/ppc_init.c b/backends/ppc_init.c
index 6054007..87864ae 100644
--- a/backends/ppc_init.c
+++ b/backends/ppc_init.c
@@ -64,6 +64,11 @@ ppc_init (elf, machine, eh, ehlen)
HOOK (eh, core_note);
HOOK (eh, auxv_info);
HOOK (eh, check_object_attribute);
+ /* gcc/config/ #define DWARF_FRAME_REGISTERS. */
+ eh->frame_state_nregs = (114 - 1) + 32;
+ HOOK (eh, frame_state);
+ HOOK (eh, abi_cfi);
+ HOOK (eh, frame_dwarf_to_regno);
return MODVERSION;
}
diff --git a/backends/s390_cfi.c b/backends/s390_cfi.c
new file mode 100644
index 0000000..66a79ff
--- /dev/null
+++ b/backends/s390_cfi.c
@@ -0,0 +1,65 @@
+/* s390 ABI-specified defaults for DWARF CFI.
+ 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 <dwarf.h>
+
+#define BACKEND s390_
+#include "libebl_CPU.h"
+
+int
+s390_abi_cfi (Ebl *ebl, Dwarf_CIE *abi_info)
+{
+ static const uint8_t abi_cfi[] =
+ {
+ /* This instruction is provided in every CIE. It is not repeated here:
+ DW_CFA_def_cfa, ULEB128_7 (15), ULEB128_7 (96) */
+ /* r14 is not callee-saved but it needs to be preserved as it is pre-set
+ by the caller. */
+ DW_CFA_same_value, ULEB128_7 (14), /* r14 */
+
+ /* Callee-saved regs. */
+#define SV(n) DW_CFA_same_value, ULEB128_7 (n)
+ SV (6), SV (7), SV (8), SV (9), SV (10), /* r6-r13, r15 */
+ SV (11), SV (12), SV (13), SV (15),
+ SV (16 + 8), SV (16 + 9), SV (16 + 10), SV (16 + 11), /* f8-f15 */
+ SV (16 + 12), SV (16 + 13), SV (16 + 14), SV (16 + 15)
+#undef SV
+ };
+
+ abi_info->initial_instructions = abi_cfi;
+ abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi];
+ abi_info->data_alignment_factor = ebl->class == ELFCLASS64 ? 8 : 4;
+
+ abi_info->return_address_register = 14;
+
+ return 0;
+}
diff --git a/backends/s390_frame_state.c b/backends/s390_frame_state.c
new file mode 100644
index 0000000..ddb15aa
--- /dev/null
+++ b/backends/s390_frame_state.c
@@ -0,0 +1,99 @@
+/* Fetch live process Dwfl_Frame_State from PID.
+ 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
+
+#ifdef __s390__
+# include <sys/user.h>
+# include <asm/ptrace.h>
+# include <sys/ptrace.h>
+#endif
+#include "libdwflP.h"
+
+#define BACKEND s390_
+#include "libebl_CPU.h"
+
+#include "core-get-pc.c"
+
+bool
+s390_frame_state (Dwfl_Frame_State *state)
+{
+ Dwfl_Frame_State_Thread *thread = state->thread;
+ Dwfl_Frame_State_Process *process = thread->process;
+ Ebl *ebl = process->ebl;
+ Elf *core = process->core;
+ pid_t tid = thread->tid;
+ if (core == NULL && tid)
+ {
+#ifndef __s390__
+ return false;
+#else /* __s390__ */
+ struct user user_regs;
+ ptrace_area parea;
+ parea.process_addr = (uintptr_t) &user_regs;
+ parea.kernel_addr = 0;
+ parea.len = sizeof (user_regs);
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea, NULL) != 0)
+ return false;
+ /* If we run as s390x we get the 64-bit registers of tid.
+ But -m31 executable seems to use only the 32-bit parts of its
+ registers so we ignore the upper half. */
+ for (unsigned u = 0; u < 16; u++)
+ dwarf_frame_state_reg_set (state, 0 + u, user_regs.regs.gprs[u]);
+ /* Avoid conversion double -> integer. */
+ eu_static_assert (sizeof user_regs.regs.fp_regs.fprs[0]
+ == sizeof state->regs[0]);
+ for (unsigned u = 0; u < 16; u++)
+ dwarf_frame_state_reg_set (state, 16 + u,
+ *((const __typeof (*state->regs) *)
+ &user_regs.regs.fp_regs.fprs[u]));
+ state->pc = user_regs.regs.psw.addr;
+ state->pc_state = DWFL_FRAME_STATE_PC_SET;
+#endif /* __s390__ */
+ }
+ else if (core)
+ {
+ /* Fetch PSWA. */
+ if (! core_get_pc (core, &state->pc,
+ ebl->class == ELFCLASS32 ? 0x4c : 0x78))
+ return false;
+ state->pc_state = DWFL_FRAME_STATE_PC_SET;
+ }
+ return true;
+}
+
+void
+s390_normalize_pc (Ebl *ebl __attribute__ ((unused)), Dwarf_Addr *pc)
+{
+ assert (ebl->class == ELFCLASS32);
+
+ /* Clear S390 bit 31. */
+ *pc &= (1U << 31) - 1;
+}
diff --git a/backends/s390_frame_unwind.c b/backends/s390_frame_unwind.c
new file mode 100644
index 0000000..fa4c0ac
--- /dev/null
+++ b/backends/s390_frame_unwind.c
@@ -0,0 +1,149 @@
+/* Get previous frame state for an existing frame state.
+ 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 <stdlib.h>
+#include <assert.h>
+#include "libdwflP.h"
+
+#define BACKEND s390_
+#include "libebl_CPU.h"
+
+bool
+s390_frame_unwind (Ebl *ebl, Dwfl_Frame_State **statep, Dwarf_Addr pc)
+{
+ Dwfl_Frame_State *state = *statep;
+ Dwfl_Frame_State_Process *process = state->thread->process;
+ assert (state->unwound == NULL);
+ /* Caller already assumed caller adjustment but S390 instructions are 4 bytes
+ long. Undo it. */
+ if ((pc & 0x3) != 0x3)
+ return false;
+ pc++;
+ /* We can assume big-endian read here. */
+ Dwarf_Addr instr;
+ if (! process->memory_read (pc, &instr, process->memory_read_user_data))
+ return false;
+ /* Fetch only the very first two bytes. */
+ instr = (instr >> (ebl->class == ELFCLASS64 ? 48 : 16)) & 0xffff;
+ /* See GDB s390_sigtramp_frame_sniffer. */
+ /* Check for 'svc'. */
+ if (((instr >> 8) & 0xff) != 0x0a)
+ return false;
+ /* Check for 'sigreturn' or 'rt_sigreturn'. */
+ if ((instr & 0xff) != 119 && (instr & 0xff) != 173)
+ return false;
+ /* See GDB s390_sigtramp_frame_unwind_cache. */
+# define S390_SP_REGNUM (0 + 15) /* S390_R15_REGNUM */
+ Dwarf_Addr this_sp;
+ if (! dwfl_frame_state_reg_get (state, S390_SP_REGNUM, &this_sp))
+ return false;
+ unsigned word_size = ebl->class == ELFCLASS64 ? 8 : 4;
+ Dwarf_Addr next_cfa = this_sp + 16 * word_size + 32;
+ /* "New-style RT frame" is not supported,
+ assuming "Old-style RT frame and all non-RT frames". */
+ Dwarf_Addr sigreg_ptr;
+ if (! process->memory_read (next_cfa + 8, &sigreg_ptr,
+ process->memory_read_user_data))
+ return false;
+ /* Skip PSW mask. */
+ sigreg_ptr += word_size;
+ /* Read PSW address. */
+ Dwarf_Addr val;
+ if (! process->memory_read (sigreg_ptr, &val, process->memory_read_user_data))
+ return false;
+ sigreg_ptr += word_size;
+ size_t nregs = ebl->frame_state_nregs;
+ Dwfl_Frame_State *unwound;
+ unwound = malloc (sizeof (*unwound) + sizeof (*unwound->regs) * nregs);
+ state->unwound = unwound;
+ unwound->thread = state->thread;
+ unwound->unwound = NULL;
+ unwound->pc = val;
+ unwound->pc_state = DWFL_FRAME_STATE_ERROR;
+ memset (unwound->regs_set, 0, sizeof (unwound->regs_set));
+ unwound->signal_frame = true;
+ /* Then the GPRs. */
+ for (int i = 0; i < 16; i++)
+ {
+ if (! process->memory_read (sigreg_ptr, &val,
+ process->memory_read_user_data))
+ return false;
+ if (! dwfl_frame_state_reg_set (unwound, 0 + i, val))
+ return false;
+ sigreg_ptr += word_size;
+ }
+ /* Then the ACRs. Skip them, they are not used in CFI. */
+ for (int i = 0; i < 16; i++)
+ sigreg_ptr += 4;
+ /* The floating-point control word. */
+ sigreg_ptr += 8;
+ /* And finally the FPRs. */
+ for (int i = 0; i < 16; i++)
+ {
+ if (! process->memory_read (sigreg_ptr, &val,
+ process->memory_read_user_data))
+ return false;
+ if (ebl->class == ELFCLASS32)
+ {
+ Dwarf_Addr val_low;
+ if (! process->memory_read (sigreg_ptr + 4, &val_low,
+ process->memory_read_user_data))
+ return false;
+ val = (val << 32) | val_low;
+ }
+ if (! dwfl_frame_state_reg_set (unwound, 16 + i, val))
+ return false;
+ sigreg_ptr += 8;
+ }
+ /* If we have them, the GPR upper halves are appended at the end. */
+ if (ebl->class == ELFCLASS32)
+ {
+ unsigned sigreg_high_off = 4;
+ sigreg_ptr += sigreg_high_off;
+ for (int i = 0; i < 16; i++)
+ {
+ if (! process->memory_read (sigreg_ptr, &val,
+ process->memory_read_user_data))
+ return false;
+ Dwarf_Addr val_low;
+ if (! dwfl_frame_state_reg_get (unwound, 0 + i, &val_low))
+ return false;
+ val = (val << 32) | val_low;
+ if (! dwfl_frame_state_reg_set (unwound, 0 + i, val))
+ return false;
+ sigreg_ptr += 4;
+ }
+ }
+ unwound->pc_state = DWFL_FRAME_STATE_PC_SET;
+ *statep = unwound;
+ return true;
+}
diff --git a/backends/s390_init.c b/backends/s390_init.c
index 91fe4b8..8c28fb8 100644
--- a/backends/s390_init.c
+++ b/backends/s390_init.c
@@ -61,6 +61,16 @@ s390_init (elf, machine, eh, ehlen)
eh->core_note = s390x_core_note;
else
HOOK (eh, core_note);
+ HOOK (eh, abi_cfi);
+ /* gcc/config/ #define DWARF_FRAME_REGISTERS 34.
+ But from the gcc/config/s390/s390.h "Register usage." comment it looks as
+ if #32 (Argument pointer) and #33 (Condition code) are not used for
+ unwinding. */
+ eh->frame_state_nregs = 32;
+ HOOK (eh, frame_state);
+ if (eh->class == ELFCLASS32)
+ HOOK (eh, normalize_pc);
+ HOOK (eh, frame_unwind);
/* Only the 64-bit format uses the incorrect hash table entry size. */
if (eh->class == ELFCLASS64)
diff --git a/libdwfl/dwfl_frame_state_pc.c b/libdwfl/dwfl_frame_state_pc.c
index 6e9928b..4d6fc8b 100644
--- a/libdwfl/dwfl_frame_state_pc.c
+++ b/libdwfl/dwfl_frame_state_pc.c
@@ -37,6 +37,7 @@ dwfl_frame_state_pc (Dwfl_Frame_State *state, Dwarf_Addr *pc, bool *minusone)
{
assert (state->pc_state == DWFL_FRAME_STATE_PC_SET);
*pc = state->pc;
+ ebl_normalize_pc (state->thread->process->ebl, pc);
if (minusone)
{
/* Bottom frame? */
diff --git a/libdwfl/dwfl_frame_unwind.c b/libdwfl/dwfl_frame_unwind.c
index 5705f51..e35ccb5 100644
--- a/libdwfl/dwfl_frame_unwind.c
+++ b/libdwfl/dwfl_frame_unwind.c
@@ -410,7 +410,7 @@ handle_cfi (Dwfl_Frame_State **statep, Dwarf_Addr pc, Dwfl_Module *mod,
{
/* REGNO is undefined. */
unsigned ra = frame->fde->cie->return_address_register;
- if (regno == ra)
+ if (ebl_frame_dwarf_to_regno (ebl, &ra) && regno == ra)
unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
continue;
}
@@ -494,6 +494,14 @@ dwfl_frame_unwind (Dwfl_Frame_State **statep)
}
}
}
+ *statep = state;
+ if (ebl_frame_unwind (state->thread->process->ebl, statep, pc))
+ return true;
+ if (state->unwound)
+ {
+ assert (state->unwound->pc_state == DWFL_FRAME_STATE_ERROR);
+ return false;
+ }
__libdwfl_seterrno (DWFL_E_NO_DWARF);
return false;
}
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 3999d66..fb2f839 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -265,6 +265,9 @@ dwfl_frame_state_reg_get (Dwfl_Frame_State *state, unsigned regno,
Dwarf_Addr *val)
{
Ebl *ebl = state->thread->process->ebl;
+ if (ebl->frame_dwarf_to_regno != NULL
+ && ! ebl->frame_dwarf_to_regno (ebl, ®no))
+ return false;
if (regno >= ebl->frame_state_nregs)
return false;
if ((state->regs_set[regno / sizeof (*state->regs_set) / 8]
@@ -283,6 +286,9 @@ dwfl_frame_state_reg_set (Dwfl_Frame_State *state, unsigned regno,
Dwarf_Addr val)
{
Ebl *ebl = state->thread->process->ebl;
+ if (ebl->frame_dwarf_to_regno != NULL
+ && ! ebl->frame_dwarf_to_regno (ebl, ®no))
+ return false;
if (regno >= ebl->frame_state_nregs)
return false;
/* For example i386 user_regs_struct has signed fields. */
diff --git a/libebl/Makefile.am b/libebl/Makefile.am
index 1e39689..92497c3 100644
--- a/libebl/Makefile.am
+++ b/libebl/Makefile.am
@@ -55,7 +55,8 @@ 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 eblgetfuncpc.c eblframestate.c
+ eblstother.c eblgetfuncpc.c eblframestate.c eblnormalizepc.c \
+ eblframeunwind.c eblframedwarftoregno.c
libebl_a_SOURCES = $(gen_SOURCES)
diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h
index 5b77f92..72f1aad 100644
--- a/libebl/ebl-hooks.h
+++ b/libebl/ebl-hooks.h
@@ -168,5 +168,18 @@ bool EBLHOOK(frame_state) (struct Dwfl_Frame_State *state);
above. */
size_t EBLHOOKVAR(frame_state_nregs);
+/* Convert *REGNO as is in DWARF to a lower range suitable for
+ Dwarf_Frame_State->REGS indexing. RETURN_ADDRESS_REGISTER should not change
+ on second call; other registers may map to numbers invalid on input. */
+bool EBLHOOK(frame_dwarf_to_regno) (Ebl *ebl, unsigned *regno);
+
+/* Optionally modify *PC as fetched from inferior data into valid PC
+ instruction pointer. */
+void EBLHOOK(normalize_pc) (Ebl *ebl, Dwarf_Addr *pc);
+
+/* See dwfl_frame_unwind. */
+bool EBLHOOK(frame_unwind) (Ebl *ebl, struct Dwfl_Frame_State **statep,
+ Dwarf_Addr pc);
+
/* Destructor for ELF backend handle. */
void EBLHOOK(destr) (struct ebl *);
diff --git a/libebl/eblframedwarftoregno.c b/libebl/eblframedwarftoregno.c
new file mode 100644
index 0000000..4cfbd46
--- /dev/null
+++ b/libebl/eblframedwarftoregno.c
@@ -0,0 +1,42 @@
+/* Convert *REGNO as is in DWARF to a lower range.
+ 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>
+
+bool
+ebl_frame_dwarf_to_regno (Ebl *ebl, unsigned *regno)
+{
+ if (ebl == NULL)
+ return false;
+ return (ebl->frame_dwarf_to_regno == NULL
+ ? true : ebl->frame_dwarf_to_regno (ebl, regno));
+}
diff --git a/libebl/eblframeunwind.c b/libebl/eblframeunwind.c
new file mode 100644
index 0000000..adc658b
--- /dev/null
+++ b/libebl/eblframeunwind.c
@@ -0,0 +1,41 @@
+/* Get previous frame state for an existing frame state.
+ 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>
+
+bool
+ebl_frame_unwind (Ebl *ebl, struct Dwfl_Frame_State **statep, Dwarf_Addr pc)
+{
+ if (ebl == NULL || ebl->frame_unwind == NULL)
+ return false;
+ return ebl->frame_unwind (ebl, statep, pc);
+}
diff --git a/libebl/eblnormalizepc.c b/libebl/eblnormalizepc.c
new file mode 100644
index 0000000..abe6352
--- /dev/null
+++ b/libebl/eblnormalizepc.c
@@ -0,0 +1,40 @@
+/* Modify PC as fetched from inferior data into valid PC.
+ 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>
+
+void
+ebl_normalize_pc (Ebl *ebl, Dwarf_Addr *pc)
+{
+ if (ebl != NULL && ebl->normalize_pc != NULL)
+ ebl->normalize_pc (ebl, pc);
+}
diff --git a/libebl/libebl.h b/libebl/libebl.h
index 09b7bfb..967980e 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -393,6 +393,20 @@ extern bool ebl_frame_state (struct Dwfl_Frame_State *state)
extern size_t ebl_frame_state_nregs (Ebl *ebl)
__nonnull_attribute__ (1);
+/* Modify PC as fetched from inferior data into valid PC. */
+extern void ebl_normalize_pc (Ebl *ebl, Dwarf_Addr *pc)
+ __nonnull_attribute__ (1, 2);
+
+/* Get previous frame state for an existing frame state. */
+struct Dwfl_Frame_State_Process;
+extern bool
+ ebl_frame_unwind (Ebl *ebl, struct Dwfl_Frame_State **statep, Dwarf_Addr pc)
+ __nonnull_attribute__ (1, 2);
+
+/* Convert *REGNO as is in DWARF to a lower range. */
+extern bool ebl_frame_dwarf_to_regno (Ebl *ebl, unsigned *regno)
+ __nonnull_attribute__ (1, 2);
+
#ifdef __cplusplus
}
#endif
diff --git a/tests/backtrace.ppc.core.bz2 b/tests/backtrace.ppc.core.bz2
new file mode 100644
index 0000000..2dca8f1
Binary files /dev/null and b/tests/backtrace.ppc.core.bz2 differ
diff --git a/tests/backtrace.ppc.exec.bz2 b/tests/backtrace.ppc.exec.bz2
new file mode 100644
index 0000000..15070a9
Binary files /dev/null and b/tests/backtrace.ppc.exec.bz2 differ
diff --git a/tests/backtrace.ppc64.core.bz2 b/tests/backtrace.ppc64.core.bz2
new file mode 100644
index 0000000..a07aa61
Binary files /dev/null and b/tests/backtrace.ppc64.core.bz2 differ
diff --git a/tests/backtrace.ppc64.exec.bz2 b/tests/backtrace.ppc64.exec.bz2
new file mode 100644
index 0000000..21a7e0d
Binary files /dev/null and b/tests/backtrace.ppc64.exec.bz2 differ
diff --git a/tests/backtrace.s390.core.bz2 b/tests/backtrace.s390.core.bz2
new file mode 100644
index 0000000..ce21012
Binary files /dev/null and b/tests/backtrace.s390.core.bz2 differ
diff --git a/tests/backtrace.s390.exec.bz2 b/tests/backtrace.s390.exec.bz2
new file mode 100644
index 0000000..8bbb75d
Binary files /dev/null and b/tests/backtrace.s390.exec.bz2 differ
diff --git a/tests/backtrace.s390x.core.bz2 b/tests/backtrace.s390x.core.bz2
new file mode 100644
index 0000000..2a2c9e7
Binary files /dev/null and b/tests/backtrace.s390x.core.bz2 differ
diff --git a/tests/backtrace.s390x.exec.bz2 b/tests/backtrace.s390x.exec.bz2
new file mode 100644
index 0000000..195d1af
Binary files /dev/null and b/tests/backtrace.s390x.exec.bz2 differ
diff --git a/tests/run-backtrace.sh b/tests/run-backtrace.sh
index 6e14653..a57d474 100755
--- a/tests/run-backtrace.sh
+++ b/tests/run-backtrace.sh
@@ -53,4 +53,15 @@ for child in backtrace-child{,-biarch}; do
check_empty $core.err
done
+for arch in ppc ppc64 s390 s390x; do
+ testfiles backtrace.$arch.{exec,core}
+ tempfiles backtrace.$arch.{bt,err}
+ echo ./backtrace ./backtrace.$arch.{exec,core}
+ mytestrun ./backtrace ./backtrace.$arch.{exec,core} 1>backtrace.$arch.bt \
+ 2>backtrace.$arch.err
+ cat backtrace.$arch.{bt,err}
+ check_gsignal backtrace.$arch.bt
+ check_empty backtrace.$arch.err
+done
+
exit 0
10 years, 3 months
elfutils 0.156 released
by Jan Kratochvil
A new release of elfutils is available now at:
https://fedorahosted.org/releases/e/l/elfutils/0.156/
* NEWS *
Version 0.156
lib: New macro COMPAT_VERSION_NEWPROTO.
libdw: Handle GNU extension opcodes in dwarf_getlocation.
libdwfl: Fix STB_GLOBAL over STB_WEAK preference in dwfl_module_addrsym.
Add minisymtab support.
Add parameter add_p_vaddr to dwfl_report_elf.
Use DT_DEBUG library search first.
libebl: Handle new core note types in EBL.
backends: Interpret NT_ARM_VFP.
Implement core file registers parsing for s390/s390x.
readelf: Add --elf-section input option to inspect an embedded ELF file.
Add -U, --unresolved-address-offsets output control.
Add --debug-dump=decodedline support.
Accept version 8 .gdb_index section format.
Adjust output formatting width.
When highpc is in constant form print it also as address.
Display raw .debug_aranges. Use libdw only for decodedaranges.
elflint: Add __bss_start__ to the list of allowed symbols.
tests: Add configure --enable-valgrind option to run all tests under valgrind.
Enable automake parallel-tests for make check.
translations: Updated Polish translation.
Updates for Automake 1.13.
* GIT SHORTLOG *
Adam Markey (1):
Handle partial read or write.
David Abdurachmanov (1):
ar.c (do_oper_delete): Fix num passed to memset.
Jan Kratochvil (30):
Code cleanup: Simplify binary_search_fde.
Fix DW_CFA_expression & co. CFA initial push.
Fix error code from __libdw_find_fde.
Fix uninitialized Dwarf_Frame->regs.
Improve ELF symbols preference (global > weak).
Fix bias for vDSOs from core files.
readelf bitmap display fix.
readelf.c: Use real output width.
Fix ebl_abi_cfi error return value.
Add __nonnull_attribute__ to dwfl_module_getelf.
Fix bias for DSOs loaded from core file with build-id.
Fix missing tests/ EXTRA_DIST for files by me.
Code cleanup: Simplify __libdwfl_report_elf.
Fix for PIE with both -e and --core in use.
backends/arm_corenote.c Code cleanup.
Implement reglocs for s390/s390x - readelf.
Implement reglocs for s390/s390x.
Fix 64-bit->32-bit vDSO reporting.
Fix dwfl_report_elf BASE alignment.
Unify {BE,LE}{32,64} in lib/system.h.
New macro COMPAT_VERSION_NEWPROTO.
Add parameter add_p_vaddr to dwfl_report_elf.
Use DT_DEBUG library search first.
NEWS: Add entries for Version 0.156.
__libdwfl_find_elf_build_id: Add missing internal_function keyword.
NEWS: Remove bugfix only entries from Version 0.156.
Fix false match of non-build-id disk library to build-id memory library.
__libdwfl_elf_address_range: Add missing internal_function keyword.
Fix run-unstrip-n.sh regression on CentOS-5 ppc.
Prepare 0.156 release.
Mark Wielaard (49):
derelocate.c (find_section): Check next section exists before accessing it.
cu.c (cudie_offset): Don't use type_sig8, it might not be initialized.
Add configure --enable-valgrind option to run all tests under valgrind.
readelf.c (print_ops): Ajust DW_OP_skip and DW_OP_bra targets calculation.
Run valgrind tests with --run-libc-freeres=no.
Add missing semicolon in show_symbols_sysv
Fix two failure condition checks in libdwfl/linux-kernel-modules.c.
Fix sig8_hash memory leak in libdw/dwarf_begin_elf.c on error.
addr2line: Cleanup Dwfl when done.
readelf: Adjust initial FDE address if pcrel before printing.
readelf: Add --elf-section input option to inspect an embedded ELF file.
libdwfl: Add minisymtab support.
tests: readelf --elf-section, dwfl_module_addrsym and dwfl_module_getsym.
libdwfl: Support auxiliary symbol table only for getsym and addrsym.
readelf: Add base to offsets in format_dwarf_addr for debug_loc/ranges.
readelf: Add -U, --unresolved-address-offsets output control.
Add readelf test for --debug-dump=loc --debug-dump=ranges, -N and -U.
backends: Check type DIE exists before calling dwarf_tag ().
elflint: Add two more symbols to gnuld list of allowed bad values.
libdwfl: Use actual file names in parse_opt failure cases.
libdw: Handle FORM_GNU_strp_alt for files with string data only in dwz file.
libdwfl: Try opening files all installed compression libraries.
elflint.c (check_symtab): Add __bss_start__ to the list of allowed symbols.
Fix two memory leaks in findtextrel and strip.
libdw and libdwfl srcfiles and srclines fixes for partial_units.
readelf: Accept version 8 .gdb_index section format.
readelf: print_gdb_index_section fix memory leak.
readelf: When highpc is in constant form also print as address.
libdw: dwarf_getsrclines mark highest address as end_sequence.
readelf: Display raw .debug_aranges. Use libdw only for decodedaranges.
readelf: Add --debug-dump=decodedline support.
libdw: DW_FORM_GNU_ref_alt is always offset_size.
Updates for Automake 1.13.
Enable automake parallel-tests for make check.
libdwfl/link_map.c: #include system.h.
tests: Add various files to tempfiles so they are always cleaned up.
tests: All update tests should use unique temporary file names and cleanup.
tests: Tests that override EXIT (0) trap need to cleanup themselves.
tests: Don't use pushd or popd, just use cd to change working directory.
libdw: dwarf_getsrclines don't set end_sequence when there are no lines.
readelf: Format first DW_OP_GNU_implicit_pointer argument as DIE offset.
libdwfl: link_map.c (report_r_debug) always release memory_callback buffer.
tests EXTRA_DIST typo, forgot extension in testfilenolines.bz2.
libdw_visit_scopes: Don't recurse into imported unit children.
getcfi_scn_eh_frame: Don't crash and burn when .eh_frame bits aren't there.
Don't assert on mod->e_type in __libdwfl_relocate_value.
libdw. Don't blow up stack in dwarf_getsrclines with lots of lines.
readelf: print actual DW_OP_GNU_parameter_ref DIE offset.
readelf: print actual DIE offsets of DW_OP_GNU_<type> ops.
Petr Machata (9):
Update elf.h from glibc.
Handle new core note types in EBL
Add allregs test for ARM back end
Change FPREGSET_SIZE in ARM backend to 116 to match sizeof struct user_fp
Test elfutils output of VMCOREINFO note.
Add back end code for interpreting NT_ARM_VFP core note.
In mixed core notes, don't let handle_core_item repeat.
Test elfutils output of a mixed core note.
Handle GNU extension opcodes in dwarf_getlocation
Piotr Drąg (1):
Updated Polish translation.
Roland McGrath (8):
Merge branch 'jankratochvil/vdso-bias'
Robustify makefile redirection use.
Missing ChangeLog entry from last commit.
nm: Fix size passed to snprintf for invalid sh_name case.
elf_getarsym: Use memcpy instead of pointer dereference so as not to assume the field is naturally aligned.
elf_getarsym: Handle unaligned data in archive index.
dwfl_link_map_report: Handle unaligned auxv data.
Make run-prelink-addr-test.sh robust in its use of ln.
10 years, 3 months
Dump of alternate .debuginfo
by Andrey Ponomarenko
Hi,
I created a dump of a library debug-info by the "eu-readelf
--debug-dump=info" command. The formal_parameter of a subprogram has
type "(GNU_ref_alt) [ N]", but N is not described anywhere in the dump.
I have take a look at the source code of elfutils and found, that
DW_FORM_GNU_ref_alt is an offset in the "alternate debuginfo":
DW_FORM_GNU_ref_alt = 0x1f20, /* offset in alternate .debuginfo. */
DW_FORM_GNU_strp_alt = 0x1f21 /* offset in alternate .debug_str. */
How can I read/dump this "alternate debuginfo"?
Thanks.
--
Andrey Ponomarenko, ROSA Lab.
10 years, 4 months
Performance of libdw
by Andrey Ponomarenko
Hi,
I've found an O(N^2) loop in the libdw library (N - number of symbols in
the library). The dwfl_module_getsym function is called N times, but it
calls resolve_symbol function each time and it loops through the number
of symbols again.
So `readelf --debug-dump=info shared_object.so` command is very slow on
large input objects. As an example, it takes several minutes to analyse
libOpenImageIO.so.1.1.11 (27mb), but readelf from binutils takes just
several seconds to do it.
The output of sprof for libelf:
% cumulative self self
time seconds seconds calls us/call name
42.16 28.42 28.42 1858018814 0.02 gelf_getsymshndx
39.49 55.04 26.62 1798636744 0.01 gelf_getshdr
18.35 67.41 12.37 1798635186 0.01 elf_getscn
0.00 67.41 0.00 1562 0.00 elf_nextscn
0.00 67.41 0.00 123 0.00 elf_ndxscn
0.00 67.41 0.00 61 0.00 elf_strptr
0.00 67.41 0.00 9 0.00 elf_getdata
0.00 67.41 0.00 7 0.00 gelf_getphdr
...
The output of sprof for libdw:
% cumulative self self
time seconds seconds calls us/call name
60.97 69.93 69.93 0 0.00 dwfl_module_getsym
26.25 100.04 30.11 0 0.00 search_table
6.73 107.76 7.72 0 0.00
dwfl_adjusted_address
4.87 113.34 5.58 0 0.00
dwfl_adjusted_st_value
0.61 114.04 0.70 0 0.00
dwfl_adjusted_aux_sym_addr
0.10 114.16 0.12 861603 0.14 dwarf_getattrs
0.10 114.27 0.11 0 0.00
__libdw_form_val_len
0.05 114.33 0.06 0 0.00 __libdw_find_attr
0.03 114.37 0.04 0 0.00 lookup
0.00 114.67 0.00 95891 0.00
dwfl_module_addrsym
...
The gelf_getsymshndx, gelf_getshdr and elf_getscn functions from libelf
are called 2 billion times and it takes about 60% of total execution
time. Another 26% of execution time are taken by the search_table
function that is called by the dwfl_module_addrsym and loops through the
number of symbols too. The dwfl_module_addrsym is called for each
symbol. So it also takes O(N^2).
How can dwfl_module_getsym and dwfl_module_addrsym functions may be
optimised to not to loop through all symbols in the library in order to
find information for just one of them? This can make the library to be
10 times faster.
Thank you.
--
Andrey Ponomarenko, ROSA Lab.
10 years, 4 months
[patch] Fix run-unstrip-n.sh regression on CentOS-5 ppc
by Jan Kratochvil
Hi,
last patch was a bit more heuristic than needed which was found on RHEL-5 ppc
(32-bit):
FAIL: run-unstrip-n.sh (exit: 1)
================================
--- unstrip.out 2013-07-23 23:23:49.000000000 +0200
+++ - 2013-07-23 23:23:49.434052534 +0200
@@ -4,4 +4,3 @@
0xfdf0000+0x1c0000 edf3dd232e09d01b90683889bd16b9406c52d4de@0xfdf0184 - - libc.so.6
0xffb0000+0x50000 edec437a85026a1cf8cda94003706202733130c1@0xffb0124 - - ld.so.1
0x10000000+0x20000 979b7a26747cc09bd84a42b311b5288c704baea5@0x10000174 . - [exe]
-0xf880000+0x201d4 - /lib/librt.so.1 /usr/lib/debug/lib/librt-2.5.so.debug librt.so.1
Therefore the new code generated this excessive line:
0xf880000+0x201d4 - /lib/librt.so.1 /usr/lib/debug/lib/librt-2.5.so.debug librt.so.1
The first part of debug dump is from DT_DEBUG, second part is from segments:
start=0xf880000 end=0xf8a01d4 l_ld=0xfd6fe20 name=/lib/librt.so.1
start=0xfc60000 end=0xfe031e4 l_ld=0xff9e270 name=/lib/libc.so.6
start=0xfe10000 end=0xfe421dc l_ld=0xfddfd98 name=/lib/libpthread.so.0
start=0xffb0000 end=0xfff0668 l_ld=0xffef9ac name=/lib/ld.so.1
module_start=0x100000 module_end=0x110000 dyn_vaddr=0x100ee4
module_start=0xfd50000 module_end=0xfd80000 dyn_vaddr=0xfd6fe20 /lib/librt.so.1
module_start=0xfdb0000 module_end=0xfdf0000 dyn_vaddr=0xfddfd98 /lib/libpthread.so.0
module_start=0xfdf0000 module_end=0xffb0000 dyn_vaddr=0xff9e270 /lib/libc.so.6
module_start=0xffb0000 module_end=0x10000000 dyn_vaddr=0xffef9ac /lib/ld.so.1
module_start=0x10000000 module_end=0x10020000 dyn_vaddr=0x10010850
When comparing conflicts for (found in segments)
module_start=0xfd50000 module_end=0xfd80000 dyn_vaddr=0xfd6fe20 /lib/librt.so.1
the code found this line conflicts (and discarded it):
start=0xfc60000 end=0xfe031e4 l_ld=0xff9e270 name=/lib/libc.so.6
but it did not discard also conflicting:
start=0xf880000 end=0xf8a01d4 l_ld=0xfd6fe20 name=/lib/librt.so.1
So I have changed/improved the algorithm - L_LD can be IMO compared exactly
but otherwise the ranges should be compared for every module, not just the
first one.
Again I am not much happy from this code, it should be using NT_FILE instead,
but when we keep compatibility with old OSes elfutils should not regress
there.
This is a code of mine written several days ago so I will check it in if there
is no review soon.
Thanks,
Jan
libdwfl/
2013-07-24 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* dwfl_segment_report_module.c (dwfl_segment_report_module): Check for
conflicts all the modules, not just the first one. Compare L_LD if it
is equal, not if it is in a module address range.
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index 41487bf..97f4a1a 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -470,28 +470,37 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
}
}
- /* Ignore this found module if it would conflict in address space with any
- already existing module of DWFL. */
if (r_debug_info != NULL)
- for (struct r_debug_info_module *module = r_debug_info->module;
- module != NULL; module = module->next)
- if ((module_end > module->start && module_start < module->end)
- || (module_start <= module->l_ld && module->l_ld < module_end))
- {
- if (! module->disk_file_has_build_id && build_id_len > 0)
- {
- if (module->elf != NULL)
- {
- elf_end (module->elf);
- close (module->fd);
- module->elf = NULL;
- module->fd = -1;
- }
- break;
- }
- else if (module->elf != NULL)
- return finish ();
- }
+ {
+ bool skip_this_module = false;
+ for (struct r_debug_info_module *module = r_debug_info->module;
+ module != NULL; module = module->next)
+ if ((module_end > module->start && module_start < module->end)
+ || dyn_vaddr == module->l_ld)
+ {
+ if (! module->disk_file_has_build_id && build_id_len > 0)
+ {
+ /* Module found in segments with build-id is more reliable
+ than a module found via DT_DEBUG on disk without any
+ build-id. */
+ if (module->elf != NULL)
+ {
+ elf_end (module->elf);
+ close (module->fd);
+ module->elf = NULL;
+ module->fd = -1;
+ }
+ }
+ else if (module->elf != NULL)
+ {
+ /* Ignore this found module if it would conflict in address
+ space with any already existing module of DWFL. */
+ skip_this_module = true;
+ }
+ }
+ if (skip_this_module)
+ return finish ();
+ }
/* Our return value now says to skip the segments contained
within the module. */
10 years, 4 months
[obv] Add missing internal_function keyword
by Jan Kratochvil
Hi,
a pity I could make that mistake again.
Checked in.
Jan
commit 744fc6f97f1c32fbab0f2a124bfa053e88fc3697
Author: Jan Kratochvil <jan.kratochvil(a)redhat.com>
Date: Tue Jul 23 17:52:01 2013 +0200
__libdwfl_elf_address_range: Add missing internal_function keyword.
Signed-off-by: Jan Kratochvil <jan.kratochvil(a)redhat.com>
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 8ab6b5b..77faa85 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,5 +1,9 @@
2013-07-23 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+ * libdwflP.h (__libdwfl_elf_address_range): Add internal_function.
+
+2013-07-23 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
* core-file.c (clear_r_debug_info): Close also ELF and FD.
(dwfl_core_file_report): Call __libdwfl_report_elf for
R_DEBUG_INFO.MODULE.
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 5437b37..1d4899b 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -396,7 +396,7 @@ extern bool __libdwfl_elf_address_range (Elf *elf, GElf_Addr base,
GElf_Addr *vaddrp,
GElf_Addr *address_syncp,
GElf_Addr *startp, GElf_Addr *endp,
- GElf_Addr *biasp, GElf_Half *e_typep);
+ GElf_Addr *biasp, GElf_Half *e_typep)
internal_function;
/* Meat of dwfl_report_elf, given elf_begin just called.
10 years, 4 months
[patch] Fix run-unstrip-n.sh regression on CentOS-5
by Jan Kratochvil
Hi,
this patch:
Use DT_DEBUG library search first.
8ff862960efb648cdff647d7fad1be5acffe9b11
[patch 2/2] Fix loading core files without build-ids
https://lists.fedorahosted.org/pipermail/elfutils-devel/2013-April/003031...
[patch 2/2 v2] Fix loading core files without build-ids
https://lists.fedorahosted.org/pipermail/elfutils-devel/2013-May/003065.html
has PASS->FAIL regression on CentOS-5 for run-unstrip-n.sh:
-actual on CentOS-5
+expected by testcase
-0xf77b3000+0x822c - /lib/librt.so.1 - librt.so.1
-0xf7603000+0x15c5c4 - /lib/libc.so.6 - libc.so.6
-0xf75e9000+0x191e4 - /lib/libpthread.so.0 - libpthread.so.0
-0xf77d7000+0x1c670 - /lib/ld-linux.so.2 - ld-linux.so.2
0x8048000+0x2000 f1c600bc36cb91bf01f9a63a634ecb79aa4c3199@0x8048178 . - [exe]
+0xf75e9000+0x1a000 29a103420abe341e92072fb14274e250e4072148@0xf75e9164 - - libpthread.so.0
+0xf7603000+0x1b0000 0b9bf374699e141e5dfc14757ff42b8c2373b4de@0xf7603184 - - libc.so.6
+0xf77b3000+0x9000 c6c5b5e35ab9589d4762ac85b4bd56b1b2720e37@0xf77b3164 - - librt.so.1
0xf77d6000+0x1000 676560b1b765cde9c2e53f134f4ee354ea894747@0xf77d6210 . - linux-gate.so.1
+0xf77d7000+0x21000 6d2cb32650054f1c176d01d48713a4a5e5e84c1a@0xf77d7124 - - ld-linux.so.2
Therefore elfutils now incorrectly matches on-disk file without build-id to an
in-core (in-memory) file with build-id.
In fact due to its known FIXME:
This verification gives false positive if in-core ELF had
build-id but on-disk ELF does not have any. But we cannot
reliably find ELF header and/or the ELF build id just from
the link map (and checking core segments is also not
reliable). */
So it probably should not be so ignorable as I did, one may want to analyze
build-id core files on CentOS-5, not sure. In fact it can be fixed, when we
find in dwfl_segment_report_module a module with build-id with conflicts in
its address range with existing non-build-id dwfl_link_map_report module we
should prefer the build-id module instead.
The problem is that once Dwfl_Module is added to Dwfl it cannot be easily
removed.
Originally elfutils called dwfl_segment_report_module first and then
dwfl_link_map_report.
Currently the order is dwfl_link_map_report and then
dwfl_segment_report_module only for modules missing from dwfl_link_map_report.
Patch below unfortunately needs bidirectional negotiation between the two
functions, therefore dwfl_link_map_report now no longer adds Dwfl_Modules to
Dwfl but it only stores information about them to r_debug_info_module.
This information is filtered then by dwfl_segment_report_module and only
filtered r_debug_info_module entries get finally added to Dwfl
(in dwfl_core_file_report).
NT_FILE would make all this magic easy but it is true that on CentOS-5 it
definitely does not exist.
Thanks,
Jan
libdwfl/
2013-07-22 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* core-file.c (clear_r_debug_info): Close also ELF and FD.
(dwfl_core_file_report): Call __libdwfl_report_elf for
R_DEBUG_INFO.MODULE.
(__libdwfl_elf_address_range): New function from code of ...
(__libdwfl_report_elf): ... this function. Call it.
* dwfl_segment_report_module.c: Include unistd.h.
(dwfl_segment_report_module): Use basename for MODULE->NAME.
Clear MODULE if it has no build-id and we have segment with build-id.
Ignore this segment only if MODULE still contains valid ELF.
* libdwflP.h (__libdwfl_elf_address_range): New declaration.
(struct r_debug_info_module): New fields fd, elf, l_addr, start, end
and disk_file_has_build_id.
(dwfl_link_map_report): Extend the comment.
* link_map.c (report_r_debug): Extend the comment. Always fill in new
r_debug_info_module. Initialize also the new r_debug_info_module
fields. Remove one FIXME comment. Call __libdwfl_elf_address_range
instead of __libdwfl_report_elf when R_DEBUG_INFO is not NULL.
tests/
2013-07-22 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* run-unstrip-n.sh (test-core.*): Ignore libc.so.6 entry and order of
the entries.
diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c
index d5e340c..7207591 100644
--- a/libdwfl/core-file.c
+++ b/libdwfl/core-file.c
@@ -390,6 +390,9 @@ clear_r_debug_info (struct r_debug_info *r_debug_info)
{
struct r_debug_info_module *module = r_debug_info->module;
r_debug_info->module = module->next;
+ elf_end (module->elf);
+ if (module->fd != -1)
+ close (module->fd);
free (module);
}
}
@@ -476,6 +479,43 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
}
while (ndx < (int) phnum);
+ /* Now report the modules from dwfl_link_map_report which were not filtered
+ out by dwfl_segment_report_module. */
+
+ Dwfl_Module **lastmodp = &dwfl->modulelist;
+ while (*lastmodp != NULL)
+ lastmodp = &(*lastmodp)->next;
+ for (struct r_debug_info_module *module = r_debug_info.module;
+ module != NULL; module = module->next)
+ if (module->elf != NULL)
+ {
+ Dwfl_Module *mod;
+ mod = __libdwfl_report_elf (dwfl, basename (module->name), module->name,
+ module->fd, module->elf, module->l_addr,
+ true, true);
+ if (mod == NULL)
+ continue;
+ module->elf = NULL;
+ module->fd = -1;
+ /* Move this module to the end of the list, so that we end
+ up with a list in the same order as the link_map chain. */
+ if (mod->next != NULL)
+ {
+ if (*lastmodp != mod)
+ {
+ lastmodp = &dwfl->modulelist;
+ while (*lastmodp != mod)
+ lastmodp = &(*lastmodp)->next;
+ }
+ *lastmodp = mod->next;
+ mod->next = NULL;
+ while (*lastmodp != NULL)
+ lastmodp = &(*lastmodp)->next;
+ *lastmodp = mod;
+ }
+ lastmodp = &mod->next;
+ }
+
clear_r_debug_info (&r_debug_info);
/* We return the number of modules we found if we found any.
diff --git a/libdwfl/dwfl_report_elf.c b/libdwfl/dwfl_report_elf.c
index 20d04da..3a4ae2e 100644
--- a/libdwfl/dwfl_report_elf.c
+++ b/libdwfl/dwfl_report_elf.c
@@ -38,18 +38,20 @@
rejiggering (see below). */
#define REL_MIN_ALIGN ((GElf_Xword) 0x100)
-Dwfl_Module *
+bool
internal_function
-__libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
- int fd, Elf *elf, GElf_Addr base, bool add_p_vaddr,
- bool sanity)
+__libdwfl_elf_address_range (Elf *elf, GElf_Addr base, bool add_p_vaddr,
+ bool sanity, GElf_Addr *vaddrp,
+ GElf_Addr *address_syncp, GElf_Addr *startp,
+ GElf_Addr *endp, GElf_Addr *biasp,
+ GElf_Half *e_typep)
{
GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
if (ehdr == NULL)
{
elf_error:
__libdwfl_seterrno (DWFL_E_LIBELF);
- return NULL;
+ return false;
}
GElf_Addr vaddr = 0;
@@ -213,11 +215,37 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
if (end == 0 && sanity)
{
__libdwfl_seterrno (DWFL_E_NO_PHDR);
- return NULL;
+ return false;
}
break;
}
+ if (vaddrp)
+ *vaddrp = vaddr;
+ if (address_syncp)
+ *address_syncp = address_sync;
+ if (startp)
+ *startp = start;
+ if (endp)
+ *endp = end;
+ if (biasp)
+ *biasp = bias;
+ if (e_typep)
+ *e_typep = ehdr->e_type;
+ return true;
+}
+Dwfl_Module *
+internal_function
+__libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
+ int fd, Elf *elf, GElf_Addr base, bool add_p_vaddr,
+ bool sanity)
+{
+ GElf_Addr vaddr, address_sync, start, end, bias;
+ GElf_Half e_type;
+ if (! __libdwfl_elf_address_range (elf, base, add_p_vaddr, sanity, &vaddr,
+ &address_sync, &start, &end, &bias,
+ &e_type))
+ return NULL;
Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name, start, end);
if (m != NULL)
{
@@ -242,7 +270,7 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
m->main.vaddr = vaddr;
m->main.address_sync = address_sync;
m->main_bias = bias;
- m->e_type = ehdr->e_type;
+ m->e_type = e_type;
}
else
{
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index d454ccb..41487bf 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -37,6 +37,7 @@
#include <sys/param.h>
#include <alloca.h>
#include <endian.h>
+#include <unistd.h>
/* A good size for the initial read from memory, if it's not too costly.
@@ -462,7 +463,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
bias += fixup;
if (module->name[0] != '\0')
{
- name = module->name;
+ name = basename (module->name);
name_is_final = true;
}
break;
@@ -471,9 +472,26 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
/* Ignore this found module if it would conflict in address space with any
already existing module of DWFL. */
- for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
- if (module_end > mod->low_addr && module_start < mod->high_addr)
- return finish ();
+ if (r_debug_info != NULL)
+ for (struct r_debug_info_module *module = r_debug_info->module;
+ module != NULL; module = module->next)
+ if ((module_end > module->start && module_start < module->end)
+ || (module_start <= module->l_ld && module->l_ld < module_end))
+ {
+ if (! module->disk_file_has_build_id && build_id_len > 0)
+ {
+ if (module->elf != NULL)
+ {
+ elf_end (module->elf);
+ close (module->fd);
+ module->elf = NULL;
+ module->fd = -1;
+ }
+ break;
+ }
+ else if (module->elf != NULL)
+ return finish ();
+ }
/* Our return value now says to skip the segments contained
within the module. */
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 69e6e12..45762c0 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -388,6 +388,16 @@ extern uint32_t __libdwfl_crc32 (uint32_t crc, unsigned char *buf, size_t len)
extern int __libdwfl_crc32_file (int fd, uint32_t *resp) attribute_hidden;
+/* Given ELF and some parameters return TRUE if the *P return value parameters
+ have been successfully filled in. Any of the *P parameters can be NULL. */
+extern bool __libdwfl_elf_address_range (Elf *elf, GElf_Addr base,
+ bool add_p_vaddr, bool sanity,
+ GElf_Addr *vaddrp,
+ GElf_Addr *address_syncp,
+ GElf_Addr *startp, GElf_Addr *endp,
+ GElf_Addr *biasp, GElf_Half *e_typep);
+ internal_function;
+
/* Meat of dwfl_report_elf, given elf_begin just called.
Consumes ELF on success, not on failure. */
extern Dwfl_Module *__libdwfl_report_elf (Dwfl *dwfl, const char *name,
@@ -453,7 +463,13 @@ typedef bool Dwfl_Module_Callback (Dwfl_Module *mod, void **userdata,
struct r_debug_info_module
{
struct r_debug_info_module *next;
- GElf_Addr l_ld;
+ /* FD is -1 iff ELF is NULL. */
+ int fd;
+ Elf *elf;
+ GElf_Addr l_addr, l_ld;
+ /* START and END are both zero if not valid. */
+ GElf_Addr start, end;
+ bool disk_file_has_build_id;
char name[0];
};
@@ -487,6 +503,8 @@ extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
Fill in R_DEBUG_INFO if it is not NULL. It should be cleared by the
caller, this function does not touch fields it does not need to modify.
+ If R_DEBUG_INFO is not NULL then no modules get added to DWFL, caller
+ has to add them from filled in R_DEBUG_INFO.
Returns the number of modules found, or -1 for errors. */
extern int dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index e752a5d..266b759 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -224,7 +224,9 @@ addrsize (uint_fast8_t elfclass)
/* Report a module for each struct link_map in the linked list at r_map
in the struct r_debug at R_DEBUG_VADDR. For r_debug_info description
- see dwfl_link_map_report in libdwflP.h.
+ see dwfl_link_map_report in libdwflP.h. If R_DEBUG_INFO is not NULL then no
+ modules get added to DWFL, caller has to add them from filled in
+ R_DEBUG_INFO.
For each link_map entry, if an existing module resides at its address,
this just modifies that module's name and suggested file name. If
@@ -355,6 +357,28 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
if (iterations == 1 && dwfl->executable_for_core != NULL)
name = dwfl->executable_for_core;
+ struct r_debug_info_module *r_debug_info_module = NULL;
+ if (r_debug_info != NULL)
+ {
+ /* Save link map information about valid shared library (or
+ executable) which has not been found on disk. */
+ const char *name1 = name == NULL ? "" : name;
+ r_debug_info_module = malloc (sizeof (*r_debug_info_module)
+ + strlen (name1) + 1);
+ if (r_debug_info_module == NULL)
+ return release_buffer (result);
+ r_debug_info_module->fd = -1;
+ r_debug_info_module->elf = NULL;
+ r_debug_info_module->l_addr = l_addr;
+ r_debug_info_module->l_ld = l_ld;
+ r_debug_info_module->start = 0;
+ r_debug_info_module->end = 0;
+ r_debug_info_module->disk_file_has_build_id = false;
+ strcpy (r_debug_info_module->name, name1);
+ r_debug_info_module->next = r_debug_info->module;
+ r_debug_info->module = r_debug_info_module;
+ }
+
Dwfl_Module *mod = NULL;
if (name != NULL)
{
@@ -374,19 +398,15 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
/* FIXME: Bias L_ADDR should be computed from the prelink
state in memory (when the file got loaded), not against
- the current on-disk file state as is computed below.
-
- This verification gives false positive if in-core ELF had
- build-id but on-disk ELF does not have any. But we cannot
- reliably find ELF header and/or the ELF build id just from
- the link map (and checking core segments is also not
- reliable). */
+ the current on-disk file state as is computed below. */
if (__libdwfl_find_elf_build_id (NULL, elf, &build_id_bits,
&build_id_elfaddr,
&build_id_len) > 0
&& build_id_elfaddr != 0)
{
+ if (r_debug_info_module != NULL)
+ r_debug_info_module->disk_file_has_build_id = true;
GElf_Addr build_id_vaddr = build_id_elfaddr + l_addr;
release_buffer (0);
int segndx = INTUSE(dwfl_addrsegment) (dwfl,
@@ -405,31 +425,38 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
}
if (valid)
- // XXX hook for sysroot
- mod = __libdwfl_report_elf (dwfl, basename (name), name,
- fd, elf, l_addr, true, true);
- if (mod == NULL)
{
- elf_end (elf);
- close (fd);
+ if (r_debug_info_module == NULL)
+ {
+ // XXX hook for sysroot
+ mod = __libdwfl_report_elf (dwfl, basename (name),
+ name, fd, elf, l_addr,
+ true, true);
+ if (mod != NULL)
+ {
+ elf = NULL;
+ fd = -1;
+ }
+ }
+ else if (__libdwfl_elf_address_range (elf, l_addr, true,
+ true, NULL, NULL,
+ &r_debug_info_module->start,
+ &r_debug_info_module->end,
+ NULL, NULL))
+ {
+ r_debug_info_module->elf = elf;
+ r_debug_info_module->fd = fd;
+ elf = NULL;
+ fd = -1;
+ }
}
+ if (elf != NULL)
+ elf_end (elf);
+ if (fd != -1)
+ close (fd);
}
}
}
- if (r_debug_info != NULL && mod == NULL)
- {
- /* Save link map information about valid shared library (or
- executable) which has not been found on disk. */
- const char *base = name == NULL ? "" : basename (name);
- struct r_debug_info_module *module;
- module = malloc (sizeof (*module) + strlen (base) + 1);
- if (module == NULL)
- return release_buffer (result);
- module->l_ld = l_ld;
- strcpy (module->name, base);
- module->next = r_debug_info->module;
- r_debug_info->module = module;
- }
if (mod != NULL)
{
diff --git a/tests/run-unstrip-n.sh b/tests/run-unstrip-n.sh
index 6ede4c7..12c3822 100755
--- a/tests/run-unstrip-n.sh
+++ b/tests/run-unstrip-n.sh
@@ -60,7 +60,12 @@ EOF
# 0x03a000 0x00007fff1596c000 linux-vdso.so.1
testfiles test-core.core test-core.exec
rm -f test-core-lib.so
-testrun_compare ${abs_top_builddir}/src/unstrip -n -e test-core.exec --core=test-core.core <<\EOF
+outfile=test-core.out
+testrun_out $outfile ${abs_top_builddir}/src/unstrip -n -e test-core.exec --core=test-core.core
+outfile2=test-core.out2
+remove_files="$remove_files $outfile2"
+grep -v libc.so.6 $outfile | sort >$outfile2
+diff -u $outfile2 - <<EOF
0x400000+0x202038 - test-core.exec - test-core.exec
0x7f67f2aaf000+0x202000 - . - test-core-lib.so
0x7fff1596c000+0x1000 a9cf37f53897b5468ee018655760be61b8633d3c@0x7fff1596c340 . - linux-vdso.so.1
10 years, 4 months
[commit] NEWS update; + expected release of 0.156
by Jan Kratochvil
Hello,
going to release 0.156 these days (Mark Wielaard is offline).
If there is anything appropriate to fix at this last moment mail me, please.
Regards,
Jan
commit a55b11834d3ee63525ff346d356e84171bad8ecb
Author: Jan Kratochvil <jan.kratochvil(a)redhat.com>
Date: Fri Jul 19 00:24:06 2013 +0200
NEWS: Add entries for Version 0.156.
Signed-off-by: Jan Kratochvil <jan.kratochvil(a)redhat.com>
diff --git a/ChangeLog b/ChangeLog
index bffe62d..9e2432b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-07-18 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * NEWS: Add entries for Version 0.156.
+
2013-04-28 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* NEWS (Version 0.156): New.
diff --git a/NEWS b/NEWS
index a71a87c..3a2cc39 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,71 @@
Version 0.156
+lib: New macro COMPAT_VERSION_NEWPROTO.
+ Fix pread and pwrite if they return incomplete data.
+
+libdw: Fix DW_CFA_expression parsing of initial pushed value.
+ Fix false error return on no matching CFI from __libdw_find_fde.
+ Fix uninitialized register contents memory in execute_cfi.
+ Handle GNU extension opcodes in dwarf_getlocation.
+ Handle FORM_GNU_strp_alt for files with string data only in dwz file.
+ srcfiles and srclines fixes for partial_units.
+ dwarf_getsrclines mark highest address as end_sequence.
+ dwarf_getsrclines don't set end_sequence when there are no lines.
+ libdw_visit_scopes: Don't recurse into imported unit children.
+ getcfi_scn_eh_frame: Don't crash when .eh_frame bits aren't there.
+ Don't blow up stack in dwarf_getsrclines with lots of lines.
+
libdwfl: dwfl_report_elf has new parameter add_p_vaddr.
+ Fix STB_GLOBAL over STB_WEAK preference in dwfl_module_addrsym.
+ Fix bias for vDSOs from core files.
+ Fix bias for DSOs loaded from core file with build-id.
+ Fix loading PIEs specified with both -e and --core.
+ Fix double free in Linux kernel modules reporting.
+ Add minisymtab support.
+ Fix 64-bit -> 32-bit vDSO reporting.
+ Try opening files with all installed compression libraries.
+ srcfiles and srclines fixes for partial_units.
+ Fix dwfl_report_elf BASE alignment.
+ Add parameter add_p_vaddr to dwfl_report_elf.
+ Use DT_DEBUG library search first.
+ Don't assert on mod->e_type in __libdwfl_relocate_value.
+
+libelf: Handle unaligned accesses.
+
+libebl: Handle new core note types in EBL.
+ Fix default_abi_cfi.
+
+backends: Fix FPREGSET_SIZE for ARM, interpret NT_ARM_VFP.
+ Implement core file registers parsing for s390/s390x.
+ Check type DIE exists before calling dwarf_tag ().
+
+readelf: Add --elf-section input option to inspect an embedded ELF file.
+ Add -U, --unresolved-address-offsets output control.
+ Add --debug-dump=decodedline support.
+ Accept version 8 .gdb_index section format.
+ Fix displaying bitmaps.
+ Adjust output formatting width.
+ Fix DW_OP_skip and DW_OP_bra targets calculation.
+ Fix printing .eh_frame pcrel addresses.
+ Fix displayed location list addresses base.
+ When highpc is in constant form print it also as address.
+ Display raw .debug_aranges. Use libdw only for decodedaranges.
+ Format first DW_OP_GNU_implicit_pointer argument as DIE offset.
+ Print actual DW_OP_GNU_parameter_ref DIE offset.
+ Print actual DIE offsets of DW_OP_GNU_<type> ops.
+
+nm: Fix invalid symbol name message output.
+
+ar: Fix memory corruption.
+
+elflint: Add __bss_start__ to the list of allowed symbols.
+
+tests: Add configure --enable-valgrind option to run all tests under valgrind.
+ Enable automake parallel-tests for make check.
+
+translations: Updated Polish translation.
+
+Updates for Automake 1.13.
Version 0.155
10 years, 4 months
[commit] NEWS: Remove bugfix only entries from Version 0.156.
by Jan Kratochvil
Hi,
as I read in some past mail NEWS is not intended to contain bugfix only
entries.
Checked in.
Jan
commit 934d36cb5fec8156fab96bcdf3939a20ff7d473f
Author: Jan Kratochvil <jan.kratochvil(a)redhat.com>
Date: Fri Jul 19 23:26:28 2013 +0200
NEWS: Remove bugfix only entries from Version 0.156.
Signed-off-by: Jan Kratochvil <jan.kratochvil(a)redhat.com>
diff --git a/ChangeLog b/ChangeLog
index 9e2432b..b2f3718 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-07-19 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * NEWS: Remove bugfix only entries from Version 0.156.
+
2013-07-18 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* NEWS: Add entries for Version 0.156.
diff --git a/NEWS b/NEWS
index 3a2cc39..d422eae 100644
--- a/NEWS
+++ b/NEWS
@@ -1,62 +1,26 @@
Version 0.156
lib: New macro COMPAT_VERSION_NEWPROTO.
- Fix pread and pwrite if they return incomplete data.
-
-libdw: Fix DW_CFA_expression parsing of initial pushed value.
- Fix false error return on no matching CFI from __libdw_find_fde.
- Fix uninitialized register contents memory in execute_cfi.
- Handle GNU extension opcodes in dwarf_getlocation.
- Handle FORM_GNU_strp_alt for files with string data only in dwz file.
- srcfiles and srclines fixes for partial_units.
- dwarf_getsrclines mark highest address as end_sequence.
- dwarf_getsrclines don't set end_sequence when there are no lines.
- libdw_visit_scopes: Don't recurse into imported unit children.
- getcfi_scn_eh_frame: Don't crash when .eh_frame bits aren't there.
- Don't blow up stack in dwarf_getsrclines with lots of lines.
-
-libdwfl: dwfl_report_elf has new parameter add_p_vaddr.
- Fix STB_GLOBAL over STB_WEAK preference in dwfl_module_addrsym.
- Fix bias for vDSOs from core files.
- Fix bias for DSOs loaded from core file with build-id.
- Fix loading PIEs specified with both -e and --core.
- Fix double free in Linux kernel modules reporting.
+
+libdw: Handle GNU extension opcodes in dwarf_getlocation.
+
+libdwfl: Fix STB_GLOBAL over STB_WEAK preference in dwfl_module_addrsym.
Add minisymtab support.
- Fix 64-bit -> 32-bit vDSO reporting.
- Try opening files with all installed compression libraries.
- srcfiles and srclines fixes for partial_units.
- Fix dwfl_report_elf BASE alignment.
Add parameter add_p_vaddr to dwfl_report_elf.
Use DT_DEBUG library search first.
- Don't assert on mod->e_type in __libdwfl_relocate_value.
-
-libelf: Handle unaligned accesses.
libebl: Handle new core note types in EBL.
- Fix default_abi_cfi.
-backends: Fix FPREGSET_SIZE for ARM, interpret NT_ARM_VFP.
+backends: Interpret NT_ARM_VFP.
Implement core file registers parsing for s390/s390x.
- Check type DIE exists before calling dwarf_tag ().
readelf: Add --elf-section input option to inspect an embedded ELF file.
Add -U, --unresolved-address-offsets output control.
Add --debug-dump=decodedline support.
Accept version 8 .gdb_index section format.
- Fix displaying bitmaps.
Adjust output formatting width.
- Fix DW_OP_skip and DW_OP_bra targets calculation.
- Fix printing .eh_frame pcrel addresses.
- Fix displayed location list addresses base.
When highpc is in constant form print it also as address.
Display raw .debug_aranges. Use libdw only for decodedaranges.
- Format first DW_OP_GNU_implicit_pointer argument as DIE offset.
- Print actual DW_OP_GNU_parameter_ref DIE offset.
- Print actual DIE offsets of DW_OP_GNU_<type> ops.
-
-nm: Fix invalid symbol name message output.
-
-ar: Fix memory corruption.
elflint: Add __bss_start__ to the list of allowed symbols.
10 years, 4 months