[patch] Code cleanup: Simplify __libdwfl_report_elf
by Jan Kratochvil
Hi Roland,
jankratochvil/basecleanup
./libdwfl/dwfl_report_elf.c
__libdwfl_report_elf <ET_DYN>
vaddr = ph->p_vaddr & -ph->p_align;
address_sync = ph->p_vaddr + ph->p_memsz;
if ((base & (ph->p_align - 1)) != 0)
base = (base + ph->p_align - 1) & -ph->p_align;
- start = base + (ph->p_vaddr & -ph->p_align);
+ start = base + vaddr;
break;
}
}
- bias = start - vaddr;
+ bias = base;
This change has no functionality effect.
It is more interesting whether dwfl_report_elf and __libdwfl_report_elf
parameter BASE was intended to be "base address" or "bias".
Currently it works as bias and it is also documented so:
./libdwfl/libdwfl.h
/* Report a module with start and end addresses computed from the ELF
program headers in the given file, plus BASE. For an ET_REL file,
But this means an application cannot specify base address as application does
not know where the ELF is prelinked to. An application also cannot open an
ELF file beforehand to find out the prelinked address by hand as
__libdw_open_file is private. Application could only parse ELF completely on
its own which does not seem right to me. Therefore I will propose some new
API function for specifying the base address later; this paragraph is offtopic
here.
This base address <-> bias confusion may also come from:
./libdwfl/link_map.c
mod = INTUSE(dwfl_report_elf) (dwfl, basename (name),
name, -1, l_addr);
possibly due to:
glibc/elf/link.h
ElfW(Addr) l_addr; /* Base address shared object is loaded at. */
which is not "Base address" but it is BIAS; fix of the glibc comment failed
with Jakub Jelinek in:
[patch] Fix l_addr comment
http://sourceware.org/ml/libc-alpha/2011-09/msg00151.html
Also the current meaning of dwfl->offline_next_address is not clear to me:
./libdwfl/offline.c
process_elf
Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf,
dwfl->offline_next_address, false);
as it means BIAS, not "next_address" here, which is for example correct for:
./src/readelf.c
process_file
/* Let 0 be the logical address of the file (or first in archive). */
dwfl->offline_next_address = 0;
./libdwfl/argp-std.c
parse_opt <'e'>
/* Start at zero so if there is just one -e foo.so,
the DSO is shown without address bias. */
dwfl->offline_next_address = 0;
but it seems incorrect to me for:
/* If this is an ET_EXEC file with fixed addresses, the address range
it consumed may or may not intersect with the arbitrary range we
will use for relocatable modules. Make sure we always use a free
range for the offline allocations. If this module did use
offline_next_address, it may have rounded it up for the module's
alignment requirements. */
if ((dwfl->offline_next_address >= mod->low_addr
|| mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
&& dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
where the code IMO expects an address and not a bias. Maybe it is in practice
"next_address" for ET_REL (which is never prelinked) and it is BIAS for ET_DYN.
I guess the current API/ABI should keep this BASE parameter to be BIAS, so
one/I can rather clarify more the code while keeping the functionality as is.
Thanks,
Jan
commit 10a94132fb2e669f4bc7adcce80844bd761ae3b0
Author: Jan Kratochvil <jan.kratochvil(a)redhat.com>
Date: Sat Oct 27 20:45:27 2012 +0200
libdwfl/
* dwfl_report_elf.c (__libdwfl_report_elf): Simplify START and BIAS
calculation.
Signed-off-by: Jan Kratochvil <jan.kratochvil(a)redhat.com>
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index bdd9440..83bdf46 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,8 @@
+2012-10-27 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Simplify START and BIAS
+ calculation.
+
2012-10-17 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* dwfl_module_getdwarf.c (mod_verify_build_id): New function with code
diff --git a/libdwfl/dwfl_report_elf.c b/libdwfl/dwfl_report_elf.c
index 35d9f48..174ce7c 100644
--- a/libdwfl/dwfl_report_elf.c
+++ b/libdwfl/dwfl_report_elf.c
@@ -183,11 +183,11 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
address_sync = ph->p_vaddr + ph->p_memsz;
if ((base & (ph->p_align - 1)) != 0)
base = (base + ph->p_align - 1) & -ph->p_align;
- start = base + (ph->p_vaddr & -ph->p_align);
+ start = base + vaddr;
break;
}
}
- bias = start - vaddr;
+ bias = base;
for (size_t i = phnum; i-- > 0;)
{
11 years, 6 months
[PATCH] readelf.c (print_ops): Ajust DW_OP_skip and DW_OP_bra targets calculation.
by Mark Wielaard
The 2-byte constant is the number of bytes of the DWARF expression to skip
forward or backward from the current operation, beginning after the 2-byte
constant.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
src/ChangeLog | 5 +++++
src/readelf.c | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/ChangeLog b/src/ChangeLog
index 9d6fbe3..9f0c525 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2012-10-16 Mark Wielaard <mjw(a)redhat.com>
+
+ * readelf.c (print_ops): DW_OP_skip and DW_OP_bra targets are
+ calculated beginning after the operand and 2-byte constant.
+
2012-10-12 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* readelf.c (ITEM_WRAP_COLUMN, REGISTER_WRAP_COLUMN): Merge to ...
diff --git a/src/readelf.c b/src/readelf.c
index 1801c1c..7f6f31c 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -3802,7 +3802,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
NEED (2);
printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n",
indent, "", (uintmax_t) offset, op_name,
- (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data)));
+ (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data) + 3));
CONSUME (2);
data += 2;
offset += 3;
--
1.7.11.7
11 years, 6 months
[patch] Fix dwfl_report_elf BASE alignment
by Jan Kratochvil
Hi Roland,
jankratochvil/basecleanup-basealign
this patch has dependency on:
[patch] Code cleanup: Simplify __libdwfl_report_elf
https://lists.fedorahosted.org/pipermail/elfutils-devel/2012-October/0027...
elfutils code does:
if ((base & (ph->p_align - 1)) != 0)
base = (base + ph->p_align - 1) & -ph->p_align;
which conflicts with the p_align ELF spec definition:
Loadable process segments must have congruent values for p_vaddr and
p_offset, modulo the page size.This member gives the value to which
the segments are aligned in memory and in the file.
(I have always found its name "align" to be confusing.)
One can see in real world runtime this "alignment" 0x200000 really is not
applied - base address 0x...92000 is not 2MB-aligned.
7f3560c92000-7f3560c93000 r-xp 00000000 fd:02 25037063 testfile-dwfl-report-elf-align-shlib.so
7f3560c93000-7f3560e92000 ---p 00001000 fd:02 25037063 testfile-dwfl-report-elf-align-shlib.so
7f3560e92000-7f3560e93000 rw-p 00000000 fd:02 25037063 testfile-dwfl-report-elf-align-shlib.so
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x00065c 0x00065c R E 0x200000
LOAD 0x000660 0x0000000000200660 0x0000000000200660 0x0001f0 0x000200 RW 0x200000
Also I do not see why an alignment of BASE (to whatever value) is useful.
This bug does not affect elfutils as they use dwfl_report_segment internally
and neither dwfl_report_elf nor __libdwfl_report_elf. Also this code is never
executed by elfutils testsuite and I do not know hot so easilt execute it:
./libdwfl/link_map.c
mod = INTUSE(dwfl_report_elf) (dwfl, basename (name),
name, -1, l_addr);
Application cannot use dwfl_report_segment as its real use requires private
elfutils members/functions.
Thanks,
Jan
commit a7f0c7072e8a420f672b5a99ea85f3d15212ffac
Author: Jan Kratochvil <jan.kratochvil(a)redhat.com>
Date: Sat Oct 27 20:50:21 2012 +0200
libdwfl/
* dwfl_report_elf.c (__libdwfl_report_elf): Remove BASE aligning.
tests/
* Makefile.am (check_PROGRAMS): Add dwfl-report-elf-align.
(TESTS): Add run-dwfl-report-elf-align.sh.
(EXTRA_DIST): Add run-dwfl-report-elf-align.sh and
testfile-dwfl-report-elf-align-shlib.so.bz2 .
(dwfl_report_elf_align_LDADD): New.
* dwfl-report-elf-align.c: New file.
* run-dwfl-report-elf-align.sh: New file.
* testfile-dwfl-report-elf-align-shlib.so.bz2: New file.
Signed-off-by: Jan Kratochvil <jan.kratochvil(a)redhat.com>
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 83bdf46..cdf539e 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,5 +1,9 @@
2012-10-27 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+ * dwfl_report_elf.c (__libdwfl_report_elf): Remove BASE aligning.
+
+2012-10-27 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
* dwfl_report_elf.c (__libdwfl_report_elf): Simplify START and BIAS
calculation.
diff --git a/libdwfl/dwfl_report_elf.c b/libdwfl/dwfl_report_elf.c
index 174ce7c..d706170 100644
--- a/libdwfl/dwfl_report_elf.c
+++ b/libdwfl/dwfl_report_elf.c
@@ -181,8 +181,6 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
{
vaddr = ph->p_vaddr & -ph->p_align;
address_sync = ph->p_vaddr + ph->p_memsz;
- if ((base & (ph->p_align - 1)) != 0)
- base = (base + ph->p_align - 1) & -ph->p_align;
start = base + vaddr;
break;
}
diff --git a/tests/ChangeLog b/tests/ChangeLog
index edb82b4..896105d 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,5 +1,16 @@
2012-10-27 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+ * Makefile.am (check_PROGRAMS): Add dwfl-report-elf-align.
+ (TESTS): Add run-dwfl-report-elf-align.sh.
+ (EXTRA_DIST): Add run-dwfl-report-elf-align.sh and
+ testfile-dwfl-report-elf-align-shlib.so.bz2 .
+ (dwfl_report_elf_align_LDADD): New.
+ * dwfl-report-elf-align.c: New file.
+ * run-dwfl-report-elf-align.sh: New file.
+ * testfile-dwfl-report-elf-align-shlib.so.bz2: New file.
+
+2012-10-27 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
* Makefile.am (EXTRA_DIST): Add testfile64.bz2, testfile65.bz2,
testfile69.core.bz2 and testfile69.so.bz2 .
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f2d2484..a1ed284 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -51,7 +51,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
dwfl-bug-getmodules dwarf-getmacros addrcfi \
test-flag-nobits dwarf-getstring rerequest_tag \
alldts md5-sha1-test typeiter low_high_pc \
- test-elf_cntl_gelf_getshdr
+ test-elf_cntl_gelf_getshdr dwfl-report-elf-align
asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
asm-tst6 asm-tst7 asm-tst8 asm-tst9
@@ -85,7 +85,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
run-readelf-d.sh run-readelf-gdb_index.sh run-unstrip-n.sh \
run-low_high_pc.sh run-macro-test.sh run-elf_cntl_gelf_getshdr.sh \
run-test-archive64.sh run-readelf-vmcoreinfo.sh \
- run-readelf-mixed-corenote.sh
+ run-readelf-mixed-corenote.sh run-dwfl-report-elf-align.sh
if !STANDALONE
check_PROGRAMS += msg_tst md5-sha1-test
@@ -180,7 +180,9 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
testfile60.bz2 testfile61.bz2 \
run-readelf-vmcoreinfo.sh testfile62.bz2 \
run-readelf-mixed-corenote.sh testfile63.bz2 testfile64.bz2 \
- testfile65.bz2 testfile69.core.bz2 testfile69.so.bz2
+ testfile65.bz2 testfile69.core.bz2 testfile69.so.bz2 \
+ run-dwfl-report-elf-align.sh \
+ testfile-dwfl-report-elf-align-shlib.so.bz2
if USE_VALGRIND
valgrind_cmd="valgrind -q --trace-children=yes --error-exitcode=1"
@@ -287,6 +289,7 @@ md5_sha1_test_LDADD = $(libeu)
typeiter_LDADD = $(libdw) $(libelf) $(libmudflap)
low_high_pc_LDADD = $(libdw) $(libelf) $(libmudflap)
test_elf_cntl_gelf_getshdr_LDADD = $(libelf) $(libmudflap)
+dwfl_report_elf_align_LDADD = $(libdw) $(libmudflap)
if GCOV
check: check-am coverage
diff --git a/tests/dwfl-report-elf-align.c b/tests/dwfl-report-elf-align.c
new file mode 100644
index 0000000..86297fa
--- /dev/null
+++ b/tests/dwfl-report-elf-align.c
@@ -0,0 +1,72 @@
+/* Test program for dwfl_report_elf incorrect BASE alignment.
+ 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 the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <error.h>
+#include <locale.h>
+#include <string.h>
+#include <stdlib.h>
+#include ELFUTILS_HEADER(dwfl)
+
+
+static const Dwfl_Callbacks offline_callbacks =
+ {
+ .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
+ .section_address = INTUSE(dwfl_offline_section_address),
+ };
+
+
+int
+main (int argc, char **argv)
+{
+ /* We use no threads here which can interfere with handling a stream. */
+ (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
+
+ /* Set locale. */
+ (void) setlocale (LC_ALL, "");
+
+ if (argc != 5)
+ error (1, 0, "dwfl-report-elf-align shlib.so base funcaddr funcname");
+
+ Dwfl *dwfl = dwfl_begin (&offline_callbacks);
+ assert (dwfl != NULL);
+
+ char *endptr;
+ uintptr_t base = strtol (argv[2], &endptr, 0);
+ assert (endptr && !*endptr);
+
+ Dwfl_Module *mod = dwfl_report_elf (dwfl, argv[1], argv[1], -1, base);
+ assert (mod != NULL);
+
+ uintptr_t funcaddr = strtol (argv[3], &endptr, 0);
+ assert (endptr && !*endptr);
+
+ Dwfl_Module *mod_found = dwfl_addrmodule (dwfl, funcaddr);
+ assert (mod_found == mod);
+
+ const char *symname = dwfl_module_addrname (mod, funcaddr);
+ assert (symname != NULL);
+ assert (strcmp (symname, argv[4]) == 0);
+
+ dwfl_end (dwfl);
+
+ return 0;
+}
diff --git a/tests/run-dwfl-report-elf-align.sh b/tests/run-dwfl-report-elf-align.sh
new file mode 100755
index 0000000..df2c583
--- /dev/null
+++ b/tests/run-dwfl-report-elf-align.sh
@@ -0,0 +1,34 @@
+#! /bin/sh
+# 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 the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+testfiles testfile-dwfl-report-elf-align-shlib.so
+
+# 7f3560c92000-7f3560c93000 r-xp 00000000 fd:02 25037063 testfile-dwfl-report-elf-align-shlib.so
+# 7f3560c93000-7f3560e92000 ---p 00001000 fd:02 25037063 testfile-dwfl-report-elf-align-shlib.so
+# 7f3560e92000-7f3560e93000 rw-p 00000000 fd:02 25037063 testfile-dwfl-report-elf-align-shlib.so
+# Program Headers:
+# Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
+# LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x00065c 0x00065c R E 0x200000
+# LOAD 0x000660 0x0000000000200660 0x0000000000200660 0x0001f0 0x000200 RW 0x200000
+# #1 0x00007f3560c92585 in shlib () from ./testfile-dwfl-report-elf-align-shlib.so
+
+./dwfl-report-elf-align ./testfile-dwfl-report-elf-align-shlib.so \
+ 0x7f3560c92000 0x7f3560c92585 shlib
+
+exit 0
diff --git a/tests/testfile-dwfl-report-elf-align-shlib.so.bz2 b/tests/testfile-dwfl-report-elf-align-shlib.so.bz2
new file mode 100755
index 0000000000000000000000000000000000000000..1f35df98ffa1dc5883acce9f3b567891f024e43e
GIT binary patch
literal 1546
zcmV+l2KD(uT4*^jL0KkKSx!>Q^#BDofB*mg{r}ege}Dh~eqaCp|NPHtQJ_~;*l2BG
zOTgc3=V{OczV0wl*EV&Ux+Vsvq$!GRDYVLH^%)OH03K67(?N)OnE)Q9ho}GpKma{J
zG-zq+01c!70L1-B^#-ZvAeo?;L8609(E*?ypa1{^Mw$Q`01X2`05oXOG5`S3003%Y
z5t3q))DKNZqyPqiqts{vMnEzE8Vv@G0LTo000000G|8X<5E>Z<nKaNangc^jnl!+S
zjG7FFOoJm#jT&ScGyuUGXfX`{44N4*5unkaNRXo`qHPUElW7}MWi-*XHiJosX`s_a
zfYIt17>odeMt}_gpazW|Q$s^cKpHg2H-+9dek8nF7>Hhj5mLIf5qL%9+>6>y987dm
zCZK~BX2dnDlxT!Vv|)gRf)rHrl_+cSr#B6QmN68Q5ERR81@S3MbLS;$5km9x0pP$G
zM2H4i#vG?TgiSG1LH7(9!XScO2fmsVhf-lP9&_G4yl6aXCgoWS7A{{z_p4}|6SR;h
z6*mr}ndBsrNDCEX_!6&#%_Zr^;5J~l6PI^+((2q?*zY)Mc0VJ)3gom7|3vJ|J&RBP
zP{LtisOagWU?fw4y0tV;s-(j6=YsBehA7d`?5>KYx@&L(GCXbfMLnj6Wv#hGs(roo
z6r*VdYIpb%IIYG`3|8sO@h3fn{Zc|&rjj*GLIAM)rj@yAi6+nx#C2^i4ncb40Y<mX
zNhC?6tu!nROdxFlHmnULu<T(Oc@TfkABX1f<G9!8C+M-5JzR1FTx6xhmJ$O;)Tnt0
zWf6#3nPU|a24*XHyEjF>Xl0?5Vcg8m8KCajWvw!0?1;G>c<3BbQiT$)H)s0IL+U6=
z1sW#KxtMobSt7>13yc-^v)K2z-Q|vJ#$vR@-M0@!m_zF)0m5J`b|Z?=mMhKv8yMtD
zB`HK&RAov8*xH~0LWXiZ8)?~|l^;o_Qmv2s(0~OA+wmPG6r#pmPeX!htFmK+r!tU6
zwTmm2`5K6X;>`&&mwm`)K+EmzCx*P*90W_1F=Rrhz;dAubJk&G&HdhDJZ8a#b?RzP
z_Xi$$d?ZVH4Y~tc0*E>I>a6cgY>-VaxVQ7lYC)NoyIV*kDvUsb8siyqLV~B20eaN3
zmtePOALR=M_uh676G!aHx<D~4!^|w59M@^nmNmy7h~rF*D&;GvLm|NNDxLqB{`<3=
zU1nB#wTp-NnVKValj$~yZH)!gD#=>BWSVZ0hQSdUZpuqryJ+&fcPc5sc40LjNQ%A&
zMPTb)*?4Kn+wa{%)PS}*W(IwSkj3M)Nv!0^H;>D7GnVjN;D>fw@OHjVRu)`kxJ(HR
z^kE4ll5GX<dM}<cn9rD+i>@s>USO4$W%soO*><0^q@LJ$NdHJu;?1v#OeV)n)nT5y
zGg-)rwfmmhv7|g})b71@SfdZC@7rHU*Ww;*Twl$XFq>k#pofB4mL0|{>%B@Mc2hZf
zbo~T*t6Z|(;ngECShMRf1xrE+hqM=FzU0$T{6dAJ0#R#Y`cP*VYk@%#wmPA{g4aY@
z$ci)7J?SPCyzrdyF!?Mla8wvSWx`xWvCx@A2JNN-RcymRsuU|6jSOnS?!zZENfhe^
zJ?|F}4rEsGs|7l9C{qJ^P9~M3vKb^AGiCut2V4$ia>9`<4WmI+gCaWjpm=hoRBD72
zLjXh$BMY?zAtyYfx|(1Wa6^JAv<OtEVF8zHy6P%5RLceg_&`CQojBrq;AY}&&D6mS
zoh4Co2J65w#CK9;I<2Dd2}EU}$SF$G-59QP8TeHl@&yG}5c)=@woKr964`XXD1rnd
zTOiQfUs^fTYoJ@MQJbw<{#zSNjv8$e*v{Eo6D&Sreh^xKSO>zk8^QZ@rz|pqAnI(b
z+yTe2-;sHuejQXC-^9z6TwZ8bxsg#+K_aMZ$PhtWBaf+dR~2Z~B)k#}{ayWAj-VT~
w3CkdHfdqj_tI8j#a!WvjqM=LVwVFt(S=+gGkst7LqkqNRkxmpO6O^*OK%{@Z*#H0l
literal 0
HcmV?d00001
11 years, 6 months
[patch 6/4] unwinder: New dwfl_fd_find_debuginfo stub
by Jan Kratochvil
Hi,
dependent on:
[patch 4/4] unwinder: The unwinder (x86* only)
present in:
jankratochvil/forunwind-baseaddr-hookvars-corereport-unwindx86-nonx86-fddebuginfo
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.
Linux kernel perf has its own logic how to find the separate debug info files.
I did not want to introduce two different ways of finding separate debug info
files into Linux kernel perf, therefore I have provided this stub function so
that an application can provide an open file descriptor with it this way.
Thanks,
Jan
libdw/
2012-11-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* libdw.map (ELFUTILS_0.156): New entry dwfl_fd_find_debuginfo.
libdwfl/
2012-11-14 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* find-debuginfo.c (dwfl_fd_find_debuginfo): New function.
* libdwfl.h (dwfl_fd_find_debuginfo): New declaration.
diff --git a/libdw/libdw.map b/libdw/libdw.map
index bf65d83..3398089 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -259,6 +259,7 @@ ELFUTILS_0.156 {
global:
dwfl_core_filename_report;
dwfl_report_elf_baseaddr;
+ dwfl_fd_find_debuginfo;
dwfl_frame_state_pid;
dwfl_frame_state_core;
dwfl_frame_state_data;
diff --git a/libdwfl/find-debuginfo.c b/libdwfl/find-debuginfo.c
index 21db91a..40c9640 100644
--- a/libdwfl/find-debuginfo.c
+++ b/libdwfl/find-debuginfo.c
@@ -269,3 +269,11 @@ dwfl_standard_find_debuginfo (Dwfl_Module *mod,
return fd;
}
INTDEF (dwfl_standard_find_debuginfo)
+
+bool
+dwfl_fd_find_debuginfo (Dwfl_Module *mod, GElf_Word debuglink_crc, int fd)
+{
+ bool cancheck = debuglink_crc != (GElf_Word) 0;
+ return validate (mod, fd, cancheck, debuglink_crc);
+}
+INTDEF (dwfl_fd_find_debuginfo)
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index dee3e2f..b63e6f8 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -304,6 +304,10 @@ extern int dwfl_standard_find_debuginfo (Dwfl_Module *, void **,
const char *, const char *,
GElf_Word, char **);
+/* Provide supplied separate debug info file FD for MOD. */
+extern bool dwfl_fd_find_debuginfo (Dwfl_Module *mod, GElf_Word debuglink_crc,
+ int fd);
+
/* This callback must be used when using dwfl_offline_* to report modules,
if ET_REL is to be supported. */
11 years, 6 months
[patch 5/4] unwinder: non-x86* parts of the unwinder
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
11 years, 6 months