From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pf1-x436.google.com (mail-pf1-x436.google.com [IPv6:2607:f8b0:4864:20::436]) by sourceware.org (Postfix) with ESMTPS id 6CFD4385840C for ; Wed, 6 Dec 2023 09:22:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6CFD4385840C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=osandov.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=osandov.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6CFD4385840C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::436 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701854571; cv=none; b=ZYhpKzeIlfBllXtEZ5QD7TKK64oAjR77STNUotaH7OmUB9Ln9HmQaIFUdn1sjtK0GYRk+WFJFSui6dB3IP0TAMqNuN5raKQvC9NCVuUTTz1Vtr+Tofo4DD72CPXGgoNqdQewWixwdsKkFQCTlC6c3S9n18H23Om8bppYNO1pSmM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701854571; c=relaxed/simple; bh=B7aFUY37qKholWiAIzrha0brTl5fkshQY7/hlMFOs1w=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=ZcEm8Md9TYdGm8/m59w0hh4eH/qx7m9NOUCFD/8p4Rt5a/zAyyxgy7cKzFGMyT+8lQTqWjsOSCC1LY3OD7/taza8IVx335S7LSwWV4IZuHzHQvmDDiibfuG+PrhTm59Ltx5DJ0FFU9EKoNqm8jL89JufmMiWYDJrwwTaOEY0jUE= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pf1-x436.google.com with SMTP id d2e1a72fcca58-6ce403523e5so2157479b3a.3 for ; Wed, 06 Dec 2023 01:22:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=osandov-com.20230601.gappssmtp.com; s=20230601; t=1701854563; x=1702459363; darn=sourceware.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=0do5vVxMhT5rUsApy2kerNeRp9nDyDYKUgt1Wolc0D0=; b=BfM71W3a6Lf2QbExphgwbargLWkzu1Y4u/pX3QN4bqbGFLO+9k1D/rlr5e0zm/amlg IwT2n1RDOlYatHJtJdpv+RwI8KPCs+TTTlXWe3wqgFZHWl2PhjTs2sdlKtPl9M9FRTNu ENzyFFIqWiDLN9Ki2bQdLNEbd892bCfsV5n1OWEtTY9jC6Le1wxbgTqXcZpUhxKSXGem H1YXAE263yo0okX7NcOoSLgnkB0zpxd7K8JVmF8/tCAvQkyFRDU7YDSd7x/lHqUx0SZa v8BooMOXxpekEUNAYAZANXjnoj3NTaX5TRMVwTf8DsuXWHUdViEGcRkcEEjpocjwCQPb ujKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701854563; x=1702459363; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0do5vVxMhT5rUsApy2kerNeRp9nDyDYKUgt1Wolc0D0=; b=mmlDjRFGt2h4NyKGss29EL7Gb7c5RS8SU0qHxKHncGpdCpDrjyoVurJDZwcC4dlPwd 3Xcll95qAeQ0yKk1+7iNPg2c9NpubYaHOh0LB4CRHeNIfYLbe0QdFaGdFUT3qUJlxrVw gi6Be1Uvh3ukZjRz6j2cYciYun2rRdK0c3GcAuzRJbfLNM3HB1+MZY5qv3h6jp5ox3MD rICRVpRPbAIlvqxupqvYrn+kxjmrXVz5z2My+BJlUoCG5PPIXB8oQn7yqpp2QkV+iOFI ZbHANKVhPuSKMHkd1XL0+6PEDVx1/P+XboD22vMm3TIaOtuNSt1PTyGvzXrjnBluA9ez lYEw== X-Gm-Message-State: AOJu0YxvyXbumSKeTNiIRgJmTtrgFiialeiv68/SqWLyvecSwbYjur1L 1BuSqLMPGtcjwc3KSwpP4aU9q3UBdBFInUHO3nI= X-Google-Smtp-Source: AGHT+IE3rNBEiCZK9wCKc+Zvu1E8Jxpv0JybvS+U/9OjnaIQd1+u8nW5Sfl9+oIK2vVp94oKKa+Vpg== X-Received: by 2002:a05:6a20:5485:b0:18b:e692:4314 with SMTP id i5-20020a056a20548500b0018be6924314mr398095pzk.56.1701854561049; Wed, 06 Dec 2023 01:22:41 -0800 (PST) Received: from telecaster.hsd1.wa.comcast.net ([2601:602:a300:3bc0::826d]) by smtp.gmail.com with ESMTPSA id j6-20020a170902c3c600b001cfd049528esm6364165plj.110.2023.12.06.01.22.39 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 Dec 2023 01:22:40 -0800 (PST) From: Omar Sandoval To: elfutils-devel@sourceware.org Subject: [PATCH v2 1/4] libdw: Parse DWARF package file index sections Date: Wed, 6 Dec 2023 01:22:16 -0800 Message-ID: <69a4646d98870478f570c50b5b3b9efc30ab2fa6.1701854319.git.osandov@fb.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,GIT_PATCH_0,KAM_LOTSOFHASH,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: From: Omar Sandoval 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 | 11 +- 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(+), 5 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 e548f38c..5363c02a 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 b2e49db2..4be32de5 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 00000000..4a4eac8c --- /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 e51d5dd7..b7f817d9 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 46ea16b3..0123cfa2 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 64d1689a..545ad043 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 5331ad45..3c5ce8dc 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 aef42267..7f8d69b5 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; @@ -684,6 +709,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) @@ -1388,6 +1420,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) diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c index ed744231..6c7dcfb5 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 5bebb2c4..0caabf25 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 2373c980..34014570 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -62,7 +62,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ dwelf_elf_e_machine_string \ getphdrnum leb128 read_unaligned \ msg_tst system-elf-libelf-test system-elf-gelf-test \ - nvidia_extended_linemap_libdw \ + nvidia_extended_linemap_libdw cu-dwp-section-info \ $(asm_TESTS) asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \ @@ -212,7 +212,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 @@ -634,7 +634,11 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ testfile-largealign.o.bz2 run-strip-largealign.sh \ run-funcretval++11.sh \ test-ar-duplicates.a.bz2 \ - run-dwfl-core-noncontig.sh testcore-noncontig.bz2 + run-dwfl-core-noncontig.sh testcore-noncontig.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 @@ -810,6 +814,7 @@ getphdrnum_LDADD = $(libelf) $(libdw) leb128_LDADD = $(libelf) $(libdw) read_unaligned_LDADD = $(libelf) $(libdw) nvidia_extended_linemap_libdw_LDADD = $(libelf) $(libdw) +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 00000000..f1756979 --- /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 00000000..202319c6 --- /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 HcmV?d00001 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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 literal 0 HcmV?d00001 diff --git a/tests/testfile-dwp.source b/tests/testfile-dwp.source new file mode 100644 index 00000000..b0b0a97c --- /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.43.0