From 985112bc7d0f4eabbaa8a33fdcb241832db54642 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Wed, 6 Dec 2023 01:22:16 -0800 Subject: [PATCH] libdw: Parse DWARF package file index sections The .debug_cu_index and .debug_tu_index sections in DWARF package files are basically hash tables mapping a unit's 8 byte signature to an offset and size in each section used by that unit [1]. Add support for parsing and doing lookups in the index sections. We look up a unit in the index when we intern it and cache its hash table row in Dwarf_CU. Then, a new function, dwarf_cu_dwp_section_info, can be used to look up the section offsets and sizes for a unit. This will mostly be used internally in libdw, but it will also be needed in static inline functions shared with eu-readelf. Additionally, making it public it makes dwp support much easier for external tools that do their own low-level parsing of DWARF information, like drgn [2]. 1: https://gcc.gnu.org/wiki/DebugFissionDWP#Format_of_the_CU_and_TU_Index_Sections 2: https://github.com/osandov/drgn * libdw/dwarf.h: Add DW_SECT_TYPES. * libdw/libdwP.h (Dwarf): Add cu_index and tu_index. (Dwarf_CU): Add dwp_row. (Dwarf_Package_Index): New type. (__libdw_dwp_find_unit): New declaration. (dwarf_cu_dwp_section_info): New INTDECL. Add DWARF_E_UNKNOWN_SECTION. * libdw/Makefile.am (libdw_a_SOURCES): Add dwarf_cu_dwp_section_info.c. * libdw/dwarf_end.c (dwarf_end): Free dwarf->cu_index and dwarf->tu_index. * libdw/dwarf_error.c (errmsgs): Add DWARF_E_UNKNOWN_SECTION. * libdw/libdw.h (dwarf_cu_dwp_section_info): New declaration. * libdw/libdw.map (ELFUTILS_0.190): Add dwarf_cu_dwp_section_info. * libdw/libdw_findcu.c (__libdw_intern_next_unit): Call __libdw_dwp_find_unit, and use it to adjust abbrev_offset and assign newp->dwp_row. * libdw/dwarf_cu_dwp_section_info.c: New file. * tests/Makefile.am (check_PROGRAMS): Add cu-dwp-section-info. (TESTS): Add run-cu-dwp-section-info.sh (EXTRA_DIST): Add run-cu-dwp-section-info.sh and new test files. (cu_dwp_section_info_LDADD): New variable. * tests/cu-dwp-section-info.c: New test. * tests/run-cu-dwp-section-info.sh: New test. * tests/testfile-dwp-4-strict.bz2: New test file. * tests/testfile-dwp-4-strict.dwp.bz2: New test file. * tests/testfile-dwp-4.bz2: New test file. * tests/testfile-dwp-4.dwp.bz2: New test file. * tests/testfile-dwp-5.bz2: New test file. * tests/testfile-dwp-5.dwp.bz2: New test file. * tests/testfile-dwp.source: New file. Signed-off-by: Omar Sandoval --- libdw/Makefile.am | 2 +- libdw/dwarf.h | 2 +- libdw/dwarf_cu_dwp_section_info.c | 371 ++++++++++++++++++++++++++++ libdw/dwarf_end.c | 3 + libdw/dwarf_error.c | 1 + libdw/libdw.h | 23 ++ libdw/libdw.map | 5 + libdw/libdwP.h | 33 +++ libdw/libdw_findcu.c | 8 + tests/.gitignore | 1 + tests/Makefile.am | 10 +- tests/cu-dwp-section-info.c | 73 ++++++ tests/run-cu-dwp-section-info.sh | 168 +++++++++++++ tests/testfile-dwp-4-strict.bz2 | Bin 0 -> 4169 bytes tests/testfile-dwp-4-strict.dwp.bz2 | Bin 0 -> 6871 bytes tests/testfile-dwp-4.bz2 | Bin 0 -> 4194 bytes tests/testfile-dwp-4.dwp.bz2 | Bin 0 -> 10098 bytes tests/testfile-dwp-5.bz2 | Bin 0 -> 4223 bytes tests/testfile-dwp-5.dwp.bz2 | Bin 0 -> 10313 bytes tests/testfile-dwp.source | 102 ++++++++ 20 files changed, 798 insertions(+), 4 deletions(-) create mode 100644 libdw/dwarf_cu_dwp_section_info.c create mode 100644 tests/cu-dwp-section-info.c create mode 100755 tests/run-cu-dwp-section-info.sh create mode 100755 tests/testfile-dwp-4-strict.bz2 create mode 100644 tests/testfile-dwp-4-strict.dwp.bz2 create mode 100755 tests/testfile-dwp-4.bz2 create mode 100644 tests/testfile-dwp-4.dwp.bz2 create mode 100755 tests/testfile-dwp-5.bz2 create mode 100644 tests/testfile-dwp-5.dwp.bz2 create mode 100644 tests/testfile-dwp.source diff --git a/libdw/Makefile.am b/libdw/Makefile.am index e548f38c9..5363c02a8 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -93,7 +93,7 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.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 dwarf_cu_info.c \ - dwarf_next_lines.c + dwarf_next_lines.c dwarf_cu_dwp_section_info.c if MAINTAINER_MODE BUILT_SOURCES = $(srcdir)/known-dwarf.h diff --git a/libdw/dwarf.h b/libdw/dwarf.h index b2e49db2c..4be32de5a 100644 --- a/libdw/dwarf.h +++ b/libdw/dwarf.h @@ -942,7 +942,7 @@ enum enum { DW_SECT_INFO = 1, - /* Reserved = 2, */ + DW_SECT_TYPES = 2, /* Only DWARF4 GNU DebugFission. Reserved in DWARF5. */ DW_SECT_ABBREV = 3, DW_SECT_LINE = 4, DW_SECT_LOCLISTS = 5, diff --git a/libdw/dwarf_cu_dwp_section_info.c b/libdw/dwarf_cu_dwp_section_info.c new file mode 100644 index 000000000..4a4eac8cb --- /dev/null +++ b/libdw/dwarf_cu_dwp_section_info.c @@ -0,0 +1,371 @@ +/* Read DWARF package file index sections. + Copyright (c) 2023 Meta Platforms, Inc. and affiliates. + 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 . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + +static Dwarf_Package_Index * +__libdw_read_package_index (Dwarf *dbg, bool tu) +{ + Elf_Data *data; + if (tu) + data = dbg->sectiondata[IDX_debug_tu_index]; + else + data = dbg->sectiondata[IDX_debug_cu_index]; + + /* We need at least 16 bytes for the header. */ + if (data == NULL || data->d_size < 16) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + const unsigned char *datap = data->d_buf; + const unsigned char *endp = datap + data->d_size; + uint16_t version; + /* In GNU DebugFission for DWARF 4, the version is 2 as a uword. In the + standardized DWARF 5 format, it is a uhalf followed by a padding uhalf. + Check for both. */ + if (read_4ubyte_unaligned (dbg, datap) == 2) + version = 2; + else + { + version = read_2ubyte_unaligned (dbg, datap); + if (version != 5) + { + __libdw_seterrno (DWARF_E_VERSION); + return NULL; + } + } + datap += 4; + uint32_t section_count = read_4ubyte_unaligned_inc (dbg, datap); + uint32_t unit_count = read_4ubyte_unaligned_inc (dbg, datap); + uint32_t slot_count = read_4ubyte_unaligned_inc (dbg, datap); + + /* The specification has a stricter requirement that + slot_count > 3 * unit_count / 2, but this is enough for us. */ + if (slot_count < unit_count) + goto invalid; + + /* After the header, the section must contain: + + 8 byte signature per hash table slot + + 4 byte index per hash table slot + + Section offset table with 1 header row, 1 row per unit, 1 column per + section, 4 bytes per field + + Section size table with 1 row per unit, 1 column per section, 4 bytes + per field + + We have to be careful about overflow when checking this. */ + const unsigned char *hash_table = datap; + if ((size_t) (endp - hash_table) < (uint64_t) slot_count * 12) + goto invalid; + const unsigned char *indices = hash_table + (size_t) slot_count * 8; + const unsigned char *sections = indices + (size_t) slot_count * 4; + if ((size_t) (endp - sections) < (uint64_t) section_count * 4) + goto invalid; + const unsigned char *section_offsets = sections + (size_t) section_count * 4; + if ((uint64_t) unit_count * section_count > UINT64_MAX / 8 + || ((size_t) (endp - section_offsets) + < (uint64_t) unit_count * section_count * 8)) + goto invalid; + const unsigned char *section_sizes + = section_offsets + (uint64_t) unit_count * section_count * 4; + + Dwarf_Package_Index *index = malloc (sizeof (*index)); + if (index == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + index->dbg = dbg; + /* Set absent sections to UINT32_MAX. */ + memset (index->sections, 0xff, sizeof (index->sections)); + for (size_t i = 0; i < section_count; i++) + { + uint32_t section = read_4ubyte_unaligned (dbg, sections + i * 4); + /* 2 is DW_SECT_TYPES in version 2 and reserved in version 5. We ignore + it for version 5. + 5 is DW_SECT_LOC in version 2 and DW_SECT_LOCLISTS in version 5. We + use the same index for both. + 7 is DW_SECT_MACINFO in version 2 and DW_SECT_MACRO in version 5. We + use the same index for both. + 8 is DW_SECT_MACRO in version 2 and DW_SECT_RNGLISTS in version 5. We + use the same index for version 2's DW_SECT_MACRO as version 2's + DW_SECT_MACINFO/version 5's DW_SECT_MACRO. + We ignore unknown sections. */ + if (section == 0) + continue; + if (version == 2) + { + if (section > 8) + continue; + else if (section == 8) + section = DW_SECT_MACRO; + } + else if (section == 2 + || (section + > sizeof (index->sections) / sizeof (index->sections[0]))) + continue; + index->sections[section - 1] = i; + } + + /* DW_SECT_INFO (or DW_SECT_TYPES for DWARF 4 type units) and DW_SECT_ABBREV + are required. */ + if (((!tu || dbg->sectiondata[IDX_debug_types] == NULL) + && index->sections[DW_SECT_INFO - 1] == UINT32_MAX) + || (tu && dbg->sectiondata[IDX_debug_types] != NULL + && index->sections[DW_SECT_TYPES - 1] == UINT32_MAX) + || index->sections[DW_SECT_ABBREV - 1] == UINT32_MAX) + { + free (index); + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + index->section_count = section_count; + index->unit_count = unit_count; + index->slot_count = slot_count; + index->last_unit_found = 0; + index->hash_table = hash_table; + index->indices = indices; + index->section_offsets = section_offsets; + index->section_sizes = section_sizes; + + return index; +} + +static Dwarf_Package_Index * +__libdw_package_index (Dwarf *dbg, bool tu) +{ + if (tu && dbg->tu_index != NULL) + return dbg->tu_index; + else if (!tu && dbg->cu_index != NULL) + return dbg->cu_index; + + Dwarf_Package_Index *index = __libdw_read_package_index (dbg, tu); + if (index == NULL) + return NULL; + + if (tu) + dbg->tu_index = index; + else + dbg->cu_index = index; + return index; +} + +static int +__libdw_dwp_unit_row (Dwarf_Package_Index *index, uint64_t unit_id, + uint32_t *unit_rowp) +{ + if (index == NULL) + return -1; + + uint32_t hash = unit_id; + uint32_t hash2 = (unit_id >> 32) | 1; + /* Only check each slot once. */ + for (uint32_t n = index->slot_count; n-- > 0; ) + { + size_t slot = hash & (index->slot_count - 1); + uint64_t sig = read_8ubyte_unaligned (index->dbg, + index->hash_table + slot * 8); + if (sig == unit_id) + { + uint32_t row = read_4ubyte_unaligned (index->dbg, + index->indices + slot * 4); + if (row > index->unit_count) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + *unit_rowp = row; + return 0; + } + else if (sig == 0 + && read_4ubyte_unaligned (index->dbg, + index->indices + slot * 4) == 0) + break; + hash += hash2; + } + *unit_rowp = 0; + return 0; +} + +static int +__libdw_dwp_section_info (Dwarf_Package_Index *index, uint32_t unit_row, + unsigned int section, Dwarf_Off *offsetp, + Dwarf_Off *sizep) +{ + if (index == NULL) + return -1; + if (unit_row == 0) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + if (index->sections[section - 1] == UINT32_MAX) + { + if (offsetp != NULL) + *offsetp = 0; + if (sizep != NULL) + *sizep = 0; + return 0; + } + size_t i = (size_t)(unit_row - 1) * index->section_count + + index->sections[section - 1]; + if (offsetp != NULL) + *offsetp = read_4ubyte_unaligned (index->dbg, + index->section_offsets + i * 4); + if (sizep != NULL) + *sizep = read_4ubyte_unaligned (index->dbg, + index->section_sizes + i * 4); + return 0; +} + +int +internal_function +__libdw_dwp_find_unit (Dwarf *dbg, bool debug_types, Dwarf_Off off, + uint16_t version, uint8_t unit_type, uint64_t unit_id8, + uint32_t *unit_rowp, Dwarf_Off *abbrev_offsetp) +{ + if (version >= 5 + && unit_type != DW_UT_split_compile && unit_type != DW_UT_split_type) + { + not_dwp: + *unit_rowp = 0; + *abbrev_offsetp = 0; + return 0; + } + bool tu = unit_type == DW_UT_split_type || debug_types; + if (dbg->sectiondata[tu ? IDX_debug_tu_index : IDX_debug_cu_index] == NULL) + goto not_dwp; + Dwarf_Package_Index *index = __libdw_package_index (dbg, tu); + if (index == NULL) + return -1; + + /* This is always called for ascending offsets. The most obvious way for a + producer to generate the section offset table is sorted by offset; both + GNU dwp and llvm-dwp do this. In this common case, we can avoid the full + lookup. */ + if (index->last_unit_found < index->unit_count) + { + Dwarf_Off offset, size; + if (__libdw_dwp_section_info (index, index->last_unit_found + 1, + debug_types ? DW_SECT_TYPES : DW_SECT_INFO, + &offset, &size) != 0) + return -1; + if (offset <= off && off - offset < size) + { + *unit_rowp = ++index->last_unit_found; + goto done; + } + else + /* The units are not sorted. Don't try again. */ + index->last_unit_found = index->unit_count; + } + + if (version >= 5 || debug_types) + { + /* In DWARF 5 and in type units, the unit signature is available in the + unit header. */ + if (__libdw_dwp_unit_row (index, unit_id8, unit_rowp) != 0) + return -1; + } + else + { + /* In DWARF 4 compilation units, the unit signature is an attribute. We + can't parse attributes in the split unit until we get the abbreviation + table offset from the package index, which is a chicken-and-egg + problem. We could get the signature from the skeleton unit, but that + may not be available. + + Instead, we resort to a linear scan through the section offset table. + Finding all units is therefore quadratic in the number of units. + However, this will likely never be needed in practice because of the + sorted fast path above. If this ceases to be the case, we can try to + plumb through the skeleton unit's signature when it is available, or + build a sorted lookup table for binary search. */ + if (index->sections[DW_SECT_INFO - 1] == UINT32_MAX) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + for (uint32_t i = 0; i < index->unit_count; i++) + { + Dwarf_Off offset, size; + __libdw_dwp_section_info (index, i + 1, DW_SECT_INFO, &offset, + &size); + if (offset <= off && off - offset < size) + { + *unit_rowp = i + 1; + goto done; + } + } + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + done: + return __libdw_dwp_section_info (index, *unit_rowp, DW_SECT_ABBREV, + abbrev_offsetp, NULL); +} + +int +dwarf_cu_dwp_section_info (Dwarf_CU *cu, unsigned int section, + Dwarf_Off *offsetp, Dwarf_Off *sizep) +{ + if (cu == NULL) + return -1; + if (section < DW_SECT_INFO || section > DW_SECT_RNGLISTS) + { + __libdw_seterrno (DWARF_E_UNKNOWN_SECTION); + return -1; + } + if (cu->dwp_row == 0) + { + if (offsetp != NULL) + *offsetp = 0; + if (sizep != NULL) + *sizep = 0; + return 0; + } + else + { + Dwarf_Package_Index *index + = cu->unit_type == DW_UT_split_compile + ? cu->dbg->cu_index : cu->dbg->tu_index; + return __libdw_dwp_section_info (index, cu->dwp_row, section, offsetp, + sizep); + } +} +INTDEF(dwarf_cu_dwp_section_info) diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c index e51d5dd78..b7f817d9f 100644 --- a/libdw/dwarf_end.c +++ b/libdw/dwarf_end.c @@ -77,6 +77,9 @@ dwarf_end (Dwarf *dwarf) { if (dwarf != NULL) { + free (dwarf->tu_index); + free (dwarf->cu_index); + if (dwarf->cfi != NULL) /* Clean up the CFI cache. */ __libdw_destroy_frame_cache (dwarf->cfi); diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c index 46ea16b3d..0123cfa2e 100644 --- a/libdw/dwarf_error.c +++ b/libdw/dwarf_error.c @@ -102,6 +102,7 @@ static const char *errmsgs[] = [DWARF_E_NOT_CUDIE] = N_("not a CU (unit) DIE"), [DWARF_E_UNKNOWN_LANGUAGE] = N_("unknown language code"), [DWARF_E_NO_DEBUG_ADDR] = N_(".debug_addr section missing"), + [DWARF_E_UNKNOWN_SECTION] = N_("unknown section"), }; #define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0])) diff --git a/libdw/libdw.h b/libdw/libdw.h index 64d1689a3..545ad043b 100644 --- a/libdw/libdw.h +++ b/libdw/libdw.h @@ -1081,6 +1081,29 @@ extern int dwarf_frame_register (Dwarf_Frame *frame, int regno, __nonnull_attribute__ (3, 4, 5); +/* Return offset and/or size of CU's contribution to SECTION in a DWARF package + file. + + If CU is not from a DWARF package file, the file does not have SECTION, or CU + does not contribute to SECTION, then *SIZEP is set to 0. + + SECTION is a DW_SECT section identifier. Note that the original GNU DWARF + package file extension for DWARF 4 used slightly different section + identifiers. This function uses the standardized section identifiers and + maps the GNU DWARF 4 identifiers to their standard DWARF 5 analogues: + DW_SECT_LOCLISTS (5) refers to .debug_locs.dwo for DWARF 4. + DW_SECT_MACRO (7) refers to .debug_macinfo.dwo for DWARF 4 or + .debug_macro.dwo for the GNU .debug_macro extension for DWARF 4 (section + identifier 8 is DW_SECT_RNGLISTS in DWARF 5, NOT DW_SECT_MACRO like in the + GNU extension.) + .debug_types.dwo does not have a DWARF 5 equivalent, so this function accepts + the original DW_SECT_TYPES (2). + + Returns 0 for success or -1 for errors. OFFSETP and SIZEP may be NULL. */ +extern int dwarf_cu_dwp_section_info (Dwarf_CU *cu, unsigned int section, + Dwarf_Off *offsetp, Dwarf_Off *sizep); + + /* Return error code of last failing function call. This value is kept separately for each thread. */ extern int dwarf_errno (void); diff --git a/libdw/libdw.map b/libdw/libdw.map index 5331ad451..3c5ce8dc7 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -373,3 +373,8 @@ ELFUTILS_0.188 { dwfl_frame_reg; dwfl_report_offline_memory; } ELFUTILS_0.186; + +ELFUTILS_0.191 { + global: + dwarf_cu_dwp_section_info; +} ELFUTILS_0.188; diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 5aca90829..674ea91ea 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -147,6 +147,7 @@ enum DWARF_E_NOT_CUDIE, DWARF_E_UNKNOWN_LANGUAGE, DWARF_E_NO_DEBUG_ADDR, + DWARF_E_UNKNOWN_SECTION, }; @@ -231,6 +232,11 @@ struct Dwarf /* Cached info from the CFI section. */ struct Dwarf_CFI_s *cfi; + /* DWARF package file CU index section. */ + struct Dwarf_Package_Index_s *cu_index; + /* DWARF package file TU index section. */ + struct Dwarf_Package_Index_s *tu_index; + /* Fake loc CU. Used when synthesizing attributes for Dwarf_Ops that came from a location list entry in dwarf_getlocation_attr. Depending on version this is the .debug_loc or .debug_loclists @@ -343,6 +349,23 @@ struct Dwarf_Aranges_s } info[0]; }; +/* DWARF package file unit index. */ +typedef struct Dwarf_Package_Index_s +{ + Dwarf *dbg; + uint32_t section_count; + uint32_t unit_count; + uint32_t slot_count; + /* Mapping from DW_SECT_* - 1 to column number in the section tables, or + UINT32_MAX if not present. */ + uint32_t sections[DW_SECT_RNGLISTS]; + /* Row number of last unit found in the index. */ + uint32_t last_unit_found; + const unsigned char *hash_table; + const unsigned char *indices; + const unsigned char *section_offsets; + const unsigned char *section_sizes; +} Dwarf_Package_Index; /* CU representation. */ struct Dwarf_CU @@ -350,6 +373,8 @@ struct Dwarf_CU Dwarf *dbg; Dwarf_Off start; Dwarf_Off end; + /* Row number of this unit in DWARF package file index. */ + uint32_t dwp_row; uint8_t address_size; uint8_t offset_size; uint16_t version; @@ -421,6 +446,7 @@ INTDECL (dwarf_attr_integrate) INTDECL (dwarf_begin) INTDECL (dwarf_begin_elf) INTDECL (dwarf_child) +INTDECL (dwarf_cu_dwp_section_info) INTDECL (dwarf_default_lower_bound) INTDECL (dwarf_dieoffset) INTDECL (dwarf_diename) @@ -727,6 +753,13 @@ extern struct Dwarf *__libdw_find_split_dbg_addr (Dwarf *dbg, void *addr) extern struct Dwarf_CU *__libdw_find_split_unit (Dwarf_CU *cu) internal_function; +/* Find a unit in a DWARF package file for __libdw_intern_next_unit. */ +extern int __libdw_dwp_find_unit (Dwarf *dbg, bool debug_types, Dwarf_Off off, + uint16_t version, uint8_t unit_type, + uint64_t unit_id8, uint32_t *unit_rowp, + Dwarf_Off *abbrev_offsetp) + __nonnull_attribute__ (1, 7, 8) 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 ed7442318..6c7dcfb5a 100644 --- a/libdw/libdw_findcu.c +++ b/libdw/libdw_findcu.c @@ -143,6 +143,13 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types) if (unlikely (*offsetp > data->d_size)) *offsetp = data->d_size; + uint32_t dwp_row; + Dwarf_Off dwp_abbrev_offset; + if (__libdw_dwp_find_unit (dbg, debug_types, oldoff, version, unit_type, + unit_id8, &dwp_row, &dwp_abbrev_offset) != 0) + return NULL; + abbrev_offset += dwp_abbrev_offset; + /* Create an entry for this CU. */ struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU); @@ -150,6 +157,7 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types) newp->sec_idx = sec_idx; newp->start = oldoff; newp->end = *offsetp; + newp->dwp_row = dwp_row; newp->address_size = address_size; newp->offset_size = offset_size; newp->version = version; diff --git a/tests/.gitignore b/tests/.gitignore index d00a883e5..d38f0f9e2 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -28,6 +28,7 @@ /backtrace-dwarf /buildid /core-dump-backtrace.lock +/cu-dwp-section-info /debugaltlink /debuginfod_build_id_find /debuglink diff --git a/tests/Makefile.am b/tests/Makefile.am index b075e3c36..d7c531445 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -63,6 +63,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ getphdrnum leb128 read_unaligned \ msg_tst system-elf-libelf-test system-elf-gelf-test \ nvidia_extended_linemap_libdw elf-print-reloc-syms \ + cu-dwp-section-info \ $(asm_TESTS) asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \ @@ -212,7 +213,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ $(asm_TESTS) run-disasm-bpf.sh run-low_high_pc-dw-form-indirect.sh \ run-nvidia-extended-linemap-libdw.sh run-nvidia-extended-linemap-readelf.sh \ run-readelf-dw-form-indirect.sh run-strip-largealign.sh \ - run-readelf-Dd.sh run-dwfl-core-noncontig.sh + run-readelf-Dd.sh run-dwfl-core-noncontig.sh run-cu-dwp-section-info.sh if !BIARCH export ELFUTILS_DISABLE_BIARCH = 1 @@ -635,7 +636,11 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ run-funcretval++11.sh \ test-ar-duplicates.a.bz2 \ run-dwfl-core-noncontig.sh testcore-noncontig.bz2 \ - testfile-dwarf5-line-clang.bz2 + testfile-dwarf5-line-clang.bz2 \ + testfile-dwp-4.bz2 testfile-dwp-4.dwp.bz2 \ + testfile-dwp-4-strict.bz2 testfile-dwp-4-strict.dwp.bz2 \ + testfile-dwp-5.bz2 testfile-dwp-5.dwp.bz2 testfile-dwp.source \ + run-cu-dwp-section-info.sh if USE_VALGRIND @@ -812,6 +817,7 @@ leb128_LDADD = $(libelf) $(libdw) read_unaligned_LDADD = $(libelf) $(libdw) nvidia_extended_linemap_libdw_LDADD = $(libelf) $(libdw) elf_print_reloc_syms_LDADD = $(libelf) +cu_dwp_section_info_LDADD = $(libdw) # We want to test the libelf headers against the system elf.h header. # Don't include any -I CPPFLAGS. Except when we install our own elf.h. diff --git a/tests/cu-dwp-section-info.c b/tests/cu-dwp-section-info.c new file mode 100644 index 000000000..f1756979b --- /dev/null +++ b/tests/cu-dwp-section-info.c @@ -0,0 +1,73 @@ +/* Test program for dwarf_cu_dwp_section_info + Copyright (c) 2023 Meta Platforms, Inc. and affiliates. + 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 . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include ELFUTILS_HEADER(dw) + +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; + while (dwarf_get_units (dbg, cu, &cu, NULL, NULL, NULL, NULL) == 0) + { +#define SECTION_INFO(section) do { \ + printf (#section ": "); \ + Dwarf_Off offset, size; \ + if (dwarf_cu_dwp_section_info (cu, DW_SECT_##section, \ + &offset, &size) == 0) \ + printf ("0x%" PRIx64 " 0x%" PRIx64 "\n", offset, size); \ + else \ + printf ("%s\n", dwarf_errmsg (-1)); \ + } while (0) + SECTION_INFO (INFO); + SECTION_INFO (TYPES); + SECTION_INFO (ABBREV); + SECTION_INFO (LINE); + SECTION_INFO (LOCLISTS); + SECTION_INFO (STR_OFFSETS); + SECTION_INFO (MACRO); + SECTION_INFO (RNGLISTS); + printf ("\n"); + } + + dwarf_end (dbg); + close (fd); + } + + return 0; +} diff --git a/tests/run-cu-dwp-section-info.sh b/tests/run-cu-dwp-section-info.sh new file mode 100755 index 000000000..202319c6c --- /dev/null +++ b/tests/run-cu-dwp-section-info.sh @@ -0,0 +1,168 @@ +#! /bin/sh +# Copyright (c) 2023 Meta Platforms, Inc. and affiliates. +# 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 . + +. $srcdir/test-subr.sh + +# See testfile-dwp.source. +testfiles testfile-dwp-5.dwp testfile-dwp-4.dwp testfile-dwp-4-strict.dwp + +testrun_compare ${abs_builddir}/cu-dwp-section-info testfile-dwp-5.dwp << EOF +file: testfile-dwp-5.dwp +INFO: 0x0 0x70 +TYPES: 0x0 0x0 +ABBREV: 0x0 0x160 +LINE: 0x0 0x7f +LOCLISTS: 0x0 0xdb +STR_OFFSETS: 0x0 0x75c +MACRO: 0x0 0x6c6 +RNGLISTS: 0x0 0x22 + +INFO: 0x70 0x108 +TYPES: 0x0 0x0 +ABBREV: 0x0 0x160 +LINE: 0x0 0x7f +LOCLISTS: 0x0 0xdb +STR_OFFSETS: 0x0 0x75c +MACRO: 0x0 0x6c6 +RNGLISTS: 0x0 0x22 + +INFO: 0x178 0x6e +TYPES: 0x0 0x0 +ABBREV: 0x160 0xca +LINE: 0x7f 0x7f +LOCLISTS: 0x0 0x0 +STR_OFFSETS: 0x75c 0x758 +MACRO: 0x6c6 0x6c5 +RNGLISTS: 0x0 0x0 + +INFO: 0x1e6 0x78 +TYPES: 0x0 0x0 +ABBREV: 0x160 0xca +LINE: 0x7f 0x7f +LOCLISTS: 0x0 0x0 +STR_OFFSETS: 0x75c 0x758 +MACRO: 0x6c6 0x6c5 +RNGLISTS: 0x0 0x0 + +INFO: 0x25e 0x193 +TYPES: 0x0 0x0 +ABBREV: 0x22a 0x18a +LINE: 0xfe 0x81 +LOCLISTS: 0xdb 0xc9 +STR_OFFSETS: 0xeb4 0x77c +MACRO: 0xd8b 0x6c6 +RNGLISTS: 0x22 0x43 + +EOF + +testrun_compare ${abs_builddir}/cu-dwp-section-info testfile-dwp-4.dwp << EOF +file: testfile-dwp-4.dwp +INFO: 0x0 0x11e +TYPES: 0x0 0x0 +ABBREV: 0x0 0x172 +LINE: 0x0 0x52 +LOCLISTS: 0x0 0x11b +STR_OFFSETS: 0x0 0x754 +MACRO: 0x0 0x6c7 +RNGLISTS: 0x0 0x0 + +INFO: 0x11e 0x76 +TYPES: 0x0 0x0 +ABBREV: 0x172 0xd7 +LINE: 0x52 0x52 +LOCLISTS: 0x0 0x0 +STR_OFFSETS: 0x754 0x750 +MACRO: 0x6c7 0x6c6 +RNGLISTS: 0x0 0x0 + +INFO: 0x194 0x1c5 +TYPES: 0x0 0x0 +ABBREV: 0x249 0x19e +LINE: 0xa4 0x53 +LOCLISTS: 0x11b 0xf1 +STR_OFFSETS: 0xea4 0x774 +MACRO: 0xd8d 0x6c7 +RNGLISTS: 0x0 0x0 + +INFO: 0x0 0x0 +TYPES: 0x0 0x6f +ABBREV: 0x0 0x172 +LINE: 0x0 0x52 +LOCLISTS: 0x0 0x11b +STR_OFFSETS: 0x0 0x754 +MACRO: 0x0 0x6c7 +RNGLISTS: 0x0 0x0 + +INFO: 0x0 0x0 +TYPES: 0x6f 0x6d +ABBREV: 0x172 0xd7 +LINE: 0x52 0x52 +LOCLISTS: 0x0 0x0 +STR_OFFSETS: 0x754 0x750 +MACRO: 0x6c7 0x6c6 +RNGLISTS: 0x0 0x0 + +EOF + +testrun_compare ${abs_builddir}/cu-dwp-section-info testfile-dwp-4-strict.dwp << EOF +file: testfile-dwp-4-strict.dwp +INFO: 0x0 0x105 +TYPES: 0x0 0x0 +ABBREV: 0x0 0x15f +LINE: 0x0 0x52 +LOCLISTS: 0x0 0xe2 +STR_OFFSETS: 0x0 0x24 +MACRO: 0x0 0x38e4 +RNGLISTS: 0x0 0x0 + +INFO: 0x105 0x72 +TYPES: 0x0 0x0 +ABBREV: 0x15f 0xd3 +LINE: 0x52 0x52 +LOCLISTS: 0x0 0x0 +STR_OFFSETS: 0x24 0x20 +MACRO: 0x38e4 0x38db +RNGLISTS: 0x0 0x0 + +INFO: 0x177 0x17b +TYPES: 0x0 0x0 +ABBREV: 0x232 0x157 +LINE: 0xa4 0x53 +LOCLISTS: 0xe2 0xb1 +STR_OFFSETS: 0x44 0x44 +MACRO: 0x71bf 0x38f5 +RNGLISTS: 0x0 0x0 + +INFO: 0x0 0x0 +TYPES: 0x0 0x6e +ABBREV: 0x0 0x15f +LINE: 0x0 0x52 +LOCLISTS: 0x0 0xe2 +STR_OFFSETS: 0x0 0x24 +MACRO: 0x0 0x38e4 +RNGLISTS: 0x0 0x0 + +INFO: 0x0 0x0 +TYPES: 0x6e 0x6b +ABBREV: 0x15f 0xd3 +LINE: 0x52 0x52 +LOCLISTS: 0x0 0x0 +STR_OFFSETS: 0x24 0x20 +MACRO: 0x38e4 0x38db +RNGLISTS: 0x0 0x0 + +EOF diff --git a/tests/testfile-dwp-4-strict.bz2 b/tests/testfile-dwp-4-strict.bz2 new file mode 100755 index 0000000000000000000000000000000000000000..4f419c07d45aea608e02da002e8c09bc35b3553b GIT binary patch literal 4169 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 literal 0 Hc-jL100001 diff --git a/tests/testfile-dwp-4.bz2 b/tests/testfile-dwp-4.bz2 new file mode 100755 index 0000000000000000000000000000000000000000..ece5817bd88a5cf195bdaa109f8f41a8d4595093 GIT binary patch literal 4194 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 Wh5R`2PSJoD2*A literal 0 Hc-jL100001 diff --git a/tests/testfile-dwp.source b/tests/testfile-dwp.source new file mode 100644 index 000000000..b0b0a97c4 --- /dev/null +++ b/tests/testfile-dwp.source @@ -0,0 +1,102 @@ +# Nonsensical program used to generate example DWARF package files with type +# units, location lists, range lists, and macros. + +# = foobar.h = + +struct Foo +{ + int a, b; + int foo (); +}; + +struct Bar +{ + long a, b; + long bar (); +}; + +#define FROB(x) ((x) ^ 0x2a2a2a2a) +#define FRY(x) ((x) * 0x100000001b3) + +inline long +fibonacci (unsigned int n) +{ + if (n == 0) + return 0; + else + { + long a = 0; + long b = 1; + for (unsigned int i = 2; i < n; i++) + { + long tmp = a + b; + a = b; + b = tmp; + } + return b; + } +} + +# = foo.cc = + +#include "foobar.h" + +#define ZERO() (1 - 1) + +int +x_x (int x) +{ + for (int i = x; i > ZERO(); i--) + x *= x; + return x; +} + +int +Foo::foo () +{ + int x = a; + if (a > b) + x -= b; + return FROB (x_x (x)); +} + +# = bar.cc = + +#include "foobar.h" + +#define ONE 1 + +long +Bar::bar () +{ + if (a == b) + return ONE; + else + return a > b ? b : a; +} + +# = main.cc = + +#include "foobar.h" + +#define MAIN_ARGS int argc, char **argv + +int +main(MAIN_ARGS) +{ + struct Foo myfoo { argc, FROB (argc) }; + struct Bar mybar { fibonacci (argc), FRY (argc) }; + return myfoo.foo() + mybar.bar(); +} + +# Built with GCC at commit 80048aa13a6b ("debug/111409 - don't generate COMDAT +# macro sections for split DWARF"). +$ g++ -gdwarf-5 -gsplit-dwarf -fdebug-types-section -g3 -O2 foo.cc bar.cc main.cc -o testfile-dwp-5 +# GNU dwp as of binutils 2.41 only supports DWARF 4. +$ llvm-dwp -e testfile-dwp-5 -o testfile-dwp-5.dwp + +$ g++ -gdwarf-4 -gsplit-dwarf -fdebug-types-section -g3 -O2 foo.cc bar.cc main.cc -o testfile-dwp-4 +$ dwp -e testfile-dwp-4 + +$ g++ -gdwarf-4 -gstrict-dwarf -gsplit-dwarf -fdebug-types-section -g3 -O2 foo.cc bar.cc main.cc -o testfile-dwp-4-strict +$ dwp -e testfile-dwp-4-strict -- 2.47.2