From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id MJapF41f4GdhmRgAWB0awg (envelope-from ) for ; Sun, 23 Mar 2025 15:22:53 -0400 Authentication-Results: simark.ca; dkim=fail reason="signature verification failed" (768-bit key; unprotected) header.d=tromey.com header.i=@tromey.com header.a=rsa-sha256 header.s=default header.b=UT2Smp6j; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 5C1B41E100; Sun, 23 Mar 2025 15:22:53 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.1 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 506021E0C0 for ; Sun, 23 Mar 2025 15:22:51 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EA47C385770D for ; Sun, 23 Mar 2025 19:22:50 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org EA47C385770D Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (768-bit key, unprotected) header.d=tromey.com header.i=@tromey.com header.a=rsa-sha256 header.s=default header.b=UT2Smp6j Received: from omta36.uswest2.a.cloudfilter.net (omta36.uswest2.a.cloudfilter.net [35.89.44.35]) by sourceware.org (Postfix) with ESMTPS id AED4D3857709 for ; Sun, 23 Mar 2025 19:20:06 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org AED4D3857709 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=tromey.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tromey.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org AED4D3857709 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=35.89.44.35 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1742757606; cv=none; b=pKNA/l5RYH5WPVyasLVbs91I2zyEbsFLCnFDp+nJdP+YbNciyKahPCZhnCutV0CrfxlOBEVzYjCoWXrAf8KMWVdyOlqD0O57eWU8e3YrTdSRJUByM01VUq+853SkXLuVu1QBLMrUC+EAz5YG14g1FTrPmG8FTO8mER7EnLOocz0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1742757606; c=relaxed/simple; bh=w2bnGPeg7r6VOPQXftlx2BO/VVsokpYPros+/s7jYvI=; h=DKIM-Signature:From:Date:Subject:MIME-Version:Message-Id:To; b=Tbc6IwAF7JdX50NEomUIzRLrL6UAKOR1cJb5QUEhgkFGpMZVcR2NimUgZd1M4AHWBRUg0W8f70m6kihxfEaMjV8L/PKzGe8SMXf/LOoYAezovdIH3Yw+DbB4xGXVbCe2nUzGHOVo/cwyDyztCaBWk6kE8f/9gpb+U56H9J2KuoQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org AED4D3857709 Received: from eig-obgw-6005a.ext.cloudfilter.net ([10.0.30.201]) by cmsmtp with ESMTPS id wNiBtyzy6METlwQrdtR6cy; Sun, 23 Mar 2025 19:20:05 +0000 Received: from box5379.bluehost.com ([162.241.216.53]) by cmsmtp with ESMTPS id wQrctPIrlZ6h1wQrct17AP; Sun, 23 Mar 2025 19:20:05 +0000 X-Authority-Analysis: v=2.4 cv=ergUzZpX c=1 sm=1 tr=0 ts=67e05ee5 a=ApxJNpeYhEAb1aAlGBBbmA==:117 a=ApxJNpeYhEAb1aAlGBBbmA==:17 a=IkcTkHD0fZMA:10 a=Vs1iUdzkB0EA:10 a=ItBw4LHWJt0A:10 a=CCpqsmhAAAAA:8 a=mDV3o1hIAAAA:8 a=cw63cuBroL_YCL7J09AA:9 a=AebKTg7pT7Qil0yy:21 a=QEXdDO2ut3YA:10 a=ul9cdbp4aOFLsgKbc677:22 a=6Ogn3jAGHLSNbaov7Orx:22 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tromey.com; s=default; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:Sender: Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender :Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=8RRQzGHbDpjQmVkFPrPMsz+2nj5bsBqmvSvCcNShkD0=; b=UT2Smp6j5S3Q1fh1td/tSoioZQ Q1R7Xn70bRFzqmtLWqlWrRsfKtJtYNjzsXMSGImwvufepCZPff/+5xLs6aQkS0Z079KeI4nBNmU1L CZgQB/eTkIDJ3k7SWzSUFJaR3; Received: from [50.214.9.178] (port=51028 helo=prentzel.rce.guest) by box5379.bluehost.com with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.1) (envelope-from ) id 1twQrc-00000004G7J-0fzK; Sun, 23 Mar 2025 13:20:04 -0600 From: Tom Tromey Date: Sun, 23 Mar 2025 13:20:01 -0600 Subject: [PATCH 2/3] Handle DWARF 5 separate debug sections MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20250323-dwz-dwarf-5-v2-v1-2-3c0775ca5514@tromey.com> References: <20250323-dwz-dwarf-5-v2-v1-0-3c0775ca5514@tromey.com> In-Reply-To: <20250323-dwz-dwarf-5-v2-v1-0-3c0775ca5514@tromey.com> To: gdb-patches@sourceware.org Cc: Tom Tromey X-Mailer: b4 0.14.2 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - box5379.bluehost.com X-AntiAbuse: Original Domain - sourceware.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - tromey.com X-BWhitelist: no X-Source-IP: 50.214.9.178 X-Source-L: No X-Exim-ID: 1twQrc-00000004G7J-0fzK X-Source: X-Source-Args: X-Source-Dir: X-Source-Sender: (prentzel.rce.guest) [50.214.9.178]:51028 X-Source-Auth: tom+tromey.com X-Email-Count: 3 X-Org: HG=bhshared;ORG=bluehost; X-Source-Cap: ZWx5bnJvYmk7ZWx5bnJvYmk7Ym94NTM3OS5ibHVlaG9zdC5jb20= X-Local-Domain: yes X-CMAE-Envelope: MS4xfFZVX1IoOsK4LjEIDVqbVMf2QyZ7JeAeZ+5us/52uP6bvv6Gx7ZI+WG9B/4oIa/9VF0cSbVd45dL4/hsoTVzA1EoXObIKZZyH0InDdGLdqiqxFbmY9A/ wnnXnWUeBRGtYYbTboW2zDM13sZkowd8fRMybNpqDznFygAXLzBnYw9EXloXaT1jtYXByXDFXVD7ShQthWmqLlMM0zlNR4h4TPE= X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org DWARF 5 standardized the .gnu_debugaltlink section that dwz emits in multi-file mode. This is handled via some new forms, and a new .debug_sup section. This patch adds support for this to gdb. It is largely straightforward, I think, though one oddity is that I chose not to have this code search the system build-id directories for the supplementary file. My feeling was that, while it makes sense for a distro to unify the build-id concept with the hash stored in the .debug_sup section, there's no intrinsic need to do so. This in turn means that a few tests -- for example those that test the index cache -- will not work in this mode. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32808 --- gdb/dwarf2/attribute.c | 5 +- gdb/dwarf2/attribute.h | 14 +- gdb/dwarf2/cooked-indexer.c | 4 +- gdb/dwarf2/die.c | 3 + gdb/dwarf2/dwz.c | 185 ++++++++++++++++++++++---- gdb/dwarf2/dwz.h | 4 +- gdb/dwarf2/macro.c | 1 + gdb/dwarf2/read.c | 17 ++- gdb/dwarf2/read.h | 8 +- gdb/testsuite/gdb.dwarf2/dwzbuildid.exp | 159 +--------------------- gdb/testsuite/gdb.dwarf2/dwzbuildid.tcl | 184 +++++++++++++++++++++++++ gdb/testsuite/gdb.dwarf2/dwzbuildid5.exp | 17 +++ gdb/testsuite/gdb.dwarf2/dwznolink.exp | 2 +- gdb/testsuite/gdb.dwarf2/no-gnu-debuglink.exp | 2 +- gdb/testsuite/lib/dwarf.exp | 18 +++ 15 files changed, 420 insertions(+), 203 deletions(-) diff --git a/gdb/dwarf2/attribute.c b/gdb/dwarf2/attribute.c index 49c0bc07d75dd23f5b4f952f4ccb7c46cebc5265..3aa4790d4f7214233d1d9fe52db80f658ac6fcd8 100644 --- a/gdb/dwarf2/attribute.c +++ b/gdb/dwarf2/attribute.c @@ -73,7 +73,8 @@ attribute::form_is_string () const || form == DW_FORM_strx3 || form == DW_FORM_strx4 || form == DW_FORM_GNU_str_index - || form == DW_FORM_GNU_strp_alt); + || form == DW_FORM_GNU_strp_alt + || form == DW_FORM_strp_sup); } /* See attribute.h. */ @@ -190,6 +191,8 @@ attribute::form_is_unsigned () const { return (form == DW_FORM_ref_addr || form == DW_FORM_GNU_ref_alt + || form == DW_FORM_ref_sup4 + || form == DW_FORM_ref_sup8 || form == DW_FORM_data2 || form == DW_FORM_data4 || form == DW_FORM_data8 diff --git a/gdb/dwarf2/attribute.h b/gdb/dwarf2/attribute.h index ce6c5639c1ae25644844447399988648842d8f58..b89136678f5fe824c21082e39242fec6d945f169 100644 --- a/gdb/dwarf2/attribute.h +++ b/gdb/dwarf2/attribute.h @@ -144,7 +144,9 @@ struct attribute || form == DW_FORM_ref4 || form == DW_FORM_ref8 || form == DW_FORM_ref_udata - || form == DW_FORM_GNU_ref_alt); + || form == DW_FORM_GNU_ref_alt + || form == DW_FORM_ref_sup4 + || form == DW_FORM_ref_sup8); } /* Check if the attribute's form is a DW_FORM_block* @@ -168,6 +170,16 @@ struct attribute "reprocessing". */ bool form_requires_reprocessing () const; + /* Check if attribute's form refers to the separate "dwz" file. + This is only useful for references to the .debug_info section, + not to the supplementary .debug_str section. */ + bool form_is_alt () const + { + return (form == DW_FORM_GNU_ref_alt + || form == DW_FORM_ref_sup4 + || form == DW_FORM_ref_sup8); + } + /* Return DIE offset of this attribute. Return 0 with complaint if the attribute is not of the required kind. */ diff --git a/gdb/dwarf2/cooked-indexer.c b/gdb/dwarf2/cooked-indexer.c index 3b80cd6c50089c82963881845713b93655b25ec4..327db33593d6f3e284ac708f9c55a6aa11ed129d 100644 --- a/gdb/dwarf2/cooked-indexer.c +++ b/gdb/dwarf2/cooked-indexer.c @@ -222,7 +222,7 @@ cooked_indexer::scan_attributes (dwarf2_per_cu *scanning_per_cu, case DW_AT_abstract_origin: case DW_AT_extension: origin_offset = attr.get_ref_die_offset (); - origin_is_dwz = attr.form == DW_FORM_GNU_ref_alt; + origin_is_dwz = attr.form_is_alt (); break; case DW_AT_external: @@ -423,7 +423,7 @@ cooked_indexer::index_imported_unit (cutu_reader *reader, if (attr.name == DW_AT_import) { sect_off = attr.get_ref_die_offset (); - is_dwz = (attr.form == DW_FORM_GNU_ref_alt + is_dwz = (attr.form_is_alt () || reader->cu ()->per_cu->is_dwz); } } diff --git a/gdb/dwarf2/die.c b/gdb/dwarf2/die.c index 9437c2f985871769156c132d96826e9527e4c14b..4cdf535f8ac438a6df1aaa8d03c7010dde3b9a09 100644 --- a/gdb/dwarf2/die.c +++ b/gdb/dwarf2/die.c @@ -90,6 +90,8 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) gdb_puts (hex_string (die->attrs[i].as_unsigned ()), f); break; case DW_FORM_GNU_ref_alt: + case DW_FORM_ref_sup4: + case DW_FORM_ref_sup8: gdb_printf (f, "alt ref address: "); gdb_puts (hex_string (die->attrs[i].as_unsigned ()), f); break; @@ -123,6 +125,7 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) case DW_FORM_strx: case DW_FORM_GNU_str_index: case DW_FORM_GNU_strp_alt: + case DW_FORM_strp_sup: gdb_printf (f, "string: \"%s\" (%s canonicalized)", die->attrs[i].as_string () ? die->attrs[i].as_string () : "", diff --git a/gdb/dwarf2/dwz.c b/gdb/dwarf2/dwz.c index 14cd8e882ba6bc16b57a82aa31296f4025261f15..76274b630e484624a6d1a97b7a5f32feb83019e1 100644 --- a/gdb/dwarf2/dwz.c +++ b/gdb/dwarf2/dwz.c @@ -21,6 +21,7 @@ #include "build-id.h" #include "debuginfod-support.h" +#include "dwarf2/leb.h" #include "dwarf2/read.h" #include "dwarf2/sect-names.h" #include "filenames.h" @@ -39,12 +40,12 @@ dwz_file::read_string (struct objfile *objfile, LONGEST str_offset) gdb_assert (str.readin); if (str.buffer == NULL) - error (_("DW_FORM_GNU_strp_alt used without .debug_str " + error (_("supplementary DWARF file missing .debug_str " "section [in module %s]"), this->filename ()); if (str_offset >= str.size) - error (_("DW_FORM_GNU_strp_alt pointing outside of " - ".debug_str section [in module %s]"), + error (_("invalid string reference to supplementary DWARF file " + "[in module %s]"), this->filename ()); gdb_assert (HOST_CHAR_BIT == 8); if (str.buffer[str_offset] == '\0') @@ -87,6 +88,139 @@ locate_dwz_sections (struct objfile *objfile, bfd *abfd, asection *sectp, } } +/* Helper that throws an exception when reading the .debug_sup + section. */ + +static void +debug_sup_failure (const char *text, bfd *abfd) +{ + error (_("%s [in modules %s]"), text, bfd_get_filename (abfd)); +} + +/* Look for the .debug_sup section and read it. If the section does + not exist, this returns false. If the section does exist but fails + to parse for some reason, an exception is thrown. Otherwise, if + everything goes well, this returns true and fills in the out + parameters. */ + +static bool +get_debug_sup_info (bfd *abfd, + std::string *filename, + size_t *buildid_len, + gdb::unique_xmalloc_ptr *buildid) +{ + asection *sect = bfd_get_section_by_name (abfd, ".debug_sup"); + if (sect == nullptr) + return false; + + bfd_byte *contents; + if (!bfd_malloc_and_get_section (abfd, sect, &contents)) + debug_sup_failure (_("could not read .debug_sup section"), abfd); + + gdb::unique_xmalloc_ptr content_holder (contents); + bfd_size_type size = bfd_section_size (sect); + + /* Version of this section. */ + if (size < 4) + debug_sup_failure (_(".debug_sup section too short"), abfd); + unsigned int version = read_2_bytes (abfd, contents); + contents += 2; + size -= 2; + if (version != 5) + debug_sup_failure (_(".debug_sup has wrong version number"), abfd); + + /* Skip the is_supplementary value. We already ensured there were + enough bytes, above. */ + ++contents; + --size; + + /* The spec says that in the supplementary file, this must be \0, + but it doesn't seem very important. */ + const char *fname = (const char *) contents; + size_t len = strlen (fname) + 1; + if (filename != nullptr) + *filename = fname; + contents += len; + size -= len; + + if (size == 0) + debug_sup_failure (_(".debug_sup section missing ID"), abfd); + + unsigned int bytes_read; + *buildid_len = read_unsigned_leb128 (abfd, contents, &bytes_read); + contents += bytes_read; + size -= bytes_read; + + if (size < *buildid_len) + debug_sup_failure (_("extra data after .debug_sup section ID"), abfd); + + if (*buildid_len != 0) + buildid->reset ((bfd_byte *) xmemdup (contents, *buildid_len, + *buildid_len)); + + return true; +} + +/* Validate that ABFD matches the given BUILDID. If DWARF5 is true, + then this is done by examining the .debug_sup data. */ + +static bool +verify_id (bfd *abfd, size_t len, const bfd_byte *buildid, bool dwarf5) +{ + if (!bfd_check_format (abfd, bfd_object)) + return false; + + if (dwarf5) + { + size_t new_len; + gdb::unique_xmalloc_ptr new_id; + + if (!get_debug_sup_info (abfd, nullptr, &new_len, &new_id)) + return false; + return (len == new_len + && memcmp (buildid, new_id.get (), len) == 0); + } + else + return build_id_verify (abfd, len, buildid); +} + +/* Find either the .debug_sup or .gnu_debugaltlink section and return + its contents. Returns true on success and sets out parameters, or + false if nothing is found. */ + +static bool +read_alt_info (bfd *abfd, std::string *filename, + size_t *buildid_len, + gdb::unique_xmalloc_ptr *buildid, + bool *dwarf5) +{ + if (get_debug_sup_info (abfd, filename, buildid_len, buildid)) + { + *dwarf5 = true; + return true; + } + + bfd_size_type buildid_len_arg; + bfd_set_error (bfd_error_no_error); + bfd_byte *buildid_out; + gdb::unique_xmalloc_ptr new_filename + (bfd_get_alt_debug_link_info (abfd, &buildid_len_arg, + &buildid_out)); + if (new_filename == nullptr) + { + if (bfd_get_error () == bfd_error_no_error) + return false; + error (_("could not read '.gnu_debugaltlink' section: %s"), + bfd_errmsg (bfd_get_error ())); + } + *filename = new_filename.get (); + + *buildid_len = buildid_len_arg; + buildid->reset (buildid_out); + *dwarf5 = false; + return true; +} + /* Attempt to find a .dwz file (whose full path is represented by FILENAME) in all of the specified debug file directories provided. @@ -95,7 +229,7 @@ locate_dwz_sections (struct objfile *objfile, bfd *abfd, asection *sectp, static gdb_bfd_ref_ptr dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid, - size_t buildid_len) + size_t buildid_len, bool dwarf5) { /* Let's assume that the path represented by FILENAME has the "/.dwz/" subpath in it. This is what (most) GNU/Linux @@ -163,7 +297,7 @@ dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid, if (dwz_bfd == nullptr) continue; - if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid)) + if (!verify_id (dwz_bfd.get (), buildid_len, buildid, dwarf5)) { dwz_bfd.reset (nullptr); continue; @@ -181,9 +315,6 @@ dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid, void dwz_file::read_dwz_file (dwarf2_per_objfile *per_objfile) { - bfd_size_type buildid_len_arg; - size_t buildid_len; - bfd_byte *buildid; dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; /* This may query the user via the debuginfod support, so it may @@ -195,24 +326,17 @@ dwz_file::read_dwz_file (dwarf2_per_objfile *per_objfile) /* Set this early, so that on error it remains NULL. */ per_bfd->dwz_file.emplace (nullptr); - bfd_set_error (bfd_error_no_error); - gdb::unique_xmalloc_ptr data - (bfd_get_alt_debug_link_info (per_bfd->obfd, - &buildid_len_arg, &buildid)); - if (data == NULL) + size_t buildid_len; + gdb::unique_xmalloc_ptr buildid; + std::string filename; + bool dwarf5; + if (!read_alt_info (per_bfd->obfd, &filename, &buildid_len, &buildid, + &dwarf5)) { - if (bfd_get_error () == bfd_error_no_error) - return; - error (_("could not read '.gnu_debugaltlink' section: %s"), - bfd_errmsg (bfd_get_error ())); + /* Nothing found, nothing to do. */ + return; } - gdb::unique_xmalloc_ptr buildid_holder (buildid); - - buildid_len = (size_t) buildid_len_arg; - - std::string filename = data.get (); - if (!IS_ABSOLUTE_PATH (filename.c_str ())) { gdb::unique_xmalloc_ptr abs = gdb_realpath (per_bfd->filename ()); @@ -225,25 +349,26 @@ dwz_file::read_dwz_file (dwarf2_per_objfile *per_objfile) gdb_bfd_ref_ptr dwz_bfd (gdb_bfd_open (filename.c_str (), gnutarget)); if (dwz_bfd != NULL) { - if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid)) + if (!verify_id (dwz_bfd.get (), buildid_len, buildid.get (), dwarf5)) dwz_bfd.reset (nullptr); } if (dwz_bfd == NULL) - dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid); + dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid.get ()); if (dwz_bfd == nullptr) { /* If the user has provided us with different debug file directories, we can try them in order. */ - dwz_bfd = dwz_search_other_debugdirs (filename, buildid, buildid_len); + dwz_bfd = dwz_search_other_debugdirs (filename, buildid.get (), + buildid_len, dwarf5); } if (dwz_bfd == nullptr) { gdb::unique_xmalloc_ptr alt_filename; scoped_fd fd - = debuginfod_debuginfo_query (buildid, buildid_len, + = debuginfod_debuginfo_query (buildid.get (), buildid_len, per_bfd->filename (), &alt_filename); if (fd.get () >= 0) @@ -254,13 +379,15 @@ dwz_file::read_dwz_file (dwarf2_per_objfile *per_objfile) if (dwz_bfd == nullptr) warning (_("File \"%s\" from debuginfod cannot be opened as bfd"), alt_filename.get ()); - else if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid)) + else if (!verify_id (dwz_bfd.get (), buildid_len, buildid.get (), + dwarf5)) dwz_bfd.reset (nullptr); } } if (dwz_bfd == NULL) - error (_("could not find '.gnu_debugaltlink' file for %s"), + error (_("could not find supplementary DWARF file (%s) for %s"), + filename.c_str (), per_bfd->filename ()); dwz_file_up result (new dwz_file (std::move (dwz_bfd))); diff --git a/gdb/dwarf2/dwz.h b/gdb/dwarf2/dwz.h index 639eea3a41850249a44259e454daa770b246ef2b..381d8dad427aab4a04d2db6608b15862aad8130b 100644 --- a/gdb/dwarf2/dwz.h +++ b/gdb/dwarf2/dwz.h @@ -34,8 +34,8 @@ struct dwz_file /* Open the separate '.dwz' debug file, if needed. This will set the appropriate field in the per-BFD structure. If the DWZ file exists, the relevant sections are read in as well. Throws an - error if the .gnu_debugaltlink section exists but the file cannot - be found. */ + exception if the .gnu_debugaltlink or .debug_sup section exists + but is invalid or if the file cannot be found. */ static void read_dwz_file (dwarf2_per_objfile *per_objfile); const char *filename () const diff --git a/gdb/dwarf2/macro.c b/gdb/dwarf2/macro.c index 2d9d4b7bbcf0e79da203fb23ecc21925f7c5ead3..7924fd2ed5160de72954360e86b560025ab12a86 100644 --- a/gdb/dwarf2/macro.c +++ b/gdb/dwarf2/macro.c @@ -259,6 +259,7 @@ skip_form_bytes (bfd *abfd, const gdb_byte *bytes, const gdb_byte *buffer_end, case DW_FORM_sec_offset: case DW_FORM_strp: case DW_FORM_GNU_strp_alt: + case DW_FORM_strp_sup: bytes += offset_size; break; diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index f4198d71ca28811bd02c5fb87b5206629f118874..e8a8c9d030282033bbcaf9d234188d06dfc32c2c 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -3920,11 +3920,13 @@ cutu_reader::skip_one_attribute (dwarf_form form, const gdb_byte *info_ptr) case DW_FORM_data4: case DW_FORM_ref4: case DW_FORM_strx4: + case DW_FORM_ref_sup4: return info_ptr + 4; case DW_FORM_data8: case DW_FORM_ref8: case DW_FORM_ref_sig8: + case DW_FORM_ref_sup8: return info_ptr + 8; case DW_FORM_data16: @@ -3937,6 +3939,7 @@ cutu_reader::skip_one_attribute (dwarf_form form, const gdb_byte *info_ptr) case DW_FORM_sec_offset: case DW_FORM_strp: case DW_FORM_GNU_strp_alt: + case DW_FORM_strp_sup: return info_ptr + m_cu->header.offset_size; case DW_FORM_exprloc: @@ -5047,7 +5050,7 @@ process_imported_unit_die (struct die_info *die, struct dwarf2_cu *cu) if (attr != NULL) { sect_offset sect_off = attr->get_ref_die_offset (); - bool is_dwz = (attr->form == DW_FORM_GNU_ref_alt || cu->per_cu->is_dwz); + bool is_dwz = attr->form_is_alt () || cu->per_cu->is_dwz; dwarf2_per_objfile *per_objfile = cu->per_objfile; dwarf2_per_cu *per_cu = dwarf2_find_containing_comp_unit (sect_off, is_dwz, @@ -14951,10 +14954,12 @@ cutu_reader::read_attribute_value (attribute *attr, unsigned form, info_ptr += 2; break; case DW_FORM_data4: + case DW_FORM_ref_sup4: attr->set_unsigned (read_4_bytes (m_abfd, info_ptr)); info_ptr += 4; break; case DW_FORM_data8: + case DW_FORM_ref_sup8: attr->set_unsigned (read_8_bytes (m_abfd, info_ptr)); info_ptr += 8; break; @@ -15006,6 +15011,7 @@ cutu_reader::read_attribute_value (attribute *attr, unsigned form, } [[fallthrough]]; case DW_FORM_GNU_strp_alt: + case DW_FORM_strp_sup: { dwz_file *dwz = per_objfile->per_bfd->get_dwz_file (true); LONGEST str_offset @@ -17288,6 +17294,7 @@ dwarf2_const_value_attr (const struct attribute *attr, struct type *type, case DW_FORM_strx: case DW_FORM_GNU_str_index: case DW_FORM_GNU_strp_alt: + case DW_FORM_strp_sup: /* The string is already allocated on the objfile obstack, point directly to it. */ *bytes = (const gdb_byte *) attr->as_string (); @@ -17494,7 +17501,7 @@ lookup_die_type (struct die_info *die, const struct attribute *attr, /* First see if we have it cached. */ - if (attr->form == DW_FORM_GNU_ref_alt) + if (attr->form_is_alt ()) { sect_offset sect_off = attr->get_ref_die_offset (); dwarf2_per_cu *per_cu @@ -18278,15 +18285,14 @@ follow_die_ref (struct die_info *src_die, const struct attribute *attr, struct dwarf2_cu *cu = *ref_cu; struct die_info *die; - if (attr->form != DW_FORM_GNU_ref_alt && src_die->sect_off == sect_off) + if (!attr->form_is_alt () && src_die->sect_off == sect_off) { /* Self-reference, we're done. */ return src_die; } die = follow_die_offset (sect_off, - (attr->form == DW_FORM_GNU_ref_alt - || cu->per_cu->is_dwz), + attr->form_is_alt () || cu->per_cu->is_dwz, ref_cu); if (!die) error (_(DWARF_ERROR_PREFIX @@ -18497,6 +18503,7 @@ dwarf2_fetch_constant_bytes (sect_offset sect_off, case DW_FORM_strx: case DW_FORM_GNU_str_index: case DW_FORM_GNU_strp_alt: + case DW_FORM_strp_sup: /* The string is already allocated on the objfile obstack, point directly to it. */ { diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index ba2dd07a2ee278228fc8ffadd56bbfe290844e74..895ebee633e8c06fce9180b81743ae249072024d 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -533,9 +533,9 @@ struct dwarf2_per_bfd } /* Return the separate '.dwz' debug file. If there is no - .gnu_debugaltlink section in the file, then the result depends on - REQUIRE: if REQUIRE is true, error out; if REQUIRE is false, - return nullptr. */ + .gnu_debugaltlink or .debug_sup section in the file, then the + result depends on REQUIRE: if REQUIRE is true, error out; if + REQUIRE is false, return nullptr. */ struct dwz_file *get_dwz_file (bool require = false) { gdb_assert (!require || this->dwz_file.has_value ()); @@ -546,7 +546,7 @@ struct dwarf2_per_bfd { result = this->dwz_file->get (); if (require && result == nullptr) - error (_("could not read '.gnu_debugaltlink' section")); + error (_("could not find supplementary DWARF file")); } return result; diff --git a/gdb/testsuite/gdb.dwarf2/dwzbuildid.exp b/gdb/testsuite/gdb.dwarf2/dwzbuildid.exp index e54508a56e7e616a56d53c2ef17dcc3198fd1cba..6cb5a709855a41b418a0861b045bda23c36ec645 100644 --- a/gdb/testsuite/gdb.dwarf2/dwzbuildid.exp +++ b/gdb/testsuite/gdb.dwarf2/dwzbuildid.exp @@ -13,160 +13,5 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -load_lib dwarf.exp - -# This test can only be run on targets which support DWARF-2 and use gas. -require dwarf2_support - -# No remote host testing either. -require {!is_remote host} - - -# Lots of source files since we test a few cases and make new files -# for each. -# The tests are: -# ok - the main file refers to a dwz and the buildids match -# mismatch - the buildids do not match -# fallback - the buildids do not match but a match is found via buildid -standard_testfile main.c \ - dwzbuildid-ok-base.S dwzbuildid-ok-sep.S \ - dwzbuildid-mismatch-base.S dwzbuildid-mismatch-sep.S \ - dwzbuildid-fallback-base.S dwzbuildid-fallback-sep.S \ - dwzbuildid-fallback-ok.S - -# Write some assembly that just has a .gnu_debugaltlink section. -proc write_just_debugaltlink {filename dwzname buildid} { - set asm_file [standard_output_file $filename] - - Dwarf::assemble $asm_file { - upvar dwzname dwzname - upvar buildid buildid - - gnu_debugaltlink $dwzname $buildid - - # Only the DWARF reader checks .gnu_debugaltlink, so make sure - # there is a bit of DWARF in here. - cu { label cu_start } { - compile_unit {{language @DW_LANG_C}} { - } - } - aranges {} cu_start { - arange {} 0 0 - } - } -} - -# Write some DWARF that also sets the buildid. -proc write_dwarf_file {filename buildid {value 99}} { - set asm_file [standard_output_file $filename] - - Dwarf::assemble $asm_file { - declare_labels int_label int_label2 - - upvar buildid buildid - upvar value value - - build_id $buildid - - cu { label cu_start } { - compile_unit {{language @DW_LANG_C}} { - int_label2: base_type { - {name int} - {byte_size 4 sdata} - {encoding @DW_ATE_signed} - } - - constant { - {name the_int} - {type :$int_label2} - {const_value $value data1} - } - } - } - - aranges {} cu_start { - arange {} 0 0 - } - } -} - -if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \ - object {nodebug}] != "" } { - return -1 -} - -# The values don't really matter, just whether they are equal. -set ok_prefix 01 -set ok_suffix 02030405060708091011121314151617181920 -set ok_suffix2 020304050607080910111213141516171819ff -set ok_buildid ${ok_prefix}${ok_suffix} -set ok_buildid2 ${ok_prefix}${ok_suffix2} -set bad_buildid [string repeat ff 20] - -set debugdir [standard_output_file {}] -set basedir $debugdir/.build-id -file mkdir $basedir $basedir/$ok_prefix - -# Test where the separate debuginfo's buildid matches. -write_just_debugaltlink $srcfile2 ${binfile}3.o $ok_buildid -write_dwarf_file $srcfile3 $ok_buildid - -# Test where the separate debuginfo's buildid does not match. -write_just_debugaltlink $srcfile4 ${binfile}5.o $ok_buildid -write_dwarf_file $srcfile5 $bad_buildid - -# Test where the separate debuginfo's buildid does not match, but then -# we find a match in the .build-id directory. -write_just_debugaltlink $srcfile6 ${binfile}7.o $ok_buildid2 -# Use 77 as the value so that if we load the bad debuginfo, we will -# see the wrong result. -write_dwarf_file $srcfile7 $bad_buildid 77 -write_dwarf_file $srcfile8 $ok_buildid2 - -# Compile everything. -for {set i 2} {$i <= 8} {incr i} { - if {[gdb_compile [standard_output_file [set srcfile$i]] \ - ${binfile}$i.o object nodebug] != ""} { - return -1 - } -} - -# Copy a file into the .build-id place for the "fallback" test. -file copy -force -- ${binfile}8.o $basedir/$ok_prefix/$ok_suffix2.debug - -proc do_test {} { - clean_restart - - gdb_test_no_output "set debug-file-directory $::debugdir" \ - "set debug-file-directory" - - gdb_load ${::binfile}-${::testname} - - if {![runto_main]} { - return - } - - if {$::testname == "mismatch"} { - gdb_test "print the_int" \ - "(No symbol table is loaded|No symbol \"the_int\" in current context).*" - } else { - gdb_test "print the_int" " = 99" - } -} - -foreach_with_prefix testname { ok mismatch fallback } { - if { $testname == "ok" } { - set objs [list ${binfile}1.o ${binfile}2.o] - } elseif { $testname == "mismatch" } { - set objs [list ${binfile}1.o ${binfile}4.o] - } elseif { $testname == "fallback" } { - set objs [list ${binfile}1.o ${binfile}6.o] - } - - if {[gdb_compile $objs ${binfile}-$testname executable {quiet}] != ""} { - unsupported "compilation failed" - continue - } - - do_test -} +set scenario gnu +source $srcdir/$subdir/dwzbuildid.tcl diff --git a/gdb/testsuite/gdb.dwarf2/dwzbuildid.tcl b/gdb/testsuite/gdb.dwarf2/dwzbuildid.tcl new file mode 100644 index 0000000000000000000000000000000000000000..b4c26a3d60022d21e806dc9400f507ffe9dbe386 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dwzbuildid.tcl @@ -0,0 +1,184 @@ +# Copyright 2013-2024 Free Software Foundation, Inc. + +# This program 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. +# +# This program 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 . + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +require dwarf2_support + +# No remote host testing either. +require {!is_remote host} + + +# Lots of source files since we test a few cases and make new files +# for each. +# The tests are: +# ok - the main file refers to a dwz and the buildids match +# mismatch - the buildids do not match +# fallback - the buildids do not match but a match is found via buildid +standard_testfile main.c \ + dwzbuildid-ok-base.S dwzbuildid-ok-sep.S \ + dwzbuildid-mismatch-base.S dwzbuildid-mismatch-sep.S \ + dwzbuildid-fallback-base.S dwzbuildid-fallback-sep.S \ + dwzbuildid-fallback-ok.S + +# Write some assembly that just has a .gnu_debugaltlink section. +proc write_just_debugaltlink {filename dwzname buildid} { + set asm_file [standard_output_file $filename] + + Dwarf::assemble $asm_file { + upvar dwzname dwzname + upvar buildid buildid + + if {$::scenario == "gnu"} { + gnu_debugaltlink $dwzname $buildid + } else { + debug_sup 0 $dwzname $buildid + } + + # Only the DWARF reader checks .gnu_debugaltlink, so make sure + # there is a bit of DWARF in here. + cu { label cu_start } { + compile_unit {{language @DW_LANG_C}} { + } + } + aranges {} cu_start { + arange {} 0 0 + } + } +} + +# Write some DWARF that also sets the buildid. +proc write_dwarf_file {filename buildid {value 99}} { + set asm_file [standard_output_file $filename] + + Dwarf::assemble $asm_file { + declare_labels int_label int_label2 + + upvar buildid buildid + upvar value value + + if {$::scenario == "gnu"} { + build_id $buildid + } else { + debug_sup 1 "" $buildid + } + + cu { label cu_start } { + compile_unit {{language @DW_LANG_C}} { + int_label2: base_type { + {name int} + {byte_size 4 sdata} + {encoding @DW_ATE_signed} + } + + constant { + {name the_int} + {type :$int_label2} + {const_value $value data1} + } + } + } + + aranges {} cu_start { + arange {} 0 0 + } + } +} + +if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \ + object {nodebug}] != "" } { + return -1 +} + +# The values don't really matter, just whether they are equal. +set ok_prefix 01 +set ok_suffix 02030405060708091011121314151617181920 +set ok_suffix2 020304050607080910111213141516171819ff +set ok_buildid ${ok_prefix}${ok_suffix} +set ok_buildid2 ${ok_prefix}${ok_suffix2} +set bad_buildid [string repeat ff 20] + +set debugdir [standard_output_file {}] +set basedir $debugdir/.build-id +file mkdir $basedir $basedir/$ok_prefix + +# Test where the separate debuginfo's buildid matches. +write_just_debugaltlink $srcfile2 ${binfile}3.o $ok_buildid +write_dwarf_file $srcfile3 $ok_buildid + +# Test where the separate debuginfo's buildid does not match. +write_just_debugaltlink $srcfile4 ${binfile}5.o $ok_buildid +write_dwarf_file $srcfile5 $bad_buildid + +# Test where the separate debuginfo's buildid does not match, but then +# we find a match in the .build-id directory. +write_just_debugaltlink $srcfile6 ${binfile}7.o $ok_buildid2 +# Use 77 as the value so that if we load the bad debuginfo, we will +# see the wrong result. +write_dwarf_file $srcfile7 $bad_buildid 77 +write_dwarf_file $srcfile8 $ok_buildid2 + +# Compile everything. +for {set i 2} {$i <= 8} {incr i} { + if {[gdb_compile [standard_output_file [set srcfile$i]] \ + ${binfile}$i.o object nodebug] != ""} { + return -1 + } +} + +# Copy a file into the .build-id place for the "fallback" test. +file copy -force -- ${binfile}8.o $basedir/$ok_prefix/$ok_suffix2.debug + +proc do_test {} { + clean_restart + + gdb_test_no_output "set debug-file-directory $::debugdir" \ + "set debug-file-directory" + + gdb_load ${::binfile}-${::testname} + + if {![runto_main]} { + return + } + + if {$::testname == "mismatch"} { + gdb_test "print the_int" \ + "(No symbol table is loaded|No symbol \"the_int\" in current context).*" + } else { + gdb_test "print the_int" " = 99" + } +} + +set tests {ok mismatch} +if {$scenario == "gnu"} { + lappend tests fallback +} +foreach_with_prefix testname $tests { + if { $testname == "ok" } { + set objs [list ${binfile}1.o ${binfile}2.o] + } elseif { $testname == "mismatch" } { + set objs [list ${binfile}1.o ${binfile}4.o] + } elseif { $testname == "fallback" } { + set objs [list ${binfile}1.o ${binfile}6.o] + } + + if {[gdb_compile $objs ${binfile}-$testname executable {quiet}] != ""} { + unsupported "compilation failed" + continue + } + + do_test +} diff --git a/gdb/testsuite/gdb.dwarf2/dwzbuildid5.exp b/gdb/testsuite/gdb.dwarf2/dwzbuildid5.exp new file mode 100644 index 0000000000000000000000000000000000000000..047626c003dc4824a8b3664b68a0aaff4b434da8 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dwzbuildid5.exp @@ -0,0 +1,17 @@ +# Copyright 2025 Free Software Foundation, Inc. + +# This program 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. +# +# This program 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 . + +set scenario dwarf5 +source $srcdir/$subdir/dwzbuildid.tcl diff --git a/gdb/testsuite/gdb.dwarf2/dwznolink.exp b/gdb/testsuite/gdb.dwarf2/dwznolink.exp index cbabe8f828d4f2e46004eb41a1e6d091cabd06ae..88fa7c03fe6cb53b7d658f76175a678342454983 100644 --- a/gdb/testsuite/gdb.dwarf2/dwznolink.exp +++ b/gdb/testsuite/gdb.dwarf2/dwznolink.exp @@ -49,5 +49,5 @@ if {[build_executable $testfile.exp $testfile \ clean_restart gdb_test "file -readnow $binfile" \ - "could not read '.gnu_debugaltlink' section" \ + "could not find supplementary DWARF file" \ "file $testfile" diff --git a/gdb/testsuite/gdb.dwarf2/no-gnu-debuglink.exp b/gdb/testsuite/gdb.dwarf2/no-gnu-debuglink.exp index 54cd199a9473998dfab08a14f27f6e82529a9ea4..1dd98174df81f650e9a276b617c575041d32560a 100644 --- a/gdb/testsuite/gdb.dwarf2/no-gnu-debuglink.exp +++ b/gdb/testsuite/gdb.dwarf2/no-gnu-debuglink.exp @@ -38,7 +38,7 @@ if { [build_executable $testfile.exp $testfile [list $srcfile $asm_file]] } { clean_restart gdb_test_no_output "maint set dwarf synchronous on" -set msg "\r\nwarning: could not find '\.gnu_debugaltlink' file for \[^\r\n\]*" +set msg "\r\nwarning: could not find supplementary DWARF file \[^\r\n\]*" gdb_test "file $binfile" "$msg" "file command" set question "Load new symbol table from .*\? .y or n. " diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index 7dcf13f2ce7bdbdd78c4972ac0e6c7a55958afdd..0b1f01c50b92fae176b97e063ffed7f57f03dc91 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -3006,6 +3006,24 @@ namespace eval Dwarf { } } + # Emit a .debug_sup section with the given file name and build-id. + # The buildid should be represented as a hexadecimal string, like + # "ffeeddcc". + proc debug_sup {is_sup filename buildid} { + _defer_output .debug_sup { + # The version. + _op .2byte 0x5 + # Supplementary marker. + _op .byte $is_sup + _op .ascii [_quote $filename] + set len [expr {[string length $buildid] / 2}] + _op .uleb128 $len + foreach {a b} [split $buildid {}] { + _op .byte 0x$a$b + } + } + } + proc _note {type name hexdata} { set namelen [expr [string length $name] + 1] set datalen [expr [string length $hexdata] / 2] -- 2.46.1