From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id kWxUGH0x1WrsYCwAWB0awg (envelope-from ) for ; Sun, 18 Oct 2026 16:52:13 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=c1QmSad4; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 587911E04F; Sun, 18 Oct 2026 16:52:13 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (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 A1E261E091 for ; Sun, 18 Oct 2026 16:52:04 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2F5F84BA2E28 for ; Sun, 18 Oct 2026 20:52:04 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2F5F84BA2E28 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=c1QmSad4 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 5F1304BA23CE for ; Sun, 18 Oct 2026 20:50:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5F1304BA23CE Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 5F1304BA23CE Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1792356653; cv=none; b=FRpAsSWm2ObATpXKIfkfXGMrM7XYIhely4zniFKnt3s/Sm2i4tl9Lr4VJOzrY9rSiDweBjITdNSdyatcRvis70A7+TOVDGwtC7BcAa7N+N+UdRtYnAQc8s7zPjZTy85mxmrUiO0hUvRB1YK34fn5jsr6YhmYk5WHKZ7IUF+xF3M= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1792356653; c=relaxed/simple; bh=jBb5WJi8dXCbdCBflfAXWTppP/qnB/hQoLepotaw4/M=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=mm63Bd0N4GqaeOHcAKKAynZpgWtFH2gACYanYVaRUSYewTJYprJC6DgvPGTexHp3wKcyvk6noFM2TQ1HfUPuwfeJptmt5wKKJN2RcvaTCh1CDDnIbdZQHxnsvqa3dGV4oKgS1MrE4sUuBc4VJqmL2Bp2qfU0uGCcZZ+OmQT7b3U= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=c1QmSad4 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5F1304BA23CE DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1792356653; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IfS0DAhkGhDdUsuQAMrEKr9CC3fgw+gaJodVXU6P1FE=; b=c1QmSad4zat2n0M6+Zyw9wWWr5rMam1j2c2bTDswckbbuwqL25K1f00cM8OZFx3dfrp4YF vPkENhGKy6rjiQeaNQTiDOaSDrmSey6GjrUiBGT7tzp/ddNexs8Sd3j0VDR2/yh0bzCw6S WJJV5pNBqrhZbCTWbgzhbHt85VA8Cm0= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-678-JBQ2aDzaNWa2BfXge1mezA-1; Sun, 18 Oct 2026 20:50:51 +0000 X-MC-Unique: JBQ2aDzaNWa2BfXge1mezA-1 X-Mimecast-MFC-AGG-ID: JBQ2aDzaNWa2BfXge1mezA_1792356650 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-48b01a74792so985889f8f.0 for ; Sun, 18 Oct 2026 13:50:51 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792356650; x=1792961450; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=IfS0DAhkGhDdUsuQAMrEKr9CC3fgw+gaJodVXU6P1FE=; b=kCow9LyEausltYdQecV/kIfKcXw/KGuZ1k6FhSy+Ln2DWf2B1fIow6cfeSn2MoCZg3 pAkuDooXsZA6fyYf50XWtlyKNc4Ep9nFfhBEtgrT2ovmICaqc001v/0UoSXyHfXrPl+U JzviBukvlaSfwnlyThe4/4xZTW2mjHxuSO4z1ihdexTx3F7DFo/8ehUnGsOi6hvus47e GRsHeP2SOfNuwuTY+r4XKiLQoyI1SEBQZsGdpuELjF6u+lu59BjLTh/oAA14SHYVaU1t d/qSUgoboOOjdNDKpyxtOeeKmrJwUgLebLvYeaYqDwXIffonlIPWp60uvWe/F/Np/Vm+ 6lvA== X-Gm-Message-State: AFq9FYL+RfY2cEZZXdaWWYn8OBmK2+TeRaGMpiVpHcZzh/Fd2WW+xbew C4d6TKQbeakwRX7tpRDnHzRDZTU1CqTt7x3+9Bx+Kd2lT6GTWG2CC2TaQYq1taX9Y5Ro0lnaq1I 6t5+vnkrIUiErFXgz48kaPOKLo2x0l61uEr99doZL4Ksa0UMDnq/IYrt97A0et90+njZVvLRzQV sPg9vGZ3aYnSLyRuhxG1tpfRLN7K6SaFjKh1jmv7H8jWKXvDc= X-Gm-Gg: AYBFou04YCFhXaZmJs/ZiEj5BcrYDC9d1ghXcWjxqby8mJSaF5gVHxR6kSBeEmLUL0f zLQn6ynQn9lZrAVPnuXMjY+x+azzbGaTQLwrOsDxBWZ7u64Ax0QPpiaoF+aOM3M7ZKBpH1TkFa6 7s3ixrzvGSFPsvdD8LBxZxjp9vrREBBKTtPl/n498kIBrmPFuojEsa25PEXOn1SJIzEENTY67lc fxmqjs/j37WL8TQHfWNPEuUgO+HQriFazsDYMPczDHhDQZX4/iF4ZBqJbIgtccZoV7IOgszEuEg mu61TqN7Yw6IC5xWZ4pRsFgIxVTVUcQViX2MDHVo23tpt4Q7ljVWl+Q2GV3QejUS4Dpe X-Received: by 2002:a05:6000:987:b0:48d:fd5b:504d with SMTP id ffacd0b85a97d-48e07f9d7e2mr11336428f8f.31.1792356650183; Sun, 18 Oct 2026 13:50:50 -0700 (PDT) X-Received: by 2002:a05:6000:987:b0:48d:fd5b:504d with SMTP id ffacd0b85a97d-48e07f9d7e2mr11336398f8f.31.1792356649579; Sun, 18 Oct 2026 13:50:49 -0700 (PDT) Received: from localhost ([213.31.44.29]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-48dfd50ae5esm20500758f8f.51.2026.10.18.13.50.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 18 Oct 2026 13:50:48 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 5/6] gdb: handle corrupted .gdb_index header offsets Date: Sun, 18 Oct 2026 21:50:34 +0100 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 2aYdB74pFFPhrdKhrH9-Aa0pSKrrM1sqnzJkPRKlKp4_1792356650 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true 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 The .gdb_index section has a header. The header is a list of offsets into the .gdb_index section. Currently GDB has basically no error checking of these offsets, the offsets can point outside the .gdb_index section and GDB will usually try to do something bad as a result. Most often a bad offset will result in GDB trying to allocate a huge amount of memory. Indeed, I don't recommend running these new tests on an unpatched GDB; I managed to bring down my machine due to excessive memory allocation. I've added a mechanism to the gdb_index proc (in lib/dwarf.exp) to allow the various .gdb_index header offsets to be overridden. Then I made use of this in gdb.dwarf2/gdb-index-corrupted.exp to override each offset in turn. I also added a new test gdb.dwarf2/gdb-index-tiny-header.exp which tests with a .gdb_index sized between 0 and 28 bytes (inclusive). This covers indexes that are too small to even hold a valid version number field, and indexes upto the size of the full header block. All of these indexes are too small to hold useful data so GDB should reject them all (without crashing). The changes in gdb/dwarf2/read-gdb-index.c are fairly straightforward; check the .gdb_index is big enough for the version field, then use the version field to check that we have all of the offsets, and that the offsets point within the .gdb_index section. Also, as the data areas that the .gdb_index header offsets point to are arranged in offset order, I also check that offsets are always equal or increasing in value. --- gdb/dwarf2/read-gdb-index.c | 59 +++++++++ .../gdb.dwarf2/gdb-index-corrupted.exp | 59 +++++++++ .../gdb.dwarf2/gdb-index-tiny-header.S | 49 +++++++ .../gdb.dwarf2/gdb-index-tiny-header.exp | 121 ++++++++++++++++++ gdb/testsuite/lib/dwarf.exp | 79 ++++++++++-- 5 files changed, 355 insertions(+), 12 deletions(-) create mode 100644 gdb/testsuite/gdb.dwarf2/gdb-index-tiny-header.S create mode 100644 gdb/testsuite/gdb.dwarf2/gdb-index-tiny-header.exp diff --git a/gdb/dwarf2/read-gdb-index.c b/gdb/dwarf2/read-gdb-index.c index 83e628d3afb..5959b0ba6bc 100644 --- a/gdb/dwarf2/read-gdb-index.c +++ b/gdb/dwarf2/read-gdb-index.c @@ -481,6 +481,22 @@ read_gdb_index_from_buffer (const char *filename, const gdb_byte *addr = &buffer[0]; offset_view metadata (buffer); + /* Emit a warning that the .gdb_index section is too small. */ + auto invalid_index_size_warning = [&] () + { + warning (_(".gdb_index section in %ps is too small (%s bytes)," + " ignoring .gdb_index"), + styled_string (file_name_style.style (), filename), + pulongest (buffer.size ())); + return false; + }; + + /* Ensure that there is at least a version number available for reading. + We cannot do a minimum buffer size check until we know what version of + index we have, so first just check we can read that safely. */ + if (buffer.size () < sizeof (offset_type)) + return invalid_index_size_warning (); + /* Version check. */ offset_type version = metadata[0]; /* GDB now requires the symbol attributes, which were added in @@ -513,6 +529,49 @@ read_gdb_index_from_buffer (const char *filename, map->version = version; + /* The .gdb_index header is a version number followed by a series of + offsets into the .gdb_index section. Each header offset points to a + data block, and the offset order, and the data block order are the + same. This means that each offset must be greater than, or equal to + the previous. The first offset should point to the first byte after + the .gdb_index header. None of the header offsets should point outside + of the .gdb_index section. + + If any of these requirements are not met then GDB can end either + crashing by accessing invalid memory, or trying to allocate a huge + amount of memory to hold an incorrectly sized data block. + + So, before we make use of the header, let's sanity check it. + + First, how many offsets do we expect in the header? Version 9 added + the shortcut table offset. */ + const size_t offset_count = version >= 9 ? 6 : 5; + + /* Ensure the buffer is large enough to contain the whole header (the + version word plus OFFSET_COUNT offset words) before reading any + offsets. */ + if (metadata.size () < offset_count + 1) + return invalid_index_size_warning (); + + /* Each offset must not be smaller than the end of the header, no larger + than the whole .gdb_index section, and no smaller than the preceding + offset. Initially set PREV to the header size to enforce the lower + bound on the first offset. */ + size_t prev = (offset_count + 1) * sizeof (offset_type); + for (size_t idx = 1; idx <= offset_count; ++idx) + { + size_t off = metadata[idx]; + if (off < prev || off > buffer.size ()) + { + warning (_("skipping .gdb_index section in %ps, an invalid offset (%s)" + " was found in the header"), + styled_string (file_name_style.style (), filename), + hex_string (off)); + return false; + } + prev = off; + } + int i = 1; *cu_list = addr + metadata[i]; *cu_list_elements = (metadata[i + 1] - metadata[i]) / 8; diff --git a/gdb/testsuite/gdb.dwarf2/gdb-index-corrupted.exp b/gdb/testsuite/gdb.dwarf2/gdb-index-corrupted.exp index 58ac13ce2ee..865e5e50f97 100644 --- a/gdb/testsuite/gdb.dwarf2/gdb-index-corrupted.exp +++ b/gdb/testsuite/gdb.dwarf2/gdb-index-corrupted.exp @@ -276,6 +276,48 @@ proc run_test { testname } { addr $_start_start "$_start_end - 2" cu_label addr "$_start_end - 4" $_start_end cu_label } + } elseif { $testname eq "header-cu-list-invalid" } { + # Create an index with an out-of-bounds CU list offset. + # GDB should detect this and reject the index. + gdb_index { header_override {cu_list 0xffffffff} } { + cu cu_label + name _start {{cu_label function global}} + } + } elseif { $testname eq "header-tu-list-invalid" } { + # Create an index with an out-of-bounds TU list offset. + # GDB should detect this and reject the index. + gdb_index { header_override {tu_list 0xffffffff} } { + cu cu_label + name _start {{cu_label function global}} + } + } elseif { $testname eq "header-address-table-invalid" } { + # Create an index with an out-of-bounds address table offset. + # GDB should detect this and reject the index. + gdb_index { header_override {address_table 0xffffffff} } { + cu cu_label + name _start {{cu_label function global}} + } + } elseif { $testname eq "header-symbol-table-invalid" } { + # Create an index with an out-of-bounds symbol table offset. + # GDB should detect this and reject the index. + gdb_index { header_override {symbol_table 0xffffffff} } { + cu cu_label + name _start {{cu_label function global}} + } + } elseif { $testname eq "header-shortcut-invalid" } { + # Create an index with an out-of-bounds shortcut table offset. + # GDB should detect this and reject the index. + gdb_index { header_override {shortcut 0xffffffff} } { + cu cu_label + name _start {{cu_label function global}} + } + } elseif { $testname eq "header-constant-pool-invalid" } { + # Create an index with an out-of-bounds constant pool offset. + # GDB should detect this and reject the index. + gdb_index { header_override {constant_pool 0xffffffff} } { + cu cu_label + name _start {{cu_label function global}} + } } elseif { $testname eq "valid-index" } { # Generate a well-formed index that includes a valid main # function (valid language, with the name pointing at the @@ -367,6 +409,17 @@ proc run_test { testname } { set expect_warning_re "" } set expect_addr_map {} + } elseif { $testname eq "header-cu-list-invalid" \ + || $testname eq "header-tu-list-invalid" \ + || $testname eq "header-address-table-invalid" \ + || $testname eq "header-symbol-table-invalid" \ + || $testname eq "header-shortcut-invalid" \ + || $testname eq "header-constant-pool-invalid" } { + # Each of these tests puts an out-of-range offset in one field of + # the index header. GDB should detect the invalid offset, emit a + # warning, and reject the index. + set expect_gdb_index_ignored true + set expect_warning_re "\r\nwarning: skipping \\.gdb_index section in \[^\r\n\]*, an invalid offset \\($::hex\\) was found in the header\r\n" } elseif { $testname eq "addr-valid" } { set expect_start true set expect_method false @@ -538,6 +591,12 @@ set tests { empty-component \ addr-swapped \ addr-overlap \ addr-valid \ + header-cu-list-invalid \ + header-tu-list-invalid \ + header-address-table-invalid \ + header-symbol-table-invalid \ + header-shortcut-invalid \ + header-constant-pool-invalid \ valid-index } foreach_with_prefix test $tests { diff --git a/gdb/testsuite/gdb.dwarf2/gdb-index-tiny-header.S b/gdb/testsuite/gdb.dwarf2/gdb-index-tiny-header.S new file mode 100644 index 00000000000..3df0fa666f9 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/gdb-index-tiny-header.S @@ -0,0 +1,49 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2026 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 . */ + +/* Create a .gdb_index section that is too small to hold a valid header. + The size of the section, in bytes, is given by the INDEX_SIZE macro + which the exp script sets when this file is assembled. + + A valid version 9 header is 28 bytes: a 4-byte version word followed by + six 4-byte offsets. Any section smaller than this is invalid and GDB + should reject it rather than reading beyond the end of the section. + + The .gdb_index format is always little-endian, so we build the section + byte by byte rather than with directives like .4byte, whose encoding + would depend on the host's endianness. The first byte is 0x09, the low + byte of a little-endian version 9 word; any remaining bytes are zero. + For sizes of 4 or more this yields a valid version word (0x09 0x00 0x00 + 0x00) so that GDB gets past its version check and on to the header size + check, with the trailing zeros standing in for a truncated set of header + offsets. For sizes below 4 there is not even room for the full version + word. */ + + .section .gdb_index +#if INDEX_SIZE > 0 + /* Low byte of a little-endian version 9 word. */ + .byte 0x09 +# if INDEX_SIZE > 1 + /* Rest of the truncated header. GDB checks the header size + before checking that the header contents are valid, so + filling with zeros, which is invalid, doesn't really + matter. */ + .fill (INDEX_SIZE - 1), 1, 0 +# endif +#endif + + .section .note.GNU-stack,"",%progbits diff --git a/gdb/testsuite/gdb.dwarf2/gdb-index-tiny-header.exp b/gdb/testsuite/gdb.dwarf2/gdb-index-tiny-header.exp new file mode 100644 index 00000000000..a99aa3b69d7 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/gdb-index-tiny-header.exp @@ -0,0 +1,121 @@ +# Copyright 2026 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 . + +# Check that GDB gracefully handles a .gdb_index section that is too small +# to contain a valid header. A valid version 9 header is 28 bytes, a 4-byte +# version word followed by six 4-byte offsets, so the section is built at +# every size from 0 up to 28 bytes in turn. Each of these should cause GDB +# to ignore the index and fall back to building a cooked index from the +# DWARF, rather than reading beyond the end of the index section. The size +# 28 case is interesting as this is big enough to hold a valid header, but +# every offset in the header is 0, which is invalid, so GDB will reject the +# index for that reason. +# +# The sizes split into a few interesting ranges: +# 0 bytes -- an empty section, silently ignored. +# 1 to 3 bytes -- too small even for the version word. +# 4 to 27 bytes -- a valid version word, but a truncated set of header +# offsets. +# 28 bytes -- a full set of header offsets, but they are all zero, +# which is invalid. + +load_lib dwarf.exp + +require dwarf2_support + +# This test installs its own hand-crafted .gdb_index into the executable. +# The 'readnow' board forces GDB to ignore the index and read the full debug +# info, making this test irrelevant. +require !readnow + +standard_testfile main.c gdb-index-tiny-header.S + +# This test relies on adding a .gdb_index. If we are using a board that +# adds an index at compile time then this test is not going to work. So +# build an executable at this point and check if it has an index already, if +# it does, then we cannot carry on. +if {[prepare_for_testing "failed to prepare" ${testfile} $srcfile]} { + return +} + +set index [have_index $binfile] +if { ![string eq $index ""] } { + unsupported "cache created at compile time" + return +} + +# Build and test one variant of the tiny .gdb_index section. SIZE is the +# number of bytes in the generated section, it is passed to the assembler +# source via the INDEX_SIZE macro. +proc run_test { size } { + set exe "${::binfile}-${size}" + + if {[build_executable "failed to build" $exe \ + [list $::srcfile $::srcfile2] \ + [list debug additional_flags=-DINDEX_SIZE=$size]] == -1} { + return + } + + clean_restart + + # Read the index synchronously as part of loading the file, so that any + # problem shows up during the 'file' command below. + gdb_test_no_output "maint set dwarf synchronous on" + + # Loading the executable. gdb_load returns -1 if GDB reports an + # internal error. + set res [gdb_load $exe] + gdb_assert { $res == 0 } "load executable" + if { $res != 0 } { + return + } + + # A non-empty but too-small section should be rejected with a warning. + # A zero byte index section is empty and is silently ignored. + if { $size == 28 } { + set warning_re \ + [string cat \ + "\r\nwarning: skipping \\.gdb_index section in \[^\r\n\]+, an invalid offset \\(0x0\\) was found in the header\r\n"] + gdb_assert { [regexp $warning_re $::gdb_file_cmd_msg] } \ + "index rejected due to invalid offset" + } elseif { $size > 0 } { + set warning_re \ + [string cat \ + "\r\nwarning: \\.gdb_index section in \[^\r\n\]* is too " \ + "small \\($::decimal bytes\\), ignoring \\.gdb_index\r\n"] + gdb_assert { [regexp $warning_re $::gdb_file_cmd_msg] } \ + "index rejected due to header size" + } else { + # The SIZE is 0, there should be no warning in this case. + gdb_assert { ![regexp "warning: " $::gdb_file_cmd_msg] } \ + "no warning seen" + } + + # The tiny .gdb_index is invalid, so GDB should ignore it and use a + # cooked index built from the DWARF instead. + set index [get_index_type [file tail $exe]] + gdb_assert { [string equal $index "cooked"] } ".gdb_index ignored" + + # Expanding all symtabs should not crash GDB. + gdb_test_no_output "maint expand-symtabs" "expand all symtabs" +} + +# Test every size from an empty section up to exactly the length of a valid +# version 9 header (28 bytes). +for { set s 0 } { $s <= 28 } { incr s } { + with_test_prefix "size $s" { + run_test $s + } +} diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index 25b88b226e0..b2b23167671 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -3822,6 +3822,19 @@ namespace eval Dwarf { # error handling. The supported part names are: # 'constant_pool'. # (default {} -- no .gdb_index parts are skipped) + # header_override + # - a dict specifying overrides for header fields. Each + # key is a header field name (cu_list, tu_list, + # address_table, symbol_table, shortcut, constant_pool) + # and the value is either: + # - a number (hex or decimal) to replace the field + # - the string 'skip' to omit the field from the header + # Any field not mentioned uses its computed value. + # Examples: + # {address_table 0xffffffff} + # {address_table 0x100 symbol_table 0x200} + # {shortcut skip constant_pool skip} + # (default {} -- no overrides) # # BODY is Tcl code that emits the parts which make up the body of # the .gdb_index section. It is evaluated in the caller's @@ -3936,6 +3949,7 @@ namespace eval Dwarf { { version 9 } { no_null false } { skip_index_part {} } + { header_override {} } } # Validate the names passed to skip_index_part to catch typos in @@ -3946,6 +3960,16 @@ namespace eval Dwarf { } } + # Validate the names passed to header_override to catch typos in + # tests. + foreach header [dict keys $header_override] { + if { [lsearch -exact { cu_list tu_list address_table symbol_table \ + shortcut constant_pool } \ + $header] == -1 } { + error "gdb_index: unknown header_override '$header'" + } + } + # A list of two entry lists describing CUs. Each sub-list has the # form {label length}. The