diff options
| -rw-r--r-- | libdw/ChangeLog | 7 | ||||
| -rw-r--r-- | libdw/Makefile.am | 2 | ||||
| -rw-r--r-- | libdw/dwarf_cu_info.c | 103 | ||||
| -rw-r--r-- | libdw/libdw.h | 14 | ||||
| -rw-r--r-- | libdw/libdw.map | 1 | ||||
| -rw-r--r-- | tests/ChangeLog | 9 | ||||
| -rw-r--r-- | tests/Makefile.am | 8 | ||||
| -rwxr-xr-x | tests/run-unit-info.sh | 80 | ||||
| -rw-r--r-- | tests/unit-info.c | 323 |
9 files changed, 542 insertions, 5 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index c302628e..08c8f7be 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,10 @@ +2018-05-20 Mark Wielaard <[email protected]> + + * dwarf_cu_info.c: New file. + * Makefile.am (libdw_a_SOURCES): Add dwarf_cu_info.c. + * libdw.h (dwarf_cu_info): New function declaration. + * libdw.map (ELFUTILS_0.171): Add dwarf_cu_info. + 2018-05-24 Mark Wielaard <[email protected]> * dwarf_ranges.c (dwarf_ranges): Check for NULL cu. diff --git a/libdw/Makefile.am b/libdw/Makefile.am index ba9919c4..41df4f3b 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -91,7 +91,7 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.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 \ - libdw_find_split_unit.c + libdw_find_split_unit.c dwarf_cu_info.c if MAINTAINER_MODE BUILT_SOURCES = $(srcdir)/known-dwarf.h diff --git a/libdw/dwarf_cu_info.c b/libdw/dwarf_cu_info.c new file mode 100644 index 00000000..30aee6c7 --- /dev/null +++ b/libdw/dwarf_cu_info.c @@ -0,0 +1,103 @@ +/* Provides information and DIEs associated with the Dwarf_CU 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 <string.h> +#include "libdwP.h" + + +int +dwarf_cu_info (Dwarf_CU *cu, + Dwarf_Half *version, uint8_t *unit_type, + Dwarf_Die *cudie, Dwarf_Die *subdie, + uint64_t *unit_id, + uint8_t *address_size, uint8_t *offset_size) +{ + if (cu == NULL) + return -1; + + if (version != NULL) + *version = cu->version; + + if (unit_type != NULL) + *unit_type = cu->unit_type; + + if (cudie != NULL) + { + if (cu->version >= 2 && cu->version <= 5 + && cu->unit_type >= DW_UT_compile + && cu->unit_type <= DW_UT_split_type) + *cudie = CUDIE (cu); + else + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + } + + if (subdie != NULL) + { + if (cu->version >= 2 && cu->version <= 5) + { + /* For types, return the actual type DIE. For skeletons, + find the associated split compile unit and return its + DIE. */ + if (cu->unit_type == DW_UT_type + || cu->unit_type == DW_UT_split_type) + *subdie = SUBDIE(cu); + else if (cu->unit_type == DW_UT_skeleton) + { + Dwarf_CU *split_cu = __libdw_find_split_unit (cu); + if (split_cu != NULL) + *subdie = CUDIE(split_cu); + else + memset (subdie, '\0', sizeof (Dwarf_Die)); + } + else + memset (subdie, '\0', sizeof (Dwarf_Die)); + } + else + goto invalid; + } + + if (unit_id != NULL) + *unit_id = cu->unit_id8; + + if (address_size != NULL) + *address_size = cu->address_size; + + if (offset_size != NULL) + *offset_size = cu->offset_size; + + return 0; +} diff --git a/libdw/libdw.h b/libdw/libdw.h index 0ca88782..a871eb29 100644 --- a/libdw/libdw.h +++ b/libdw/libdw.h @@ -297,13 +297,25 @@ extern int dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off, DW_UT_type for DW_TAG_type_unit or DW_UT_partial for DW_TAG_partial_unit), otherwise it is set to zero. If unavailable (the version or unit type is unknown) the CU DIE is cleared. - Likewise ff the sub DIE isn't isn't available (the unit type is not + Likewise if the sub DIE isn't isn't available (the unit type is not DW_UT_type or DW_UT_split_type) the sub DIE tag is cleared. */ extern int dwarf_get_units (Dwarf *dwarf, Dwarf_CU *cu, Dwarf_CU **next_cu, Dwarf_Half *version, uint8_t *unit_type, Dwarf_Die *cudie, Dwarf_Die *subdie) __nonnull_attribute__ (3); +/* Provides information and DIEs associated with the given Dwarf_CU + unit. Returns -1 on error, zero on success. Arguments not needed + may be NULL. If they are NULL and aren't known yet, they won't be + looked up. If the subdie doesn't exist for this unit_type it will + be cleared. If there is no unit_id for this unit type it will be + set to zero. */ +extern int dwarf_cu_info (Dwarf_CU *cu, + Dwarf_Half *version, uint8_t *unit_type, + Dwarf_Die *cudie, Dwarf_Die *subdie, + uint64_t *unit_id, + uint8_t *address_size, uint8_t *offset_size); + /* Decode one DWARF CFI entry (CIE or FDE) from the raw section data. The E_IDENT from the originating ELF file indicates the address size and byte order used in the CFI section contained in DATA; diff --git a/libdw/libdw.map b/libdw/libdw.map index 4577d058..17c99f61 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -350,4 +350,5 @@ ELFUTILS_0.171 { dwarf_die_addr_die; dwarf_get_units; dwarf_getabbrevattr_data; + dwarf_cu_info; } ELFUTILS_0.170; diff --git a/tests/ChangeLog b/tests/ChangeLog index 86bcf9db..a93b0e98 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,12 @@ +2018-05-20 Mark Wielaard <[email protected]> + + * unit-info.c: New test. + * run-unit-info.sh: New test runner. + * Makefile.am (check_PROGRAMS): Add unit-info. + (TESTS): Add run-unit-info.sh + (EXTRA_INFO): Likewise. + (unit_info_LDADD): New variable. + 2018-05-24 Mark Wielaard <[email protected]> * get-units-invalid.c (main): Add check for invalid dwarf_ranges. diff --git a/tests/Makefile.am b/tests/Makefile.am index 08d84649..9beae140 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -57,7 +57,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ elfgetzdata elfputzdata zstrptr emptyfile vendorelf \ fillfile dwarf_default_lower_bound dwarf-die-addr-die \ get-units-invalid get-units-split attr-integrate-skel \ - all-dwarf-ranges + all-dwarf-ranges unit-info asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \ asm-tst6 asm-tst7 asm-tst8 asm-tst9 @@ -143,7 +143,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ run-dwarf-die-addr-die.sh \ run-get-units-invalid.sh run-get-units-split.sh \ run-attr-integrate-skel.sh \ - run-all-dwarf-ranges.sh + run-all-dwarf-ranges.sh run-unit-info.sh if !BIARCH export ELFUTILS_DISABLE_BIARCH = 1 @@ -370,7 +370,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ testfile-world5.dwo.bz2 testfile-world4.dwo.bz2 \ run-attr-integrate-skel.sh \ run-all-dwarf-ranges.sh testfilesplitranges4.debug.bz2 \ - testfile-ranges-hello.dwo.bz2 testfile-ranges-world.dwo.bz2 + testfile-ranges-hello.dwo.bz2 testfile-ranges-world.dwo.bz2 \ + run-unit-info.sh if USE_VALGRIND valgrind_cmd='valgrind -q --leak-check=full --error-exitcode=1' @@ -533,6 +534,7 @@ get_units_invalid_LDADD = $(libdw) get_units_split_LDADD = $(libdw) attr_integrate_skel_LDADD = $(libdw) all_dwarf_ranges_LDADD = $(libdw) +unit_info_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/run-unit-info.sh b/tests/run-unit-info.sh new file mode 100755 index 00000000..f4ce427b --- /dev/null +++ b/tests/run-unit-info.sh @@ -0,0 +1,80 @@ +#! /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}/unit-info testfile-debug-types + +# see run-readelf-dwz-multi.sh +testfiles testfile_multi_main testfile_multi.dwz + +testrun ${abs_builddir}/unit-info testfile_multi_main + +# see tests/run-dwflsyms.sh +testfiles testfilebazdbgppc64.debug + +testrun ${abs_builddir}/unit-info testfilebazdbgppc64.debug + +# see tests/testfile-dwarf-45.source +testfiles testfile-dwarf-4 testfile-dwarf-5 +testfiles testfile-splitdwarf-4 testfile-splitdwarf-5 +testfiles testfile-hello4.dwo testfile-hello5.dwo +testfiles testfile-world4.dwo testfile-world5.dwo + +testrun ${abs_builddir}/unit-info testfile-dwarf-4 +testrun ${abs_builddir}/unit-info testfile-dwarf-5 + +# The consistency checks should find most issue, but make sure the +# output is also what we expect in case we break dwarf_get_units and +# dwarf_cu_info at the same time. +testrun_compare ${abs_builddir}/unit-info \ + testfile-splitdwarf-4 testfile-splitdwarf-5 <<\EOF +file: testfile-splitdwarf-4 +Iterate getting all info, compare with dwarf_cu_info. +0 cu dietag: 11, subtag: 11, version 4, unit_type 4 +0 subdietag: 11, subtag: 0, version 4, unit_type 5 +1 cu dietag: 11, subtag: 11, version 4, unit_type 4 +1 subdietag: 11, subtag: 0, version 4, unit_type 5 +rechecking: testfile-splitdwarf-4 +Iterate no info, compare recorded info with dwarf_cu_info. +0 re dietag: 11, subtag: 11, version 4, unit_type 4 +0 subdietag: 11, subtag: 0, version 4, unit_type 5 +1 re dietag: 11, subtag: 11, version 4, unit_type 4 +1 subdietag: 11, subtag: 0, version 4, unit_type 5 + +file: testfile-splitdwarf-5 +Iterate getting all info, compare with dwarf_cu_info. +0 cu dietag: 4a, subtag: 11, version 5, unit_type 4 +0 subdietag: 11, subtag: 0, version 5, unit_type 5 +1 cu dietag: 4a, subtag: 11, version 5, unit_type 4 +1 subdietag: 11, subtag: 0, version 5, unit_type 5 +rechecking: testfile-splitdwarf-5 +Iterate no info, compare recorded info with dwarf_cu_info. +0 re dietag: 4a, subtag: 11, version 5, unit_type 4 +0 subdietag: 11, subtag: 0, version 5, unit_type 5 +1 re dietag: 4a, subtag: 11, version 5, unit_type 4 +1 subdietag: 11, subtag: 0, version 5, unit_type 5 + +EOF + +# Self test +testrun_on_self ${abs_builddir}/unit-info + +exit 0 diff --git a/tests/unit-info.c b/tests/unit-info.c new file mode 100644 index 00000000..4fb9a984 --- /dev/null +++ b/tests/unit-info.c @@ -0,0 +1,323 @@ +/* Test dwarf_cu_info properties. + 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> + +/* Yeah, lazy, 16K CUs should be enough for everybody... */ +#define MAX_UNITS 16384 +struct info +{ + int dietag; + int subtag; + Dwarf_Half version; + uint8_t unit_type; + uint64_t id; + uint8_t addr_size; + uint8_t off_size; +}; +static struct info unit_info[MAX_UNITS]; + +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_Half version; + Dwarf_Die cudie, subdie; + uint8_t unit_type; + size_t u, units; + u = units = 0; + printf ("Iterate getting all info, compare with dwarf_cu_info.\n"); + while (dwarf_get_units (dbg, cu, &cu, &version, + &unit_type, &cudie, &subdie) == 0) + { + int dietag = dwarf_tag (&cudie); + int subtag = dwarf_tag (&subdie); + + unit_info[u].dietag = dietag; + unit_info[u].subtag = subtag; + unit_info[u].version = version; + unit_info[u].unit_type = unit_type; + + printf ("%zu cu dietag: %x, subtag: %x, version %" PRIx32 + ", unit_type %" PRIx8 "\n", + u, dietag, subtag, version, unit_type); + + uint64_t unit_id; + uint8_t addr_size, off_size; + if (dwarf_cu_info (cu, + &version, &unit_type, &cudie, &subdie, + &unit_id, &addr_size, &off_size) != 0) + { + printf ("Invalid dwarf_cu_info: %s\n", dwarf_errmsg (-1)); + return -1; + } + + dietag = dwarf_tag (&cudie); + subtag = dwarf_tag (&subdie); + + if (unit_info[u].dietag != dietag) + { + printf("Unequal dietags\n"); + return -1; + } + + if (unit_info[u].subtag != subtag) + { + printf("Unequal subtags\n"); + return -1; + } + + if (unit_info[u].version != version) + { + printf("Unequal versions\n"); + return -1; + } + + if (unit_info[u].unit_type != unit_type) + { + printf("Unequal unit_types\n"); + return -1; + } + + unit_info[u].id = unit_id; + unit_info[u].addr_size = addr_size; + unit_info[u].off_size = off_size; + + if (unit_type == DW_UT_skeleton) + { + if (dwarf_cu_info (subdie.cu, + &version, &unit_type, &cudie, &subdie, + &unit_id, &addr_size, &off_size) != 0) + { + printf ("Invalid subdie dwarf_cu_info: %s\n", + dwarf_errmsg (-1)); + return -1; + } + + dietag = dwarf_tag (&cudie); + subtag = dwarf_tag (&subdie); + + printf ("%zu subdietag: %x, subtag: %x, version %" PRIx32 + ", unit_type %" PRIx8 "\n", + u, dietag, subtag, version, unit_type); + + /* subdie is now cudie. */ + if (unit_info[u].subtag != dietag) + { + printf ("Inconsistent subdie tag\n"); + return -1; + } + + if (unit_info[u].id != unit_id) + { + printf ("Unequal subdie ids\n"); + return -1; + } + + if (unit_info[u].addr_size != addr_size) + { + printf ("Unequal subdie addr_size\n"); + return -1; + } + + if (unit_info[u].off_size != off_size) + { + printf ("Unequal subdie off_size\n"); + return -1; + } + } + + if (u >= MAX_UNITS) + { + printf ("Oops, more than 16K units...\n"); + return -1; + } + u = ++units; + } + + dwarf_end (dbg); + close (fd); + + /* And again... */ + printf ("rechecking: %s\n", argv[i]); + fd = open (argv[i], O_RDONLY); + dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg == NULL) + { + printf ("%s not usable: %s\n", argv[i], dwarf_errmsg (-1)); + return -1; + } + + cu = NULL; + u = 0; + printf ("Iterate no info, compare recorded info with dwarf_cu_info.\n"); + while (dwarf_get_units (dbg, cu, &cu, NULL, NULL, NULL, NULL) == 0) + { + if (u > units) + { + printf ("Got too many units???\n"); + return -1; + } + + uint64_t unit_id; + uint8_t addr_size, off_size; + if (dwarf_cu_info (cu, + &version, &unit_type, &cudie, &subdie, + &unit_id, &addr_size, &off_size) != 0) + { + printf ("Invalid dwarf_cu_info: %s\n", dwarf_errmsg (-1)); + return -1; + } + + int dietag = dwarf_tag (&cudie); + int subtag = dwarf_tag (&subdie); + + printf ("%zu re dietag: %x, subtag: %x, version %" PRIx32 + ", unit_type %" PRIx8 "\n", + u, dietag, subtag, version, unit_type); + + if (unit_info[u].dietag != dietag) + { + printf("Unequal dietags %x != %x\n", unit_info[u].dietag, dietag); + return -1; + } + + if (unit_info[u].subtag != subtag) + { + printf("Unequal subtags\n"); + return -1; + } + + if (unit_info[u].version != version) + { + printf("Unequal versions\n"); + return -1; + } + + if (unit_info[u].unit_type != unit_type) + { + printf("Unequal unit_types\n"); + return -1; + } + + if (unit_info[u].id != unit_id) + { + printf ("Unequal subdie ids\n"); + return -1; + } + + if (unit_info[u].addr_size != addr_size) + { + printf ("Unequal subdie addr_size\n"); + return -1; + } + + if (unit_info[u].off_size != off_size) + { + printf ("Unequal subdie off_size\n"); + return -1; + } + + if (unit_type == DW_UT_skeleton) + { + if (dwarf_cu_info (subdie.cu, + &version, &unit_type, &cudie, &subdie, + &unit_id, &addr_size, &off_size) != 0) + { + printf ("Invalid subdie dwarf_cu_info: %s\n", + dwarf_errmsg (-1)); + return -1; + } + + dietag = dwarf_tag (&cudie); + subtag = dwarf_tag (&subdie); + + printf ("%zu subdietag: %x, subtag: %x, version %" PRIx32 + ", unit_type %" PRIx8 "\n", + u, dietag, subtag, version, unit_type); + + /* subdie is now cudie. */ + subtag = dwarf_tag (&cudie); + if (unit_info[u].subtag != subtag) + { + printf ("Inconsistent subdie tag\n"); + return -1; + } + + if (unit_info[u].id != unit_id) + { + printf ("Unequal subdie ids\n"); + return -1; + } + + if (unit_info[u].addr_size != addr_size) + { + printf ("Unequal subdie addr_size\n"); + return -1; + } + + if (unit_info[u].off_size != off_size) + { + printf ("Unequal subdie off_size\n"); + return -1; + } + } + + if (u >= MAX_UNITS) + { + printf ("Oops, more than 16K units...\n"); + return -1; + } + u++; + } + + if (u != units) + { + printf ("Got not enough units???\n"); + return -1; + } + + dwarf_end (dbg); + close (fd); + + printf ("\n"); + } + + return 0; +} |
