This is the mail archive of the
elfutils-devel@sourceware.org
mailing list for the elfutils project.
Re: [PATCH] libdw: Make dwarf_getfuncs find all (defining) DW_TAG_subprogram DIEs.
- From: Mark Wielaard <mjw at redhat dot com>
- To: elfutils-devel at lists dot fedorahosted dot org
- Date: Thu, 10 Oct 2013 11:48:38 +0200
- Subject: Re: [PATCH] libdw: Make dwarf_getfuncs find all (defining) DW_TAG_subprogram DIEs.
On Mon, 2013-10-07 at 10:53 -0700, Josh Stone wrote:
> BTW, I thought of another corner case which I think will break
> offset-resuming in dwarf_getfuncs: DW_AT_import+DW_FORM_GNU_ref_alt.
> The die offsets from the main file and alt file will almost surely
> overlap, and if you happen to have a subprogram at the same offset in
> both, then it's not possible to tell which one to resume on.
Unfortunately you seem to be right, even if that is somewhat unlikely.
> Must the offsets used by dwarf_getfuncs be die offsets? After all, they
> are type ptrdiff_t, not Dwarf_Off. This particular problem might be
> solved by instead using die->addr for the "offset" value.
Yes, that seems to be the correct fix.
Please check the attached.
Thanks,
Mark
>From 9bf031c13f490d012d42d24bd6577fe34d453a67 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mjw@redhat.com>
Date: Thu, 10 Oct 2013 11:40:12 +0200
Subject: [PATCH] libdw: Handle dwz multi files correctly in dwarf_getfuncs.
Don't use DIE offsets, but use their addresses to make sure they are unique.
Reported-by: Josh Stone <jistone@redhat.com>
Signed-off-by: Mark Wielaard <mjw@redhat.com>
---
libdw/ChangeLog | 8 ++++++++
libdw/dwarf_getfuncs.c | 26 +++++++++++++-------------
tests/ChangeLog | 6 ++++++
tests/Makefile.am | 3 ++-
tests/run-allfcts-multi.sh | 31 +++++++++++++++++++++++++++++++
5 files changed, 60 insertions(+), 14 deletions(-)
create mode 100755 tests/run-allfcts-multi.sh
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 960f5aa..1bf1de9 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,11 @@
+2013-10-10 Mark Wielaard <mjw@redhat.com>
+
+ * dwarf_getfuncs.c (struct visitor_info): Rename start_offset to
+ start_addr and rename last_offset to last_addr. Now both void *.
+ (tree_visitor): Use start_add and die_addr instead of start_offset
+ and die_offset.
+ (dwarf_getfuncs): Use last_addr instead of last_offset.
+
2013-10-06 Mark Wielaard <mjw@redhat.com>
* cfi.c (execute_cfi): Make sure DW_CFA_expression and
diff --git a/libdw/dwarf_getfuncs.c b/libdw/dwarf_getfuncs.c
index 87e0341..82894c9 100644
--- a/libdw/dwarf_getfuncs.c
+++ b/libdw/dwarf_getfuncs.c
@@ -43,11 +43,11 @@ struct visitor_info
/* The user arg value to dwarf_getfuncs. */
void *arg;
- /* The DIE offset where to (re)start the search. Zero for all. */
- Dwarf_Off start_offset;
+ /* Addr of the DIE offset where to (re)start the search. Zero for all. */
+ void *start_addr;
- /* Last subprogram DIE offset seen. */
- Dwarf_Off last_offset;
+ /* Last subprogram DIE addr seen. */
+ void *last_addr;
/* The CU only contains C functions. Allows pruning of most subtrees. */
bool c_cu;
@@ -59,8 +59,8 @@ tree_visitor (unsigned int depth __attribute__ ((unused)),
{
struct visitor_info *const v = arg;
Dwarf_Die *die = &chain->die;
- Dwarf_Off start_offset = v->start_offset;
- Dwarf_Off die_offset = INTUSE(dwarf_dieoffset) (die);
+ void *start_addr = v->start_addr;
+ void *die_addr = die->addr;
/* Pure C CUs can only contain defining subprogram DIEs as direct
children of the CU DIE or as nested function inside a normal C
@@ -75,11 +75,11 @@ tree_visitor (unsigned int depth __attribute__ ((unused)),
return DWARF_CB_OK;
}
- /* Skip all DIEs till we found the (re)start offset. */
- if (start_offset != 0)
+ /* Skip all DIEs till we found the (re)start addr. */
+ if (start_addr != NULL)
{
- if (die_offset == start_offset)
- v->start_offset = 0;
+ if (die_addr == start_addr)
+ v->start_addr = NULL;
return DWARF_CB_OK;
}
@@ -88,7 +88,7 @@ tree_visitor (unsigned int depth __attribute__ ((unused)),
|| INTUSE(dwarf_hasattr) (die, DW_AT_declaration))
return DWARF_CB_OK;
- v->last_offset = die_offset;
+ v->last_addr = die_addr;
return (*v->callback) (die, v->arg);
}
@@ -105,13 +105,13 @@ dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *),
|| lang == DW_LANG_C
|| lang == DW_LANG_C99);
- struct visitor_info v = { callback, arg, offset, 0, c_cu };
+ struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu };
struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu),
.parent = NULL };
int res = __libdw_visit_scopes (0, &chain, &tree_visitor, NULL, &v);
if (res == DWARF_CB_ABORT)
- return v.last_offset;
+ return (ptrdiff_t) v.last_addr;
else
return res;
}
diff --git a/tests/ChangeLog b/tests/ChangeLog
index db248dc..2873377 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2013-10-10 Mark Wielaard <mjw@redhat.com>
+
+ * run-allfcts-multi.sh: New test.
+ * Makefile.am (TESTS): Add run-allcft-multi.sh if ENABLE_DWZ.
+ (EXTRA_DIST): Add run-allfcts-multi.sh.
+
2013-10-06 Mark Wielaard <mjw@redhat.com>
* run-addrcfi.sh: Remove nop from expected ppc and ppc64
diff --git a/tests/Makefile.am b/tests/Makefile.am
index de98e45..9cfeb33 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -106,7 +106,7 @@ TESTS += $(asm_TESTS)
endif
if ENABLE_DWZ
-TESTS += run-readelf-dwz-multi.sh
+TESTS += run-readelf-dwz-multi.sh run-allfcts-multi.sh
endif
@@ -164,6 +164,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
run-readelf-dwz-multi.sh libtestfile_multi_shared.so.bz2 \
testfile_multi.dwz.bz2 testfile_multi_main.bz2 \
testfile-dwzstr.bz2 testfile-dwzstr.multi.bz2 \
+ run-allfcts-multi.sh \
run-prelink-addr-test.sh \
testfile52-32.so.bz2 testfile52-32.so.debug.bz2 \
testfile52-32.prelink.so.bz2 testfile52-32.noshdrs.so.bz2 \
diff --git a/tests/run-allfcts-multi.sh b/tests/run-allfcts-multi.sh
new file mode 100755
index 0000000..58524fb
--- /dev/null
+++ b/tests/run-allfcts-multi.sh
@@ -0,0 +1,31 @@
+#! /bin/sh
+# Copyright (C) 2013 Red Hat, Inc.
+# This file is part of elfutils.
+# Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+#
+# 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
+
+# See run-readelf-dwz-multi.sh
+testfiles libtestfile_multi_shared.so testfile_multi_main testfile_multi.dwz
+testfiles testfile-dwzstr testfile-dwzstr.multi
+
+testrun_compare ${abs_builddir}/allfcts testfile_multi_main libtestfile_multi_shared.so testfile-dwzstr <<\EOF
+/home/mark/src/tests/dwz/main.c:3:main
+/home/mark/src/tests/dwz/shared.c:3:call_foo
+/home/mark/src/tests/main.c:8:main
+EOF
+
+exit 0
--
1.7.1