* [pushed] [gdb/tui] Improve section handling in tui_find_backward_disassembly_start_address
@ 2026-09-19 15:59 Tom de Vries
0 siblings, 0 replies; only message in thread
From: Tom de Vries @ 2026-09-19 15:59 UTC (permalink / raw)
To: gdb-patches
Consider a hello world:
...
$ gcc hello.c -g
...
and gdb setup like this:
...
$ gdb a.out -ex "layout asm" -ex "disassemble _start"
...
which gives us the following asm window:
...
┌─────────────────────────────────────────────────────────────────────┐
│ 0x401040 <_start> endbr64 │
│ 0x401044 <_start+4> xor %ebp,%ebp │
│ 0x401046 <_start+6> mov %rdx,%r9 │
│ 0x401049 <_start+9> pop %rsi │
│ 0x40104a <_start+10> mov %rsp,%rdx │
│ 0x40104d <_start+13> and $0xfffffffffffffff0,%rsp │
│ 0x401051 <_start+17> push %rax │
│ 0x401052 <_start+18> push %rsp │
│ 0x401053 <_start+19> xor %r8d,%r8d │
│ 0x401056 <_start+22> xor %ecx,%ecx │
└─────────────────────────────────────────────────────────────────────┘
...
The _start function sits at the start of the text section:
...
Disassembly of section .plt:
...
0000000000401030 <puts@plt>:
401030: ff 25 ca 2f 00 00 jmp *0x2fca(%rip)
401036: 68 00 00 00 00 push $0x0
40103b: e9 e0 ff ff ff jmp 401020 <_init+0x20>
Disassembly of section .text:
0000000000401040 <_start>:
...
and using <Up Arrow> we can scroll to the last instruction of the plt section,
at 0x40103b.
To make this happen:
- tui_find_backward_disassembly_start_address is called with addr == 0x401040
- lookup_minimal_symbol_by_pc_section is called with addr - 1
- minimal symbol puts@plt is found
- its address is returned and used as starting point for disassembly
However, tui_find_backward_disassembly_start_address uses two types of
information: minimal symbols, and sections.
If we disable the minimal symbol handling in
tui_find_backward_disassembly_start_address, we're no longer able to scroll to
the instruction at 0x40103b.
The section handling code:
....
/* Find the section that ADDR is in, and look for the start of the
section. */
struct obj_section *section = find_pc_section (addr);
if (section != NULL)
return section->addr ();
...
looks up the section for 0x401040, which is .text, and it returns its start
address, which is also 0x401040, signalling that we cannot scroll to before
that address.
Fix this by using addr - 1.
This happens to work because there's no section hole between sections plt and
text.
---
gdb/testsuite/gdb.tui/scroll-back.S | 52 ++++++++++++++++
gdb/testsuite/gdb.tui/scroll-back.exp | 89 +++++++++++++++++++++++++++
gdb/tui/tui-disasm.c | 6 +-
3 files changed, 144 insertions(+), 3 deletions(-)
create mode 100644 gdb/testsuite/gdb.tui/scroll-back.S
create mode 100644 gdb/testsuite/gdb.tui/scroll-back.exp
diff --git a/gdb/testsuite/gdb.tui/scroll-back.S b/gdb/testsuite/gdb.tui/scroll-back.S
new file mode 100644
index 00000000000..0ee1067ad2c
--- /dev/null
+++ b/gdb/testsuite/gdb.tui/scroll-back.S
@@ -0,0 +1,52 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ .section .text
+ .global main
+main:
+ nop
+
+#ifdef __arm__
+ .section .text_1,"ax",%progbits
+#else
+ .section .text_1,"ax",@progbits
+#endif
+
+ # This is foo, but we don't use a symbol. We use a repetition of 8 to
+ # get the end of the section to be 8-byte aligned, to increase the
+ # chances of avoiding a section hole in between .text_1 and .text_2.
+ .rept 8
+ nop
+ .endr
+
+ .align 1
+
+#ifdef __arm__
+ .section .text_2,"ax",%progbits
+#else
+ .section .text_2,"ax",@progbits
+#endif
+
+ .global bar
+bar:
+ nop
+
+#ifdef __arm__
+ .section .note.GNU-stack,"",%progbits
+#else
+ .section .note.GNU-stack,"",@progbits
+#endif
diff --git a/gdb/testsuite/gdb.tui/scroll-back.exp b/gdb/testsuite/gdb.tui/scroll-back.exp
new file mode 100644
index 00000000000..76eb66eafca
--- /dev/null
+++ b/gdb/testsuite/gdb.tui/scroll-back.exp
@@ -0,0 +1,89 @@
+# 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/>.
+
+# Setup TUI such that the first instruction in the disassembly window is the
+# start of a section. Then scroll back to the last instruction of the
+# previous section. ATM this won't work if there's a section hole.
+#
+# The .S file tries to make sure that there's no section hole, but AFAIU that
+# can't be guaranteed. If this test-case detects a section hole, it bails
+# out with unsupported.
+#
+# The .S file is odd in the sense that the "previous section" doesn't contain
+# any symbols. This is done to trigger a different path in
+# tui_find_backward_disassembly_start_address.
+
+# This test-case uses two extra text sections. This is not supported on cygwin.
+require {!istarget *-*-cygwin*}
+
+tuiterm_env
+
+standard_testfile scroll-back.S
+
+if {[build_executable "failed to prepare" $testfile $srcfile \
+ {nodebug}] == -1} {
+ return
+}
+
+Term::clean_restart 24 80 $testfile
+if {![Term::prepare_for_tui]} {
+ unsupported "TUI not supported"
+ return
+}
+
+set re_no_hole \
+ [subst_vars \
+ {$hex:\s+$hex}]
+set re_hole \
+ [subst_vars \
+ {$hex:\s+Cannot access memory at address $hex}]
+
+set section_hole -1
+gdb_test_multiple "x /cx bar-1" "" {
+ -re -wrap $re_no_hole {
+ set section_hole 0
+ }
+ -re -wrap $re_hole {
+ set section_hole 1
+ }
+}
+
+if {$section_hole != 0} {
+ unsupported "require no section hole between .text_1 and .text_2"
+ return
+}
+
+gdb_assert {[Term::command_no_prompt_prefix "layout asm"] == 1}
+gdb_assert {[Term::command "disassemble bar"] == 1}
+
+set first_line_asm {1 1 78 1}
+Term::check_region_contents "first insn bar" {*}$first_line_asm \
+ [subst_vars \
+ {$hex\s+<bar>\s+nop}]
+
+# Send an up arrow.
+set esc "\033"
+set left_square_bracket "\["
+set csi "$esc$left_square_bracket"
+set cursor_up "${csi}A"
+send_gdb $cursor_up
+
+Term::dump_screen
+
+gdb_assert \
+ {[Term::wait_for_region_contents {*}$first_line_asm \
+ [subst_vars \
+ {$hex\s+nop}]]} \
+ "last insn foo"
diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index 7dcb59e6264..1a1866003dd 100644
--- a/gdb/tui/tui-disasm.c
+++ b/gdb/tui/tui-disasm.c
@@ -177,9 +177,9 @@ tui_find_backward_disassembly_start_address (CORE_ADDR addr)
else if (msym_prev.minsym != nullptr)
return msym_prev.value_address ();
- /* Find the section that ADDR is in, and look for the start of the
- section. */
- struct obj_section *section = find_pc_section (addr);
+ /* Find the first section with start address before ADDR, and use its start
+ address. */
+ struct obj_section *section = find_pc_section (addr - 1);
if (section != NULL)
return section->addr ();
base-commit: dd41575147933228c3996204b68c6c6e6ed3d9e8
--
2.51.0
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-19 16:00 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-19 15:59 [pushed] [gdb/tui] Improve section handling in tui_find_backward_disassembly_start_address Tom de Vries
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox