diff options
| -rw-r--r-- | libdw/ChangeLog | 15 | ||||
| -rw-r--r-- | libdw/Makefile.am | 3 | ||||
| -rw-r--r-- | libdw/dwarf_end.c | 5 | ||||
| -rw-r--r-- | libdw/dwarf_get_units.c | 23 | ||||
| -rw-r--r-- | libdw/libdwP.h | 14 | ||||
| -rw-r--r-- | libdw/libdw_find_split_unit.c | 118 | ||||
| -rw-r--r-- | libdw/libdw_findcu.c | 1 | ||||
| -rw-r--r-- | tests/ChangeLog | 20 | ||||
| -rw-r--r-- | tests/Makefile.am | 10 | ||||
| -rw-r--r-- | tests/get-units-split.c | 101 | ||||
| -rwxr-xr-x | tests/run-get-units-split.sh | 65 | ||||
| -rw-r--r-- | tests/testfile-dwarf-45.source | 8 | ||||
| -rw-r--r-- | tests/testfile-hello4.dwo.bz2 | bin | 0 -> 1453 bytes | |||
| -rw-r--r-- | tests/testfile-hello5.dwo.bz2 | bin | 0 -> 1520 bytes | |||
| -rwxr-xr-x | tests/testfile-splitdwarf-4.bz2 | bin | 0 -> 3591 bytes | |||
| -rwxr-xr-x | tests/testfile-splitdwarf-5.bz2 | bin | 0 -> 3611 bytes | |||
| -rw-r--r-- | tests/testfile-world4.dwo.bz2 | bin | 0 -> 1444 bytes | |||
| -rw-r--r-- | tests/testfile-world5.dwo.bz2 | bin | 0 -> 1498 bytes |
18 files changed, 374 insertions, 9 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 385f52c2..a87a7092 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,5 +1,20 @@ 2018-05-15 Mark Wielaard <[email protected]> + * Makefile.am (libdw_a_SOURCES): Add libdw_find_split_unit.c. + * dwarf_end.c (cu_free): Free split Dwarf. + * dwarf_get_units.c (dwarf_get_units): Handle DW_UT_skeleton by + calling __libdw_find_split_unit. + * libdwP.h (struct Dwarf_CU): Add split Dwarf_CU field. + (__libdw_find_split_unit): New function prototype. + (str_offsets_base_off): Use cu Dwarf if dbg is NULL. + (filepath): Rename to ... + (__libdw_filepath): This. Which is the actual function name in + dwarf_getalt.c. + (libdw_find_split_unit.c): New file. + * libdw_findcu.c (__libdw_intern_next_unit): Initialize split to -1. + +2018-05-15 Mark Wielaard <[email protected]> + * libdwP.h (__libdw_first_die_from_cu_start): Adjust commented out asserts. * libdw_findcu.c (__libdw_intern_next_unit): For version 4 DWARF if diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 8848f141..ba9919c4 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -90,7 +90,8 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.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_die_addr_die.c dwarf_get_units.c + dwarf_die_addr_die.c dwarf_get_units.c \ + libdw_find_split_unit.c if MAINTAINER_MODE BUILT_SOURCES = $(srcdir)/known-dwarf.h diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c index f6915abf..43223de0 100644 --- a/libdw/dwarf_end.c +++ b/libdw/dwarf_end.c @@ -55,6 +55,11 @@ cu_free (void *arg) Dwarf_Abbrev_Hash_free (&p->abbrev_hash); tdestroy (p->locs, noop_free); + + /* Free split dwarf one way (from skeleton to split). */ + if (p->unit_type == DW_UT_skeleton + && p->split != NULL && p->split != (void *)-1) + INTUSE(dwarf_end) (p->split->dbg); } diff --git a/libdw/dwarf_get_units.c b/libdw/dwarf_get_units.c index 19ff5de1..aece17ef 100644 --- a/libdw/dwarf_get_units.c +++ b/libdw/dwarf_get_units.c @@ -100,10 +100,25 @@ dwarf_get_units (Dwarf *dwarf, Dwarf_CU *cu, Dwarf_CU **next_cu, if (subdie != NULL) { - if (next->version >= 2 && next->version <= 5 - && (next->unit_type == DW_UT_type - || next->unit_type == DW_UT_split_type)) - *subdie = SUBDIE(next); + if (next->version >= 2 && next->version <= 5) + { + /* For types, return the actual type DIE. For skeletons, + find the associated split compile unit and return its + DIE. */ + if (next->unit_type == DW_UT_type + || next->unit_type == DW_UT_split_type) + *subdie = SUBDIE(next); + else if (next->unit_type == DW_UT_skeleton) + { + Dwarf_CU *split_cu = __libdw_find_split_unit (next); + if (split_cu != NULL) + *subdie = CUDIE(split_cu); + else + memset (subdie, '\0', sizeof (Dwarf_Die)); + } + else + memset (subdie, '\0', sizeof (Dwarf_Die)); + } else memset (subdie, '\0', sizeof (Dwarf_Die)); } diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 25a5ad31..60572276 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -314,6 +314,12 @@ struct Dwarf_CU size_t subdie_offset; uint64_t unit_id8; + /* If this is a skeleton unit this points to the split compile unit. + Or the other way around if this is a split compile unit. Set to -1 + if not yet searched. Always use __libdw_find_split_unit to access + this field. */ + struct Dwarf_CU *split; + /* Hash table for the abbreviations. */ Dwarf_Abbrev_Hash abbrev_hash; /* Offset of the first abbreviation. */ @@ -589,6 +595,9 @@ extern struct Dwarf_CU *__libdw_findcu (Dwarf *dbg, Dwarf_Off offset, bool tu) extern struct Dwarf_CU *__libdw_findcu_addr (Dwarf *dbg, void *addr) __nonnull_attribute__ (1) internal_function; +/* Find the split (or skeleton) unit. */ +extern struct Dwarf_CU *__libdw_find_split_unit (Dwarf_CU *cu); + /* Get abbreviation with given code. */ extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu, unsigned int code) @@ -972,6 +981,9 @@ str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu) cu->str_off_base = 0; return cu->str_off_base; } + + if (dbg == NULL) + dbg = cu->dbg; } else return cu->str_off_base; @@ -1051,7 +1063,7 @@ static inline Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu) constructed NULL is returned. The caller is responsible for freeing the result if not NULL. */ -char * filepath (int fd, const char *dir, const char *file) +char * __libdw_filepath (int fd, const char *dir, const char *file) internal_function; diff --git a/libdw/libdw_find_split_unit.c b/libdw/libdw_find_split_unit.c new file mode 100644 index 00000000..0f74b39a --- /dev/null +++ b/libdw/libdw_find_split_unit.c @@ -0,0 +1,118 @@ +/* Find the split (or skeleton) unit for a given unit. + 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 "libdwP.h" +#include "libelfP.h" + +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + + +Dwarf_CU * +internal_function +__libdw_find_split_unit (Dwarf_CU *cu) +{ + /* Only try once. */ + if (cu->split != (Dwarf_CU *) -1) + return cu->split; + + /* We need a skeleton unit with a comp_dir and [GNU_]dwo_name attributes. + The split unit will be the first in the dwo file and should have the + same id as the skeleton. */ + if (cu->unit_type == DW_UT_skeleton) + { + Dwarf_Die cudie = CUDIE (cu); + Dwarf_Attribute compdir, dwo_name; + /* It is fine if compdir doesn't exists, but then dwo_name needs + to be an absolute path. Also try relative path first. */ + dwarf_attr (&cudie, DW_AT_comp_dir, &compdir); + if (dwarf_attr (&cudie, DW_AT_dwo_name, &dwo_name) != NULL + || dwarf_attr (&cudie, DW_AT_GNU_dwo_name, &dwo_name) != NULL) + { + const char *comp_dir = dwarf_formstring (&compdir); + const char *dwo_file = dwarf_formstring (&dwo_name); + int fd = cu->dbg->elf->fildes; + char *dwo_path = __libdw_filepath (fd, NULL, dwo_file); + if (dwo_path == NULL && comp_dir != NULL) + dwo_path = __libdw_filepath (fd, comp_dir, dwo_file); + if (dwo_path != NULL) + { + int split_fd = open (dwo_path, O_RDONLY); + if (split_fd != -1) + { + Dwarf *split_dwarf = dwarf_begin (split_fd, DWARF_C_READ); + if (split_dwarf != NULL) + { + Dwarf_CU *split = NULL; + while (dwarf_get_units (split_dwarf, split, &split, + NULL, NULL, NULL, NULL) == 0) + { + if (split->unit_type == DW_UT_split_compile + && cu->unit_id8 == split->unit_id8) + { + /* Link skeleton and split compule units. */ + cu->split = split; + split->split = cu; + + /* We have everything we need from this + ELF file. And we are going to close + the fd to not run out of file + descriptors. */ + elf_cntl (split_dwarf->elf, ELF_C_FDDONE); + break; + } + + if (cu->split == (Dwarf_CU *) -1) + dwarf_end (split_dwarf); + } + /* Always close, because we don't want to run + out of file descriptors. See also the + elf_fcntl ELF_C_FDDONE call above. */ + } + close (split_fd); + } + free (dwo_path); + } + } + } + + /* If we found nothing, make sure we don't try again. */ + if (cu->split == (Dwarf_CU *) -1) + cu->split = NULL; + + return cu->split; +} diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c index 0a65c973..d6975f34 100644 --- a/libdw/libdw_findcu.c +++ b/libdw/libdw_findcu.c @@ -116,6 +116,7 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types) newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset; newp->lines = NULL; newp->locs = NULL; + newp->split = (Dwarf_CU *) -1; newp->base_address = (Dwarf_Addr) -1; newp->addr_base = (Dwarf_Off) -1; newp->str_off_base = (Dwarf_Off) -1; diff --git a/tests/ChangeLog b/tests/ChangeLog index 16011c80..b865ad54 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,23 @@ +2018-05-16 Mark Wielaard <[email protected]> + + * Makefile.am (check_PROGRAMS): Add get-units-split. + (TESTS): Add run-get-units-split.sh. + (EXTRA_DIST): Add run-get-units-split.sh, testfile-hello4.dwo.bz2, + testfile-hello5.dwo.bz2, testfile-splitdwarf-4.bz2, + testfile-splitdwarf-5.bz2, testfile-world5.dwo.bz2 and + testfile-world4.dwo.bz2. + (get_units_split_LDADD): New variable. + * get-units-split.c: New test. + * run-get-units-split.sh: New test runner. + * testfile-dwarf-45.source: Extend with build instructions for new + test files. + * testfile-hello4.dwo.bz2: New test file. + * testfile-hello5.dwo.bz2: Likewise. + * testfile-splitdwarf-4.bz2: Likewise. + * testfile-splitdwarf-5.bz2: Likewise. + * testfile-world5.dwo.bz2 and: Likewise. + * testfile-world4.dwo.bz2: Likewise. + 2018-05-09 Mark Wielaard <[email protected]> * run-readelf-zdebug.sh: Adjust test output for new header layout. diff --git a/tests/Makefile.am b/tests/Makefile.am index ac16a5ec..07165d84 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -56,7 +56,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ elfshphehdr elfstrmerge dwelfgnucompressed elfgetchdr \ elfgetzdata elfputzdata zstrptr emptyfile vendorelf \ fillfile dwarf_default_lower_bound dwarf-die-addr-die \ - get-units-invalid + get-units-invalid get-units-split asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \ asm-tst6 asm-tst7 asm-tst8 asm-tst9 @@ -140,7 +140,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ run-readelf-zdebug.sh run-readelf-zdebug-rel.sh \ emptyfile vendorelf fillfile dwarf_default_lower_bound \ run-dwarf-die-addr-die.sh \ - run-get-units-invalid.sh + run-get-units-invalid.sh run-get-units-split.sh if !BIARCH export ELFUTILS_DISABLE_BIARCH = 1 @@ -361,7 +361,10 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ testfile-bpf-dis1.expect.bz2 testfile-bpf-dis1.o.bz2 \ testfile-m68k-core.bz2 testfile-m68k.bz2 testfile-m68k-s.bz2 \ run-dwarf-die-addr-die.sh \ - run-get-units-invalid.sh + run-get-units-invalid.sh run-get-units-split.sh \ + testfile-hello4.dwo.bz2 testfile-hello5.dwo.bz2 \ + testfile-splitdwarf-4.bz2 testfile-splitdwarf-5.bz2 \ + testfile-world5.dwo.bz2 testfile-world4.dwo.bz2 if USE_VALGRIND valgrind_cmd='valgrind -q --leak-check=full --error-exitcode=1' @@ -521,6 +524,7 @@ fillfile_LDADD = $(libelf) dwarf_default_lower_bound_LDADD = $(libdw) dwarf_die_addr_die_LDADD = $(libdw) get_units_invalid_LDADD = $(libdw) +get_units_split_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/get-units-split.c b/tests/get-units-split.c new file mode 100644 index 00000000..410483a0 --- /dev/null +++ b/tests/get-units-split.c @@ -0,0 +1,101 @@ +/* Test dwarf_get_units finds split DWO CUs. + 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/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include ELFUTILS_HEADER(dw) +#include <stdio.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + + +int +main (int argc, char *argv[]) +{ + for (int i = 1; i < argc; i++) + { + printf ("file: %s\n", argv[i]); + int fd = open (argv[i], O_RDONLY); + Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg == NULL) + { + printf ("%s not usable: %s\n", argv[i], dwarf_errmsg (-1)); + return -1; + } + + Dwarf_CU *cu = NULL; + Dwarf_Die cudie, subdie; + uint8_t unit_type; + int count = 0; + while (dwarf_get_units (dbg, cu, &cu, NULL, + &unit_type, &cudie, &subdie) == 0) + { + count++; + printf ("Got cudie unit_type: %" PRIx8 "\n", unit_type); + + if (unit_type == DW_UT_skeleton) + { + Dwarf_CU *skel_cu = cudie.cu; + Dwarf_CU *split_cu = subdie.cu; + Dwarf_Die skel_die, split_die; + uint64_t skel_id, split_id; + + printf ("Found a skeleton unit, with split die: %s\n", + dwarf_diename (&subdie)); + + if (dwarf_cu_die (skel_cu, &skel_die, NULL, NULL, NULL, NULL, + &skel_id, NULL) == NULL) + { + printf ("bad skel_cu: %s\n", dwarf_errmsg (-1)); + return -1; + } + + if (dwarf_cu_die (split_cu, &split_die, NULL, NULL, NULL, NULL, + &split_id, NULL) == NULL) + { + printf ("bad skel_cu: %s\n", dwarf_errmsg (-1)); + return -1; + } + + if (skel_id != split_id) + { + printf ("Skeleton id and Split id not equal!\n"); + return -1; + } + } + } + + if (count == 0) + { + printf ("No units found\n"); + return -1; + } + + dwarf_end (dbg); + close (fd); + + printf ("\n"); + } + + return 0; +} diff --git a/tests/run-get-units-split.sh b/tests/run-get-units-split.sh new file mode 100755 index 00000000..7b13694b --- /dev/null +++ b/tests/run-get-units-split.sh @@ -0,0 +1,65 @@ +#! /bin/sh +# 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/>. + +. $srcdir/test-subr.sh + +# See run-typeiter.sh +testfiles testfile-debug-types + +testrun ${abs_builddir}/get-units-split testfile-debug-types + +# see run-readelf-dwz-multi.sh +testfiles testfile_multi_main testfile_multi.dwz + +testrun ${abs_builddir}/get-units-split testfile_multi_main + +# see tests/run-dwflsyms.sh +testfiles testfilebazdbgppc64.debug + +testrun ${abs_builddir}/get-units-split testfilebazdbgppc64.debug + +# see tests/testfile-dwarf-45.source +testfiles testfile-dwarf-4 testfile-dwarf-5 +testfiles testfile-splitdwarf-4 testfile-hello4.dwo testfile-world4.dwo +testfiles testfile-splitdwarf-5 testfile-hello5.dwo testfile-world5.dwo + +testrun ${abs_builddir}/get-units-split testfile-dwarf-4 +testrun ${abs_builddir}/get-units-split testfile-dwarf-5 + +# These two files are the only ones that actually have skeleton units. +testrun_compare ${abs_builddir}/get-units-split testfile-splitdwarf-4 << \EOF +file: testfile-splitdwarf-4 +Got cudie unit_type: 4 +Found a skeleton unit, with split die: hello.c +Got cudie unit_type: 4 +Found a skeleton unit, with split die: world.c + +EOF + +testrun_compare ${abs_builddir}/get-units-split testfile-splitdwarf-5 << \EOF +file: testfile-splitdwarf-5 +Got cudie unit_type: 4 +Found a skeleton unit, with split die: hello.c +Got cudie unit_type: 4 +Found a skeleton unit, with split die: world.c + +EOF + +# Self test +testrun_on_self ${abs_builddir}/get-units-split + +exit 0 diff --git a/tests/testfile-dwarf-45.source b/tests/testfile-dwarf-45.source index c9c44463..584c8f7e 100644 --- a/tests/testfile-dwarf-45.source +++ b/tests/testfile-dwarf-45.source @@ -79,3 +79,11 @@ $ gcc -o testfile-dwarf-4 hello.o world.o $ gcc -gdwarf-5 -gno-as-loc-support -gno-variable-location-views -O2 -c world.c $ gcc -gdwarf-5 -gno-as-loc-support -gno-variable-location-views -O2 -c hello.c $ gcc -o testfile-dwarf-5 hello.o world.o + +$ gcc -gdwarf-4 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2 -o testfile-world4.o -c world.c +$ gcc -gdwarf-4 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2 -o testfile-hello4.o -c hello.c +$ gcc -o testfile-splitdwarf-4 testfile-hello4.o testfile-world4.o + +$ gcc -gdwarf-5 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2 -o testfile-world5.o -c world.c +$ gcc -gdwarf-5 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2 -o testfile-hello5.o -c hello.c +$ gcc -o testfile-splitdwarf-5 testfile-hello5.o testfile-world5.o diff --git a/tests/testfile-hello4.dwo.bz2 b/tests/testfile-hello4.dwo.bz2 Binary files differnew file mode 100644 index 00000000..fe02d65c --- /dev/null +++ b/tests/testfile-hello4.dwo.bz2 diff --git a/tests/testfile-hello5.dwo.bz2 b/tests/testfile-hello5.dwo.bz2 Binary files differnew file mode 100644 index 00000000..e911375e --- /dev/null +++ b/tests/testfile-hello5.dwo.bz2 diff --git a/tests/testfile-splitdwarf-4.bz2 b/tests/testfile-splitdwarf-4.bz2 Binary files differnew file mode 100755 index 00000000..a1871e61 --- /dev/null +++ b/tests/testfile-splitdwarf-4.bz2 diff --git a/tests/testfile-splitdwarf-5.bz2 b/tests/testfile-splitdwarf-5.bz2 Binary files differnew file mode 100755 index 00000000..27ff3bd6 --- /dev/null +++ b/tests/testfile-splitdwarf-5.bz2 diff --git a/tests/testfile-world4.dwo.bz2 b/tests/testfile-world4.dwo.bz2 Binary files differnew file mode 100644 index 00000000..297fe5fa --- /dev/null +++ b/tests/testfile-world4.dwo.bz2 diff --git a/tests/testfile-world5.dwo.bz2 b/tests/testfile-world5.dwo.bz2 Binary files differnew file mode 100644 index 00000000..d5c852c3 --- /dev/null +++ b/tests/testfile-world5.dwo.bz2 |
