* [PATCH] [gdb] Support default locations in DWARF5 loclists
@ 2026-04-25 7:39 Gregori Mignerot
2026-04-26 3:21 ` Simon Marchi
2026-04-26 4:01 ` Simon Marchi
0 siblings, 2 replies; 4+ messages in thread
From: Gregori Mignerot @ 2026-04-25 7:39 UTC (permalink / raw)
To: gdb-patches; +Cc: Gregori Mignerot
Add support and a test for default location entries in DWARF5 loclists
(DW_LLE_default_location, section 2.6.2 in the DWARF5 standard)
---
gdb/dwarf2/loc.c | 60 ++++++--
.../gdb.dwarf2/loclists-default-location.c | 37 +++++
.../gdb.dwarf2/loclists-default-location.exp | 144 ++++++++++++++++++
gdb/testsuite/lib/dwarf.exp | 33 +++-
4 files changed, 258 insertions(+), 16 deletions(-)
create mode 100644 gdb/testsuite/gdb.dwarf2/loclists-default-location.c
create mode 100644 gdb/testsuite/gdb.dwarf2/loclists-default-location.exp
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index a493a46dcfc..214c81ec4ea 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 = 4,
+ /* This is followed by a normal location expression as in .debug_loc,
+ to use when no other entry matches the current PC */
+ DEBUG_LOC_DEFAULT_LOCATION = 5,
+
/* An internal value indicating there is insufficient data. */
DEBUG_LOC_BUFFER_OVERFLOW = -1,
@@ -275,9 +279,12 @@ decode_debug_loclists_addresses (dwarf2_per_cu *per_cu,
*new_ptr = loc_ptr;
return DEBUG_LOC_START_END;
+ case DW_LLE_default_location:
+ *new_ptr = 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;
}
@@ -379,6 +386,11 @@ dwarf2_find_location_expression (const dwarf2_loclist_baton *baton,
unrelocated_addr base_address = baton->base_address;
const gdb_byte *loc_ptr, *buf_end;
+ /* When no DEBUG_LOC_DEFAULT_LOCATION is found
+ return NULL with length 0 (= no location found) */
+ const gdb_byte *default_loc_ptr = NULL;
+ size_t default_locexpr_length = 0;
+
loc_ptr = baton->data;
buf_end = baton->data + baton->size;
@@ -410,8 +422,8 @@ dwarf2_find_location_expression (const dwarf2_loclist_baton *baton,
switch (kind)
{
case DEBUG_LOC_END_OF_LIST:
- *locexpr_length = 0;
- return NULL;
+ *locexpr_length = default_locexpr_length;
+ return default_loc_ptr;
case DEBUG_LOC_BASE_ADDRESS:
base_address = high;
@@ -420,6 +432,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;
case DEBUG_LOC_BUFFER_OVERFLOW:
@@ -458,6 +471,14 @@ dwarf2_find_location_expression (const dwarf2_loclist_baton *baton,
loc_ptr += bytes_read;
}
+ if (kind == DEBUG_LOC_DEFAULT_LOCATION)
+ {
+ default_loc_ptr = loc_ptr;
+ default_locexpr_length = length;
+ loc_ptr += length;
+ continue;
+ }
+
if (low == high && unrel_pc == low && at_entry)
{
/* This is entry PC record present only at entry point
@@ -4031,6 +4052,18 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
&low, &high, byte_order,
addr_size, signed_addr_p);
loc_ptr = new_ptr;
+ if (dlbaton->dwarf_version < 5)
+ {
+ length = extract_unsigned_integer (loc_ptr, 2, byte_order);
+ loc_ptr += 2;
+ }
+ else
+ {
+ unsigned int bytes_read;
+ length = read_unsigned_leb128 (NULL, loc_ptr, &bytes_read);
+ loc_ptr += bytes_read;
+ }
+
switch (kind)
{
case DEBUG_LOC_END_OF_LIST:
@@ -4043,6 +4076,15 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
paddress (gdbarch, (CORE_ADDR) base_address));
continue;
+ case 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 += length;
+ continue;
+
case DEBUG_LOC_START_END:
case DEBUG_LOC_START_LENGTH:
case DEBUG_LOC_OFFSET_PAIR:
@@ -4069,18 +4111,6 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
CORE_ADDR low_reloc = per_objfile->relocate (low);
CORE_ADDR high_reloc = per_objfile->relocate (high);
- if (dlbaton->dwarf_version < 5)
- {
- length = extract_unsigned_integer (loc_ptr, 2, byte_order);
- loc_ptr += 2;
- }
- else
- {
- unsigned int bytes_read;
- length = read_unsigned_leb128 (NULL, loc_ptr, &bytes_read);
- loc_ptr += 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/testsuite/gdb.dwarf2/loclists-default-location.c
new file mode 100644
index 00000000000..fc388dcb106
--- /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 <http://www.gnu.org/licenses/>. */
+
+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..76d46a4bc18
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/loclists-default-location.exp
@@ -0,0 +1,144 @@
+# 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 <http://www.gnu.org/licenses/>.
+
+# 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 func1_len
+ lassign [function_range func2 $srcdir/$subdir/$srcfile] func2_addr func2_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 "default_first"
+ DW_AT_location 0 DW_FORM_loclistx
+ DW_AT_type :$int_type
+ }
+
+ DW_TAG_variable {
+ DW_AT_name "default_last"
+ DW_AT_location 1 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} {
+ # With the default location first in the list (default_first)
+ list_ {
+ # Applies by default in func2
+ default_location {
+ DW_OP_constu 0x2222
+ DW_OP_stack_value
+ }
+
+ # When in func1.
+ start_end $func1_addr "$func1_addr + $func1_len" {
+ DW_OP_constu 0x1111
+ DW_OP_stack_value
+ }
+ }
+
+ # With the default location last in the list (default_last)
+ list_ {
+ # When in func1.
+ start_end $func1_addr "$func1_addr + $func1_len" {
+ DW_OP_constu 0x3333
+ DW_OP_stack_value
+ }
+
+ # Applies by default in func2
+ default_location {
+ DW_OP_constu 0x4444
+ 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 default_first" " = 0x1111"
+ gdb_test "print /x default_last" " = 0x3333"
+ }
+
+ with_test_prefix "default location" {
+ gdb_continue_to_breakpoint "func2"
+ gdb_test "print /x default_first" " = 0x2222"
+ gdb_test "print /x default_last" " = 0x4444"
+ }
+}
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
- }}}
+ }}}}
# Emit end of list.
_op .byte 0x00 "DW_LLE_end_of_list"
@@ -2520,6 +2521,36 @@ namespace eval Dwarf {
incr _debug_loclists_locdesc_count
}
+ # 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_list'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_count}_start"
+ set locdesc_end_label ".Lloclists_table_${_debug_loclists_table_count}_list_${_debug_loclists_list_count}_locdesc_${_debug_loclists_locdesc_count}_end"
+ _op .uleb128 "$locdesc_end_label - $locdesc_start_label" "locdesc length"
+
+ define_label $locdesc_start_label
+ set dwarf_version 5
+ _location $locdesc $dwarf_version $_debug_loclists_addr_size $_debug_loclists_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 is
--
2.53.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] [gdb] Support default locations in DWARF5 loclists
2026-04-25 7:39 [PATCH] [gdb] Support default locations in DWARF5 loclists Gregori Mignerot
@ 2026-04-26 3:21 ` Simon Marchi
2026-04-26 7:47 ` Grégori MIGNEROT
2026-04-26 4:01 ` Simon Marchi
1 sibling, 1 reply; 4+ messages in thread
From: Simon Marchi @ 2026-04-26 3:21 UTC (permalink / raw)
To: Gregori Mignerot, gdb-patches
On 2026-04-25 03:39, Gregori Mignerot wrote:
> Add support and a test for default location entries in DWARF5 loclists
> (DW_LLE_default_location, section 2.6.2 in the DWARF5 standard)
Thanks for the patch. One thing to clear up first, since this patch
can't be considered trivial, do you have a copyright assignment on file
with the FSF? If not, you'll need to get one before we can merge your
patch. See here:
https://gitweb.git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=doc/Copyright/request-assign.future;hb=HEAD
Thanks,
Simon
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] [gdb] Support default locations in DWARF5 loclists
2026-04-25 7:39 [PATCH] [gdb] Support default locations in DWARF5 loclists Gregori Mignerot
2026-04-26 3:21 ` Simon Marchi
@ 2026-04-26 4:01 ` Simon Marchi
1 sibling, 0 replies; 4+ messages in thread
From: Simon Marchi @ 2026-04-26 4:01 UTC (permalink / raw)
To: Gregori Mignerot, gdb-patches
On 2026-04-25 03:39, Gregori Mignerot wrote:
> @@ -4031,6 +4052,18 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
> &low, &high, byte_order,
> addr_size, signed_addr_p);
> loc_ptr = new_ptr;
> + if (dlbaton->dwarf_version < 5)
> + {
> + length = extract_unsigned_integer (loc_ptr, 2, byte_order);
> + loc_ptr += 2;
> + }
> + else
> + {
> + unsigned int bytes_read;
> + length = read_unsigned_leb128 (NULL, loc_ptr, &bytes_read);
> + loc_ptr += bytes_read;
> + }
> +
This change doesn't seem right. It will make it so that we'll read a
length even if the "kind" doesn't imply a length. That is, when kind is
DEBUG_LOC_END_OF_LIST or DEBUG_LOC_BASE_ADDRESS (or
DEBUG_LOC_BUFFER_OVERFLOW / DEBUG_LOC_INVALID_ENTRY).
> diff --git a/gdb/testsuite/gdb.dwarf2/loclists-default-location.c b/gdb/testsuite/gdb.dwarf2/loclists-default-location.c
> new file mode 100644
> index 00000000000..fc388dcb106
> --- /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 <http://www.gnu.org/licenses/>. */
This copyright header is not formatted correctly (there shouldn't be the
leading asterisks. Copy it from another existing source file in this
directory.
> + loclists {is-64 $is_64} {
> + # The lists in this table are accessed by index (DW_FORM_loclistx).
> + table {post-header-label cu_table} {
> + # With the default location first in the list (default_first)
> + list_ {
> + # Applies by default in func2
> + default_location {
> + DW_OP_constu 0x2222
> + DW_OP_stack_value
> + }
> +
> + # When in func1.
> + start_end $func1_addr "$func1_addr + $func1_len" {
> + DW_OP_constu 0x1111
> + DW_OP_stack_value
> + }
> + }
Just wondering, is this valid DWARF? The spec implies that the default
location has the be last (if present):
A location list consists of a sequence of zero or more bounded
location description or base address entries, optionally followed by
a default location entry, and terminated by an end-of-list entry.
I'm not sure why DWARF 5 requires that, it seems to me like it would
work just as well if the default location was allowed to be anywhere in
the list. Do you know about producers that do this?
Also, could you add somme checks in the test to exercise
loclist_describe_location?
Simon
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] [gdb] Support default locations in DWARF5 loclists
2026-04-26 3:21 ` Simon Marchi
@ 2026-04-26 7:47 ` Grégori MIGNEROT
0 siblings, 0 replies; 4+ messages in thread
From: Grégori MIGNEROT @ 2026-04-26 7:47 UTC (permalink / raw)
To: Simon Marchi, gdb-patches
> One thing to clear up first, since this patch can't be considered
trivial, do you have a copyright assignment on file with the FSF?
I don't, just sent the request, thanks
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-04-26 7:47 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-04-25 7:39 [PATCH] [gdb] Support default locations in DWARF5 loclists Gregori Mignerot
2026-04-26 3:21 ` Simon Marchi
2026-04-26 7:47 ` Grégori MIGNEROT
2026-04-26 4:01 ` Simon Marchi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox