diff options
| -rw-r--r-- | libdw/ChangeLog | 9 | ||||
| -rw-r--r-- | libdw/Makefile.am | 3 | ||||
| -rw-r--r-- | libdw/dwarf_die_addr_die.c | 58 | ||||
| -rw-r--r-- | libdw/libdw.h | 12 | ||||
| -rw-r--r-- | libdw/libdw.map | 5 | ||||
| -rw-r--r-- | libdw/libdwP.h | 4 | ||||
| -rw-r--r-- | libdw/libdw_findcu.c | 35 | ||||
| -rw-r--r-- | tests/ChangeLog | 9 | ||||
| -rw-r--r-- | tests/Makefile.am | 9 | ||||
| -rw-r--r-- | tests/dwarf-die-addr-die.c | 172 | ||||
| -rwxr-xr-x | tests/run-dwarf-die-addr-die.sh | 38 |
11 files changed, 349 insertions, 5 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 7a6d3110..a65d691e 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,12 @@ +2018-01-25 Mark Wielaard <[email protected]> + + * 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 <[email protected]> * cfi.c (execute_cfi): Use FALLTHROUGH macro instead of comment. diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 8545b5b4..b1da4406 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -89,7 +89,8 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \ 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 diff --git a/libdw/dwarf_die_addr_die.c b/libdw/dwarf_die_addr_die.c new file mode 100644 index 00000000..02d63b7f --- /dev/null +++ b/libdw/dwarf_die_addr_die.c @@ -0,0 +1,58 @@ +/* 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; +} diff --git a/libdw/libdw.h b/libdw/libdw.h index 1dcc8153..d85d2859 100644 --- a/libdw/libdw.h +++ b/libdw/libdw.h @@ -350,6 +350,18 @@ extern Dwarf_Die *dwarf_diecu (Dwarf_Die *die, Dwarf_Die *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 diff --git a/libdw/libdw.map b/libdw/libdw.map index 14307056..cdc63ce2 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -344,3 +344,8 @@ ELFUTILS_0.170 { dwarf_default_lower_bound; dwarf_line_file; } ELFUTILS_0.167; + +ELFUTILS_0.171 { + global: + dwarf_die_addr_die; +} ELFUTILS_0.170; diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 0681aa15..a38dcfb3 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -449,6 +449,10 @@ extern struct Dwarf_CU *__libdw_intern_next_unit (Dwarf *dbg, bool debug_types) 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) diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c index 4e025e26..3ec1ce59 100644 --- a/libdw/libdw_findcu.c +++ b/libdw/libdw_findcu.c @@ -1,5 +1,5 @@ /* 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 <[email protected]>, 2003. @@ -167,3 +167,36 @@ __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool debug_types) } /* 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; +} diff --git a/tests/ChangeLog b/tests/ChangeLog index 5ee8626e..eb4576ca 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,12 @@ +2018-01-25 Mark Wielaard <[email protected]> + + * 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 <[email protected]> * elfstrmerge.c (main): Use FALLTHROUGH macro instead of comment. diff --git a/tests/Makefile.am b/tests/Makefile.am index 1fce4474..fe6c8ec5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -55,7 +55,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ 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 @@ -137,7 +137,8 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ 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 @@ -352,7 +353,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ 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' @@ -510,6 +512,7 @@ emptyfile_LDADD = $(libelf) 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. diff --git a/tests/dwarf-die-addr-die.c b/tests/dwarf-die-addr-die.c new file mode 100644 index 00000000..b4f6dbcd --- /dev/null +++ b/tests/dwarf-die-addr-die.c @@ -0,0 +1,172 @@ +/* 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; +} diff --git a/tests/run-dwarf-die-addr-die.sh b/tests/run-dwarf-die-addr-die.sh new file mode 100755 index 00000000..16fe7b04 --- /dev/null +++ b/tests/run-dwarf-die-addr-die.sh @@ -0,0 +1,38 @@ +#! /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 |
