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 <[email protected]> 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 <[email protected]> Signed-off-by: Mark Wielaard <[email protected]> --- 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 <[email protected]> + + * 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 <[email protected]> * 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 <[email protected]> + + * 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 <[email protected]> * 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 <[email protected]>, 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
