From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id J9/ZOtL0qWopYxAAWB0awg (envelope-from ) for ; Tue, 15 Sep 2026 21:45:54 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=tivGvRUv; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id D3DA01E06B; Tue, 15 Sep 2026 21:45:54 -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.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [IPv6:2620:52:6:3111::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 828061E051 for ; Tue, 15 Sep 2026 21:45:53 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EC46B4B9DB49 for ; Wed, 16 Sep 2026 01:45:51 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org EC46B4B9DB49 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=tivGvRUv Received: from smtp.polymtl.ca (smtp.polymtl.ca [132.207.4.11]) by sourceware.org (Postfix) with ESMTPS id 1E2CF4BA2E09 for ; Wed, 16 Sep 2026 01:45:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1E2CF4BA2E09 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=polymtl.ca Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=polymtl.ca ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 1E2CF4BA2E09 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=132.207.4.11 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1789523126; cv=none; b=T3MfK+qQHZ3BMfJ+X56VHLEjc+27tJCfNtBjd7gPFHevEnbudSLE8NUzWrsJfjDuiJQfpfxkWCutvh5Hs2fKY7PQvzRfZ74VsaEMQlzD20u6zHAAEV017EzpEdFMuT/4xSXAzFDfTn6V5+Fjh3WeityEREEu1Kiv1sC5rrwXW0A= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1789523126; c=relaxed/simple; bh=fXO9GRjB1x8AsJW6ik8tGfAgOeAUxQ6w7t3ZCIzpexM=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=paiHd3ylvTxXwyMXrZb5Ynm+f6WhV2CTo9NiiHaAbMIQQdmIJNkK2bXYqt6wNyEmOtXsD3BnQ1Ge4tURJoD4s1PVDkA4njlI58kR0SBR15a5Ss+mF6oB43+VeYHq9iU19e6Bc2U9AwVFMzAVj5zqFMgaFdmi6tyP13byb6+XrRY= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=tivGvRUv DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1E2CF4BA2E09 Received: from simark.ca (simark.ca [158.69.221.121]) (authenticated bits=0) by smtp.polymtl.ca (8.14.7/8.14.7) with ESMTP id 68G1jGwn186265 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 15 Sep 2026 21:45:20 -0400 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp.polymtl.ca 68G1jGwn186265 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=polymtl.ca; s=oct2025; t=1789523121; bh=D82wg8CrCqTFVIoXeEPi/GiqObT32pLN/MGA84++QZ8=; h=From:To:Cc:Subject:Date:From; b=tivGvRUvVzqfzdebh5trpTrcEtmsNk0YwgbUW5yNPcqpaJNowVQs+dCXEM+3kUTLy VOzLpC4YC5408IFD8oEyp+UYSgSCoYFWX488B72VWkgSqU7Iwt6hVCADbWUOxVfqoW 4kB1qBVgJFgmKFAwkrReVAhDsS6Tip7CSuuPVKu13+7Zg7tHE6zQEo15spRFFAZ1J+ 34hWJasQhuCNB3QMXsNSMhzw0tJ+kG2iwAk7BhOKJqHj+ht9jfhffydwA2x4dvaGLJ 36LHcFNf1OLBd8fj4EitfTSac+p2eRVYzzXfU9VqT3UyklN3yjx58qeStO8g+wyLbM 7ctrSgsINl5SQ== Received: by simark.ca (Postfix) id CCE951E051; Tue, 15 Sep 2026 21:45:14 -0400 (EDT) From: simon.marchi@polymtl.ca To: gdb-patches@sourceware.org Cc: Simon Marchi Subject: [PATCH] gdb/dwarf: fix reading DW_FORM_addrx with address size of 2 Date: Tue, 15 Sep 2026 21:45:10 -0400 Message-ID: <20260916014513.3386344-1-simon.marchi@polymtl.ca> X-Mailer: git-send-email 2.55.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Poly-FromMTA: (simark.ca [158.69.221.121]) at Wed, 16 Sep 2026 01:45:16 +0000 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 From: Simon Marchi While investigating AVR binaries for bug 34638, I stumbled on a crash of GDB when loading an AVR binary generated by clang: $ cat repro.c volatile int sink; static void helper (int v) { sink = v; } int main (void) { helper (42); return 0; } $ clang --target=avr -mmcu=atmega328p -g -O1 -o repro repro.c /usr/bin/avr-ld: warning: _clear_bss.o: missing .note.GNU-stack section implies executable stack /usr/bin/avr-ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker $ ./gdb -q -nx --data-directory data-directory repro Reading symbols from repro... (gdb) ================================================================= ==2749200==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7bacecc1ca81 at pc 0x560d4a5964d6 bp 0x7b8ce9ffc410 sp 0x7b8ce9ffc400 READ of size 1 at 0x7bacecc1ca81 thread T1 #0 0x560d4a5964d5 in bfd_getl64 /home/simark/src/binutils-gdb/bfd/libbfd.c:903 #1 0x560d48b83034 in read_addr_index_1 /home/simark/src/binutils-gdb/gdb/dwarf2/read.c:14676 #2 0x560d48b83160 in read_addr_index /home/simark/src/binutils-gdb/gdb/dwarf2/read.c:14684 #3 0x560d48b802de in cutu_reader::read_attribute_reprocess(attribute*, dwarf_tag) /home/simark/src/binutils-gdb/gdb/dwarf2/read.c:14257 #4 0x560d48b7c7fe in cutu_reader::read_toplevel_die(gdb::array_view) /home/simark/src/binutils-gdb/gdb/dwarf2/read.c:13811 #5 0x560d48b3292a in cutu_reader::cutu_reader(dwarf2_per_cu&, dwarf2_per_objfile&, dwarf2_cu*, bool, std::optional, abbrev_table_cache&) /home/simark/src/binutils-gdb/gdb/dwarf2/read.c:2833 #6 0x560d48bc47ba in std::__detail::_MakeUniq::__single_object std::make_unique(dwarf2_per_cu&, dwarf2_per_objfile&, decltype(nullptr)&&, bool&&, std::nullopt_t const&, abbrev_table_cache&) /usr/include/c++/16/bits/unique_ptr.h:1105 #7 0x560d48b33caf in cooked_index_worker_debug_info::process_unit(dwarf2_per_cu*, dwarf2_per_objfile*, cooked_index_worker_result*) /home/simark/src/binutils-gdb/gdb/dwarf2/read.c:3165 #8 0x560d48bb72eb in cooked_index_worker_debug_info::parallel_indexing_worker::process_one(dwarf2_per_cu&)::{lambda()#1}::operator()() const /home/simark/src/binutils-gdb/gdb/dwarf2/read.c:3065 The problem is that the CU generated by Clang has an address size of 2: Compilation Unit @ offset 0x5f4: Length: 0x66 (32-bit) Version: 5 Unit Type: DW_UT_compile (1) Abbrev Offset: 0x5a2 Pointer Size: 2 But read_addr_index_1 only knows how to read addresses of size 4 and 8: if (addr_size == 4) return (unrelocated_addr) bfd_get_32 (abfd, info_ptr); else return (unrelocated_addr) bfd_get_64 (abfd, info_ptr); This ends up reading 8 bytes instead of two which either returns a wrong value, reads past the end of the section, or both. Use extract_unsigned_integer with the CU's address size instead of hardcoding sizes. This also shows that the bounds check just above is not sufficient. I only verifies that the entry starts inside the section, but not that it fits in it entirely. Adjust it to account for the size of the entry. I added a dwarf2_per_bfd::byte_order helper method to conveniently get the endianness from a bfd, it could probably get reused elsewhere. Add a test using the DWARF assembler. I wanted to write it using proper DWARF 5, so I added DW_FORM_addrx and DW_AT_addr_base handling in lib/dwarf.exp, which so far only knew about the DWARF 4 GNU extension spellings of those. Without the fix, it either fails with an ASan abort if GDB is built with that, or one of the "info address" commands simply returns the wrong answer. Change-Id: I1212178394bc13c4a049c21684245ebb54c5d6f6 --- gdb/dwarf2/read.c | 25 +++---- gdb/dwarf2/read.h | 4 ++ gdb/testsuite/gdb.dwarf2/dw2-addr-size-2.c | 22 ++++++ gdb/testsuite/gdb.dwarf2/dw2-addr-size-2.exp | 74 ++++++++++++++++++++ gdb/testsuite/lib/dwarf.exp | 2 + 5 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-addr-size-2.c create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-addr-size-2.exp diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 7e1a0d686a9e..eee04533ef33 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -14655,25 +14655,26 @@ read_addr_index_1 (dwarf2_per_objfile *per_objfile, unsigned int addr_index, std::optional addr_base, int addr_size) { struct objfile *objfile = per_objfile->objfile; - bfd *abfd = objfile->obfd.get (); - const gdb_byte *info_ptr; + dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; ULONGEST addr_base_or_zero = addr_base.has_value () ? *addr_base : 0; - per_objfile->per_bfd->addr.read (objfile); - if (per_objfile->per_bfd->addr.buffer == NULL) + per_bfd->addr.read (objfile); + if (per_bfd->addr.buffer == NULL) error (_("DW_FORM_addr_index used without .debug_addr section [in module %s]"), objfile_name (objfile)); - if (addr_base_or_zero + addr_index * addr_size - >= per_objfile->per_bfd->addr.size) + + /* Check that the whole entry fits inside the section. */ + if (addr_base_or_zero + (addr_index + 1) * (ULONGEST) addr_size + > per_bfd->addr.size) error (_("DW_FORM_addr_index pointing outside of " ".debug_addr section [in module %s]"), objfile_name (objfile)); - info_ptr = (per_objfile->per_bfd->addr.buffer + addr_base_or_zero - + addr_index * addr_size); - if (addr_size == 4) - return (unrelocated_addr) bfd_get_32 (abfd, info_ptr); - else - return (unrelocated_addr) bfd_get_64 (abfd, info_ptr); + + const gdb_byte *info_ptr + = per_bfd->addr.buffer + addr_base_or_zero + addr_index * addr_size; + + return (unrelocated_addr) extract_unsigned_integer (info_ptr, addr_size, + per_bfd->byte_order ()); } /* Given index ADDR_INDEX in .debug_addr, fetch the value. */ diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index 15dd2abf3a1e..4f4f493e88dd 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -582,6 +582,10 @@ struct dwarf2_per_bfd const char *filename () const { return bfd_get_filename (this->obfd); } + /* Return the endianness of the BFD. */ + bfd_endian byte_order () const + { return bfd_big_endian (this->obfd) ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE; } + /* Return the unit given its index. */ dwarf2_per_cu &get_unit (int index) const { diff --git a/gdb/testsuite/gdb.dwarf2/dw2-addr-size-2.c b/gdb/testsuite/gdb.dwarf2/dw2-addr-size-2.c new file mode 100644 index 000000000000..6a0e311ef418 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-addr-size-2.c @@ -0,0 +1,22 @@ +/* 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 . */ + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/dw2-addr-size-2.exp b/gdb/testsuite/gdb.dwarf2/dw2-addr-size-2.exp new file mode 100644 index 000000000000..c34cebb2f296 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-addr-size-2.exp @@ -0,0 +1,74 @@ +# 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 . + +# Test a CU with an address size that is neither 4 nor 8. +# +# In particular, test reading DW_FORM_addrx attributes from a CU whose address +# size is 2, which used to crash GDB. This is seen in binaries produced by +# Clang for AVR. + +load_lib dwarf.exp + +require dwarf2_support + +standard_testfile .c -dw.S + +set func_one_addr 0x1234 +set func_two_addr 0x1238 + +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + # Capture a label to the start of the .debug_addr section. + set addr_base_lbl [debug_addr_label] + + cu { + version 5 + addr_size 2 + } { + compile_unit { + DW_AT_name dw2-addr-size-2.c + DW_AT_comp_dir /tmp + DW_AT_addr_base $addr_base_lbl + DW_AT_low_pc $::func_one_addr DW_FORM_addrx + DW_AT_high_pc 8 DW_FORM_data1 + } { + subprogram { + DW_AT_name func_one + DW_AT_low_pc $::func_one_addr DW_FORM_addrx + DW_AT_high_pc 4 DW_FORM_data1 + DW_AT_external 1 flag + } { + } + subprogram { + DW_AT_name func_two + DW_AT_low_pc $::func_two_addr DW_FORM_addrx + DW_AT_high_pc 4 DW_FORM_data1 + DW_AT_external 1 flag + } { + } + } + } +} + +if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 +} + +gdb_test "info address func_one" \ + "Symbol \"func_one\" is a function at address $func_one_addr\\." + +gdb_test "info address func_two" \ + "Symbol \"func_two\" is a function at address $func_two_addr\\." diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index 839c51742650..a0487637a561 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -808,6 +808,7 @@ namespace eval Dwarf { _op .${_cu_addr_size}byte $value } + DW_FORM_addrx - DW_FORM_GNU_addr_index { variable _debug_addr_index variable _cu_addr_size @@ -948,6 +949,7 @@ namespace eval Dwarf { DW_AT_name { return DW_FORM_string } + DW_AT_addr_base - DW_AT_GNU_addr_base { return DW_FORM_sec_offset } base-commit: 346e832c2a919ee5e618c0b50c367cc8b3a07699 -- 2.55.0