* [PATCH v4 01/11] [gdb/tui] Use early exit in tui_find_disassembly_address
2026-10-07 9:40 [PATCH v4 00/11] [gdb/tui] Some section hole handling fixes Tom de Vries
@ 2026-10-07 9:40 ` Tom de Vries
2026-10-07 9:40 ` [PATCH v4 02/11] [gdb/tui] Make low_prev loop-local " Tom de Vries
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Tom de Vries @ 2026-10-07 9:40 UTC (permalink / raw)
To: gdb-patches
The function tui_find_disassembly_address handles forward and backward
disassembling. The first part is small, so handle it in an early exit.
No functional changes.
---
gdb/tui/tui-disasm.c | 211 +++++++++++++++++++++----------------------
1 file changed, 103 insertions(+), 108 deletions(-)
diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index 1a1866003dd..e9f5969a6e6 100644
--- a/gdb/tui/tui-disasm.c
+++ b/gdb/tui/tui-disasm.c
@@ -192,16 +192,12 @@ tui_find_backward_disassembly_start_address (CORE_ADDR addr)
static CORE_ADDR
tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
{
- CORE_ADDR new_low;
- int max_lines;
-
- max_lines = (from > 0) ? from : - from;
+ int max_lines = (from > 0) ? from : - from;
if (max_lines == 0)
return pc;
std::vector<tui_asm_line> asm_lines;
- new_low = pc;
if (from > 0)
{
/* Always disassemble 1 extra instruction here, then if the last
@@ -210,116 +206,115 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
tui_disassemble (gdbarch, asm_lines, pc, max_lines + 1);
if (asm_lines.empty ())
return pc;
- new_low = asm_lines.back ().addr;
+ return asm_lines.back ().addr;
}
- else
+
+ /* In order to disassemble backwards we need to find a suitable
+ address to start disassembling from and then work forward until we
+ re-find the address we're currently at. We can then figure out
+ which address will be at the top of the TUI window after our
+ backward scroll. During our backward disassemble we need to be
+ able to distinguish between the case where the last address we
+ _can_ disassemble is ADDR, and the case where the disassembly
+ just happens to stop at ADDR, for this reason we increase
+ MAX_LINES by one. */
+ max_lines++;
+
+ /* When we disassemble a series of instructions this will hold the
+ address of the last instruction disassembled. */
+ CORE_ADDR last_addr;
+
+ /* And this will hold the address of the next instruction that would
+ have been disassembled. */
+ CORE_ADDR next_addr;
+
+ /* As we search backward if we find an address that looks like a
+ promising starting point then we record it in this structure. If
+ the next address we try is not a suitable starting point then we
+ will fall back to the address held here. */
+ std::optional<CORE_ADDR> possible_new_low;
+
+ /* The previous value of NEW_LOW so we know if the new value is
+ different or not. */
+ CORE_ADDR prev_low;
+
+ CORE_ADDR new_low = pc;
+ do
{
- /* In order to disassemble backwards we need to find a suitable
- address to start disassembling from and then work forward until we
- re-find the address we're currently at. We can then figure out
- which address will be at the top of the TUI window after our
- backward scroll. During our backward disassemble we need to be
- able to distinguish between the case where the last address we
- _can_ disassemble is ADDR, and the case where the disassembly
- just happens to stop at ADDR, for this reason we increase
- MAX_LINES by one. */
- max_lines++;
-
- /* When we disassemble a series of instructions this will hold the
- address of the last instruction disassembled. */
- CORE_ADDR last_addr;
-
- /* And this will hold the address of the next instruction that would
- have been disassembled. */
- CORE_ADDR next_addr;
-
- /* As we search backward if we find an address that looks like a
- promising starting point then we record it in this structure. If
- the next address we try is not a suitable starting point then we
- will fall back to the address held here. */
- std::optional<CORE_ADDR> possible_new_low;
-
- /* The previous value of NEW_LOW so we know if the new value is
- different or not. */
- CORE_ADDR prev_low;
-
- do
- {
- /* Find an address from which we can start disassembling. */
- prev_low = new_low;
- new_low = tui_find_backward_disassembly_start_address (new_low);
-
- /* Disassemble forward. */
- next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
- if (asm_lines.empty ())
- break;
- last_addr = asm_lines.back ().addr;
-
- /* If disassembling from the current value of NEW_LOW reached PC
- (or went past it) then this would do as a starting point if we
- can't find anything better, so remember it. */
- if (last_addr >= pc && new_low != prev_low
- && asm_lines.size () >= max_lines)
- possible_new_low.emplace (new_low);
-
- /* Continue searching until we find a value of NEW_LOW from which
- disassembling MAX_LINES instructions doesn't reach PC. We
- know this means we can find the required number of previous
- instructions then. */
- }
- while ((last_addr > pc
- || (last_addr == pc && asm_lines.size () < max_lines))
- && new_low != prev_low);
+ /* Find an address from which we can start disassembling. */
+ prev_low = new_low;
+ new_low = tui_find_backward_disassembly_start_address (new_low);
- /* If we failed to disassemble the required number of lines, try to fall
- back to a previous possible start address in POSSIBLE_NEW_LOW. */
- if (asm_lines.size () < max_lines)
- {
- if (!possible_new_low.has_value ())
- return new_low;
+ /* Disassemble forward. */
+ next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
+ if (asm_lines.empty ())
+ break;
+ last_addr = asm_lines.back ().addr;
- /* Take the best possible match we have. */
- new_low = *possible_new_low;
- next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
- }
+ /* If disassembling from the current value of NEW_LOW reached PC
+ (or went past it) then this would do as a starting point if we
+ can't find anything better, so remember it. */
+ if (last_addr >= pc && new_low != prev_low
+ && asm_lines.size () >= max_lines)
+ possible_new_low.emplace (new_low);
+
+ /* Continue searching until we find a value of NEW_LOW from which
+ disassembling MAX_LINES instructions doesn't reach PC. We
+ know this means we can find the required number of previous
+ instructions then. */
+ }
+ while ((last_addr > pc
+ || (last_addr == pc && asm_lines.size () < max_lines))
+ && new_low != prev_low);
- /* The following walk forward assumes that ASM_LINES contains exactly
- MAX_LINES entries. */
- gdb_assert (asm_lines.size () == max_lines);
+ /* If we failed to disassemble the required number of lines, try to fall
+ back to a previous possible start address in POSSIBLE_NEW_LOW. */
+ if (asm_lines.size () < max_lines)
+ {
+ if (!possible_new_low.has_value ())
+ return new_low;
- /* Scan forward disassembling one instruction at a time until
- the last visible instruction of the window matches the pc.
- We keep the disassembled instructions in the 'lines' window
- and shift it downward (increasing its addresses). */
- int pos = max_lines - 1;
- last_addr = asm_lines.back ().addr;
- if (last_addr < pc)
- do
- {
- pos++;
- if (pos >= max_lines)
- pos = 0;
-
- CORE_ADDR old_next_addr = next_addr;
- std::vector<tui_asm_line> single_asm_line;
- next_addr = tui_disassemble (gdbarch, single_asm_line,
- next_addr, 1);
- /* If there are some problems while disassembling exit. */
- if (next_addr <= old_next_addr)
- return pc;
- gdb_assert (single_asm_line.size () == 1);
- asm_lines[pos] = single_asm_line[0];
- } while (next_addr <= pc);
- pos++;
- if (pos >= max_lines)
- pos = 0;
- new_low = asm_lines[pos].addr;
-
- /* When scrolling backward the addresses should move backward, or at
- the very least stay the same if we are at the first address that
- can be disassembled. */
- gdb_assert (new_low <= pc);
+ /* Take the best possible match we have. */
+ new_low = *possible_new_low;
+ next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
}
+
+ /* The following walk forward assumes that ASM_LINES contains exactly
+ MAX_LINES entries. */
+ gdb_assert (asm_lines.size () == max_lines);
+
+ /* Scan forward disassembling one instruction at a time until
+ the last visible instruction of the window matches the pc.
+ We keep the disassembled instructions in the 'lines' window
+ and shift it downward (increasing its addresses). */
+ int pos = max_lines - 1;
+ last_addr = asm_lines.back ().addr;
+ if (last_addr < pc)
+ do
+ {
+ pos++;
+ if (pos >= max_lines)
+ pos = 0;
+
+ CORE_ADDR old_next_addr = next_addr;
+ std::vector<tui_asm_line> single_asm_line;
+ next_addr = tui_disassemble (gdbarch, single_asm_line,
+ next_addr, 1);
+ /* If there are some problems while disassembling exit. */
+ if (next_addr <= old_next_addr)
+ return pc;
+ gdb_assert (single_asm_line.size () == 1);
+ asm_lines[pos] = single_asm_line[0];
+ } while (next_addr <= pc);
+ pos++;
+ if (pos >= max_lines)
+ pos = 0;
+ new_low = asm_lines[pos].addr;
+
+ /* When scrolling backward the addresses should move backward, or at
+ the very least stay the same if we are at the first address that
+ can be disassembled. */
+ gdb_assert (new_low <= pc);
return new_low;
}
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v4 02/11] [gdb/tui] Make low_prev loop-local in tui_find_disassembly_address
2026-10-07 9:40 [PATCH v4 00/11] [gdb/tui] Some section hole handling fixes Tom de Vries
2026-10-07 9:40 ` [PATCH v4 01/11] [gdb/tui] Use early exit in tui_find_disassembly_address Tom de Vries
@ 2026-10-07 9:40 ` Tom de Vries
2026-10-07 9:40 ` [PATCH v4 03/11] [gdb/tui] Disassemble less often " Tom de Vries
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Tom de Vries @ 2026-10-07 9:40 UTC (permalink / raw)
To: gdb-patches
There's a loop in tui_find_disassembly_address:
...
CORE_ADDR prev_low;
...
do
{
...
if (last_addr >= pc && new_low != prev_low
&& asm_lines.size () >= max_lines)
...
}
while ((last_addr > pc
|| (last_addr == pc && asm_lines.size () < max_lines))
&& new_low != prev_low);
...
Simplify the two conditions by handling new_low == prev_low before:
...
if (new_low == prev_low)
break;
...
Now that prev_low is no longer tested in the loop condition, make it a
loop-local variable.
No functional changes.
---
gdb/tui/tui-disasm.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index e9f5969a6e6..18439580ffb 100644
--- a/gdb/tui/tui-disasm.c
+++ b/gdb/tui/tui-disasm.c
@@ -234,15 +234,14 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
will fall back to the address held here. */
std::optional<CORE_ADDR> possible_new_low;
- /* The previous value of NEW_LOW so we know if the new value is
- different or not. */
- CORE_ADDR prev_low;
-
CORE_ADDR new_low = pc;
do
{
+ /* The previous value of NEW_LOW so we know if the new value is
+ different or not. */
+ CORE_ADDR prev_low = new_low;
+
/* Find an address from which we can start disassembling. */
- prev_low = new_low;
new_low = tui_find_backward_disassembly_start_address (new_low);
/* Disassemble forward. */
@@ -251,11 +250,13 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
break;
last_addr = asm_lines.back ().addr;
+ if (new_low == prev_low)
+ break;
+
/* If disassembling from the current value of NEW_LOW reached PC
(or went past it) then this would do as a starting point if we
can't find anything better, so remember it. */
- if (last_addr >= pc && new_low != prev_low
- && asm_lines.size () >= max_lines)
+ if (last_addr >= pc && asm_lines.size () >= max_lines)
possible_new_low.emplace (new_low);
/* Continue searching until we find a value of NEW_LOW from which
@@ -263,9 +264,8 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
know this means we can find the required number of previous
instructions then. */
}
- while ((last_addr > pc
- || (last_addr == pc && asm_lines.size () < max_lines))
- && new_low != prev_low);
+ while (last_addr > pc
+ || (last_addr == pc && asm_lines.size () < max_lines));
/* If we failed to disassemble the required number of lines, try to fall
back to a previous possible start address in POSSIBLE_NEW_LOW. */
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v4 03/11] [gdb/tui] Disassemble less often in tui_find_disassembly_address
2026-10-07 9:40 [PATCH v4 00/11] [gdb/tui] Some section hole handling fixes Tom de Vries
2026-10-07 9:40 ` [PATCH v4 01/11] [gdb/tui] Use early exit in tui_find_disassembly_address Tom de Vries
2026-10-07 9:40 ` [PATCH v4 02/11] [gdb/tui] Make low_prev loop-local " Tom de Vries
@ 2026-10-07 9:40 ` Tom de Vries
2026-10-07 9:40 ` [PATCH v4 04/11] [gdb/tui] Fix buglet " Tom de Vries
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Tom de Vries @ 2026-10-07 9:40 UTC (permalink / raw)
To: gdb-patches
In tui_find_disassembly_address we have the following code:
...
CORE_ADDR new_low = pc;
do
{
/* The previous value of NEW_LOW so we know if the new value is
different or not. */
CORE_ADDR prev_low = new_low;
/* Find an address from which we can start disassembling. */
new_low = tui_find_backward_disassembly_start_address (new_low);
/* Disassemble forward. */
next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
if (asm_lines.empty ())
break;
last_addr = asm_lines.back ().addr;
if (new_low == prev_low)
break;
...
Say we enter this code with some pc, and have pc == prev_low == new_low before
the call to tui_find_backward_disassembly_start_address.
If tui_find_backward_disassembly_start_address also returns pc, there's no
point in trying to disassemble starting from pc.
Fix this by moving this check to just after
tui_find_backward_disassembly_start_address:
...
new_low = tui_find_backward_disassembly_start_address (new_low);
if (new_low == prev_low)
break;
...
At the point of the break, asm_lines either is:
- empty because it hasn't been set yet, or
- the result of disassembling starting at prev_low, which also happens to be
new_low.
While I think that's fine, I think it's clearer if we don't carry over
asm_lines from a previous iteration, and do asm_lines.clear () at the start of
the loop.
---
gdb/tui/tui-disasm.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index 18439580ffb..a6cf12ba9c2 100644
--- a/gdb/tui/tui-disasm.c
+++ b/gdb/tui/tui-disasm.c
@@ -237,12 +237,16 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
CORE_ADDR new_low = pc;
do
{
+ asm_lines.clear ();
+
/* The previous value of NEW_LOW so we know if the new value is
different or not. */
CORE_ADDR prev_low = new_low;
/* Find an address from which we can start disassembling. */
new_low = tui_find_backward_disassembly_start_address (new_low);
+ if (new_low == prev_low)
+ break;
/* Disassemble forward. */
next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
@@ -250,9 +254,6 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
break;
last_addr = asm_lines.back ().addr;
- if (new_low == prev_low)
- break;
-
/* If disassembling from the current value of NEW_LOW reached PC
(or went past it) then this would do as a starting point if we
can't find anything better, so remember it. */
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v4 04/11] [gdb/tui] Fix buglet in tui_find_disassembly_address
2026-10-07 9:40 [PATCH v4 00/11] [gdb/tui] Some section hole handling fixes Tom de Vries
` (2 preceding siblings ...)
2026-10-07 9:40 ` [PATCH v4 03/11] [gdb/tui] Disassemble less often " Tom de Vries
@ 2026-10-07 9:40 ` Tom de Vries
2026-10-07 9:40 ` [PATCH v4 05/11] [gdb] Factor out update_section_map Tom de Vries
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Tom de Vries @ 2026-10-07 9:40 UTC (permalink / raw)
To: gdb-patches
In commit 72535eb14bd ("[gdb/tui] Fix segfault in
tui_find_disassembly_address"), in a loop in tui_find_disassembly_address I added:
...
/* Disassemble forward. */
next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
+ if (asm_lines.empty ())
+ break;
last_addr = asm_lines.back ().addr;
...
In retrospect, I think I missed something there.
After the loop, new_low may be returned:
...
if (asm_lines.size () < max_lines)
{
if (!possible_new_low.has_value ())
return new_low;
...
so we'd be returning an address from where in fact we can't disassemble.
Fix this by reverting to prev_low in this case.
---
gdb/tui/tui-disasm.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index a6cf12ba9c2..c242614be45 100644
--- a/gdb/tui/tui-disasm.c
+++ b/gdb/tui/tui-disasm.c
@@ -251,7 +251,10 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
/* Disassemble forward. */
next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
if (asm_lines.empty ())
- break;
+ {
+ new_low = prev_low;
+ break;
+ }
last_addr = asm_lines.back ().addr;
/* If disassembling from the current value of NEW_LOW reached PC
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v4 05/11] [gdb] Factor out update_section_map
2026-10-07 9:40 [PATCH v4 00/11] [gdb/tui] Some section hole handling fixes Tom de Vries
` (3 preceding siblings ...)
2026-10-07 9:40 ` [PATCH v4 04/11] [gdb/tui] Fix buglet " Tom de Vries
@ 2026-10-07 9:40 ` Tom de Vries
2026-10-07 9:40 ` [PATCH v4 06/11] [gdb] Add section_addrmap Tom de Vries
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Tom de Vries @ 2026-10-07 9:40 UTC (permalink / raw)
To: gdb-patches
Factor out update_section_map out of find_pc_section.
---
gdb/objfiles.c | 35 +++++++++++++++++++++++------------
1 file changed, 23 insertions(+), 12 deletions(-)
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index edaf7a10d86..453397c4f43 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -927,25 +927,18 @@ bsearch_cmp (const void *key, const void *elt)
return 1;
}
-/* Returns a section whose range includes PC or NULL if none found. */
+/* Update the section map for PSPACE. */
-struct obj_section *
-find_pc_section (CORE_ADDR pc)
+static void
+update_section_map (struct program_space *pspace)
{
- struct objfile_pspace_info *pspace_info;
- struct obj_section *s, **sp;
+ struct objfile_pspace_info *pspace_info = get_objfile_pspace_data (pspace);
- /* Check for mapped overlay section first. */
- s = find_pc_mapped_section (pc);
- if (s)
- return s;
-
- pspace_info = get_objfile_pspace_data (current_program_space);
if (pspace_info->section_map_dirty
|| (pspace_info->new_objfiles_available
&& !pspace_info->inhibit_updates))
{
- update_section_map (current_program_space,
+ update_section_map (pspace,
&pspace_info->sections,
&pspace_info->num_sections);
@@ -954,6 +947,24 @@ find_pc_section (CORE_ADDR pc)
pspace_info->new_objfiles_available = 0;
pspace_info->section_map_dirty = 0;
}
+}
+
+/* Returns a section whose range includes PC or NULL if none found. */
+
+struct obj_section *
+find_pc_section (CORE_ADDR pc)
+{
+ struct obj_section *s, **sp;
+
+ /* Check for mapped overlay section first. */
+ s = find_pc_mapped_section (pc);
+ if (s)
+ return s;
+
+ update_section_map (current_program_space);
+
+ struct objfile_pspace_info *pspace_info
+ = get_objfile_pspace_data (current_program_space);
/* The C standard (ISO/IEC 9899:TC2) requires the BASE argument to
bsearch be non-NULL. */
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v4 06/11] [gdb] Add section_addrmap
2026-10-07 9:40 [PATCH v4 00/11] [gdb/tui] Some section hole handling fixes Tom de Vries
` (4 preceding siblings ...)
2026-10-07 9:40 ` [PATCH v4 05/11] [gdb] Factor out update_section_map Tom de Vries
@ 2026-10-07 9:40 ` Tom de Vries
2026-10-07 9:40 ` [PATCH v4 07/11] [gdb] Extend addrmap::find with low/high results Tom de Vries
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Tom de Vries @ 2026-10-07 9:40 UTC (permalink / raw)
To: gdb-patches
Add a function section_addrmap that returns an addrmap that maps addresses to
sections, mapping the same way as find_pc_section does.
---
gdb/objfiles.c | 27 +++++++++++++++++++++++++++
gdb/objfiles.h | 6 ++++++
2 files changed, 33 insertions(+)
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 453397c4f43..2b03f424756 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -984,6 +984,33 @@ find_pc_section (CORE_ADDR pc)
return NULL;
}
+/* See objfiles.h. */
+
+std::unique_ptr<addrmap_mutable>
+section_addrmap ()
+{
+ std::unique_ptr<addrmap_mutable> res (new addrmap_mutable ());
+
+ /* Insert mapped overlay sections first. */
+ if (overlay_debugging)
+ for (objfile &objfile : current_program_space->objfiles ())
+ for (obj_section &osect : objfile.sections ())
+ if (section_is_mapped (&osect))
+ res->set_empty (osect.addr (), osect.endaddr () - 1, &osect);
+
+ update_section_map (current_program_space);
+
+ struct objfile_pspace_info *pspace_info
+ = get_objfile_pspace_data (current_program_space);
+
+ for (int i = 0; i < pspace_info->num_sections; ++i)
+ {
+ obj_section *s = pspace_info->sections[i];
+ res->set_empty (s->addr (), s->endaddr () - 1, s);
+ }
+
+ return res;
+}
/* Return non-zero if PC is in a section called NAME. */
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index fa265f83b79..b193aec3be7 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -38,6 +38,7 @@
struct htab;
struct objfile_data;
struct partial_symbol;
+struct addrmap_mutable;
/* This structure maintains information on a per-objfile basis about the
"entry point" of the objfile, and the scope within which the entry point
@@ -956,6 +957,11 @@ extern void objfile_purge_solibs (program_space *pspace);
extern struct obj_section *find_pc_section (CORE_ADDR pc);
+/* Returns an addrmap mapping addresses to sections, similar to how
+ find_pc_section maps. */
+
+extern std::unique_ptr<addrmap_mutable> section_addrmap ();
+
/* Return true if PC is in a section called NAME. */
extern bool pc_in_section (CORE_ADDR, const char *);
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v4 07/11] [gdb] Extend addrmap::find with low/high results
2026-10-07 9:40 [PATCH v4 00/11] [gdb/tui] Some section hole handling fixes Tom de Vries
` (5 preceding siblings ...)
2026-10-07 9:40 ` [PATCH v4 06/11] [gdb] Add section_addrmap Tom de Vries
@ 2026-10-07 9:40 ` Tom de Vries
2026-10-07 9:40 ` [PATCH v4 08/11] [gdb] Make gdb_disassembly return number of insns Tom de Vries
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Tom de Vries @ 2026-10-07 9:40 UTC (permalink / raw)
To: gdb-patches
An addrmap contains a mapping from CORE_ADDR to void *.
The function addrmap::find:
...
void *find (CORE_ADDR addr)
...
returns a void * for a given addr, but doesn't give us an answer about the
range of addresses containing addr for which it would return the same value.
Add a alternative using parameters low/high:
...
void *find (CORE_ADDR addr, CORE_ADDR *low, CORE_ADDR *high)
...
---
gdb/addrmap.c | 78 +++++++++++++++++++++++++++++++++++++++++++++------
gdb/addrmap.h | 23 ++++++++++-----
2 files changed, 86 insertions(+), 15 deletions(-)
diff --git a/gdb/addrmap.c b/gdb/addrmap.c
index a311592c3bb..ce7f8afccf4 100644
--- a/gdb/addrmap.c
+++ b/gdb/addrmap.c
@@ -31,7 +31,7 @@ static_assert (sizeof (splay_tree_value) >= sizeof (void *));
/* Fixed address maps. */
void *
-addrmap_fixed::do_find (CORE_ADDR addr) const
+addrmap_fixed::do_find (CORE_ADDR addr, CORE_ADDR *low, CORE_ADDR *high) const
{
const struct addrmap_transition *bottom = &transitions[0];
const struct addrmap_transition *top = &transitions[num_transitions - 1];
@@ -58,6 +58,12 @@ addrmap_fixed::do_find (CORE_ADDR addr) const
top = mid - 1;
}
+ if (low != nullptr)
+ *low = bottom->addr;
+ if (high != nullptr)
+ *high = (bottom == &transitions[num_transitions - 1]
+ ? (CORE_ADDR)-1
+ : (bottom + 1)->addr - 1);
return bottom->value;
}
@@ -119,7 +125,7 @@ addrmap_mutable::splay_tree_predecessor (CORE_ADDR addr) const
splay_tree_node
-addrmap_mutable::splay_tree_successor (CORE_ADDR addr)
+addrmap_mutable::splay_tree_successor (CORE_ADDR addr) const
{
return ::splay_tree_successor (tree, (splay_tree_key) &addr);
}
@@ -266,25 +272,54 @@ addrmap_mutable::set_empty (CORE_ADDR start, CORE_ADDR end_inclusive,
void *
-addrmap_mutable::do_find (CORE_ADDR addr) const
+addrmap_mutable::do_find (CORE_ADDR addr, CORE_ADDR *low, CORE_ADDR *high) const
{
if (tree == nullptr)
- return nullptr;
+ {
+ if (low != nullptr)
+ *low = 0;
+ if (high != nullptr)
+ *high = (CORE_ADDR)-1;
+ return nullptr;
+ }
+
+ auto return_value = [this, &low, &high] (splay_tree_node &n)
+ {
+ if (low != nullptr)
+ *low = addrmap_node_key (n);
+ if (high != nullptr)
+ {
+ splay_tree_node succ = splay_tree_successor (addrmap_node_key (n));
+ if (succ != nullptr)
+ *high = addrmap_node_key (succ) - 1;
+ else
+ *high = (CORE_ADDR)-1;
+ }
+ return addrmap_node_value (n);
+ };
splay_tree_node n = splay_tree_lookup (addr);
if (n != nullptr)
{
gdb_assert (addrmap_node_key (n) == addr);
- return addrmap_node_value (n);
+ return return_value (n);
}
n = splay_tree_predecessor (addr);
if (n != nullptr)
{
gdb_assert (addrmap_node_key (n) < addr);
- return addrmap_node_value (n);
+ return return_value (n);
}
+ if (low != nullptr)
+ *low = 0;
+ if (high != nullptr)
+ {
+ splay_tree_node succ = splay_tree_successor (addr);
+ gdb_assert (succ != nullptr);
+ *high = addrmap_node_key (succ) - 1;
+ }
return nullptr;
}
@@ -436,10 +471,22 @@ test_addrmap ()
/* Create mutable addrmap. */
auto_obstack temp_obstack;
addrmap_mutable map;
+ addrmap_fixed *map2;
/* Check initial state. */
check_addrmap_find (map, array, 0, 19, nullptr);
+ CORE_ADDR low, high;
+ {
+ map2 = new (&temp_obstack) addrmap_fixed (&temp_obstack, &map);
+ for (addrmap *m : {(addrmap *)&map, (addrmap *)map2})
+ {
+ SELF_CHECK (m->find (core_addr (&array[0]), &low, &high) == nullptr);
+ SELF_CHECK (low == 0 && high == (CORE_ADDR)-1);
+ }
+ map2 = nullptr;
+ }
+
/* Insert address range into mutable addrmap. */
bool full_range_p
= map.set_empty (core_addr (&array[10]), core_addr (&array[12]), val1);
@@ -449,8 +496,7 @@ test_addrmap ()
check_addrmap_find (map, array, 13, 19, nullptr);
/* Create corresponding fixed addrmap. */
- addrmap_fixed *map2
- = new (&temp_obstack) addrmap_fixed (&temp_obstack, &map);
+ map2 = new (&temp_obstack) addrmap_fixed (&temp_obstack, &map);
SELF_CHECK (map2 != nullptr);
check_addrmap_find (*map2, array, 0, 9, nullptr);
check_addrmap_find (*map2, array, 10, 12, val1);
@@ -472,6 +518,22 @@ test_addrmap ()
SELF_CHECK (map.foreach (callback) == 0);
SELF_CHECK (map2->foreach (callback) == 0);
+ for (addrmap *m : {(addrmap *)&map, (addrmap *)map2})
+ {
+ SELF_CHECK (m->find (core_addr (&array[0]), &low, &high) == nullptr);
+ SELF_CHECK (low == 0 && high == core_addr (&array[9]));
+
+ for (int i = 10; i <= 12; i++)
+ {
+ m->find (core_addr (&array[i]), &low, &high);
+ SELF_CHECK (low == core_addr (&array[10])
+ && high == core_addr (&array[12]));
+ }
+
+ SELF_CHECK (m->find (core_addr (&array[19]), &low, &high) == nullptr);
+ SELF_CHECK (low == core_addr (&array[13]) && high == (CORE_ADDR)-1);
+ }
+
/* Relocate fixed addrmap. */
map2->relocate (1);
check_addrmap_find (*map2, array, 0, 10, nullptr);
diff --git a/gdb/addrmap.h b/gdb/addrmap.h
index a702341ef8f..029f58133c3 100644
--- a/gdb/addrmap.h
+++ b/gdb/addrmap.h
@@ -45,12 +45,18 @@ using addrmap_foreach_const_fn
/* The base class for addrmaps. */
struct addrmap
{
- /* Return the object associated with ADDR in MAP. */
+ /* Return the object associated with ADDR in MAP. If LOW and HIGH are
+ non-nullptr, use them to return the range associated with ADDR. */
+ const void *find (CORE_ADDR addr, CORE_ADDR *low,
+ CORE_ADDR *high) const
+ { return this->do_find (addr, low, high); }
const void *find (CORE_ADDR addr) const
- { return this->do_find (addr); }
+ { return this->do_find (addr, nullptr, nullptr); }
+ void *find (CORE_ADDR addr, CORE_ADDR *low, CORE_ADDR *high)
+ { return this->do_find (addr, low, high); }
void *find (CORE_ADDR addr)
- { return this->do_find (addr); }
+ { return this->do_find (addr, nullptr, nullptr); }
/* Call FN for every address in MAP, following an in-order traversal.
If FN ever returns a non-zero value, the iteration ceases
@@ -68,7 +74,8 @@ struct addrmap
private:
/* Worker for find, implemented by sub-classes. */
- virtual void *do_find (CORE_ADDR addr) const = 0;
+ virtual void *do_find (CORE_ADDR addr, CORE_ADDR *low,
+ CORE_ADDR *high) const = 0;
/* Worker for foreach, implemented by sub-classes. */
virtual int do_foreach (addrmap_foreach_fn fn) const = 0;
@@ -94,7 +101,8 @@ struct addrmap_fixed final : public addrmap,
void relocate (CORE_ADDR offset);
private:
- void *do_find (CORE_ADDR addr) const override;
+ void *do_find (CORE_ADDR addr, CORE_ADDR *low,
+ CORE_ADDR *high) const override;
int do_foreach (addrmap_foreach_fn fn) const override;
/* A transition: a point in an address map where the value changes.
@@ -193,7 +201,8 @@ struct addrmap_mutable final : public addrmap
void clear ();
private:
- void *do_find (CORE_ADDR addr) const override;
+ void *do_find (CORE_ADDR addr, CORE_ADDR *low,
+ CORE_ADDR *high) const override;
int do_foreach (addrmap_foreach_fn fn) const override;
/* A splay tree, with a node for each transition; there is a
@@ -220,7 +229,7 @@ struct addrmap_mutable final : public addrmap
void force_transition (CORE_ADDR addr);
splay_tree_node splay_tree_lookup (CORE_ADDR addr) const;
splay_tree_node splay_tree_predecessor (CORE_ADDR addr) const;
- splay_tree_node splay_tree_successor (CORE_ADDR addr);
+ splay_tree_node splay_tree_successor (CORE_ADDR addr) const;
void splay_tree_remove (CORE_ADDR addr);
void splay_tree_insert (CORE_ADDR key, void *value);
};
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v4 08/11] [gdb] Make gdb_disassembly return number of insns
2026-10-07 9:40 [PATCH v4 00/11] [gdb/tui] Some section hole handling fixes Tom de Vries
` (6 preceding siblings ...)
2026-10-07 9:40 ` [PATCH v4 07/11] [gdb] Extend addrmap::find with low/high results Tom de Vries
@ 2026-10-07 9:40 ` Tom de Vries
2026-10-07 9:40 ` [PATCH v4 09/11] [gdb] Handle sections when disassembling Tom de Vries
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Tom de Vries @ 2026-10-07 9:40 UTC (permalink / raw)
To: gdb-patches
Currently the function gdb_disassembly returns void.
Make it return the number of disassembled instructions.
---
gdb/disasm.c | 32 ++++++++++++++++++++++----------
gdb/disasm.h | 10 +++++++---
2 files changed, 29 insertions(+), 13 deletions(-)
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 01361fe4323..ec922fbd323 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -524,7 +524,7 @@ dump_insns (struct gdbarch *gdbarch,
N.B. This view is deprecated. */
-static void
+static int
do_mixed_source_and_assembly_deprecated
(struct gdbarch *gdbarch, struct ui_out *uiout,
struct symtab *symtab,
@@ -669,6 +669,8 @@ do_mixed_source_and_assembly_deprecated
if (how_many >= 0 && num_displayed >= how_many)
break;
}
+
+ return num_displayed;
}
/* The idea here is to present a source-O-centric view of a
@@ -676,7 +678,7 @@ do_mixed_source_and_assembly_deprecated
in source order, with (possibly) out of order assembly
immediately following. */
-static void
+static int
do_mixed_source_and_assembly (struct gdbarch *gdbarch,
struct ui_out *uiout,
struct symtab *main_symtab,
@@ -906,16 +908,18 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
last_symtab = sal.symtab;
last_line = sal.line;
}
+
+ return num_displayed;
}
-static void
+static int
do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
CORE_ADDR low, CORE_ADDR high,
int how_many, gdb_disassembly_flags flags)
{
ui_out_emit_list list_emitter (uiout, "asm_insns");
- dump_insns (gdbarch, uiout, low, high, how_many, flags, NULL);
+ return dump_insns (gdbarch, uiout, low, high, how_many, flags, NULL);
}
/* Combine implicit and user disassembler options and return them
@@ -1141,13 +1145,16 @@ gdb_disassembler::print_insn (CORE_ADDR memaddr,
return length;
}
-void
+/* See disasm.h. */
+
+int
gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
gdb_disassembly_flags flags, int how_many,
CORE_ADDR low, CORE_ADDR high)
{
struct symtab *symtab;
int nlines = -1;
+ int num_displayed = 0;
/* Assume symtab is valid for whole PC range. */
symtab = find_symtab_for_pc (low);
@@ -1157,17 +1164,22 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
if (!(flags & (DISASSEMBLY_SOURCE_DEPRECATED | DISASSEMBLY_SOURCE))
|| nlines <= 0)
- do_assembly_only (gdbarch, uiout, low, high, how_many, flags);
+ num_displayed
+ = do_assembly_only (gdbarch, uiout, low, high, how_many, flags);
else if (flags & DISASSEMBLY_SOURCE)
- do_mixed_source_and_assembly (gdbarch, uiout, symtab, low, high,
- how_many, flags);
+ num_displayed
+ = do_mixed_source_and_assembly (gdbarch, uiout, symtab, low, high,
+ how_many, flags);
else if (flags & DISASSEMBLY_SOURCE_DEPRECATED)
- do_mixed_source_and_assembly_deprecated (gdbarch, uiout, symtab,
- low, high, how_many, flags);
+ num_displayed
+ = do_mixed_source_and_assembly_deprecated (gdbarch, uiout, symtab,
+ low, high, how_many, flags);
gdb_flush (gdb_stdout);
+
+ return num_displayed;
}
/* Print the instruction at address MEMADDR in debugged memory,
diff --git a/gdb/disasm.h b/gdb/disasm.h
index 57195564ca8..9109dbf0a79 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -323,9 +323,13 @@ struct disasm_insn
unsigned int is_speculative:1;
};
-extern void gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
- gdb_disassembly_flags flags, int how_many,
- CORE_ADDR low, CORE_ADDR high);
+/* Print at most HOW_MANY instructions of the instruction stream at
+ [LOW, HIGH) on UIOUT using FLAGS. Return the number of the instructions
+ printed. */
+
+extern int gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
+ gdb_disassembly_flags flags, int how_many,
+ CORE_ADDR low, CORE_ADDR high);
/* Print the instruction at address MEMADDR in debugged memory,
on STREAM. Returns the length of the instruction, in bytes,
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v4 09/11] [gdb] Handle sections when disassembling
2026-10-07 9:40 [PATCH v4 00/11] [gdb/tui] Some section hole handling fixes Tom de Vries
` (7 preceding siblings ...)
2026-10-07 9:40 ` [PATCH v4 08/11] [gdb] Make gdb_disassembly return number of insns Tom de Vries
@ 2026-10-07 9:40 ` Tom de Vries
2026-10-07 9:40 ` [PATCH v4 10/11] [gdb] Don't stop disassembly at section hole Tom de Vries
2026-10-07 9:40 ` [PATCH v4 11/11] [RFC, gdb/tui] Don't scroll into non-code sections Tom de Vries
10 siblings, 0 replies; 12+ messages in thread
From: Tom de Vries @ 2026-10-07 9:40 UTC (permalink / raw)
To: gdb-patches
Consider the following session:
...
$ gdb -q -batch a.out -ex start -ex "disassemble _init,0x0000000000401030"
...
Dump of assembler code from 0x401000 to 0x401030:
...
0x000000000040101a <_init+26>: ret
0x000000000040101b: add %al,(%rax)
0x000000000040101d: add %al,(%rax)
0x000000000040101f: add %bh,%bh
0x0000000000401021: xor $0x2fca,%eax
0x0000000000401026: jmp *0x2fcc(%rip)
0x000000000040102c: nopl 0x0(%rax)
End of assembler dump.
...
If disassemble with objdump instead, we get:
...
Disassembly of section .init:
0000000000401000 <_init>:
...
40101a: c3 ret
Disassembly of section .plt:
0000000000401020 <puts@plt-0x10>:
401020: ff 35 ca 2f 00 00 push 0x2fca(%rip)
401026: ff 25 cc 2f 00 00 jmp *0x2fcc(%rip)
40102c: 0f 1f 40 00 nopl 0x0(%rax)
...
Note the xor vs push.
So gdb:
- first disassembles the .init section
- then disassembles the section hole in between .init and .plt
- interprets the first byte of .plt as the last byte of an instruction
starting in the section hole
- continues disassembling at .plt+1 instead of .plt+0
Fix this in gdb_disassembly by making it section-aware, and not disassembling
across a section change, getting us instead:
...
0x000000000040101a <_init+26>: ret
0x000000000040101b: add %al,(%rax)
0x000000000040101d: add %al,(%rax)
0x000000000040101f: add %bh,%bh
0x0000000000401020: push 0x2fca(%rip) # 0x403ff0
0x0000000000401026: jmp *0x2fcc(%rip) # 0x403ff8
0x000000000040102c: nopl 0x0(%rax)
...
Likewise in tui_disassemble.
Also add a test-case for the fix in gdb_disassembly:
gdb.base/disasm-section-sync.exp.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34617
---
gdb/disasm.c | 50 +++++++++-
gdb/testsuite/gdb.base/disasm-section-sync.S | 47 +++++++++
.../gdb.base/disasm-section-sync.exp | 28 ++++++
gdb/tui/tui-disasm.c | 99 ++++++++++++++-----
4 files changed, 195 insertions(+), 29 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/disasm-section-sync.S
create mode 100644 gdb/testsuite/gdb.base/disasm-section-sync.exp
diff --git a/gdb/disasm.c b/gdb/disasm.c
index ec922fbd323..23d0c880777 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -34,6 +34,7 @@
#include "cli/cli-style.h"
#include "objfiles.h"
#include "inferior.h"
+#include "addrmap.h"
/* Disassemble functions.
FIXME: We should get rid of all the duplicate code in gdb that does
@@ -1145,12 +1146,12 @@ gdb_disassembler::print_insn (CORE_ADDR memaddr,
return length;
}
-/* See disasm.h. */
+/* Helper function for gdb_disassembly. */
-int
-gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
- gdb_disassembly_flags flags, int how_many,
- CORE_ADDR low, CORE_ADDR high)
+static int
+gdb_disassembly_1 (struct gdbarch *gdbarch, struct ui_out *uiout,
+ gdb_disassembly_flags flags, int how_many,
+ CORE_ADDR low, CORE_ADDR high)
{
struct symtab *symtab;
int nlines = -1;
@@ -1182,6 +1183,45 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
return num_displayed;
}
+/* See disasm.h. */
+
+int
+gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
+ gdb_disassembly_flags flags, int how_many,
+ CORE_ADDR low, CORE_ADDR high)
+{
+ std::unique_ptr<addrmap_mutable> map = section_addrmap ();
+ bool update_how_many = how_many != -1;
+ int num_displayed = 0;
+ while (low < high)
+ {
+ CORE_ADDR tmp_high = high;
+
+ CORE_ADDR range_high;
+ map->find (low, nullptr, &range_high);
+
+ /* Don't disassemble past a section change. */
+ if (range_high != (CORE_ADDR)-1)
+ tmp_high = std::min (tmp_high, range_high + 1);
+
+ int res
+ = gdb_disassembly_1 (gdbarch, uiout, flags, how_many, low,
+ tmp_high);
+ num_displayed += res;
+
+ if (update_how_many)
+ {
+ how_many -= res;
+ if (how_many <= 0)
+ break;
+ }
+
+ low = tmp_high;
+ }
+
+ return num_displayed;
+}
+
/* Print the instruction at address MEMADDR in debugged memory,
on STREAM. Returns the length of the instruction, in bytes,
and, if requested, the number of branch delay slot instructions. */
diff --git a/gdb/testsuite/gdb.base/disasm-section-sync.S b/gdb/testsuite/gdb.base/disasm-section-sync.S
new file mode 100644
index 00000000000..06949c4b444
--- /dev/null
+++ b/gdb/testsuite/gdb.base/disasm-section-sync.S
@@ -0,0 +1,47 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright (C) 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_1,"ax",@progbits
+ .globl foo_1
+ .type foo_1, @function
+foo_1:
+ endbr64
+ sub $0x8,%rsp
+ mov 0x2fd1(%rip),%rax
+ test %rax,%rax
+ je 401016
+ call *%rax
+ add $0x8,%rsp
+ ret
+
+ # Get instruction decoding out of sync.
+ .byte 0
+
+ .section .text_2,"ax",@progbits
+ .globl foo_2
+ .type foo_2, @function
+foo_2:
+ push 0x2fca(%rip)
+ jmp *0x2fcc(%rip)
+ nopl 0x0(%rax)
+
+ .globl foo_3
+ .type foo_3, @function
+foo_3:
+ nop
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.base/disasm-section-sync.exp b/gdb/testsuite/gdb.base/disasm-section-sync.exp
new file mode 100644
index 00000000000..2f8b01cae52
--- /dev/null
+++ b/gdb/testsuite/gdb.base/disasm-section-sync.exp
@@ -0,0 +1,28 @@
+# Copyright (C) 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/>.
+
+# Check that disassembling stops and starts at section boundaries.
+
+require is_x86_64_m64_target
+
+standard_testfile .S main.c
+
+if { [prepare_for_testing "failed to prepare" $testfile \
+ [list $srcfile $srcfile2] {nodebug}] } {
+ return
+}
+
+# Regression test for PR34617.
+gdb_test "disassemble foo_1,foo_3" "push.*"
diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index c242614be45..ba11b8e8188 100644
--- a/gdb/tui/tui-disasm.c
+++ b/gdb/tui/tui-disasm.c
@@ -38,6 +38,7 @@
#include "tui/tui-location.h"
#include "gdbsupport/selftest.h"
#include "inferior.h"
+#include "addrmap.h"
struct tui_asm_line
{
@@ -80,23 +81,13 @@ len_without_escapes (const std::string &str)
return len;
}
-/* Function to disassemble up to COUNT instructions starting from address
- PC into the ASM_LINES vector (which will be emptied of any previous
- contents). Return the address after the last disassembled instruction.
- When ADDR_SIZE is non-null then place the maximum size of an address and
- label into the value pointed to by ADDR_SIZE, and set the addr_size
- field on each item in ASM_LINES, otherwise the addr_size fields within
- ASM_LINES are undefined.
+/* Helper function for tui_disassemble. */
- It is worth noting that ASM_LINES might not have COUNT entries when this
- function returns. If the disassembly is truncated for some other
- reason, for example, we hit invalid memory, then ASM_LINES can have
- fewer entries than requested. */
static CORE_ADDR
-tui_disassemble (struct gdbarch *gdbarch,
- std::vector<tui_asm_line> &asm_lines,
- CORE_ADDR pc, int count,
- size_t *addr_size = nullptr)
+tui_disassemble_1 (struct gdbarch *gdbarch,
+ std::vector<tui_asm_line> &asm_lines, CORE_ADDR pc,
+ std::optional<CORE_ADDR> high_pc, int count,
+ size_t *addr_size)
{
bool term_out = disassembler_styling && gdb_stdout->can_emit_style_escape ();
string_file gdb_dis_out (term_out);
@@ -104,20 +95,29 @@ tui_disassemble (struct gdbarch *gdbarch,
? (decltype (stream))&null_stream
: (decltype (stream))&gdb_dis_out);
- /* Must start with an empty list. */
- asm_lines.clear ();
-
/* Now construct each line. */
for (int i = 0; i < count; ++i)
{
tui_asm_line tal;
+ if (high_pc.has_value () && pc >= *high_pc)
+ break;
+
/* Save the instruction address. */
tal.addr = pc;
try
{
- pc += gdb_print_insn (gdbarch, pc, stream, NULL);
+ int len = gdb_print_insn (gdbarch, pc, stream, NULL);
+ CORE_ADDR next_pc = pc + len;
+ if (high_pc.has_value () && next_pc > *high_pc)
+ {
+ /* Instruction spans high_pc. */
+ gdb_dis_out = "(bad)";
+ next_pc = *high_pc;
+ }
+
+ pc = next_pc;
}
catch (const gdb_exception_error &except)
{
@@ -153,6 +153,53 @@ tui_disassemble (struct gdbarch *gdbarch,
return pc;
}
+/* Function to disassemble up to COUNT instructions starting from address
+ PC into the ASM_LINES vector (which will be emptied of any previous
+ contents). Return the address after the last disassembled instruction.
+ When ADDR_SIZE is non-null then place the maximum size of an address and
+ label into the value pointed to by ADDR_SIZE, and set the addr_size
+ field on each item in ASM_LINES, otherwise the addr_size fields within
+ ASM_LINES are undefined.
+
+ MAP contains a map from adressess to sections and corresponding ranges.
+
+ It is worth noting that ASM_LINES might not have COUNT entries when this
+ function returns. If the disassembly is truncated for some other
+ reason, for example, we hit invalid memory, then ASM_LINES can have
+ fewer entries than requested. */
+
+static CORE_ADDR
+tui_disassemble (struct gdbarch *gdbarch,
+ std::vector<tui_asm_line> &asm_lines,
+ addrmap_mutable &map, CORE_ADDR pc, int count,
+ size_t *addr_size = nullptr)
+{
+ /* Must start with an empty list. */
+ asm_lines.clear ();
+
+ while (count > 0)
+ {
+ CORE_ADDR range_high;
+ map.find (pc, nullptr, &range_high);
+
+ /* Don't disassemble past a section change. */
+ std::optional<CORE_ADDR> high_pc;
+ if (range_high != (CORE_ADDR)-1)
+ high_pc = range_high + 1;
+
+ int prev_nr_lines = asm_lines.size ();
+ pc = tui_disassemble_1 (gdbarch, asm_lines, pc, high_pc, count,
+ addr_size);
+ int nr_lines = asm_lines.size () - prev_nr_lines;
+ if (nr_lines == 0)
+ break;
+
+ count -= nr_lines;
+ }
+
+ return pc;
+}
+
/* Look backward from ADDR for an address from which we can start
disassembling, this needs to be something we can be reasonably
confident will fall on an instruction boundary. We use msymbol
@@ -197,13 +244,14 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
return pc;
std::vector<tui_asm_line> asm_lines;
+ std::unique_ptr<addrmap_mutable> map = section_addrmap ();
if (from > 0)
{
/* Always disassemble 1 extra instruction here, then if the last
instruction fails to disassemble we will take the address of the
previous instruction that did disassemble as the result. */
- tui_disassemble (gdbarch, asm_lines, pc, max_lines + 1);
+ tui_disassemble (gdbarch, asm_lines, *map, pc, max_lines + 1);
if (asm_lines.empty ())
return pc;
return asm_lines.back ().addr;
@@ -249,7 +297,8 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
break;
/* Disassemble forward. */
- next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
+ next_addr
+ = tui_disassemble (gdbarch, asm_lines, *map, new_low, max_lines);
if (asm_lines.empty ())
{
new_low = prev_low;
@@ -280,7 +329,8 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
/* Take the best possible match we have. */
new_low = *possible_new_low;
- next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
+ next_addr
+ = tui_disassemble (gdbarch, asm_lines, *map, new_low, max_lines);
}
/* The following walk forward assumes that ASM_LINES contains exactly
@@ -303,7 +353,7 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
CORE_ADDR old_next_addr = next_addr;
std::vector<tui_asm_line> single_asm_line;
next_addr = tui_disassemble (gdbarch, single_asm_line,
- next_addr, 1);
+ *map, next_addr, 1);
/* If there are some problems while disassembling exit. */
if (next_addr <= old_next_addr)
return pc;
@@ -347,8 +397,9 @@ tui_disasm_window::set_contents (struct gdbarch *arch,
/* Get temporary table that will hold all strings (addr & insn). */
std::vector<tui_asm_line> asm_lines;
+ std::unique_ptr<addrmap_mutable> map = section_addrmap ();
size_t addr_size = 0;
- tui_disassemble (m_gdbarch, asm_lines, pc, max_lines, &addr_size);
+ tui_disassemble (m_gdbarch, asm_lines, *map, pc, max_lines, &addr_size);
/* Align instructions to the same column. */
insn_pos = (1 + (addr_size / tab_len)) * tab_len;
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v4 10/11] [gdb] Don't stop disassembly at section hole
2026-10-07 9:40 [PATCH v4 00/11] [gdb/tui] Some section hole handling fixes Tom de Vries
` (8 preceding siblings ...)
2026-10-07 9:40 ` [PATCH v4 09/11] [gdb] Handle sections when disassembling Tom de Vries
@ 2026-10-07 9:40 ` Tom de Vries
2026-10-07 9:40 ` [PATCH v4 11/11] [RFC, gdb/tui] Don't scroll into non-code sections Tom de Vries
10 siblings, 0 replies; 12+ messages in thread
From: Tom de Vries @ 2026-10-07 9:40 UTC (permalink / raw)
To: gdb-patches
Consider the following session:
...
$ gdb -q -batch a.out -ex "disassemble _init,0x0000000000401030"
Dump of assembler code from 0x401000 to 0x401030:
...
0x000000000040101a <_init+26>: ret
0x000000000040101b:
Cannot access memory at address 0x40101b
...
If we disassemble with objdump instead, we get:
...
Disassembly of section .init:
0000000000401000 <_init>:
...
40101a: c3 ret
Disassembly of section .plt:
0000000000401020 <puts@plt-0x10>:
401020: ff 35 ca 2f 00 00 push 0x2fca(%rip)
401026: ff 25 cc 2f 00 00 jmp *0x2fcc(%rip)
40102c: 0f 1f 40 00 nopl 0x0(%rax)
...
The disassembling stops at the section hole, when running into a memory error.
Fix this by if necessary skipping over the section hole.
This also fixes the paradoxical situation reported in PR34399 where it's
possible to scroll forward into a section hole, but not back out of it.
Without the "Fix buglet in tui_find_disassembly_address" patch in this series,
this patch regresses as follows:
...
FAIL: gdb.tui/tui-layout-asm-short-prog.exp: check first line is back
...
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34399
---
gdb/disasm.c | 44 ++++++++++++++++++++++++++++++++++++++++++--
gdb/disasm.h | 8 ++++++++
gdb/tui/tui-disasm.c | 42 ++++++++++++++++++++++++++++++++----------
3 files changed, 82 insertions(+), 12 deletions(-)
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 23d0c880777..e847e3ee0ff 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -1185,6 +1185,37 @@ gdb_disassembly_1 (struct gdbarch *gdbarch, struct ui_out *uiout,
/* See disasm.h. */
+bool
+disassemble_section_p (addrmap_mutable &map,
+ struct obj_section *s, CORE_ADDR range_low,
+ CORE_ADDR range_high)
+{
+ if (s == nullptr)
+ {
+ struct obj_section *prev = (range_low == 0
+ ? nullptr
+ : (obj_section *)map.find (range_low - 1));
+ struct obj_section *next = (range_high == (CORE_ADDR)-1
+ ? nullptr
+ : (obj_section *)map.find (range_high + 1));
+ bool section_hole
+ = (prev != nullptr && next != nullptr
+ && prev->objfile == next->objfile);
+ if (section_hole)
+ {
+ /* Don't disassemble if it would trigger a memory error. */
+ return target_has_registers ();
+ }
+
+ /* Random memory not in a section; might contain JIT-ed instructions. */
+ return true;
+ }
+
+ return true;
+}
+
+/* See disasm.h. */
+
int
gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
gdb_disassembly_flags flags, int how_many,
@@ -1197,8 +1228,17 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
{
CORE_ADDR tmp_high = high;
- CORE_ADDR range_high;
- map->find (low, nullptr, &range_high);
+ CORE_ADDR range_low, range_high;
+ struct obj_section *s
+ = (obj_section *)map->find (low, &range_low, &range_high);
+ if (!disassemble_section_p (*map, s, range_low, range_high))
+ {
+ if (range_high == (CORE_ADDR)-1)
+ break;
+
+ low = range_high + 1;
+ continue;
+ }
/* Don't disassemble past a section change. */
if (range_high != (CORE_ADDR)-1)
diff --git a/gdb/disasm.h b/gdb/disasm.h
index 9109dbf0a79..0366de8f673 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -26,6 +26,7 @@
struct gdbarch;
struct ui_out;
struct ui_file;
+struct addrmap_mutable;
/* A wrapper around a disassemble_info and a gdbarch. This is the core
set of data that all disassembler sub-classes will need. This class
@@ -323,6 +324,13 @@ struct disasm_insn
unsigned int is_speculative:1;
};
+/* Return true if memory in [RANGE_LOW, RANGE_HIGH] should be disassembled.
+ S is either the corresponding section, or nullptr if the range doesn't
+ match a section. */
+
+extern bool disassemble_section_p (addrmap_mutable &map, struct obj_section *s,
+ CORE_ADDR range_low, CORE_ADDR range_high);
+
/* Print at most HOW_MANY instructions of the instruction stream at
[LOW, HIGH) on UIOUT using FLAGS. Return the number of the instructions
printed. */
diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index ba11b8e8188..09136b6fc60 100644
--- a/gdb/tui/tui-disasm.c
+++ b/gdb/tui/tui-disasm.c
@@ -179,8 +179,17 @@ tui_disassemble (struct gdbarch *gdbarch,
while (count > 0)
{
- CORE_ADDR range_high;
- map.find (pc, nullptr, &range_high);
+ CORE_ADDR range_low, range_high;
+ struct obj_section *s
+ = (struct obj_section *)map.find (pc, &range_low, &range_high);
+ if (!disassemble_section_p (map, s, range_low, range_high))
+ {
+ if (range_high == (CORE_ADDR)-1)
+ break;
+
+ pc = range_high + 1;
+ continue;
+ }
/* Don't disassemble past a section change. */
std::optional<CORE_ADDR> high_pc;
@@ -206,17 +215,34 @@ tui_disassemble (struct gdbarch *gdbarch,
addresses, or the start of a section. */
static CORE_ADDR
-tui_find_backward_disassembly_start_address (CORE_ADDR addr)
+tui_find_backward_disassembly_start_address (addrmap_mutable &map, CORE_ADDR addr)
{
if (addr == 0)
{
/* We cannot go backwards from zero. */
return addr;
}
+ CORE_ADDR search_addr = addr - 1;
+
+ struct obj_section *s = nullptr;
+ CORE_ADDR range_low, range_high;
+ while (true)
+ {
+ s = (struct obj_section *)map.find (search_addr, &range_low,
+ &range_high);
+
+ if (disassemble_section_p (map, s, range_low, range_high))
+ break;
+
+ if (range_low == 0)
+ return addr;
+
+ search_addr = range_low - 1;
+ }
bound_minimal_symbol msym_prev;
bound_minimal_symbol msym
- = lookup_minimal_symbol_by_pc_section (addr - 1, nullptr,
+ = lookup_minimal_symbol_by_pc_section (search_addr, nullptr,
lookup_msym_prefer::TEXT,
&msym_prev);
if (msym.minsym != nullptr)
@@ -226,11 +252,7 @@ tui_find_backward_disassembly_start_address (CORE_ADDR 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 ();
-
- return addr;
+ return range_low;
}
/* Find the disassembly address that corresponds to FROM lines above
@@ -292,7 +314,7 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
CORE_ADDR prev_low = new_low;
/* Find an address from which we can start disassembling. */
- new_low = tui_find_backward_disassembly_start_address (new_low);
+ new_low = tui_find_backward_disassembly_start_address (*map, new_low);
if (new_low == prev_low)
break;
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v4 11/11] [RFC, gdb/tui] Don't scroll into non-code sections
2026-10-07 9:40 [PATCH v4 00/11] [gdb/tui] Some section hole handling fixes Tom de Vries
` (9 preceding siblings ...)
2026-10-07 9:40 ` [PATCH v4 10/11] [gdb] Don't stop disassembly at section hole Tom de Vries
@ 2026-10-07 9:40 ` Tom de Vries
10 siblings, 0 replies; 12+ messages in thread
From: Tom de Vries @ 2026-10-07 9:40 UTC (permalink / raw)
To: gdb-patches
We can disassemble a data section using objdump -D:
...
Disassembly of section .rodata:
0000000000402000 <_IO_stdin_used>:
402000: 01 00 add %eax,(%rax)
402002: 02 00 add (%rax),%al
402004: 68 65 6c 6c 6f push $0x6f6c6c65
...
...
and likewise using gdb:
...
(gdb) disassemble 0x0000000000402000,0x000000000040200c
Dump of assembler code from 0x402000 to 0x40200c:
0x0000000000402000 <_IO_stdin_used+0>: add %eax,(%rax)
0x0000000000402002 <_IO_stdin_used+2>: add (%rax),%al
0x0000000000402004: push $0x6f6c6c65
0x0000000000402009: .byte 0
End of assembler dump.
...
Generally it's not useful to do this, so we could skip such sections during
disassembling, but OTOH the user may explicitly ask for it using a disassemble command.
Fix this by:
- propagating an explicit_p parameter to disassemble_section_p, and
- returning false in disassemble_section_p for data sections not explicitly
requested.
I tested this by disassembling .rodata and then scrolling up.
This triggered an assert, which I fixed with some extra code in
tui_find_disassembly_address:
...
/* If there are some problems while disassembling exit. */
if (next_addr <= old_next_addr)
return pc;
+ if (next_addr > pc)
+ break;
gdb_assert (single_asm_line.size () == 1);
...
Concretely what happens, if you disassembly .rodata and:
- scroll up, you get the last instruction of the text section
- scroll down, you get an empty screen, and a subsequent scroll
up gets the last instruction of the text section
I'm not terribly happy with this behavior, hence this is an RFC.
But perhaps this is cornercase enough to be acceptable behavior.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34604
---
gdb/cli/cli-cmds.c | 11 ++++++-----
gdb/disasm.c | 13 ++++++++++---
gdb/disasm.h | 6 ++++--
gdb/tui/tui-disasm.c | 12 ++++++++----
gdb/tui/tui-disasm.h | 3 ++-
gdb/tui/tui-source.c | 2 +-
gdb/tui/tui-source.h | 3 ++-
gdb/tui/tui-winsource.c | 13 +++++++------
gdb/tui/tui-winsource.h | 12 ++++++++----
gdb/tui/tui.c | 4 ++--
gdb/tui/tui.h | 3 ++-
11 files changed, 52 insertions(+), 30 deletions(-)
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 8a85c813277..c119ca9a3df 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -1583,11 +1583,11 @@ static void
print_disassembly (struct gdbarch *gdbarch, const char *name,
CORE_ADDR low, CORE_ADDR high,
const struct block *block,
- gdb_disassembly_flags flags)
+ gdb_disassembly_flags flags, bool explicit_p = false)
{
#if defined(TUI)
if (tui_is_window_visible (DISASSEM_WIN))
- tui_show_assembly (gdbarch, low);
+ tui_show_assembly (gdbarch, low, explicit_p);
else
#endif
{
@@ -1605,7 +1605,8 @@ print_disassembly (struct gdbarch *gdbarch, const char *name,
paddress (gdbarch, high)));
/* Dump the specified range. */
- gdb_disassembly (gdbarch, current_uiout, flags, -1, low, high);
+ gdb_disassembly (gdbarch, current_uiout, flags, -1, low, high,
+ explicit_p);
}
else
{
@@ -1620,7 +1621,7 @@ print_disassembly (struct gdbarch *gdbarch, const char *name,
styled_string (address_style.style (),
paddress (gdbarch, range_high)));
gdb_disassembly (gdbarch, current_uiout, flags, -1,
- range_low, range_high);
+ range_low, range_high, explicit_p);
}
}
gdb_printf (_("End of assembler dump.\n"));
@@ -1787,7 +1788,7 @@ disassemble_command (const char *arg, int from_tty)
high += low;
}
- print_disassembly (gdbarch, name, low, high, block, flags);
+ print_disassembly (gdbarch, name, low, high, block, flags, true);
}
/* Command completion for the disassemble command. */
diff --git a/gdb/disasm.c b/gdb/disasm.c
index e847e3ee0ff..bf40e50acae 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -1188,7 +1188,7 @@ gdb_disassembly_1 (struct gdbarch *gdbarch, struct ui_out *uiout,
bool
disassemble_section_p (addrmap_mutable &map,
struct obj_section *s, CORE_ADDR range_low,
- CORE_ADDR range_high)
+ CORE_ADDR range_high, bool explicit_p)
{
if (s == nullptr)
{
@@ -1211,6 +1211,13 @@ disassemble_section_p (addrmap_mutable &map,
return true;
}
+ if (!explicit_p)
+ {
+ /* When not explicitly required, skip over non-code sections. */
+ return (s->the_bfd_section->flags & SEC_CODE) != 0;
+ }
+
+ /* Explicitly requested, allow any section. */
return true;
}
@@ -1219,7 +1226,7 @@ disassemble_section_p (addrmap_mutable &map,
int
gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
gdb_disassembly_flags flags, int how_many,
- CORE_ADDR low, CORE_ADDR high)
+ CORE_ADDR low, CORE_ADDR high, bool explicit_p)
{
std::unique_ptr<addrmap_mutable> map = section_addrmap ();
bool update_how_many = how_many != -1;
@@ -1231,7 +1238,7 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
CORE_ADDR range_low, range_high;
struct obj_section *s
= (obj_section *)map->find (low, &range_low, &range_high);
- if (!disassemble_section_p (*map, s, range_low, range_high))
+ if (!disassemble_section_p (*map, s, range_low, range_high, explicit_p))
{
if (range_high == (CORE_ADDR)-1)
break;
diff --git a/gdb/disasm.h b/gdb/disasm.h
index 0366de8f673..cb242c997ae 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -329,7 +329,8 @@ struct disasm_insn
match a section. */
extern bool disassemble_section_p (addrmap_mutable &map, struct obj_section *s,
- CORE_ADDR range_low, CORE_ADDR range_high);
+ CORE_ADDR range_low, CORE_ADDR range_high,
+ bool explicit_p = false);
/* Print at most HOW_MANY instructions of the instruction stream at
[LOW, HIGH) on UIOUT using FLAGS. Return the number of the instructions
@@ -337,7 +338,8 @@ extern bool disassemble_section_p (addrmap_mutable &map, struct obj_section *s,
extern int gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
gdb_disassembly_flags flags, int how_many,
- CORE_ADDR low, CORE_ADDR high);
+ CORE_ADDR low, CORE_ADDR high,
+ bool explicit_p = false);
/* Print the instruction at address MEMADDR in debugged memory,
on STREAM. Returns the length of the instruction, in bytes,
diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index 09136b6fc60..090ec484d05 100644
--- a/gdb/tui/tui-disasm.c
+++ b/gdb/tui/tui-disasm.c
@@ -172,7 +172,7 @@ static CORE_ADDR
tui_disassemble (struct gdbarch *gdbarch,
std::vector<tui_asm_line> &asm_lines,
addrmap_mutable &map, CORE_ADDR pc, int count,
- size_t *addr_size = nullptr)
+ size_t *addr_size = nullptr, bool explicit_p = false)
{
/* Must start with an empty list. */
asm_lines.clear ();
@@ -182,7 +182,7 @@ tui_disassemble (struct gdbarch *gdbarch,
CORE_ADDR range_low, range_high;
struct obj_section *s
= (struct obj_section *)map.find (pc, &range_low, &range_high);
- if (!disassemble_section_p (map, s, range_low, range_high))
+ if (!disassemble_section_p (map, s, range_low, range_high, explicit_p))
{
if (range_high == (CORE_ADDR)-1)
break;
@@ -379,6 +379,8 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
/* If there are some problems while disassembling exit. */
if (next_addr <= old_next_addr)
return pc;
+ if (next_addr > pc)
+ break;
gdb_assert (single_asm_line.size () == 1);
asm_lines[pos] = single_asm_line[0];
} while (next_addr <= pc);
@@ -397,7 +399,8 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
/* Function to set the disassembly window's content. */
bool
tui_disasm_window::set_contents (struct gdbarch *arch,
- const struct symtab_and_line &sal)
+ const struct symtab_and_line &sal,
+ bool explicit_p)
{
int i;
int max_lines;
@@ -421,7 +424,8 @@ tui_disasm_window::set_contents (struct gdbarch *arch,
std::vector<tui_asm_line> asm_lines;
std::unique_ptr<addrmap_mutable> map = section_addrmap ();
size_t addr_size = 0;
- tui_disassemble (m_gdbarch, asm_lines, *map, pc, max_lines, &addr_size);
+ tui_disassemble (m_gdbarch, asm_lines, *map, pc, max_lines, &addr_size,
+ explicit_p);
/* Align instructions to the same column. */
insn_pos = (1 + (addr_size / tab_len)) * tab_len;
diff --git a/gdb/tui/tui-disasm.h b/gdb/tui/tui-disasm.h
index 46a974af2a6..43ab26d757e 100644
--- a/gdb/tui/tui-disasm.h
+++ b/gdb/tui/tui-disasm.h
@@ -57,7 +57,8 @@ struct tui_disasm_window : public tui_source_window_base
void do_scroll_vertical (int num_to_scroll) override;
bool set_contents (struct gdbarch *gdbarch,
- const struct symtab_and_line &sal) override;
+ const struct symtab_and_line &sal,
+ bool explicit_p = false) override;
private:
/* Answer whether a particular line number or address is displayed
diff --git a/gdb/tui/tui-source.c b/gdb/tui/tui-source.c
index 466e9972106..c34427b2a8d 100644
--- a/gdb/tui/tui-source.c
+++ b/gdb/tui/tui-source.c
@@ -50,7 +50,7 @@ tui_source_window::~tui_source_window ()
/* Function to display source in the source window. */
bool
tui_source_window::set_contents (struct gdbarch *arch,
- const struct symtab_and_line &sal)
+ const struct symtab_and_line &sal, bool)
{
struct symtab *s = sal.symtab;
int line_no = sal.line;
diff --git a/gdb/tui/tui-source.h b/gdb/tui/tui-source.h
index 95c28dbb0a3..1495762bcb2 100644
--- a/gdb/tui/tui-source.h
+++ b/gdb/tui/tui-source.h
@@ -65,7 +65,8 @@ struct tui_source_window : public tui_source_window_base
void do_scroll_vertical (int num_to_scroll) override;
bool set_contents (struct gdbarch *gdbarch,
- const struct symtab_and_line &sal) override;
+ const struct symtab_and_line &sal,
+ bool explicit_p) override;
int extra_margin () const override
{
diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c
index c7149ff7c80..dbd3cbd8da6 100644
--- a/gdb/tui/tui-winsource.c
+++ b/gdb/tui/tui-winsource.c
@@ -147,10 +147,10 @@ tui_source_window_base::style_changed ()
void
tui_source_window_base::update_source_window
(struct gdbarch *gdbarch,
- const struct symtab_and_line &sal)
+ const struct symtab_and_line &sal, bool explicit_p)
{
m_horizontal_offset = 0;
- update_source_window_as_is (gdbarch, sal);
+ update_source_window_as_is (gdbarch, sal, explicit_p);
}
@@ -159,9 +159,9 @@ tui_source_window_base::update_source_window
void
tui_source_window_base::update_source_window_as_is
(struct gdbarch *gdbarch,
- const struct symtab_and_line &sal)
+ const struct symtab_and_line &sal, bool explicit_p)
{
- bool ret = set_contents (gdbarch, sal);
+ bool ret = set_contents (gdbarch, sal, explicit_p);
if (!ret)
erase_source_content ();
@@ -190,14 +190,15 @@ tui_source_window_base::update_source_window_with_addr (struct gdbarch *gdbarch,
/* Function to ensure that the source and/or disassembly windows
reflect the input address. */
void
-tui_update_source_windows_with_addr (struct gdbarch *gdbarch, CORE_ADDR addr)
+tui_update_source_windows_with_addr (struct gdbarch *gdbarch, CORE_ADDR addr,
+ bool explicit_p)
{
struct symtab_and_line sal {};
if (addr != 0)
sal = find_sal_for_pc (addr, 0);
for (struct tui_source_window_base *win_info : tui_source_windows ())
- win_info->update_source_window (gdbarch, sal);
+ win_info->update_source_window (gdbarch, sal, explicit_p);
}
/* Function to ensure that the source and/or disassembly windows
diff --git a/gdb/tui/tui-winsource.h b/gdb/tui/tui-winsource.h
index 533b159be9b..2c4f6f7fa5e 100644
--- a/gdb/tui/tui-winsource.h
+++ b/gdb/tui/tui-winsource.h
@@ -104,7 +104,8 @@ struct tui_source_window_base : public tui_win_info
void do_erase_source_content (const char *string);
virtual bool set_contents (struct gdbarch *gdbarch,
- const struct symtab_and_line &sal) = 0;
+ const struct symtab_and_line &sal,
+ bool explicit_p = false) = 0;
/* Return the number of extra margin characters needed by this
instance. */
@@ -163,9 +164,11 @@ struct tui_source_window_base : public tui_win_info
virtual void maybe_update (struct gdbarch *gdbarch, symtab_and_line sal) = 0;
void update_source_window_as_is (struct gdbarch *gdbarch,
- const struct symtab_and_line &sal);
+ const struct symtab_and_line &sal,
+ bool explicit_p = false);
void update_source_window (struct gdbarch *gdbarch,
- const struct symtab_and_line &sal);
+ const struct symtab_and_line &sal,
+ bool explicit_p = false);
/* Scan the source window and the breakpoints to update the
break_mode information for each line. Returns true if something
@@ -352,7 +355,8 @@ extern void tui_update_all_breakpoint_info (struct breakpoint *being_deleted);
/* Function to display the "main" routine. */
extern void tui_display_main (void);
-extern void tui_update_source_windows_with_addr (struct gdbarch *, CORE_ADDR);
+extern void tui_update_source_windows_with_addr (struct gdbarch *, CORE_ADDR,
+ bool = false);
extern void tui_update_source_windows_with_line (struct symtab_and_line sal);
/* Extract some source text from PTR. Returns a string holding the
diff --git a/gdb/tui/tui.c b/gdb/tui/tui.c
index a9a23f29b9a..51f17eb4a31 100644
--- a/gdb/tui/tui.c
+++ b/gdb/tui/tui.c
@@ -744,11 +744,11 @@ tui_disable_command (const char *args, int from_tty)
}
void
-tui_show_assembly (struct gdbarch *gdbarch, CORE_ADDR addr)
+tui_show_assembly (struct gdbarch *gdbarch, CORE_ADDR addr, bool explicit_p)
{
tui_batch_rendering suppress;
tui_add_win_to_layout (DISASSEM_WIN);
- tui_update_source_windows_with_addr (gdbarch, addr);
+ tui_update_source_windows_with_addr (gdbarch, addr, explicit_p);
}
bool
diff --git a/gdb/tui/tui.h b/gdb/tui/tui.h
index b24fed2b322..c55dbd9ee32 100644
--- a/gdb/tui/tui.h
+++ b/gdb/tui/tui.h
@@ -60,7 +60,8 @@ enum tui_win_type
extern CORE_ADDR tui_get_low_disassembly_address (struct gdbarch *,
CORE_ADDR, CORE_ADDR);
-extern void tui_show_assembly (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void tui_show_assembly (struct gdbarch *gdbarch, CORE_ADDR addr,
+ bool explicit_p = false);
extern bool tui_is_window_visible (enum tui_win_type type);
extern bool tui_get_command_dimension (unsigned int *width,
unsigned int *height);
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread