+2018-01-25 Mark Wielaard <mark@klomp.org>
+
+ * Makefile.am (libdw_a_SOURCES): Add dwarf_die_addr_die.c.
+ * dwarf_die_addr_die.c: New file.
+ * libdw.h (dwarf_die_addr_die): New function declaration.
+ * libdw.map (ELFUTILS_0.171): New section with dwarf_die_addr_die.
+ * libdwP.h (__libdw_findcu_addr): New internal function declaration.
+ * libdw_findcu.c (__libdw_findcu_addr): New internal function.
+
2018-02-09 Joshua Watt <JPEWhacker@gmail.com>
* cfi.c (execute_cfi): Use FALLTHROUGH macro instead of comment.
dwarf_aggregate_size.c dwarf_getlocation_implicit_pointer.c \
dwarf_getlocation_die.c dwarf_getlocation_attr.c \
dwarf_getalt.c dwarf_setalt.c dwarf_cu_getdwarf.c \
- dwarf_cu_die.c dwarf_peel_type.c dwarf_default_lower_bound.c
+ dwarf_cu_die.c dwarf_peel_type.c dwarf_default_lower_bound.c \
+ dwarf_die_addr_die.c
if MAINTAINER_MODE
BUILT_SOURCES = $(srcdir)/known-dwarf.h
--- /dev/null
+/* Return offset of DIE.
+ Copyright (C) 2018 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>
+#include "libdwP.h"
+
+
+Dwarf_Die *
+dwarf_die_addr_die (Dwarf *dbg, void *addr, Dwarf_Die *result)
+{
+ if (dbg == NULL)
+ return NULL;
+
+ Dwarf_CU *cu = __libdw_findcu_addr (dbg, addr);
+
+ if (cu == NULL)
+ {
+ Dwarf *alt = INTUSE (dwarf_getalt) (dbg);
+ if (alt != NULL)
+ cu = __libdw_findcu_addr (alt, addr);
+ }
+
+ if (cu == NULL)
+ return NULL;
+
+ *result = (Dwarf_Die) { .addr = addr, .cu = cu };
+
+ return result;
+}
uint8_t *address_sizep, uint8_t *offset_sizep)
__nonnull_attribute__ (2);
+/* Given a Dwarf_Die addr returns a (reconstructed) Dwarf_Die, or NULL
+ if the given addr didn't come from a valid Dwarf_Die. In particular
+ it will make sure that the correct Dwarf_CU pointer is set for the
+ Dwarf_Die, the Dwarf_Abbrev pointer will not be set up yet (it will
+ only be once the Dwarf_Die is used to read attributes, children or
+ siblings). This functions can be used to keep a reference to a
+ Dwarf_Die which you want to refer to later. The addr, and the result
+ of this function, is only valid while the associated Dwarf is valid. */
+extern Dwarf_Die *dwarf_die_addr_die (Dwarf *dbg, void *addr,
+ Dwarf_Die *result)
+ __nonnull_attribute__ (3);
+
/* Return the CU DIE and the header info associated with a Dwarf_Die
or Dwarf_Attribute. A Dwarf_Die or a Dwarf_Attribute is associated
with a particular Dwarf_CU handle. This function returns the CU or
dwarf_default_lower_bound;
dwarf_line_file;
} ELFUTILS_0.167;
+
+ELFUTILS_0.171 {
+ global:
+ dwarf_die_addr_die;
+} ELFUTILS_0.170;
extern struct Dwarf_CU *__libdw_findcu (Dwarf *dbg, Dwarf_Off offset, bool tu)
__nonnull_attribute__ (1) internal_function;
+/* Find CU for given DIE address. */
+extern struct Dwarf_CU *__libdw_findcu_addr (Dwarf *dbg, void *addr)
+ __nonnull_attribute__ (1) internal_function;
+
/* Get abbreviation with given code. */
extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu,
unsigned int code)
/* Find CU for given offset.
- Copyright (C) 2003-2010, 2014 Red Hat, Inc.
+ Copyright (C) 2003-2010, 2014, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
}
/* NOTREACHED */
}
+
+struct Dwarf_CU *
+internal_function
+__libdw_findcu_addr (Dwarf *dbg, void *addr)
+{
+ void **tree;
+ Dwarf_Off start;
+ if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf
+ && addr < (dbg->sectiondata[IDX_debug_info]->d_buf
+ + dbg->sectiondata[IDX_debug_info]->d_size))
+ {
+ tree = &dbg->cu_tree;
+ start = addr - dbg->sectiondata[IDX_debug_info]->d_buf;
+ }
+ else if (dbg->sectiondata[IDX_debug_types] != NULL
+ && addr >= dbg->sectiondata[IDX_debug_types]->d_buf
+ && addr < (dbg->sectiondata[IDX_debug_types]->d_buf
+ + dbg->sectiondata[IDX_debug_types]->d_size))
+ {
+ tree = &dbg->tu_tree;
+ start = addr - dbg->sectiondata[IDX_debug_types]->d_buf;
+ }
+ else
+ return NULL;
+
+ struct Dwarf_CU fake = { .start = start, .end = 0 };
+ struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
+
+ if (found != NULL)
+ return *found;
+
+ return NULL;
+}
+2018-01-25 Mark Wielaard <mark@klomp.org>
+
+ * Makefile.am (check_PROGRAMS): Add dwarf-die-addr-die.
+ (TESTS): Add run-dwarf-die-addr-die.sh.
+ (EXTRA_DIST): Likewise.
+ (dwarf_die_addr_die_LDADD): New variable.
+ * dwarf-die-addr-die.c: New file.
+ * run-dwarf-die-addr-die.sh: New test.
+
2018-02-09 Joshua Watt <JPEWhacker@gmail.com>
* elfstrmerge.c (main): Use FALLTHROUGH macro instead of comment.
getsrc_die strptr newdata elfstrtab dwfl-proc-attach \
elfshphehdr elfstrmerge dwelfgnucompressed elfgetchdr \
elfgetzdata elfputzdata zstrptr emptyfile vendorelf \
- fillfile dwarf_default_lower_bound
+ fillfile dwarf_default_lower_bound dwarf-die-addr-die
asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
asm-tst6 asm-tst7 asm-tst8 asm-tst9
run-elfgetzdata.sh run-elfputzdata.sh run-zstrptr.sh \
run-compress-test.sh \
run-readelf-zdebug.sh run-readelf-zdebug-rel.sh \
- emptyfile vendorelf fillfile dwarf_default_lower_bound
+ emptyfile vendorelf fillfile dwarf_default_lower_bound \
+ run-dwarf-die-addr-die.sh
if !BIARCH
export ELFUTILS_DISABLE_BIARCH = 1
run-zstrptr.sh run-compress-test.sh \
run-disasm-bpf.sh \
testfile-bpf-dis1.expect.bz2 testfile-bpf-dis1.o.bz2 \
- testfile-m68k-core.bz2 testfile-m68k.bz2 testfile-m68k-s.bz2
+ testfile-m68k-core.bz2 testfile-m68k.bz2 testfile-m68k-s.bz2 \
+ run-dwarf-die-addr-die.sh
if USE_VALGRIND
valgrind_cmd='valgrind -q --leak-check=full --error-exitcode=1'
vendorelf_LDADD = $(libelf)
fillfile_LDADD = $(libelf)
dwarf_default_lower_bound_LDADD = $(libdw)
+dwarf_die_addr_die_LDADD = $(libdw)
# We want to test the libelf header against the system elf.h header.
# Don't include any -I CPPFLAGS.
--- /dev/null
+/* Test program for dwarf_die_addr_die.
+ Copyright (C) 2018 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 ELFUTILS_HEADER(dw)
+#include <dwarf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+/* The main Dwarf file. */
+static Dwarf *dwarf;
+
+int
+check_die (Dwarf_Die *die)
+{
+ if (dwarf_tag (die) == DW_TAG_invalid)
+ {
+ printf ("Invalid die\n");
+ return -1;
+ }
+
+ int res = 0;
+ void *addr = die->addr;
+ Dwarf_Die die2;
+ if (dwarf_die_addr_die (dwarf, addr, &die2) == NULL)
+ {
+ printf ("Bad die addr die at offset %" PRIx64 "\n",
+ dwarf_dieoffset (die));
+ res = -1;
+ }
+
+ if (dwarf_tag (die) != dwarf_tag (&die2))
+ {
+ printf ("Tags differ for die at offset %" PRIx64 "\n",
+ dwarf_dieoffset (die));
+ res = -1;
+ }
+
+ if (dwarf_cuoffset (die) != dwarf_cuoffset (&die2))
+ {
+ printf ("CU offsets differ for die at offset %" PRIx64 "\n",
+ dwarf_dieoffset (die));
+ res = -1;
+ }
+
+ Dwarf_Die child;
+ if (dwarf_child (die, &child) == 0)
+ res |= check_die (&child);
+
+ Dwarf_Die sibling;
+ if (dwarf_siblingof (die, &sibling) == 0)
+ res |= check_die (&sibling);
+
+ return res;
+}
+
+int
+check_dbg (Dwarf *dbg)
+{
+ int res = 0;
+ Dwarf_Off off = 0;
+ Dwarf_Off old_off = 0;
+ size_t hsize;
+ Dwarf_Off abbrev;
+ uint8_t addresssize;
+ uint8_t offsetsize;
+ while (dwarf_nextcu (dbg, off, &off, &hsize, &abbrev, &addresssize,
+ &offsetsize) == 0)
+ {
+ Dwarf_Die die;
+ if (dwarf_offdie (dbg, old_off + hsize, &die) != NULL)
+ {
+ printf ("checking CU at %" PRIx64 "\n", old_off);
+ res |= check_die (&die);
+ }
+
+ old_off = off;
+ }
+
+ // Same for type...
+ Dwarf_Half version;
+ uint64_t typesig;
+ Dwarf_Off typeoff;
+ off = 0;
+ old_off = 0;
+ while (dwarf_next_unit (dbg, off, &off, &hsize, &version, &abbrev,
+ &addresssize, &offsetsize, &typesig, &typeoff) == 0)
+ {
+ Dwarf_Die die;
+ if (dwarf_offdie_types (dbg, old_off + hsize, &die) != NULL)
+ {
+ printf ("checking TU at %" PRIx64 "\n", old_off);
+ res |= check_die (&die);
+ }
+
+ // We should have seen this already, but double check...
+ if (dwarf_offdie_types (dbg, old_off + typeoff, &die) != NULL)
+ {
+ printf ("checking Type DIE at %" PRIx64 "\n",
+ old_off + hsize + typeoff);
+ res |= check_die (&die);
+ }
+
+ old_off = off;
+ }
+
+ Dwarf *alt = dwarf_getalt (dbg);
+ if (alt != NULL)
+ {
+ printf ("checking alt debug\n");
+ res |= check_dbg (alt);
+ }
+
+ return res;
+}
+
+int
+main (int argc, char *argv[])
+{
+ if (argc < 2)
+ {
+ printf ("No file given.\n");
+ return -1;
+ }
+
+ const char *name = argv[1];
+ int fd = open (name, O_RDONLY);
+ if (fd < 0)
+ {
+ printf ("Cannnot open '%s': %s\n", name, strerror (errno));
+ return -1;
+ }
+
+ dwarf = dwarf_begin (fd, DWARF_C_READ);
+ if (dwarf == NULL)
+ {
+ printf ("Not a Dwarf file '%s': %s\n", name, dwarf_errmsg (-1));
+ close (fd);
+ return -1;
+ }
+
+ printf ("checking %s\n", name);
+ int res = check_dbg (dwarf);
+
+ dwarf_end (dwarf);
+ close (fd);
+
+ return res;
+}
--- /dev/null
+#! /bin/sh
+# Copyright (C) 2012, 2015 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
+
+# See run-typeiter.sh
+testfiles testfile-debug-types
+
+testrun ${abs_builddir}/dwarf-die-addr-die testfile-debug-types
+
+# see run-readelf-dwz-multi.sh
+testfiles testfile_multi_main testfile_multi.dwz
+
+testrun ${abs_builddir}/dwarf-die-addr-die testfile_multi_main
+
+# see tests/run-dwflsyms.sh
+testfiles testfilebazdbgppc64.debug
+
+testrun ${abs_builddir}/dwarf-die-addr-die testfilebazdbgppc64.debug
+
+# Self test
+testrun_on_self ${abs_builddir}/dwarf-die-addr-die
+
+exit 0