* [PATCH v3 0/5] [gdb/tui] Some section hole handling fixes
@ 2026-09-21 20:55 Tom de Vries
2026-09-21 20:55 ` [PATCH v3 1/5] [gdb] Factor out update_section_map Tom de Vries
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Tom de Vries @ 2026-09-21 20:55 UTC (permalink / raw)
To: gdb-patches
This series consists of 5 patches.
The first three patches are refactoring/infrastructure patches:
- factor out update_section_map
- add section_addrmap
- extend addrmap::find with low/high results
The fourth patch fixes PR34617, for both TUI and CLI.
The fifth patch prevents stopping disassembly at section holes for CLI
and TUI, fixing PR34399.
Changes in v2:
- add patch fixing tui_disassemble comment after review comment
- drop restrictive fix for PR tui/34399 after review comments
- add patches implementing an enabling fix for PR tui/34399.
Changes in v3:
- committed the first three patches of v2
- drop the find_pc_section refactoring approach of the 4th and 5th patches of
v2
- instead add three refactoring/infrastructure patches:
- factor out update_section_map
- add section_addrmap
- extend addrmap::find with low/high results
- rework the last two patches into these two patches:
- handle sections when disassembling
- don't stop disassembly at section hole
Versions:
- v1 https://sourceware.org/pipermail/gdb-patches/2026-August/229584.html
- v2 https://sourceware.org/pipermail/gdb-patches/2026-September/230207.html
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34399
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34617
Tom de Vries (5):
[gdb] Factor out update_section_map
[gdb] Add section_addrmap
[gdb] Extend addrmap::find with low/high results
[gdb] Handle sections when disassembling
[gdb] Don't stop disassembly at section hole
gdb/addrmap.c | 78 ++++++++++++++++++++++++---
gdb/addrmap.h | 23 +++++---
gdb/disasm.c | 123 ++++++++++++++++++++++++++++++++++++++-----
gdb/disasm.h | 14 +++++
gdb/objfiles.c | 62 +++++++++++++++++-----
gdb/objfiles.h | 6 +++
gdb/tui/tui-disasm.c | 120 ++++++++++++++++++++++++++++++-----------
7 files changed, 356 insertions(+), 70 deletions(-)
base-commit: 3e5100fe3b15e2b3ece60f57b4c1ecc0c50cae53
--
2.51.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 1/5] [gdb] Factor out update_section_map
2026-09-21 20:55 [PATCH v3 0/5] [gdb/tui] Some section hole handling fixes Tom de Vries
@ 2026-09-21 20:55 ` Tom de Vries
2026-09-21 20:55 ` [PATCH v3 2/5] [gdb] Add section_addrmap Tom de Vries
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Tom de Vries @ 2026-09-21 20:55 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] 6+ messages in thread
* [PATCH v3 2/5] [gdb] Add section_addrmap
2026-09-21 20:55 [PATCH v3 0/5] [gdb/tui] Some section hole handling fixes Tom de Vries
2026-09-21 20:55 ` [PATCH v3 1/5] [gdb] Factor out update_section_map Tom de Vries
@ 2026-09-21 20:55 ` Tom de Vries
2026-09-21 20:55 ` [PATCH v3 3/5] [gdb] Extend addrmap::find with low/high results Tom de Vries
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Tom de Vries @ 2026-09-21 20:55 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] 6+ messages in thread
* [PATCH v3 3/5] [gdb] Extend addrmap::find with low/high results
2026-09-21 20:55 [PATCH v3 0/5] [gdb/tui] Some section hole handling fixes Tom de Vries
2026-09-21 20:55 ` [PATCH v3 1/5] [gdb] Factor out update_section_map Tom de Vries
2026-09-21 20:55 ` [PATCH v3 2/5] [gdb] Add section_addrmap Tom de Vries
@ 2026-09-21 20:55 ` Tom de Vries
2026-09-21 20:55 ` [PATCH v3 4/5] [gdb] Handle sections when disassembling Tom de Vries
2026-09-21 20:55 ` [PATCH v3 5/5] [gdb] Don't stop disassembly at section hole Tom de Vries
4 siblings, 0 replies; 6+ messages in thread
From: Tom de Vries @ 2026-09-21 20:55 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 gives 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..cc98ece6f3f 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)
+ *low = 0;
+ if (high)
+ *high = (CORE_ADDR)-1;
+ return nullptr;
+ }
+
+ auto return_value = [this, &low, &high] (splay_tree_node &n)
+ {
+ if (low)
+ *low = addrmap_node_key (n);
+ if (high)
+ {
+ 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);
+ }
+ delete map2;
+ }
+
/* 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] 6+ messages in thread
* [PATCH v3 4/5] [gdb] Handle sections when disassembling
2026-09-21 20:55 [PATCH v3 0/5] [gdb/tui] Some section hole handling fixes Tom de Vries
` (2 preceding siblings ...)
2026-09-21 20:55 ` [PATCH v3 3/5] [gdb] Extend addrmap::find with low/high results Tom de Vries
@ 2026-09-21 20:55 ` Tom de Vries
2026-09-21 20:55 ` [PATCH v3 5/5] [gdb] Don't stop disassembly at section hole Tom de Vries
4 siblings, 0 replies; 6+ messages in thread
From: Tom de Vries @ 2026-09-21 20:55 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.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34617
---
gdb/disasm.c | 72 ++++++++++++++++++++++++++++++-------
gdb/tui/tui-disasm.c | 85 ++++++++++++++++++++++++++++++++++----------
2 files changed, 125 insertions(+), 32 deletions(-)
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 01361fe4323..9e8334b065e 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
@@ -524,7 +525,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 +670,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 +679,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 +909,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,10 +1146,12 @@ gdb_disassembler::print_insn (CORE_ADDR memaddr,
return length;
}
-void
-gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
- gdb_disassembly_flags flags, int how_many,
- CORE_ADDR low, CORE_ADDR high)
+/* Helper function for gdb_disassembly. */
+
+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;
@@ -1155,19 +1162,58 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
if (symtab != NULL && symtab->linetable () != NULL)
nlines = symtab->linetable ()->nitems;
+ int num_displayed = 0;
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;
+}
+
+void
+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;
+
+ 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);
+
+ if (update_how_many)
+ {
+ how_many -= res;
+ if (how_many <= 0)
+ break;
+ }
+
+ low = tmp_high;
+ }
}
/* Print the instruction at address MEMADDR in debugged memory,
diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index 1a1866003dd..26afc4bd978 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. */
+ tal.insn = "(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.
+
+ 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)
+{
+ std::unique_ptr<addrmap_mutable> map = section_addrmap ();
+
+ /* 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
--
2.51.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 5/5] [gdb] Don't stop disassembly at section hole
2026-09-21 20:55 [PATCH v3 0/5] [gdb/tui] Some section hole handling fixes Tom de Vries
` (3 preceding siblings ...)
2026-09-21 20:55 ` [PATCH v3 4/5] [gdb] Handle sections when disassembling Tom de Vries
@ 2026-09-21 20:55 ` Tom de Vries
4 siblings, 0 replies; 6+ messages in thread
From: Tom de Vries @ 2026-09-21 20:55 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.
Note that we don't run into this memory error with a live inferior, as
demonstrated in the previous patch.
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.
This also contains a small fix in tui_find_disassembly_address, to fix a
regression in gdb.tui/tui-layout-asm-short-prog.exp.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34399
---
gdb/disasm.c | 55 ++++++++++++++++++++++++++++++++++++++++++--
gdb/disasm.h | 14 +++++++++++
gdb/tui/tui-disasm.c | 39 ++++++++++++++++++++-----------
3 files changed, 93 insertions(+), 15 deletions(-)
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 9e8334b065e..f0c642b2367 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -1182,6 +1182,53 @@ gdb_disassembly_1 (struct gdbarch *gdbarch, struct ui_out *uiout,
return num_displayed;
}
+/* See disasm.h. */
+
+CORE_ADDR
+disassemble_skip_sections (addrmap_mutable *map, CORE_ADDR pc,
+ struct obj_section *s, CORE_ADDR *range_low,
+ CORE_ADDR *range_high, int direction)
+{
+ if (s != nullptr)
+ return pc;
+
+ struct obj_section *prev = nullptr, *next = nullptr;
+ CORE_ADDR prev_low, prev_high;
+ if (*range_low != 0)
+ prev
+ = (struct obj_section *)map->find (*range_low-1, &prev_low, &prev_high);
+ CORE_ADDR next_low, next_high;
+ if (*range_high != (CORE_ADDR)-1)
+ next
+ = (struct obj_section *)map->find (*range_high+1, &next_low, &next_high);
+
+ bool section_hole
+ = prev != nullptr && next != nullptr && prev->objfile == next->objfile;
+ if (!section_hole)
+ return pc;
+
+ if (target_has_registers ())
+ {
+ /* Reading from the section hole doesn't trigger a memory error, so
+ don't skip it. */
+ return pc;
+ }
+
+ if (direction == 1)
+ {
+ *range_low = next_low;
+ *range_high = next_high;
+ return next_low;
+ }
+ else if (direction == -1)
+ {
+ *range_low = prev_low;
+ *range_high = prev_high;
+ return prev_high;
+ }
+ gdb_assert_not_reached ();
+}
+
void
gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
gdb_disassembly_flags flags, int how_many,
@@ -1194,8 +1241,12 @@ 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
+ = (struct obj_section *)map->find (low, &range_low, &range_high);
+
+ low = disassemble_skip_sections (map.get (), low, s, &range_low,
+ &range_high);
/* Don't disassemble past a section change. */
if (range_high != (CORE_ADDR)-1)
diff --git a/gdb/disasm.h b/gdb/disasm.h
index 57195564ca8..c73f15c204d 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,19 @@ struct disasm_insn
unsigned int is_speculative:1;
};
+
+/* For an attempt to disassemble PC in section S (which may be nullptr) and
+ range [RANGE_LOW, RANGE_HIGH], skip over S if needed.
+ If so, return an updated PC and [RANGE_LOW, RANGE_HIGH].
+ If DIRECTION == 1 disassemble forward, if DIRECTION == -1, disassemble
+ backward. */
+
+extern CORE_ADDR disassemble_skip_sections (addrmap_mutable *map, CORE_ADDR pc,
+ struct obj_section *s,
+ CORE_ADDR *range_low,
+ CORE_ADDR *range_high,
+ int direction = 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);
diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index 26afc4bd978..2cfc9c9e838 100644
--- a/gdb/tui/tui-disasm.c
+++ b/gdb/tui/tui-disasm.c
@@ -179,8 +179,13 @@ 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);
+
+ pc = disassemble_skip_sections (map.get (), pc, s, &range_low,
+ &range_high);
+
/* Don't disassemble past a section change. */
std::optional<CORE_ADDR> high_pc;
@@ -206,7 +211,8 @@ 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)
{
@@ -214,9 +220,16 @@ tui_find_backward_disassembly_start_address (CORE_ADDR addr)
return addr;
}
+ CORE_ADDR range_low, range_high;
+ struct obj_section *s
+ = (struct obj_section *)map->find (addr - 1, &range_low, &range_high);
+
+ addr = disassemble_skip_sections (map, addr - 1, s, &range_low,
+ &range_high, -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 (addr, nullptr,
lookup_msym_prefer::TEXT,
&msym_prev);
if (msym.minsym != nullptr)
@@ -224,13 +237,7 @@ tui_find_backward_disassembly_start_address (CORE_ADDR addr)
else if (msym_prev.minsym != nullptr)
return msym_prev.value_address ();
- /* 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
@@ -290,16 +297,22 @@ tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
different or not. */
CORE_ADDR prev_low;
+ std::unique_ptr<addrmap_mutable> map = section_addrmap ();
+
do
{
/* Find an address from which we can start disassembling. */
prev_low = new_low;
- new_low = tui_find_backward_disassembly_start_address (new_low);
+ new_low = tui_find_backward_disassembly_start_address (map.get (),
+ new_low);
/* 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] 6+ messages in thread
end of thread, other threads:[~2026-09-21 20:57 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-21 20:55 [PATCH v3 0/5] [gdb/tui] Some section hole handling fixes Tom de Vries
2026-09-21 20:55 ` [PATCH v3 1/5] [gdb] Factor out update_section_map Tom de Vries
2026-09-21 20:55 ` [PATCH v3 2/5] [gdb] Add section_addrmap Tom de Vries
2026-09-21 20:55 ` [PATCH v3 3/5] [gdb] Extend addrmap::find with low/high results Tom de Vries
2026-09-21 20:55 ` [PATCH v3 4/5] [gdb] Handle sections when disassembling Tom de Vries
2026-09-21 20:55 ` [PATCH v3 5/5] [gdb] Don't stop disassembly at section hole 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