Matthieu Longo [Mon, 2 Feb 2026 14:54:55 +0000 (14:54 +0000)]
bfd: fix memory leak when default-initializing an OAv2 attribute
To merge an OAv2 attribute, the input values must either be present in
the subsections being merged, or a default value must be created for the
missing ones. Note that this default value is not necessarily null.
In the current implementation of oav2_attr_default(), the default value
is created by copying another attribute provided as a template. As a
result, a string attribute may be copied from the template if it is not
NULL. The copied value is overwritten with whatever default the backend
provides for that attribute.
In oav2_attr_overwrite_with_default(), when no default attribute value
is found in the backend, a string attribute is simply assigned NULL.
This ignores the possibility that the original value may be non-NULL,
and causes the previously allocated memory for the string to be leaked.
This issue was detected by the LeakSanitizer (see the relevant part of
the stack trace below).
This patch fixes the memory leak by freeing the existing value before
assigning NULL to the attribute.
==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 5 byte(s) in 1 object(s) allocated from:
#2 xstrdup ../../libiberty/xstrdup.c:34
#3 _bfd_elf_obj_attr_v2_copy ../../bfd/elf-attrs.c:3185
#4 oav2_attr_default ../../bfd/elf-attrs.c:1109
#5 handle_optional_subsection_merge ../../bfd/elf-attrs.c:1558
Matthieu Longo [Mon, 2 Feb 2026 14:40:22 +0000 (14:40 +0000)]
bfd: fix memory leak when assigning the merge result of OAv2 string attributes
oav2_attr_merge() merges input OAv2 attributes and returns a merge result,
which is then assigned to the previous value held by REF.
In the current implementation of handle_optional_subsection_merge(), when
merging string attributes, the existing value is overwritten without first
being freed. This results in a memory leak. This issue was detected by
LeakSanitizer (see the relevant stack trace below).
This patch fixes the memory leak by wrapping the assignment of the merge
result to REF inside a helper function. For string attributes, the helper
frees the previous value before performing the assignment. This approach
also centralizes the logic and makes easier to correctly free and assign
more complex structures in the future, if needed.
Matthieu Longo [Fri, 30 Jan 2026 11:20:02 +0000 (11:20 +0000)]
Object Attributes v2: clean up attributes data when freeing BFDs
Once attributes merge is complete, object attributes from input files
are no longer needed and can be safely released. The same applies to
object attributes associated to the output object. Ideally, a single
clean-up mechanism should handle both inputs and output cases. GNU ld
already provides such a mechanism via _bfd_elf_free_cached_info().
The previous patch series that introduced support for Object Attributes
v2 did not free any OAv2 data, resulting in leaks of all OAv2-related
resources.
This patch adds a new helper, _bfd_elf_cleanup_object_attributes, to
the OAv2 API to deallocate all OAv2 resources associated with a BFD.
The helper is invoked from _bfd_elf_free_cached_info().
The patch also fixes a logical error after the attributes merge, where
object attributes were copied from the accumulator into output_bfd. A
simple pointer copy is insufficient because ownership of the wrapper
must be fully swapped between the two BFDs to ensure resources are
deallocated correctly.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33858 Co-authored-by: Alan Modra <amodra@gmail.com>
Jan Beulich [Fri, 6 Feb 2026 07:52:29 +0000 (08:52 +0100)]
gas: drop pointless tc_fix_adjustable()
Instances yielding constant 1 / true are meaningless, as that's write.c's
default anyway. In KVX also drop TC_FIX_ADJUSTABLE(), which had no user
already when KVX support was first introduced. Since the comment mentions
them: Linkonce sections are taken care of in write.c.
Jan Beulich [Fri, 6 Feb 2026 07:52:02 +0000 (08:52 +0100)]
ld: fold .note.GNU-stack during relocatable linking
PR ld/33851
While in all binutils components we've switched the section to be of
SHT_NOTE type, assembly sources as well as other tools may still generate
SHT_PROGBITS instances. When doing relocatable links, input sections with
differing types would cause multiple output sections to be created, which
some tools choke upon. Fold incoming sections into a single one, the type
of which will be the type of the first section encountered.
David Faust [Wed, 4 Feb 2026 21:53:34 +0000 (13:53 -0800)]
bpf: add may_goto instruction [PR32176]
The BPF "may_goto" instruction is a special sort of conditional jump
where the condition is determined by the BPF runtime. That is, it is
a no-op until the runtime decides otherwise.
For normal asm syntax, the mnemonic "jcond" is chosen in keeping with
the style of following the opcode definitions in the Linux kernel uapi
BPF headers.
This instruction is not currently emitted by GCC, but it can be inserted
into BPF programs via macros defined in the Linux kernel.
The compunit_symtab::includes field says that it contains the flattened
list of all recursively included symtabs:
/* Vector of included compunit symtabs. When searching the static or global
block of this compunit, the corresponding block of all
included compunits will also be searched. Note that this
list must be flattened -- the symbol reader is responsible for
ensuring that this vector contains the transitive closure of all
included compunits. */
std::vector<compunit_symtab *> includes;
The DWARF reader appears to do exactly that, see
recursively_compute_inclusions.
It therefore seems unnecessary to do a recursive search, in
recursively_find_pc_sect_compunit_symtab, it will search some symtabs
multiple times. I confirmed this by hacking the function to print the
searched CUs and to never find anything:
for (compunit_symtab *include : cust->includes)
if (compunit_symtab *found
And then:
$ ./gdb -nx --data-directory=data-directory ~/build/babeltrace/src/lib/.libs/libbabeltrace2.so.0.0.0 -ex "p bt_common_assert_failed" -batch | grep 'Search CU' | sort | uniq -c
1 Search CU 0x7c83249e44b0
1 Search CU 0x7c83249e4690
1 Search CU 0x7c83249e4870
1 Search CU 0x7c83249e4960
1 Search CU 0x7c83249e4b40
1 Search CU 0x7c83249e4d20
1 Search CU 0x7c83249e4f00
2 Search CU 0x7c83249e4ff0
2 Search CU 0x7c83249e50e0
4 Search CU 0x7c83249e51d0
2 Search CU 0x7c83249e52c0
2 Search CU 0x7c83249e53b0
4 Search CU 0x7c83249e54a0
Change recursively_find_pc_sect_compunit_symtab to only search the
flattened list, and rename it accordingly.
With the patch, the same hack (putting the print in the "is_the_one"
lambda) and command as above shows that all CUs are searched exactly
once:
1 Search CU 0x7cc78ffe44b0
1 Search CU 0x7cc78ffe4690
1 Search CU 0x7cc78ffe4870
1 Search CU 0x7cc78ffe4960
1 Search CU 0x7cc78ffe4b40
1 Search CU 0x7cc78ffe4d20
1 Search CU 0x7cc78ffe4f00
1 Search CU 0x7cc78ffe4ff0
1 Search CU 0x7cc78ffe50e0
1 Search CU 0x7cc78ffe51d0
1 Search CU 0x7cc78ffe52c0
1 Search CU 0x7cc78ffe53b0
1 Search CU 0x7cc78ffe54a0
I am not sure how blockvectors work exactly, whether the blockvector of
the includer CU is a superset of the blockvectors of the includees. I
ask that because it seems like in practice, the requested PC always
seems to be found in the first searched CU. I haven't investigated this
point more than that though.
Simon Marchi [Fri, 30 Jan 2026 02:55:27 +0000 (21:55 -0500)]
gdb/symtab: make compunit_symtab::includes a std::vector
Since compunit_symtab is now a properly constructed and destructed
object, we can use fancy C++ things in it. Change the includes field to
be an std::vector.
Previously, the includes list was NULL-terminated. I went through all
users and I'm pretty sure that none of them rely on it being
NULL-terminated anymore.
Change-Id: Ie68a8dc0f227fd49c291d85c3e8e020463e9d0d4 Approved-By: Tom Tromey <tom@tromey.com>
Simon Marchi [Fri, 30 Jan 2026 02:55:26 +0000 (21:55 -0500)]
gdb/block: make find_iterator_compunit_symtab a method of block_iterator
I noticed some code in bkscm_print_block_syms_progress_smob peeking a
bit in the implementation details of block_iterator, and doing
essentially the same thing as the existing static function
find_iterator_compunit_symtab.
Change find_iterator_compunit_symtab to become
block_iterator::compunit_symtab, and use it in
bkscm_print_block_syms_progress_smob.
Change-Id: I344a2155a2edb5d278e98684c71f1ee161e8d1d4 Approved-By: Tom Tromey <tom@tromey.com>
Simon Marchi [Sat, 24 Jan 2026 05:15:00 +0000 (00:15 -0500)]
gdb/amd-dbgapi: add basic watchpoint support
Add basic watchpoint support for the amd-dbgapi target. This means
placing write watchpoints on globally addressable memory. More
complexity will come eventually to allow placing watchpoints on the
various other address spaces, but that will require adding proper
support for non-default address spaces first.
Implementation
--------------
I think the implementation is not too surprising, just adding the
required target methods. But there are some things worthy of mention:
- amd-dbgapi does not support read watchpoints. If the core attempts
to insert a read (or access, which means read/write) watchpoint,
amd_dbgapi_target::insert_watchpoint returns an error.
If we silently let the beneath target (linux-nat) install the read
watchpoint, it would be potentially confusing. Everything would look
fine to the user, but a read from the GPU would not be caught, so it
would look like the watchpoint doesn't work.
There is a loophole though: read watchpoints created before the
runtime is loaded (and therefore the amd-dbgapi target is pushed)
will still be inserted. Only when execution stops, and the user
tries to resume again, will the check in
amd_dbgapi_target::insert_watchpoint be hit.
Another option would be to allow the host read watchpoint to go
through, but warn that the reads from the AMD GPU device will not be
watched. We would need to be smart to avoid flooding the user with
warnings. But I decided to upstream the current ROCgdb behavior
first, we can always change it later.
- When the amd-dbgapi target gets pushed, we create amd-dbgapi
watchpoints for any existing hardware write watchpoint location.
- When the core asks the target to insert a watchpoint, we ask the
target beneath to insert it first. If the beneath target fails, we
return immediately with an error.
- When the core asks to remove a watchpoint, we ask the target beneath
to to remove it first. Even if it fails, we still try to remove the
amd-dbgapi watchpoint.
- When stopping after a watchpoint hit while the "precise-memory"
setting is not enabled, it is possible for the wave to stop a few
instructions later than the instruction that made the write that
triggered the watchpoint. We print a warning in that case, similar
to what we do when a memory violation happens while "precis-memory"
is disabled.
Testing
-------
- Tests precise-memory-warning-watchpoint.exp and
watchpoint-at-end-of-shader.exp are more or less brought as-is from
downstream ROCgdb. I modified precise-memory-warning-watchpoint.exp
to watch a hipMalloc'ed region instead of a `__device__` global
variable. The latter doesn't work upstream, because we don't yet
support the DWARF constructs that describe the variable location.
- I added test watchpoint-basic.exp with various simple cases to
exercises different code paths added by this patch.
Differences from downstream ROCgdb
----------------------------------
While extracting this code from ROCgdb, I made a few minor but possibly
significant (read: erroneous) changes. Those should be reviewed
carefully. I think that some code in ROCgdb was written at a time where
the amd-dbgapi target was always pushed at the very start of the
inferior execution, so assumptions were different.
- The value type for the `amd_dbgapi_inferior_info::watchpoint_map` map
is now a structure, instead of an std::pair, just because it makes
the code more readable.
- The insert_watchpoint and remove_watchpoint methods (and perhaps
others) now assume that if they are called, the runtime is in the
"enabled" state.
- insert_initial_watchpoints has one more check (loc->owner->type !=
bp_hardware_watchpoint), to filter out non-write watchpoints.
Otherwise, I think that we could mistakenly insert some write
watchpoints for some pre-existing read watchpoints.
- Because it is possible for read watchpoints to be created before the
target is pushed, remove_watchpoint returns early if it sees that the
code asks for the removal of a read watchpoint, instead of asserting
"type == hw_write" (this was caught by the new test).
The first half of this condition should always be true, due to how
std::upper_bound works.
For the second part: if the watchpoint was created successfully, it
is because it did fully cover the requested region (see
insert_one_watchpoint). I don't see why the core would ask us to
remove a watchpoint that wasn't successfully inserted. I am not 100%
sure about that one, there might be some edge cases where this is not
true.
- I changed a manual free in stopped_by_watchpoint to a
gdb::unique_xmalloc_ptr, even though it changes nothing functionally.
- I merged some conditions in amd_dbgapi_target_normal_stop.
Change-Id: Ia15fb7434dc0c142a5a32997ada2e3a163c89f98 Approved-by: Lancelot Six <lancelot.six@amd.com> Co-Authored-By: Laurent Morichetti <laurent.morichetti@amd.com>
Nick Clifton [Thu, 5 Feb 2026 16:17:59 +0000 (16:17 +0000)]
Objdump: New feature display of global variable info based on DWARF info section
Adds the new option --map-global-vars to objdump. This displays the type and location of global files in binaries that contain suiteable debug information.
Indu Bhagat [Wed, 4 Feb 2026 22:56:58 +0000 (14:56 -0800)]
bfd: sframe: use better wording for error messages
Fix PR ld/33849.
Change the messages to display the owner BFD, together with the section
name. E.g., when mixing SFrame V2 and V3, the linker will now emit
something like:
error in test.o (.sframe); unexpected SFrame format version 2
Alan Modra [Wed, 4 Feb 2026 22:04:31 +0000 (08:34 +1030)]
PR 33593 Misplaced synthetic plt symbols in aarch64 PIE binaries
elfNN_aarch64_plt_sym_val wrongly treats PIEs. PIEs are an executable
but not ET_EXEC, instead being ET_DYN with DF_1_PIE set in DT_FLAGS_1
to distinguish them from shared libraries.
get_plt_type scans .dynamic for DT_AARCH64_BTI_PLT and
DT_AARCH64_PAC_PLT, setting PLT_BTI and PLT_PAC in the function return
value respectively. It's easy enough to extend the .dynamic scan to
also return DF_1_PIE in tdata is_pie.
The patch also makes a few tidies, things I noticed when scanning all
the code dealing with sw_protections.plt_type.
PR 33593
* elfnn-aarch64.c (get_plt_type): Return DF_1_PIE via tdata is_pie.
(elfNN_aarch64_plt_sym_val): Handle PIEs as well as ET_EXEC.
(setup_plt_values): Delete wrong ET_EXEC comments.
(elfNN_aarch64_late_size_sections): Remove excess parentheses.
(elfNN_aarch64_finish_dynamic_sections): Rename type to plt_type,
and simplify test for PLT_BTI or PLT_BTI_PAC.
Tom Tromey [Tue, 3 Feb 2026 20:03:45 +0000 (13:03 -0700)]
Add null check for character type name
The internal AdaCore test suite found that
wchar_printer::get_default_encoding checks the name of a type without
first seeing if the name is null:
else if (streq (chtype->name (), "wchar_t"))
Mysteriously, though, this only seems to happen for certain targets
and perhaps only under certain conditions (I couldn't reproduce it
msyelf).
I felt that the fix is fairly obvious and that this isn't really worth
writing a test for. However I can write one using the DWARF assembler
if someone feels it is worthwhile.
The previous commit fixed an issue where BFD was failing to parse the
NT_PRSTATUS notes in a core file. As a result of this the general
purpose registers were not available to GDB, and as a result GDB would
not add any threads to the inferior when opening a core file.
As GDB requires each inferior to have at least one thread, there is
code in GDB to handle this no-registers case, and add a dummy thread
to the inferior. However, a bug in this code was causing GDB to
crash. It is this crash that the above commit fixed.
This commit adds a test for this fix.
The test contains a Python script which adds a new Python command to
GDB. This Python command can be used to modify an on-disk core file.
The command opens the core file, locates the notes segments, and then
looks through the notes to find NT_PRSTATUS notes. The type value for
these NT_PRSTATUS notes is then changed to a value that GDB doesn't
understand (0xffffffff).
Now when GDB opens the core file the NT_PRSTATUS are no longer
NT_PRSTATUS notes; the core file will appear to have no such notes,
and the previous bug will be triggered.
Running this new test with GDB 16 will trigger the crash. With
current HEAD of master, which includes the above commit, this test
should pass.
I originally wrote the Python script in this test as a standalone
Python script, not as a GDB command, but some of the gcc compiler farm
test machines still have Python 2 as the default. This means that the
corefile-no-threads.exp script would have to figure out which Python
executable to use to run the script.
Much easier to just use GDB's builtin Python interpreter. We know
that this will be at least Python 3.4 (GDB's minimum Python
requirement).
I've tested this on x86-64 in 64-bit and 32-bit mode. And on a big
endian PPC64 machine.
Matthieu Longo [Fri, 30 Jan 2026 18:12:20 +0000 (18:12 +0000)]
aarch64: fix buffer overflow in aarch64-gen
A refactoring in [1] introduced a buffer overflow. A new enum value,
last_iclass, was added at the end of 'enum aarch64_insn_class' to
refer to the last instruction class. This value is then used to size
the array iclass_has_subclasses_p, which is intended to have one
element per enum value.
However, because the enum values start at index 0, last_iclass is
off by one when used as the array length. As a result, the array is
allocated with element too few, leading to a buffer overflow when
accessing the 'lut' class.
The fix adds +1 to last_iclass when defining the array size.
==ERROR: AddressSanitizer: global-buffer-overflow
READ of size 1 at 0x5555556d8d5d thread T0
#0 0x5555555c918d in read_table ./opcodes/aarch64-gen.c:207
#1 0x5555555ca0d1 in initialize_decoder_tree ./opcodes/aarch64-gen.c:435
#2 0x5555555ceaa6 in main ./opcodes/aarch64-gen.c:1386
Andrew Burgess [Thu, 27 Mar 2025 10:53:43 +0000 (10:53 +0000)]
gdb: fix-up truncated inline function block ranges
This commit aims to improve GDB's handling of inline functions. There
are two mechanisms which can tell GDB, or the user of GDB, that the
inferior is within an inline function, these are the block range
associated with an inline instance of a function, and also the line
table, which associates addresses with source lines in the program.
Currently, gcc truncates the address range for, at least some, inline
function blocks, such that a given address is considered outside the
inline function. However, the line table maps that same address to a
line within the inline function.
A consequence of this, is that, when using 'next' to move the inferior
forward, GDB will often stop the inferior believing that the inferior
has left an inline function, and indeed, GDB will claim that the
inferior is in the outer, non-inline function, but GDB will then
display a source line from the inline function as the current location.
An example of this problem can be seen with the test
gdb.cp/step-and-next-inline.exp. Using the
step-and-next-inline-no-header binary that is built as part of the
test:
(gdb) file ./gdb/testsuite/outputs/gdb.cp/step-and-next-inline/step-and-next-inline-no-header
Reading symbols from ./gdb/testsuite/outputs/gdb.cp/step-and-next-inline/step-and-next-inline-no-header...
(gdb) break get_alias_set
Breakpoint 1 at 0x401160: file /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.cp/step-and-next-inline.cc, line 51.
(gdb) run
Starting program: /tmp/build/gdb/testsuite/outputs/gdb.cp/step-and-next-inline/step-and-next-inline-no-header
Breakpoint 1, get_alias_set (t=t@entry=0x404038 <xx>)
at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.cp/step-and-next-inline.cc:51
51 if (t != NULL
(gdb) next
52 && TREE_TYPE (t).z != 1
(gdb) next
43 return x; <------------- Problem line.
(gdb) bt
#0 get_alias_set (t=t@entry=0x404038 <xx>) at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.cp/step-and-next-inline.cc:43
#1 0x000000000040105e in main () at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.cp/step-and-next-inline.cc:64
(gdb)
I've labelled the issue as 'Problem line'. After the second 'next'
GDB stopped thinking it was in get_alias_set, but printed a line from
the inline function behind the TREE_TYPE macro. The 'Problem line'
should have been line 53, not line 43.
The $pc at which GDB stopped is 0x40116f. If we then use 'objdump
--dwarf=decodedline' to view the line table for the executable, this
is what we see:
File name Line number Starting address View Stmt
...
step-and-next-inline.cc 38 0x401165 x
step-and-next-inline.cc 40 0x401165 1 x
step-and-next-inline.cc 40 0x401165 2
step-and-next-inline.cc 40 0x401167
step-and-next-inline.cc 42 0x40116f x
step-and-next-inline.cc 43 0x40116f 1 x
step-and-next-inline.cc 43 0x40116f 2
step-and-next-inline.cc 52 0x40116f 3
step-and-next-inline.cc 52 0x401172
step-and-next-inline.cc 38 0x401177 x
step-and-next-inline.cc 40 0x401177 1 x
step-and-next-inline.cc 40 0x401177 2
...
NOTE: I use objdump to view the line table, not 'maintenance info
line-table' as GDB drops some line table entries that it sees as
irrelevant. Using objdump give a complete view of the line table.
We can see that address 0x40116f is associated with three line
numbers, 42, and 43 are both within the inline function, and 52 is the
line from which the inline function was called. Notice too that 52 is
a non-statement line.
If we now look at the block structure for the previous $pc
value 0x40116e (i.e. $pc - 1), then we see this:
Here we see 'tree_check', the inline function that backs the TREE_TYPE
macro, this is the inline function we have just stepped out of. This
makes sense as the end-address for the tree_check block is 0x40116f,
and as the block's end address is not inclusive, that means that
0x40116f is the first address outside the block, which, is the current
$pc value.
And so, we can see what's going on. When the 'next' starts GDB is in
get_alias_set, GDB steps forward, entering tree_check. GDB then uses
the extent of the block to figure out where the inline function ends,
and steps forward to that address (0x40116f). At this point, GDB
looks up the current line in the line table (43), and reports a stop
at this line.
In this commit, the fix I propose is to look for the line table
pattern seen above, a sequence of line table entries, that end with a
non-statement entry for the calling line of an inline function,
located at the exact end address of an inline function block.
When such a pattern is found, then we can extend the inline function's
address range to the next line table address, so long as doing so does
not extend the inline function beyond the extent of the containing,
non-inline, function.
In the above example, the block for the tree_check function would be
extended to end at 0x401172. With this fix in place, and with the
same test binary, GDB now behaves like this:
(gdb) break get_alias_set
Breakpoint 1 at 0x401160: file /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.cp/step-and-next-inline.cc, line 51.
(gdb) run
Starting program: /tmp/build/gdb/testsuite/outputs/gdb.cp/step-and-next-inline/step-and-next-inline-no-header
Breakpoint 1, get_alias_set (t=t@entry=0x404038 <xx>)
at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.cp/step-and-next-inline.cc:51
51 if (t != NULL
(gdb) next
52 && TREE_TYPE (t).z != 1
(gdb) next
53 && TREE_TYPE (t).z != 2
(gdb)
The block for the inline function has been updated, like this:
This original patch series from Bernd Edlinger contains a number of
different fixes, some have already been split out and merged into GDB,
but the core idea for how to improve inline function handling by
extending the inline block range is the same, however, the mechanism
Bernd uses is significantly different.
In the above series, the approach taken is to mark the line table at
the end address of an inline function, and a few addresses beyond
that (see the is-weak flag in the above series). Then, when looking
up the block for a given address, if the address is within this marked
region, then we actually return the previous (inline function) block.
I believe that the above is a fair high-level summary of how the above
patch solves the inline function range problem. Any differences are
down to my misunderstanding the above patch, for which I apologise.
My problem with the above patch is that it breaks what I think should
be an invariant of GDB, that when looking up a block for a given
address, the block returned must contain the address within its
ranges. I feel that, if we start to break this invariant, then we
risk introducing bugs within, e.g. the stepping control code.
In contrast, my approach solves this problem during the DWARF parsing,
where problem cases are identified, and the DWARF "fixed" by extending
the block ranges. After this, no additional changes are needed in
GDB, the address to block mapping can work as normal, and the stepping
logic can continue to work just as it always has.
The test changes for gdb.cp/step-and-next-inline.exp have been taken
from Bernd's original patch series, and I've added a Co-Author tag for
Bernd to reflect this, as well as for the inspiration that I took from
his original series when creating this alternative proposal.
If/when this patch is merged, I plan to follow up with some cleanup to
the test case gdb.cp/step-and-next-inline.exp. I think this test
should really be moved to gdb.opt/, it's really testing optimisation
debug, not C++ features, but also the structure of the test file is a
bit of a mess. I think with some restructuring we could make the test
more readable, and also, maybe, test some additional compiler
flags (e.g. more optimisation levels). I've not done the refactoring
in this patch in order to make it clearer what new tests I've added,
and also, I want to leave the test similar to what's in Bernd's
original series, to make comparison easier.
The gdb.cp/step-and-next-inline.exp test was originally added by me
back in 2019, so the problems with it are of my own making.
For testing I've obviously run the entire test suite, but of
particular interest are these tests:
I've run these tests with a range of different gcc versions: 9.5.0,
10.5.0, 11.5.0, 12.2.0, 13.3.0, 14.2.0, 15.1.0. These tests all
relate to optimised debug of inline functions, and all passed with all
compiler versions listed here.
Andrew Burgess [Thu, 20 Mar 2025 11:07:02 +0000 (11:07 +0000)]
gdb: record block end addresses while parsing DIEs
Continuing to work towards the goal of improving GDB's ability to
debug optimised code, this commit stores a map from the end address
of a block (or a block's sub-range) to the block pointer. This
information is collected while parsing the DIEs.
This new map is required as a consequence of the previous commit. The
optimised code fix ups require that we can map from an address back to
a block, something that the address map was perfect for, but the
previous commit deferred building the address map until later on.
The problem is that the optimised code fixes in the next commit
require the address to block map, but also adjust block ranges, which
invalidates the address to block map. We could try to build the full
address to block early on, and then update it as the optimised code
fixes are performed, but this is expensive.
The solution I propose is to build a light weight, partial map, that
only holds the interesting (inline) blocks. This partial map is only
needed between reading the DIE and applying the optimised code fixes,
after which it is done with, and as a consequence we don't need to
update this map as the optimised code fixes adjust block ranges, this
makes the partial map cheaper.
This commit is all about building the new partial map. Currently,
nothing is done with this information; the information is recorded as
the block ranges are parsed, and then discarded after the line table
has been built. But in the next commit, this will be used to help
adjust the ranges of some inline blocks, and this will improve GDB's
ability to debug optimised code.
There should be no user visible changes after this commit.
Andrew Burgess [Mon, 5 Jan 2026 13:44:59 +0000 (13:44 +0000)]
gdb: remove buildsym_compunit::record_block_range
After the last commit I realised that the function
buildsym_compunit::record_block_range is not really needed any more.
This function is basically checking for non-contiguous blocks, and
setting m_pending_addrmap_interesting when a non-contiguous block is
seen.
We can move this check into buildsym_compunit::make_blockvector which
is the only place m_pending_addrmap_interesting is used, we already
loop over all blocks in this function.
This allows us to remove record_block_range and
m_pending_addrmap_interesting from buildsym_compunit.
There is one weird thing in this patch, in dwarf2/read.c, the function
dwarf2_record_single_block_range is now empty, but I've retained this
function. A later patch in this series adds some code back into this
function, so I don't want to delete it here.
Andrew Burgess [Thu, 26 Jun 2025 10:38:53 +0000 (11:38 +0100)]
gdb: create address map after parsing all DIE
Continuing the work done in the last two commits, this commit defers
building the addrmap for a blockvector until after all the DIE have
been read, and the line table processed.
The benefit of this is that any changes to a block's ranges done
during line table processing (see the next commit) will be reflected
in the blockvector's addrmap.
The alternative to this is to build the addrmap as we initially see
each block, but then adjust the addrmap if we later decide to modify a
block. I think deferring the addrmap creation is cleaner, and is less
work overall.
The addrmap requires that we add the innermost blocks first. I
achieve this by walking the blockvector backward, as we always add
parent blocks before their more inner child blocks.
However, the blocks are not added to the blockvector in exactly the
same order as we recorded them before this patch. The key difference
here is that sibling blocks might not appear in the block vector in
the same order as we parsed them from the DWARF.
So long as sibling blocks don't overlap, this shouldn't make any
difference to the final addrmap that is constructed. But if the
sibling blocks do overlap, then there might be an observable change in
behaviour after this patch. But it is not clear to me how critical
this change actually is. As far as I can tell from my experiments, if
two siblings overlap then, for the overlap region, GDB is only able to
find information (e.g. local variables) from one sibling. This is
true before and after this patch, but which sibling is found might
change.
Andrew Burgess [Thu, 20 Mar 2025 10:46:31 +0000 (10:46 +0000)]
gdb: move block range recording into its own function
Like the previous commit, this is a refactor that makes a later commit
in this series easier. The later commit improves GDB's ability to
debug optimised code. To do this I propose to "fix" the address
ranges of some inline blocks.
In order to know which blocks to fix, I need to record the end address
of inline blocks.
And so, I'd like to create a single common function where block ranges
are recorded, in a later commit I can then hook into this function to
record the block's end address(es). This commit sets up this single
common function.
The new function I'm adding dwarf2_record_single_block_range, takes a
currently unused argument unrel_high. This argument will be needed in
the later commit. I've added it now as this will allow the later
commit to be smaller and more focused. I only plan to push this
commit as part of the larger series, so I don't think adding
the (currently) unused argument is too much of a problem.
There should be no user visible change after this commit.
Andrew Burgess [Mon, 17 Mar 2025 15:41:25 +0000 (15:41 +0000)]
gdb: split dwarf line table parsing in two
A later commit in this series, that improves GDB's ability to debug
optimised code, wants to use the line table information in order to
"fix" inline blocks with a truncated address range. For the reasoning
behind wanting to do that, please read ahead in the series.
Assuming that we accept for now the need to use the line table
information to adjust the block ranges, then why is this commit
needed?
GDB splits the line table data info different symtabs, adding end of
sequence markers as we move between symtabs. This seems to work fine
for GDB, but causes a problem for me in this case.
What I will want to do is this: scan the line table and spot line
table entries that corresponds to the end addresses of an inline
block's address range. If the block meets certain requirements, then
the end address of the block is adjusted to be that of the next line
table entry.
The way that GDB currently splits the line table entries between
symtabs makes this harder. I will have the set of blocks end
addresses which I know might be fixable, but to find the line table
entry corresponding to that address requires searching through all the
symtabs. Having found the entry for the end address, I then need to
find the next line table entry. For some blocks this is easy, it's
the next entry in the same symtab. But for other blocks the next
entry might be in a different symtab, which requires yet another full
search.
I did try implementing this approach, but the number of full symtab
searches is significant, and it had a significant impact on GDB's
debug parsing performance. The impact was such that an operation that
currently takes ~7seconds would take ~3minutes or more. Now I could
possibly improve that 3 minutes figure by optimising the code some,
but I think that would add unnecessary complexity.
By deferring building the line table until after we have parsed the
DIEs it becomes simple to spot when a line table entry corresponds to
a block end address, and finding the next entry is always trivial, as,
at this point, the next entry is just the next entry which we will
process. With this approach I see no noticable impact on DWARF
parsing performance.
This patch is just the refactoring. There's no finding block end
addresses and "fixing" being done here. This just sets things up for
the later commits.
The existing code has a single function handle_DW_AT_stmt_list which
loads the line table header and then calls dwarf_decode_lines to
decode the line table itself, splitting the line table entries between
symtabs.
After this commit handle_DW_AT_stmt_list is renamed to
decode_line_header_for_cu, this loads the line table header and
creates the symtabs based off the line table, but doesn't process the
line table. The dwarf_decode_lines function is no longer called at
this point.
In read_file_scope is where dwarf_decode_lines is now called. This
relies on the line table having been loaded earlier, and processes the
line table entries, splitting them between symtabs.
There should be no user visible changes after this commit.
That series has the fixes here merged along with other changes, and
takes a different approach for how to handle the issue addressed here.
Credit for identifying the original issue belongs with Bernd, the
author of the original patch, who I have included as a co-author on
this patch. A brief description of how the approach taken in this
patch differs from the approach Bernd took can be found at the end of
this commit message.
When compiling with optimisation, it can often happen that gcc will
emit an inline function instance with an empty range associated. This
can happen in two ways. The inline function might have a DW_AT_low_pc
and DW_AT_high_pc, where the high-pc is an offset from the low-pc, but
the high-pc offset is given as 0 by gcc.
Alternatively, the inline function might have a DW_AT_ranges, and one
of the sub-ranges might be empty, though usually in this case, other
ranges will be non-empty.
The second case is made worse in that sometimes gcc will specify a
DW_AT_entry_pc value which points to the address of the empty
sub-range.
My understanding of the DWARF spec is that empty ranges as seen in
these examples indicate that no instructions are associated with the
inline function, and indeed, this is how GDB handles these cases,
rejecting blocks and sub-ranges which are empty.
DWARF-5, 2.17.2, Contiguous Address Range:
The value of the DW_AT_low_pc attribute is the address of the
first instruction associated with the entity. If the value of the
DW_AT_high_pc is of class address, it is the address of the first
location past the last instruction associated with the entity...
DWARF-5, 2.17.3, Non-Contiguous Address Ranges:
A bounded range entry whose beginning and ending address offsets
are equal (including zero) indicates an empty range and may be
ignored.
As a consequence, an attempt by the user to place a breakpoint on an
inline function with an empty low/high address range will trigger
GDB's pending breakpoint message:
(gdb) b foo
Function "foo" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
While, having the entry-pc point at an empty range forces GDB to
ignore the given entry-pc and select a suitable alternative.
If instead of ignoring these empty ranges, we instead teach GDB to
treat these as non-empty, what we find is that, in all the cases I've
seen, the debug experience is improved.
As a minimum, in the low/high case, GDB now knows about the inline
function, and can place breakpoints that will be hit. Further, in
most cases, local variables from the inline function can be accessed.
If we do start treating empty address ranges as non-empty then we are
deviating from the DWARF spec. It is not clear if we are working
around a gcc bug (I suspect so), or if gcc actually considers the
inline function gone, and we're just getting lucky that the debug
experience seems improved.
My proposed strategy for handling these empty address ranges is to
only perform this work around if the compiler is gcc, so far I've not
seen this issue with Clang (the only other compiler I've tested),
though extending this to other compilers in the future would be
trivial.
Additionally, I only apply the work around for
DW_TAG_inlined_subroutine DIEs, as I've only seen the issue for
inline functions.
If we find a suitable empty address range then the fix-up is to give
the address range a length of 1 byte.
Now clearly, in most cases, 1 byte isn't even going to cover a single
instruction, but so far this doesn't seem to be a problem. An
alternative to using a 1-byte range would be to try and disassemble
the code at the given address, calculate the instruction length, and
use that, the length of one instruction. But this means that the
DWARF parser now needs to make use of the disassembler, which feels
like a big change that I'd rather avoid if possible.
The other alternative is to allow blocks to be created with zero
length address ranges and then change the rest of GDB to allow for
lookup of zero sized blocks to succeed. This is the approach taken by
the original patch series that I linked above.
The results achieved by the original patch are impressive, and Bernd,
the original patch author, makes a good argument that at least some of
the problems relating to empty ranges are a result of deficiencies in
the DWARF specification rather than issues with gcc.
However, I remain unconvinced. But even if I accept that the issue is
with DWARF itself rather than gcc, the question still remains; should
we fix the problem by synthesising new DWARF attributes and/or accept
non-standard DWARF during the dwarf2/read.c phase, and then update GDB
to handle the new reality, or should we modify the incoming DWARF as
we read it to make it fit GDB's existing algorithms.
The original patch, I believe, took the former approach, while I
favour the later, and so, for now, I propose that the single byte
range proposal is good enough, at least until we find counter examples
where this doesn't work.
This leaves just one question: what about the remaining work in the
original patch. That work deals with problems around the end address
of non-empty ranges. The original patch handled that case using the
same algorithm changes, which is neat, but I think there are
alternative solutions that should be investigated. If the
alternatives don't end up working out, then it's trivial to revert
this patch in the future and adopt the original proposal.
For testing I have two approaches, C/C++ test compiled with
optimisation that show the problems discussed. These are good because
they show that these issues do crop up in compiled code. But they are
bad in that the next compiler version might change the way the test is
optimised such that the problem no longer shows.
And so I've backed up the real code tests with DWARF assembler tests
which reproduce each issue.
The DWARF assembler tests are not really impacted by which gcc version
is used, but I've run all of these tests using gcc versions 8.4.0,
9.5.0, 10.5.0, 11.5.0, 12.2.0, and 14.2.0. I see failures in all of
the new tests when using an unpatched GDB, and no failures when using
a patched GDB.
Alan Modra [Tue, 3 Feb 2026 21:01:26 +0000 (07:31 +1030)]
objdump -d with -j and objdump disassembly of .plt
objdump -D disassembles non-code sections, paying no heed to symbols
in those sections. I think "objdump -d -j .data" should do the same,
ie. not switch into dumping the section as data because an object
symbol is encountered.
On the other hand, dissassembly of .plt which is a code section, can
dump the first part of .plt as data due to the presense of
_PROCEDURE_LINKAGE_TABLE_. Fix that too.
Alan Modra [Tue, 3 Feb 2026 20:22:55 +0000 (06:52 +1030)]
ctf_dump_objts output string
"Section is indexed" and "No symbol table" are generated at the
beginning of ctf_dump_objts but not output, resulting in an asan
complaint about leaked memory. Clearly the messages should either not
be generated, or they should be output. I chose to do the latter in
this patch, which requires some testsuite adjustment.
libctf/
* ctf-dump.c (ctf_dump_objts): Output "Section is indexed" and
"No symbol table" strings, enclosed in parentheses and
indented.
ld/
* testsuite/ld-ctf/data-func-conflicted-vars.d: Update.
* testsuite/ld-ctf/data-func-conflicted.d: Update.
Tom de Vries [Tue, 3 Feb 2026 16:45:38 +0000 (17:45 +0100)]
[pre-commit] Require pre-commit v4.5.1
In December 2025, pre-commit v4.5.1 was released. We currently require v3.2.0
(released in March 2023), or later.
It occurred to me that allowing such a large range of releases might lead to
developers experiencing different behaviors, perhaps running into bugs that
are already fixed in later releases.
Fix this by requiring the latest release, v4.5.1.
The drawback is that we now require a more recent python: v3.10.
[ In more detail, pre-commit requires:
- at v3.2.0, python 3.8
- since v3.6.0, python 3.9
- since v4.4.0, python 3.10. ]
Tested on x86_64-linux, python 3.13.11 by doing "pre-commit run --all-files".
Tom Tromey [Sun, 1 Feb 2026 21:42:30 +0000 (14:42 -0700)]
Convert dw2-case-insensitive.exp to DWARF assembler
I used contrib/dwarf-to-dwarf-assembler.py to convert
dw2-case-insensitive.exp to use the DWARF assembler. The output
needed some minor changes to fully work, but not really all that much.
The .c file also needed a small change, and I went ahead and removed
other extraneous code.
Tom Tromey [Tue, 27 Jan 2026 02:27:01 +0000 (19:27 -0700)]
Remove "readnow" from two tests
These tests both claim that -readnow is needed for proper operation,
but (1) this isn't true, and (2) if it were true it would be a bug in
gdb. So, remove the use of readnow.
Tom de Vries [Mon, 2 Feb 2026 20:36:48 +0000 (21:36 +0100)]
[gdb/testsuite] Use valnum_re more often (part 3)
Also transform '\\\$\[0-9\].*' into valnum_re, assuming that '\\\$\[0-9\]+' was
meant.
Done using these commands to cover '\\\$' vs '\\$' and '\[0-9\]' vs '\[0-9]':
...
find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\\\$\\\[0-9\\\]\.\*/${::valnum_re}/g'
find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\\\$\\\[0-9\]\.\*/${::valnum_re}/g'
find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\$\\\[0-9\\\]\.\*/${::valnum_re}/g'
find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\$\\\[0-9\]\.\*/${::valnum_re}/g'
...
Tom de Vries [Mon, 2 Feb 2026 20:36:48 +0000 (21:36 +0100)]
[gdb/testsuite] Use valnum_re more often (part 2)
Also transform '\\\$\[0-9\]*' into valnum_re, assuming that '\\\$\[0-9\]+' was
meant.
Done using these commands to cover '\\\$' vs '\\$' and '\[0-9\]' vs '\[0-9]':
...
$ find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\\\$\\\[0-9\\\]\*/${::valnum_re}/g'
$ find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\\\$\\\[0-9\]\*/${::valnum_re}/g'
$ find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\$\\\[0-9\\\]\*/${::valnum_re}/g'
$ find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\$\\\[0-9\]\*/${::valnum_re}/g'
...
Tom de Vries [Mon, 2 Feb 2026 20:36:48 +0000 (21:36 +0100)]
[gdb/testsuite] Use valnum_re more often (part 1)
Use valnum_re more often. Do this by replacing "\\\$\[0-9\]+" and similar.
I ran these commands handling 6 variants of $decimal:
...
$ find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\\\$\\\[0-9\\\]+/${::valnum_re}/g
$ find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\\\$\\\[0-9\]+/${::valnum_re}/g'
$ find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\\\$$decimal/${::valnum_re}/g'
$ find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\\\$$::decimal/${::valnum_re}/g'
$ find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\\\$${decimal}/${::valnum_re}/g'
$ find gdb/testsuite/ -type f -name *.exp* \
| xargs sed -i 's/\\\\\\$${::decimal}/${::valnum_re}/g'
...
and then once more matching '\\$' instead of '\\\$'.
Andrew Burgess [Mon, 2 Feb 2026 18:39:40 +0000 (18:39 +0000)]
gdb/testsuite: disable progress bars for new debuginfod test
The recently added gdb.debuginfod/solib-with-dwz.exp test script
wasn't disabling progress bars. This makes the gdb.log harder to
read. Add the line to turn progress bars like we do in all the other
debuginfod tests.
There should be no change in what is actually being tested after this
commit.
Tom de Vries [Mon, 2 Feb 2026 18:22:51 +0000 (19:22 +0100)]
[gdb/testsuite] Fix pi approximation
In gdb.dap/ada-non-ascii/prog.adb, I came across the following:
...
π : Integer := 3; -- The Indiana Approximation.
...
This article [1] explains the background behind the comment: the Indiana pi
bill.
Given that the common interpretation seems to be that the bill implies that
π == 3.2 [2]:
...
The bill ... has been claimed to imply a number of different values for π,
although the closest it comes to explicitly asserting one is the wording "the
ratio of the diameter and circumference is as five-fourths to four", which
would make π = 16⁄5 = 3.2, ... .
...
change the type to float, and set it to 3.2.
Luckily, in this particular case, changing the approximation of π has no
effect, so the test-case still passes :) .
Tested on x86_64-linux.
Approved-by: Kevin Buettner <kevinb@redhat.com>
[1] https://en.wikipedia.org/wiki/Indiana_pi_bill
[2] https://en.wikipedia.org/wiki/Approximations_of_pi#Indiana_bill
Simon Marchi [Mon, 26 Jan 2026 17:01:17 +0000 (12:01 -0500)]
gdb/dwarf: turn some errors into asserts
There are some nullptr checks on the return value of load_cu that I
think can't possibly ever be true. load_cu returns nullptr only if the
CU is "dummy". A "dummy" CU is one that has a header but no DIE. The
body (the part after the header, included in the unit reported by the
header) is either empty or consists only of zeroes (null entries).
In the various spots I modified we are doing some work (e.g. evaluating an
expression) in the context of PER_CU, so PER_CU can't possibly be empty
/ dummy.
Change those conditions to asserts. No behavior change expected, unless
my reasoning is incorrect.
Change-Id: Ic8b0614a15d82d0aaadb8182ee641662cc71dc54 Approved-by: Kevin Buettner <kevinb@redhat.com>
Simon Marchi [Mon, 26 Jan 2026 15:54:00 +0000 (10:54 -0500)]
gdb: tighten assertions in set_type_vptr_*
In C++, only structures and classes (represented by TYPE_CODE_STRUCT)
can participate in inheritance. I therefore think it does not make
sense to allow for TYPE_CODE_UNION in set_type_vptr_basetype and
set_type_vptr_fieldno. Remove the possibility for the type to be a
union in these functions.
Also, for the same reason, add an assertion that checks the type of
basetype in set_type_vptr_basetype.
I did not change the getters (internal_type_vptr_fieldno and
internal_type_vptr_basetype), because it seems like they are called by
code that handles similarly both structures and unions. Making those
stricter would require adding conditions in those callers, which doesn't
look like an improvement. For unions, they will correctly return an
"invalid" value.
Change allocate_cplus_struct_type to not use set_type_vptr_fieldno to
initialize the field to -1, otherwise it would trip the assertion when
initializing for a union type.
Change-Id: Id9b2dc288f24d50eb50da46782b5ec6de5682e81 Approved-by: Kevin Buettner <kevinb@redhat.com>
Tom de Vries [Mon, 2 Feb 2026 14:48:38 +0000 (15:48 +0100)]
[gdb/doc] Use '@:' after abbreviation
In gdb/doc/gdb.texinfo, we have:
...
For every type there is also a default kind associated with it, e.g.@
@code{Integer} in @value{GDBN} will internally be an @code{Integer*4} (see the
table below for default types).
...
While the @NL command [1] does probably prevent the sentence ending at 'e.g.',
the usual way to accomplish this is to use '@:' [2], so use that instead.
Andrew Burgess [Wed, 21 Jan 2026 12:25:43 +0000 (13:25 +0100)]
gdb: fix gdb.base/inline-frame-cycle-unwind.exp for s390x
With test-case gdb.base/inline-frame-cycle-unwind.exp on s390x-linux, I run
into:
...
(gdb) bt
#0 inline_func () at inline-frame-cycle-unwind.c:49
#1 normal_func () at inline-frame-cycle-unwind.c:32
#2 0x000000000100065c in inline_func () at inline-frame-cycle-unwind.c:45
#3 normal_func () at inline-frame-cycle-unwind.c:32
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) FAIL: $exp: bt: cycle at level 5: backtrace when the unwind is broken \
at frame 5
...
In contrast, on x86_64-linux, I get:
...
(gdb) bt
#0 inline_func () at inline-frame-cycle-unwind.c:49
#1 normal_func () at inline-frame-cycle-unwind.c:32
#2 0x0000000000401157 in inline_func () at inline-frame-cycle-unwind.c:45
#3 normal_func () at inline-frame-cycle-unwind.c:32
#4 0x0000000000401157 in inline_func () at inline-frame-cycle-unwind.c:45
#5 normal_func () at inline-frame-cycle-unwind.c:32
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) PASS: $exp: bt: cycle at level 5: backtrace when the unwind is broken \
at frame 5
...
To understand what's going wrong here, we first need to understand
what this test was trying to do.
The test tries to create a frame-cycle using a custom Python
unwinder. A frame-cycle occurs when a frame in the backtrace has the
same frame-id as an earlier frame. As soon as GDB finds a frame with
a frame-id that it has seen before then the backtrace will be
terminated with the message:
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
A Python frame unwinder does two jobs:
- It provides the frame-id for a frame #n, and
- it provides the unwound register values for the previous (#n + 1)
frame.
For a frame not claimed by a Python frame unwinder, GDB will compute
the frame-id based off of the register values. Particularly, the $pc
and $sp, or $fp registers (or the architecture's equivalent).
In this test then, our frame unwinder does something a little
strange. When we want to stop at frame #5, the frame unwinder claims
frame #5. The frame unwinder then tries to give frame #5 its "normal"
frame-id, but, instead of unwinding the register values, we provide
frame #6 with all of the register values from frame #5 unmodified.
The frame unwinder does not claim frame #6, instead GDB uses its
"normal" logic to compute the frame-id. As the registers in frame #6
are identical to the values in frame #5, GDB computes the same
frame-id for frame #6 as we supplied for frame #5, and thus a frame
cycle is created.
Notice I said that we try to give frame #5 its "normal" frame-id.
When this test was originally written there was no easy way to access
the frame-id for a frame. So instead, the test was written to try and
recreate the frame-id based on the frame stack pointers, and the frame
size (difference between subsequent frames). And this worked fine for
a bunch of common architectures, like x86-64 and AArch64.
But unfortunately this frame-id computation doesn't work on s390.
For this explanation we only care about two parts of the frame-id, the
code address, and the stack address. The code address part is usually
the start of the function for a particular frame. Our computation of
this was fine.
The stack address in the frame-id isn't the actual $sp value.
Instead, this is usually the Call Frame Address (CFA) as defined in
the DWARF. How this is calculated really depends on the DWARF, but is
often influenced by the architectures ABI.
On x86-64 and AArch64 the CFA is usually the $sp immediately on entry
to a frame, before any stack adjustment is performed. Thus, if we
take the frame size (difference between $sp in two frames), and add
this to the current $sp value, we successfully calculate the CFA,
which we can use in the frame-id.
On s390 though, this is not the case, the calculation of the CFA is
more complex as the s390 ABI requires that caller frames allocate a
160 byte Register Save Area below the stack pointer. Because of this,
when the Python unwinder ties to calculate the real frame-id for a
frame, it gets the CFA wrong, and inadvertently ends up calculating a
frame-id which matches an earlier frame-id. In the example above,
frame #5 ends up matching frame #3. Because frame #4 is an inline
frame GDB ends up terminating the backtrace after frame #3.
The fix for this is actually pretty simple. Since this test was
originally written GDB has gained the 'maint print frame-id' command.
So instead of trying to calculate the frame-id we can just capture the
frame-ids that GDB generates, and then, once the Python frame unwinder
is in use, we can repeat the previously captured frame-id back to
GDB.
This fixes the issues seen on s390, and doesn't impact testing on the
other architectures.
Simon Marchi [Sat, 31 Jan 2026 04:32:49 +0000 (23:32 -0500)]
gdb/dwarf: make abbrev_table_cache read-through, make it mandatory
This patch implements some performance improvements initially sent as
part of this series [1], but now as a single patch. There was some push
back from Tom regarding the increased memory usage, but I think that my
solution is still desirable: it makes the code simpler, and I think that
the memory usage it not an issue (the usage is transient and the amount
of memory used by the abbrev tables is relatively low).
As a reminder, here is the problem I'm looking to solve: when using
split DWARF (.dwo files) plus type units, all units inside a .dwo file
(generally one compile unit plus many type units) share the same abbrev
table. So we end up re-reading that same abbrev tables many times, and
its gets very noticeable in function process_skeletonless_type_units.
cooked_index_worker_debug_info::process_type_units does some work to
avoid this problem, but it only works when everything is in the main
file (not using split DWARF).
Right now, we cache abbrev tables only in specific cases during
indexing, like when one CU imports things from another CU. My previous
series changed cutu_reader so that it would add any abbrev table it
would read to the abbrev table cache (if it was passed one as a
parameter). This allowed using a cache in
process_skeletonless_type_units and cut the time down significantly.
This patch goes a bit further in order to simplify cutu_reader even
further:
- It makes the abbrev table cache read-through, meaning that when you
request an abbrev table and it's not in the cache, it will go read
it (and cache it).
- It makes passing an abbrev table cache to the constructors mandatory
(even when we wouldn't benefit from using a cache).
The result is that cutu_reader doesn't need to manage multiple cases of
how to obtain an abbrev table, and it doesn't need to manage adding
abbrev tables to the cache. It no longer needs to manage the ownership
of the abbrev tables either: the abbrev tables are always owned by the
cache. And the cases of abbrev table sharing are well handled
transparently.
This means that we pay a small price when we don't necessarily need to
(sometimes building and destroying an abbrev_table_cache for just one
cutu_reader), but I think that this price is not significant and the
code simplification is welcome.
In concrete terms, this patch:
- changes abbrev_table_cache::find to become abbrev_table_cache::get,
making it read-through
- removes abbrev_table_cache::add
- removes the abbrev_table parameter from the main cutu_reader
constructor
- makes the abbrev_table_cache parameter mandatory (a reference) in the
main cutu_reader constructor, adds it to the alternative constructor,
and passes it down to a few methods
- adjusts the cutu_reader code obtaining an abbrev table to just call
abbrev_table_cache::get
- adjusts all the cutu_reader users to pass an abbrev_table_cache (if
not already)
- removes the code in
cooked_index_worker_debug_info::process_type_units meant to
efficiently handle TUs that share abbrev tables - the cache now does
this
The specific split DWARF + type units performance problem at the origin
of this work gets fixed by the fact that
cooked_index_worker_debug_info::process_skeletonless_type_unit now
passes an abbrev table cache to cutu_reader, and
cutu_reader::read_cutu_die_from_dwo uses it.
As a test, I'm using a build of Blender compiled with -gsplit-dwarf and
-fdebug-types-section. I run this:
$ ./gdb -nx -q --data-directory=data-directory -ex 'maint set dwarf sync on' -ex 'maintenance set per-command time on' -ex "file /data1/smarchi/blender-build/relwithdebinfo-clang-debugtypes-splitdwarf/bin/blender" -batch
and look at the time taken by the "DWARF skeletonless type units"
step. Before looks like:
Time for "DWARF skeletonless type units": wall 11.131, user 10.699, sys 0.431, user+sys 11.130, 100.0 % CPU
and after looks like:
Time for "DWARF skeletonless type units": wall 1.751, user 1.221, sys 0.518, user+sys 1.739, 99.3 % CPU
The total run time (wall clock time) of the command goes from about 18.5
seconds to about 9.5 seconds.
I removed this assert in cutu_reader, because it relies on abbrev_cache
as a flag for whether we're in the indexer:
/* If an existing_cu is provided, a dwarf2_cu must not exist for
this_cu in per_objfile yet. Here, CACHE doubles as a flag to
let us know that the CU is being scanned using the parallel
indexer. This assert is avoided in this case because (1) it
is irrelevant, and (2) the get_cu method is not
thread-safe. */
gdb_assert (abbrev_cache != nullptr
|| per_objfile.get_cu (&this_cu) == nullptr);
It's not clear to me if this assert is important or how to implement it
differently.
Tom Tromey [Sun, 14 Dec 2025 15:23:30 +0000 (08:23 -0700)]
Introduce character-printing class
This patch introduces a new class for printing character and string
literals by rewriting some code in valprint. The new class is
designed to be subclassed to provide language-specific character
printing.
Tom Tromey [Sun, 13 Feb 2022 18:05:46 +0000 (11:05 -0700)]
Change generic_emit_char to print the quotes
All callers of generic_emit_char print the quotes around the
character, then pass the quote character to the function. It seemed
better to just have generic_emit_char print the quotes itself.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Tom Tromey [Sun, 13 Feb 2022 16:21:20 +0000 (09:21 -0700)]
Remove language_defn::emitchar
Nothing outside of the specific language implementations ever calls
language_defn::emitchar. This patch removes this method and updates
the rest of the code. In some spots, the method is entirely removed;
in others, just the 'override' is removed.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Tom Tromey [Sat, 18 Oct 2025 18:25:04 +0000 (12:25 -0600)]
Add quotemeta to gdb test suite
AdaCore has an internal test suite written in Python. One nice
facility it has is called "quotemeta", and it is an alternative to
using regular expressions to match gdb output.
This patch adds a similar library, written in Tcl, to the gdb test
suite. The idea here is to simplify certain kinds of checks and to
avoid the painful combination of both Tcl and regexp quoting.
There is a comment in the code that explains quotemeta in detail. If
you've used the AdaCore test suite, note that this implementation has
some extensions, namely the @{...} forms. (I do wonder here if <...>
would be a better choice, to avoid Tcl issues with braces.)
I've converted part of a Rust test case to demonstrate the effect.
The most dramatic example is this change:
At least for me the latter is much easier to understand; and also it
doesn't cheat on the history part of the output, because it's less
painful to do this properly now.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33551 Reviewed-By: Tom de Vries <tdevries@suse.de>
Alan Modra [Fri, 30 Jan 2026 20:35:55 +0000 (07:05 +1030)]
readelf vs. mapping symbols
This reverts commit 45cf0b829303, which isn't needed after commit 6d7e5bcca5. Mapping symbols are like any other local symbol, and
shouldn't appear after the end of a section.
The real bug that resulted in both of these commits is that st_value
in an executable or shared library is the symbol address. It was
wrong to compare an address against a section size (you'd need to
subtract off the section vma first). The second commit limited the
warning to ET_REL where st_value is a section offset and thus can be
compared directly to the section size.
Add simple tests that verify the behavior of garbage collection of
SFrame sections during linking.
x86_64-specific tests:
- sframe-gc-sections-1.d checks that none of the functions get
discarded with --gc-sections
- sframe-gc-sections-2a.d checks the behavior of --gc-sections with two
distinct .text.* sections (similar to -ffunction-sections compiler
option)
- sframe-gc-sections-2b.d checks the same behaviour as
sframe-gc-sections-2a.d, but with a linker script that discards
.eh_frame sections. This testcase is keep it ensured that the two
section's GC behaviours are not unnecessarily inter-twined.
All targets supporting sframe tests:
- pr32769.rd simple linking test in presence of --gc-sections
option.
- pr32769-2.d checks the behavior of --gc-sections with two .text.*
sections, one section is discarded
- pr32769-2r.d Like the above, but using -r option when linking and
checking for the relocations.
- pr32769-3.d checks the behavior of --gc-sections with multiple
sections, none is drop.
ld: bfd: sframe: KEEP .sframe sections and support gc-sections
Fix PR ld/32769
Currently, specifying --gc-sections causes the linker to discard all
input .sframe sections. Fix this behaviour by adding KEEP for .sframe
sections, like it is being done for .eh_frame sections, in the default
ELF linker script.
Additionally, add logic in the linker to gc mark .sframe sections.
_bfd_elf_gc_mark () now is aware of SFrame sections. It relies on
elf_section_sframe () to get the SFrame section associated with the
text section.
Also, the _bfd_elf_parse_sframe is changed to return TRUE when the
input sframe section is already parsed. It fixes calling
_bfd_elf_discard_section_sframe function in bfd_elf_discard_info,
enabling correct behavior for discarding unneeded sframe sections.
Indu Bhagat [Fri, 30 Jan 2026 04:02:57 +0000 (20:02 -0800)]
include: libsframe: rename SFrame V3 Flexible FDE macros to CTRLWORD
The existing SFrame V3 macros for Flexible FDEs used the term 'OFFSET'
to refer to the data word encoding control/register data word. This can
be confusing, as the control data word (register ID, dereference flags)
is distinct from a stack offset.
This patch renames these macros to use 'CTRLWORD' to better reflect
their purpose. It also updates the assembler and libsframe dumper to
use the new nomenclature.
No functional change.
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
gas/
* gen-sframe.c (sframe_get_fre_dataword_size): Use
SFRAME_V3_FLEX_FDE_CTRLWORD_ENCODE.
(output_sframe_row_entry_datawords): Likewise.
include/
* sframe.h (SFRAME_V3_FLEX_FDE_REG_ENCODE): Rename from ..
(SFRAME_V3_FLEX_FDE_CTRLWORD_ENCODE): .. to.
(SFRAME_V3_FLEX_FDE_CTRLWORD_REGNUM): Rename from
SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM to this.
(SFRAME_V3_FLEX_FDE_CTRLWORD_DEREF_P): Rename from
SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P to this.
(SFRAME_V3_FLEX_FDE_CTRLWORD_REG_P): Rename from
SFRAME_V3_FLEX_FDE_OFFSET_REG_P to this.
(SFRAME_V3_FRE_RA_UNDEFINED_P): Add new V3 macro.
libsframe/
* sframe-dump.c (dump_sframe_func_fres_flex): Update all
callers to use the new CTRLWORD macros.
libsframe/testsuite/
* libsframe.decode/be-flipping-v3.c: Use renamed macros.
Tom Tromey [Thu, 22 Jan 2026 20:31:12 +0000 (13:31 -0700)]
Remove alloca from lookup_cmd
lookup_cmd uses alloca to make a copy of a string, just for an error
message. However, it's just as easy to use "%.*s" (already used once
in undef_cmd_error) and to pass in a string_view, avoiding the need
for an alloca and a copy.
Matthieu Longo [Tue, 27 Jan 2026 12:33:42 +0000 (12:33 +0000)]
gdb: make remaining Python extension objects inherit from PyObject
Previous patches made some Python extension objects ipublicly inherit
directly or indirectly from PyObject.
In the interest of consistency, this patch makes all remaining Python
extension objects still not inheriting from PyObject do so.
Matthieu Longo [Sat, 25 Oct 2025 22:55:29 +0000 (23:55 +0100)]
gdb: cast all Python extension objects passed to gdbpy_ref_policy to PyObject*
When enabling the Python limited API, pointers to Python C extension
objects can no longer be implicitly converted to 'PyObject *' by the
compiler.
gdbpy_ref_policy is a templated class that provides a generic interface
for incrementing and decrementing the reference counter on the given
object. It is used as a specialisation of the policy parameter in
gdb::ref_ptr, together with PyObject as the parameter type. As a result,
gdbpy_ref_policy always expects an argument derived from PyObject.
This patch fixes the resulting compilation issue by adding an explicit
static_cast to 'PyObject *' before passing the value to Py_INCREF and
Py_DECREF. As a side effect, these casts enforce, at compile time, that
the template type passed to gdbpy_ref_policy is a subclass of PyObject.
To provide a clearer diagnostic when an incorrect type is used, a
static_assert is added to gdbpy_ref_policy, avoiding obscure errors
originating from the static_cast. Finally, all C Python extension types
passed to gdbpy_ref_policy are updated to inherit from PyObject.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830 Approved-By: Tom Tromey <tom@tromey.com>
Matthieu Longo [Thu, 17 Jul 2025 17:36:41 +0000 (18:36 +0100)]
gdb: new setters and getters for __dict__, and attributes
GDB is currently using the Python unlimited API. Migrating the codebase
to the Python limited API would have for benefit to make a GDB build
artifacts compatible with older and newer versions of Python that they
were built with.
This patch prepares the ground for migrating the existing C extension
types from static types to heap-allocated ones, by removing the
dependency on tp_dictoffset, which is unavailable when using the limited
API.
One of the most common incompatibilities in the current static type
declarations is the tp_dictoffset slot, which specifies the dictionary
offset within the instance structure. Historically, the unlimited
API has provided two approaches to supply a dictionary for __dict__:
* A managed dictionary.
Setting Py_TPFLAGS_MANAGED_DICT in tp_flags indicates that the
instances of the type have a __dict__ attribute, and that the
dictionary is managed by Python.
According to the Python documentation, this is the recommended approach.
However, this flag was introduced in 3.12, together with
PyObject_VisitManagedDict() and PyObject_ClearManagedDict(), neither
of which is part of the limited API (at least for now). As a result,
this recommended approach is not viable in the context of the limited
API.
* An instance dictionary, for which the offset in the instance is
provided via tp_dictoffset.
According to the Python documentation, this "tp slot" is on the
deprecation path, and Py_TPFLAGS_MANAGED_DICT should be used instead.
Given the age of the GDB codebase and the requirement to support older
Python versions (>= 3.4), no need to argue that today, the implementation
of __dict__ relies on tp_dictoffset. However, in the context of the
limited API, PyType_Slot does not provide a Py_tp_dictoffset member, so
another approach is needed to provide __dict__ to instances of C extension
types.
Given the constraints of the limited API, the proposed solution consists
in providing a dictionary through a common base class, gdbpy__dict__wrapper.
This helper class owns a dictionary member corresponding to __dict__, and
any C extension type requiring a __dict__ must inherit from it. Since
extension object must also be convertible to PyObject, this wrapper class
publicly inherits from PyObject as well.
Access to the dictionary is provided via a custom getter defined in a
PyGetSetDef, similarily to what was previously done with gdb_py_generic_dict().
Because __dict__ participates in attribute look-up, and since this dictionary
is neither managed by Python nor exposed via tp_dictoffset, custom
implementations of tp_getattro and tp_setattro are required to correctly
redirect attribute look-ups to the dictionary. These custom implementations
— equivalent to PyObject_GenericGetAttr() and PyObject_GenericSetAttr() —
must be installed via tp_getattro / tp_setattro for static types, or
Py_tp_getattro / Py_tp_setattro for heap-allocated types.
- gdbpy__dict__wrapper: a base class for C extension objects that own a
__dict__.
- gdb_py_generic_dict_getter: a __dict__ getter for extension types
derived from gdbpy__dict__wrapper.
- gdb_py_generic_getattro: equivalent of PyObject_GenericGetAttr, but
fixes the look-up of __dict__.
- gdb_py_generic_setattro: equivalent of PyObject_GenericSetAttr, but
fixes the look-up of __dict__.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830 Approved-By: Tom Tromey <tom@tromey.com>
Matthieu Longo [Mon, 5 Jan 2026 11:14:28 +0000 (12:14 +0100)]
gdbpy_registry: cast C extension type object to PyObject * before Py_XINCREF
When enabling the Python limited API, pointers to Python C extension
objects can no longer be implicitly converted to 'PyObject *' by the
compiler.
The lookup() method of gbdpy_registry returns a new reference to the
type object of the looked-up entry. It does so by calling Py_XINCREF()
to increment the reference counter of the returned type object. The
template parameter obj_type corresponds to the type of C extension
object type. With the Python limited API enabled, obj_type can no longer
be implicitly converted to 'PyObject *' when passed to Py_XINCREF().
This patch fixes the resulting compilation issue by adding an explicit
static_cast to 'PyObject *' before passing the value to Py_XINCREF().
As a side effect, this cast enforces, at compile time, that the template
type 'Storage::obj_type' passed to gdbpy_registry is a subclass of
PyObject. To provide a clearer diagnostic when an incorrect type is used,
a static_assert is added to gdbpy_registry, avoiding obscure errors
originating from the static_cast. Finally, the relevant C extension types
passed to gdbpy_registry are updated to inherit publicly from PyObject.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830 Approved-By: Tom Tromey <tom@tromey.com>
Alan Modra [Wed, 28 Jan 2026 21:49:44 +0000 (08:19 +1030)]
PR 33852 Different objects for same input
Testcase:
$ cat aff.s
.quad x@ntpoff
$ gas/as-new -m64 aff.s -o t.o
with MALLOC_PERTURB_ this reliably shows uninitialised memory making
its way into the output.
R_390_TLS_LE64 howto was sized incorrectly, resulting in the
initialisation in s390_elf_cons zeroing only the first four bytes.
* elf64-s390.c (elf_howto_table <R_390_TLS_LE64>): Correct
size and bitsize.
This patch replaces PyImport_ExtendInittab () with its limited C
API equivalent, PyImport_AppendInittab (), a convenience wrapper
around PyImport_ExtendInittab ().
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830 Approved-By: Tom Tromey <tom@tromey.com>
Matthieu Longo [Tue, 6 Jan 2026 13:12:38 +0000 (13:12 +0000)]
Python limited API: migrate Py_CompileStringExFlags and PyRun_SimpleString
This patch replaces Py_CompileStringExFlags () with its limited C API
equivalent, Py_CompileString (). The eval_python_command () helper is
now exposed through the private GDB Python API as a utility function.
PyRun_SimpleString () is replaced with eval_python_command () to avoid
code duplication.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830 Approved-By: Tom Tromey <tom@tromey.com>