From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id NikeJoD88GmhbwEAWB0awg (envelope-from ) for ; Tue, 28 Apr 2026 14:29:20 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=laposte.net header.i=@laposte.net header.a=rsa-sha256 header.s=lpn-wlmd header.b=jh/ZJuZF; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 8482B1E0BA; Tue, 28 Apr 2026 14:29:20 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_MSPIKE_H2,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 8CC721E067 for ; Tue, 28 Apr 2026 14:29:18 -0400 (EDT) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id E58F64BBC092 for ; Tue, 28 Apr 2026 18:29:17 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E58F64BBC092 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=laposte.net header.i=@laposte.net header.a=rsa-sha256 header.s=lpn-wlmd header.b=jh/ZJuZF Received: from smtp-outgoing-1901.laposte.net (smtp-outgoing-1901.laposte.net [160.92.124.105]) by sourceware.org (Postfix) with ESMTPS id 209194BA23DA for ; Tue, 28 Apr 2026 18:28:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 209194BA23DA Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=laposte.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=laposte.net ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 209194BA23DA Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=160.92.124.105 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777400930; cv=none; b=BSOp8qpZfIhnGYcwZtqi5hieTn3t1f+w/iSWuB4dWp5GG9uYz39xWxbpP23QB8MSHadIqPClpDWA8qh1TxQlGil2Z6iR+UMVPCE87QcMJULTfPQKV5vvPX1NjlFWeYFWJ0IQcE0k2DegCova57dWZu/lutu25lWptL8oovK6fE4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777400930; c=relaxed/simple; bh=awX3Px0TG96qzhxnbYIGCBhN0EFgQH6g1IvjR3dHiAk=; h=From:To:Subject:Date:Message-ID:MIME-Version:DKIM-Signature; b=pPOwYjjrOhQ6bpy54A9B9BCAl5Wfb3CI3sAdhUilaCVrLHxG/QCBTjphXrWPhPh73czqTMcxnTJV79uQN4P4m1uCRvEyZEGxRIKeEj9/PKabrc52lbsk3O+oi7S81qTf7sEcO7rh2kS+wczbch6KO54U2FvqcoxApiuv725Yths= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 209194BA23DA X-mail-filterd: {"version":"1.9.5","queueID":"4g4ppy2dCBzqSH5","contextId": "a125fe21-d403-44ee-a410-fc46ef0c2708"} Received: from outgoing-mail.laposte.net (localhost.localdomain [127.0.0.1]) by mlpnf0108.laposte.net (SMTP Server) with ESMTP id 4g4ppy2dCBzqSH5; Tue, 28 Apr 2026 20:28:42 +0200 (CEST) X-mail-filterd: {"version":"1.9.5","queueID":"4g4ppy1Ws6zqSGl","contextId": "17df3ece-6410-4d2f-a82c-94b9241f75b7"} X-lpn-mailing: LEGIT X-lpn-spamrating: 40 X-lpn-spamlevel: not-spam Received: from desktop.lan (unknown [82.67.162.110]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mlpnf0108.laposte.net (SMTP Server) with ESMTPSA id 4g4ppy1Ws6zqSGl; Tue, 28 Apr 2026 20:28:40 +0200 (CEST) From: Gregori Mignerot To: gdb-patches@sourceware.org Cc: Gregori Mignerot Subject: [PATCH v4] [gdb] Support default locations in DWARF5 loclists Date: Tue, 28 Apr 2026 20:26:57 +0200 Message-ID: <20260428182836.1426182-1-gregori.mignerot@laposte.net> X-Mailer: git-send-email 2.53.0 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=laposte.net; s=lpn-wlmd; t=1777400923; bh=awX3Px0TG96qzhxnbYIGCBhN0EFgQH6g1IvjR3dHiAk=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Transfer-Encoding; b=jh/ZJuZFPuqEBSWq8XXrDHd9T05mRlB3PZbyX/E5tDIiNWVDxg6udh8o+A2BEzlhCgY1rQo/oX3IConSAtQg62VBaIZGJ4Bm9BU/Ra6hSPShHhSTUMBTEqWpg7q7fnZR6Iiqwri60WanWc6+ErLmfpgeGQvlrnjRG3hwHxRPeCqXzSfDtlapaFN2trL63fKnHKVvRAZpofCQqtX4Pzl4wTrWuM8FVndXAqzyF91IgjOvVYBPDaD8YdSSLRf7BOuEzZ+cuinnMAM9mZY6mLJsPIVzdAGr4PuI2UslDUTYCVdwkiSltc0mjXoJVn3fe2b7I7Z8mPtZkk6czIlUrmSbQQ==; 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 Add support and a test for default location entries in DWARF5 loclists (DW_LLE_default_location, section 2.6.2 in the DWARF5 standard) --- > Ok, and just out of curiosity (since you don't mention any producers > that use DW_LLE_default_location), does the motivation for this change > come from a real-world use case? I tried to use it in a hobby project, and then found out GDB doesn't support it. I figured it would be a good thing and a good exercise to add it > If you configure pre-commit [1], it will also point those out I didn't know about pre-commit, thanks for the tip Fixed those warnings gdb/dwarf2/loc.c | 56 ++++++-- .../gdb.dwarf2/loclists-default-location.c | 37 +++++ .../gdb.dwarf2/loclists-default-location.exp | 129 ++++++++++++++++++ gdb/testsuite/lib/dwarf.exp | 33 ++++- 4 files changed, 241 insertions(+), 14 deletions(-) create mode 100644 gdb/testsuite/gdb.dwarf2/loclists-default-location.c create mode 100644 gdb/testsuite/gdb.dwarf2/loclists-default-location.ex= p diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c index a493a46dcfc..c3826e9c0d5 100644 --- a/gdb/dwarf2/loc.c +++ b/gdb/dwarf2/loc.c @@ -83,6 +83,10 @@ enum debug_loc_kind the applicable base address. */ DEBUG_LOC_OFFSET_PAIR =3D 4, =20 + /* This is followed by a normal location expression, + to use when no other entry matches the current PC. */ + DEBUG_LOC_DEFAULT_LOCATION =3D 5, + /* An internal value indicating there is insufficient data. */ DEBUG_LOC_BUFFER_OVERFLOW =3D -1, =20 @@ -275,9 +279,12 @@ decode_debug_loclists_addresses (dwarf2_per_cu *per_= cu, *new_ptr =3D loc_ptr; return DEBUG_LOC_START_END; =20 + case DW_LLE_default_location: + *new_ptr =3D loc_ptr; + return DEBUG_LOC_DEFAULT_LOCATION; + /* Following cases are not supported yet. */ case DW_LLE_startx_endx: - case DW_LLE_default_location: default: return DEBUG_LOC_INVALID_ENTRY; } @@ -420,6 +427,7 @@ dwarf2_find_location_expression (const dwarf2_loclist= _baton *baton, case DEBUG_LOC_START_END: case DEBUG_LOC_START_LENGTH: case DEBUG_LOC_OFFSET_PAIR: + case DEBUG_LOC_DEFAULT_LOCATION: break; =20 case DEBUG_LOC_BUFFER_OVERFLOW: @@ -458,6 +466,16 @@ dwarf2_find_location_expression (const dwarf2_loclis= t_baton *baton, loc_ptr +=3D bytes_read; } =20 + /* DW_LLE_default_location can only appear as the last entry + (other than the "end of list" entry) of a location list. If we + see it, we know we don't have to search further. */ + + if (kind =3D=3D DEBUG_LOC_DEFAULT_LOCATION) + { + *locexpr_length =3D length; + return loc_ptr; + } + if (low =3D=3D high && unrel_pc =3D=3D low && at_entry) { /* This is entry PC record present only at entry point @@ -4046,6 +4064,7 @@ loclist_describe_location (struct symbol *symbol, C= ORE_ADDR addr, case DEBUG_LOC_START_END: case DEBUG_LOC_START_LENGTH: case DEBUG_LOC_OFFSET_PAIR: + case DEBUG_LOC_DEFAULT_LOCATION: break; =20 case DEBUG_LOC_BUFFER_OVERFLOW: @@ -4057,6 +4076,29 @@ loclist_describe_location (struct symbol *symbol, = CORE_ADDR addr, gdb_assert_not_reached ("bad debug_loc_kind"); } =20 + if (dlbaton->dwarf_version < 5) + { + length =3D extract_unsigned_integer (loc_ptr, 2, byte_order); + loc_ptr +=3D 2; + } + else + { + unsigned int bytes_read; + length =3D read_unsigned_leb128 (NULL, loc_ptr, &bytes_read); + loc_ptr +=3D bytes_read; + } + + if (kind =3D=3D DEBUG_LOC_DEFAULT_LOCATION) + { + gdb_printf (stream, _(" Default location: ")); + locexpr_describe_location_1 (symbol, addr, stream, loc_ptr, length, + addr_size, offset_size, + dlbaton->per_cu, per_objfile); + gdb_printf (stream, "\n"); + loc_ptr +=3D length; + continue; + } + /* Otherwise, a location expression entry. */ if (!dlbaton->from_dwo && kind =3D=3D DEBUG_LOC_OFFSET_PAIR) { @@ -4069,18 +4111,6 @@ loclist_describe_location (struct symbol *symbol, = CORE_ADDR addr, CORE_ADDR low_reloc =3D per_objfile->relocate (low); CORE_ADDR high_reloc =3D per_objfile->relocate (high); =20 - if (dlbaton->dwarf_version < 5) - { - length =3D extract_unsigned_integer (loc_ptr, 2, byte_order); - loc_ptr +=3D 2; - } - else - { - unsigned int bytes_read; - length =3D read_unsigned_leb128 (NULL, loc_ptr, &bytes_read); - loc_ptr +=3D bytes_read; - } - /* (It would improve readability to print only the minimum necessary digits of the second number of the range.) */ gdb_printf (stream, _(" Range %s-%s: "), diff --git a/gdb/testsuite/gdb.dwarf2/loclists-default-location.c b/gdb/t= estsuite/gdb.dwarf2/loclists-default-location.c new file mode 100644 index 00000000000..5b7889f3352 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/loclists-default-location.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2026 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 .= */ + +static int +func1 (void) +{ + asm ("func1_label: .global func1_label\n"); + return 1; +} + +static int +func2 (void) +{ + asm ("func2_label: .global func2_label\n"); + return 2; +} + +int +main (void) +{ + func1 (); + func2 (); +} diff --git a/gdb/testsuite/gdb.dwarf2/loclists-default-location.exp b/gdb= /testsuite/gdb.dwarf2/loclists-default-location.exp new file mode 100644 index 00000000000..e42adb6cfde --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/loclists-default-location.exp @@ -0,0 +1,129 @@ +# 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 support for DW_LLE_default_location + +load_lib dwarf.exp + +require dwarf2_support + +# Test with 32-bit and 64-bit DWARF. +foreach_with_prefix is_64 {false true} { + if { $is_64 } { + standard_testfile .c -dw64.S + set testfile ${testfile}-dw64 + } else { + standard_testfile .c -dw32.S + set testfile ${testfile}-dw32 + } + + # Get the addresses / lengths of func1 and func2. + lassign [function_range func1 $srcdir/$subdir/$srcfile] func1_addr f= unc1_len + lassign [function_range func2 $srcdir/$subdir/$srcfile] func2_addr f= unc2_len + + set asm_file [standard_output_file $srcfile2] + Dwarf::assemble $asm_file { + global func1_addr func1_len + global func2_addr func2_len + global is_64 + + # The CU uses the DW_FORM_loclistx form to refer to the .debug_loclists + # section. + cu { + version 5 + is_64 $is_64 + } { + declare_labels int_type + + DW_TAG_compile_unit { + DW_AT_loclists_base cu_table DW_FORM_sec_offset + } { + int_type: DW_TAG_base_type { + DW_AT_byte_size 4 DW_FORM_data1 + DW_AT_encoding @DW_ATE_signed + DW_AT_name "int" + } + + DW_TAG_variable { + DW_AT_name "x" + DW_AT_location 0 DW_FORM_loclistx + DW_AT_type :$int_type + } + + DW_TAG_subprogram { + DW_AT_name "func1" + DW_AT_low_pc $func1_addr + DW_AT_high_pc $func1_len DW_FORM_udata + } + + DW_TAG_subprogram { + DW_AT_name "func2" + DW_AT_low_pc $func2_addr + DW_AT_high_pc $func2_len DW_FORM_udata + } + } + } + + loclists {is-64 $is_64} { + # The lists in this table are accessed by index (DW_FORM_loclistx). + table {post-header-label cu_table} { + list_ { + # When in func1. + start_end $func1_addr "$func1_addr + $func1_len" { + DW_OP_constu 1111 + DW_OP_stack_value + } + + # Applies by default in func2 + default_location { + DW_OP_constu 2222 + DW_OP_stack_value + } + } + } + } + } + + if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 + } + + if { ![runto_main] } { + return + } + + gdb_breakpoint "func1" + gdb_breakpoint "func2" + + with_test_prefix "non-default location" { + gdb_continue_to_breakpoint "func1" + gdb_test "print x" " =3D 1111" + } + + with_test_prefix "default location" { + gdb_continue_to_breakpoint "func2" + gdb_test "print x" " =3D 2222" + } + + gdb_test_sequence "info address x" "info address" [list \ + "Symbol \"x\" is multi-location:" \ + "\\s*Range $hex-$hex: a complex DWARF expression:" \ + "\\s*0: DW_OP_constu 1111" \ + "\\s*3: DW_OP_stack_value" \ + "\\s*Default location: a complex DWARF expression:" \ + "\\s*0: DW_OP_constu 2222" \ + "\\s*3: DW_OP_stack_value"] +} diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index 5358dc317a1..5be57a74d42 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -2432,8 +2432,9 @@ namespace eval Dwarf { with_override Dwarf::start_length Dwarf::_loclists_start_length { with_override Dwarf::base_address Dwarf::_loclists_base_address { with_override Dwarf::start_end Dwarf::_loclists_start_end { + with_override Dwarf::default_location Dwarf::_loclists_default_location= { uplevel $_level $body - }}} + }}}} =20 # Emit end of list. _op .byte 0x00 "DW_LLE_end_of_list" @@ -2520,6 +2521,36 @@ namespace eval Dwarf { incr _debug_loclists_locdesc_count } =20 + # Emit a DW_LLE_default_location entry. + # + # This proc is meant to be used within proc _loclists_list's body. = It is + # made available as `default_location` while inside proc _loclists_l= ist's body. + + proc _loclists_default_location { locdesc } { + variable _debug_loclists_addr_size + variable _debug_loclists_offset_size + variable _debug_loclists_table_count + variable _debug_loclists_list_count + variable _debug_loclists_locdesc_count + variable _level + + set locdesc [uplevel $_level [list subst $locdesc]] + + _op .byte 0x05 "DW_LLE_default_location" + + # Length of location description. + set locdesc_start_label ".Lloclists_table_${_debug_loclists_table_count= }_list_${_debug_loclists_list_count}_locdesc_${_debug_loclists_locdesc_co= unt}_start" + set locdesc_end_label ".Lloclists_table_${_debug_loclists_table_count}_= list_${_debug_loclists_list_count}_locdesc_${_debug_loclists_locdesc_coun= t}_end" + _op .uleb128 "$locdesc_end_label - $locdesc_start_label" "locdesc lengt= h" + + define_label $locdesc_start_label + set dwarf_version 5 + _location $locdesc $dwarf_version $_debug_loclists_addr_size $_debug_lo= clists_offset_size + define_label $locdesc_end_label + + incr _debug_loclists_locdesc_count + } + # Emit a DWARF .debug_macro section. # # BODY must be Tcl code that emits the content of the section. It i= s --=20 2.53.0