* [PATCH 00/10] [gdb] Add superblocks range loops
@ 2026-05-01 12:44 Tom de Vries
2026-05-01 12:44 ` [PATCH 01/10] [gdb] Use block::containing_function Tom de Vries
` (10 more replies)
0 siblings, 11 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
To: gdb-patches
This series attempts to rewrite code like this:
...
while (block != NULL)
{
...
block = block->superblock ();
}
...
using range loops.
I haven't rewritten loops in block.c itself.
An RFC was submitted here [1].
Changes in v1:
- commit first two patches of RFC
- add a patch adding uses of block::containing_function
- add patches adding and using block::containing_function_block
- add next_iterator unit test, also excercising incomplete type case
- modernize next_iterator by replacing typedef with using
- rewrite base_next_iterator to use Curiously Recurring Template Pattern
- use using to import constructors in next_iterator
- move comment part showing "using a pointer-to-member template argument
T::next" to commit message
- change names to block_and_superblocks block_and_superblocks_in_fn
- add some missing comments
- complete the refactoring using the range loops
- clarify behaviour of block_and_superblocks_in_fn in relation to static and
global blocks in commit message
- also avoid static and global blocks in function_block_iterator::next
[1] https://sourceware.org/pipermail/gdb-patches/2026-April/226720.html
Tom de Vries (10):
[gdb] Use block::containing_function
[gdb] Factor out block::containing_function_block
[gdb] Use block::containing_function_block
[gdb] Add unit test for next_iterator
[gdbsupport] Use using instead of typedef in next_iterator
[gdbsupport] Factor out base_next_iterator
[gdb] Add block::block_and_superblocks
[gdb] Use block::block_and_superblocks
[gdb] Add block::block_and_superblocks_in_fn
[gdb] Use block::block_and_superblocks_in_fn
gdb/Makefile.in | 1 +
gdb/ada-lang.c | 61 ++++------
gdb/block.c | 18 ++-
gdb/block.h | 102 ++++++++++++++++
gdb/blockframe.c | 11 +-
gdb/compile/compile-c-symbols.c | 10 +-
gdb/compile/compile-object-load.c | 8 +-
gdb/cp-namespace.c | 6 +-
gdb/cp-support.c | 8 +-
gdb/d-namespace.c | 6 +-
gdb/dwarf2/line-program.c | 24 ++--
gdb/f-valprint.c | 19 ++-
gdb/go-lang.c | 31 ++---
gdb/guile/scm-frame.c | 13 +-
gdb/infrun.c | 10 +-
gdb/inline-frame.c | 45 ++++---
gdb/linespec.c | 22 ++--
gdb/mi/mi-cmd-stack.c | 155 +++++++++++-------------
gdb/python/py-frame.c | 13 +-
gdb/python/py-unwind.c | 15 +--
gdb/stack.c | 15 +--
gdb/symmisc.c | 9 +-
gdb/symtab.c | 69 ++++++-----
gdb/tracepoint.c | 9 +-
gdb/unittests/next-iterator-selftests.c | 105 ++++++++++++++++
gdbsupport/next-iterator.h | 48 +++++---
gdbsupport/safe-iterator.h | 12 +-
27 files changed, 511 insertions(+), 334 deletions(-)
create mode 100644 gdb/unittests/next-iterator-selftests.c
base-commit: 27d21139e356aca4b77d32e81105c465f1e6650c
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 01/10] [gdb] Use block::containing_function
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
@ 2026-05-01 12:44 ` Tom de Vries
2026-05-01 12:44 ` [PATCH 02/10] [gdb] Factor out block::containing_function_block Tom de Vries
` (9 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
To: gdb-patches
Add uses of block::containing_function.
---
gdb/go-lang.c | 31 ++++++++++++-------------------
1 file changed, 12 insertions(+), 19 deletions(-)
diff --git a/gdb/go-lang.c b/gdb/go-lang.c
index 3b388c961fa..657679f3fe8 100644
--- a/gdb/go-lang.c
+++ b/gdb/go-lang.c
@@ -430,28 +430,21 @@ go_symbol_package_name (const struct symbol *sym)
gdb::unique_xmalloc_ptr<char>
go_block_package_name (const struct block *block)
{
- while (block != NULL)
- {
- struct symbol *function = block->function ();
-
- if (function != NULL)
- {
- gdb::unique_xmalloc_ptr<char> package_name
- = go_symbol_package_name (function);
-
- if (package_name != NULL)
- return package_name;
+ struct symbol *function
+ = block != nullptr ? block->containing_function () : nullptr;
+ if (function == nullptr)
+ return nullptr;
- /* Stop looking if we find a function without a package name.
- We're most likely outside of Go and thus the concept of the
- "current" package is gone. */
- return NULL;
- }
+ gdb::unique_xmalloc_ptr<char> package_name
+ = go_symbol_package_name (function);
- block = block->superblock ();
- }
+ if (package_name != nullptr)
+ return package_name;
- return NULL;
+ /* Stop looking if we find a function without a package name.
+ We're most likely outside of Go and thus the concept of the
+ "current" package is gone. */
+ return nullptr;
}
/* See language.h. */
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 02/10] [gdb] Factor out block::containing_function_block
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
2026-05-01 12:44 ` [PATCH 01/10] [gdb] Use block::containing_function Tom de Vries
@ 2026-05-01 12:44 ` Tom de Vries
2026-05-01 12:44 ` [PATCH 03/10] [gdb] Use block::containing_function_block Tom de Vries
` (8 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
To: gdb-patches
Factor out new function block::containing_function_block out of
block::containing_function.
---
gdb/block.c | 18 ++++++++++++++----
gdb/block.h | 5 +++++
2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/gdb/block.c b/gdb/block.c
index e7424c52aff..7b006617d1a 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -99,15 +99,25 @@ block::linkage_function () const
/* See block.h. */
-struct symbol *
-block::containing_function () const
+const struct block *
+block::containing_function_block () const
{
const block *bl = this;
- while (bl->function () == NULL && bl->superblock () != NULL)
+ while (bl->function () == nullptr && bl->superblock () != nullptr)
bl = bl->superblock ();
- return bl->function ();
+ return bl->function () != nullptr ? bl : nullptr;
+}
+
+/* See block.h. */
+
+struct symbol *
+block::containing_function () const
+{
+ const block *bl = containing_function_block ();
+
+ return bl != nullptr ? bl->function () : nullptr;
}
/* See block.h. */
diff --git a/gdb/block.h b/gdb/block.h
index cd02006f860..b70b27f6509 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -258,6 +258,11 @@ struct block : public allocate_on_obstack<block>
struct symbol *containing_function () const;
+ /* Return the block for the closest enclosing function, which might be an
+ inline function. */
+
+ const struct block *containing_function_block () const;
+
/* Return the static block associated with this block. Return NULL
if block is a global block. */
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 03/10] [gdb] Use block::containing_function_block
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
2026-05-01 12:44 ` [PATCH 01/10] [gdb] Use block::containing_function Tom de Vries
2026-05-01 12:44 ` [PATCH 02/10] [gdb] Factor out block::containing_function_block Tom de Vries
@ 2026-05-01 12:44 ` Tom de Vries
2026-05-01 12:44 ` [PATCH 04/10] [gdb] Add unit test for next_iterator Tom de Vries
` (7 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
To: gdb-patches
Add uses of block::containing_function_block.
---
gdb/guile/scm-frame.c | 13 ++++++-------
gdb/linespec.c | 15 +++++++--------
gdb/python/py-frame.c | 13 ++++++-------
gdb/python/py-unwind.c | 13 +++++--------
4 files changed, 24 insertions(+), 30 deletions(-)
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 722a754caab..ffcc3049074 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -598,7 +598,7 @@ static SCM
gdbscm_frame_block (SCM self)
{
frame_smob *f_smob;
- const struct block *block = NULL, *fn_block;
+ const struct block *block = nullptr;
bool found = false;
f_smob = frscm_get_frame_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
@@ -625,12 +625,11 @@ gdbscm_frame_block (SCM self)
_("<gdb:frame>"));
}
- for (fn_block = block;
- fn_block != NULL && fn_block->function () == NULL;
- fn_block = fn_block->superblock ())
- continue;
-
- if (block == NULL || fn_block == NULL || fn_block->function () == NULL)
+ const struct block *fn_block
+ = (block != nullptr
+ ? block->containing_function_block ()
+ : nullptr);
+ if (fn_block == nullptr)
{
scm_misc_error (FUNC_NAME, _("cannot find block for frame"),
scm_list_1 (self));
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 45e12e09272..6ed4b4553d3 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -3860,17 +3860,16 @@ find_label_symbols (struct linespec_state *self,
set_current_program_space (self->program_space);
block = get_current_search_block ();
- for (;
- block && !block->function ();
- block = block->superblock ())
- ;
-
- if (!block)
+ const struct block *fn_block
+ = (block != nullptr
+ ? block->containing_function_block ()
+ : nullptr);
+ if (fn_block == nullptr)
return {};
- fn_sym = block->function ();
+ fn_sym = fn_block->function ();
- find_label_symbols_in_block (block, name, fn_sym, completion_mode,
+ find_label_symbols_in_block (fn_block, name, fn_sym, completion_mode,
&result, label_funcs_ret);
}
else
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 1420d2ac5b9..42a281b9712 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -299,7 +299,7 @@ static PyObject *
frapy_block (PyObject *self, PyObject *args)
{
frame_info_ptr frame;
- const struct block *block = NULL, *fn_block;
+ const struct block *block = nullptr;
try
{
@@ -311,12 +311,11 @@ frapy_block (PyObject *self, PyObject *args)
return gdbpy_handle_gdb_exception (nullptr, except);
}
- for (fn_block = block;
- fn_block != NULL && fn_block->function () == NULL;
- fn_block = fn_block->superblock ())
- ;
-
- if (block == NULL || fn_block == NULL || fn_block->function () == NULL)
+ const struct block *fn_block
+ = (block != nullptr
+ ? block->containing_function_block ()
+ : nullptr);
+ if (fn_block == nullptr)
{
PyErr_SetString (PyExc_RuntimeError,
_("Cannot locate block for frame."));
diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c
index dcf86f7db3d..6dc5e11cf87 100644
--- a/gdb/python/py-unwind.c
+++ b/gdb/python/py-unwind.c
@@ -646,14 +646,11 @@ pending_framepy_block (PyObject *self, PyObject *args)
return gdbpy_handle_gdb_exception (nullptr, except);
}
- for (fn_block = block;
- fn_block != nullptr && fn_block->function () == nullptr;
- fn_block = fn_block->superblock ())
- ;
-
- if (block == nullptr
- || fn_block == nullptr
- || fn_block->function () == nullptr)
+ const struct block *fn_block
+ = (block != nullptr
+ ? block->containing_function_block ()
+ : nullptr);
+ if (fn_block == nullptr)
{
PyErr_SetString (PyExc_RuntimeError,
_("Cannot locate block for frame."));
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 04/10] [gdb] Add unit test for next_iterator
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
` (2 preceding siblings ...)
2026-05-01 12:44 ` [PATCH 03/10] [gdb] Use block::containing_function_block Tom de Vries
@ 2026-05-01 12:44 ` Tom de Vries
2026-05-01 12:44 ` [PATCH 05/10] [gdbsupport] Use using instead of typedef in next_iterator Tom de Vries
` (6 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
To: gdb-patches
I noticed that next_iterator doesn't have a selftest. Add this.
---
gdb/Makefile.in | 1 +
gdb/unittests/next-iterator-selftests.c | 105 ++++++++++++++++++++++++
2 files changed, 106 insertions(+)
create mode 100644 gdb/unittests/next-iterator-selftests.c
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index e38ba95eebd..8b1a40dad7e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -476,6 +476,7 @@ SELFTESTS_SRCS = \
unittests/lookup_name_info-selftests.c \
unittests/memory-map-selftests.c \
unittests/memrange-selftests.c \
+ unittests/next-iterator-selftests.c \
unittests/offset-type-selftests.c \
unittests/observable-selftests.c \
unittests/packed-selftests.c \
diff --git a/gdb/unittests/next-iterator-selftests.c b/gdb/unittests/next-iterator-selftests.c
new file mode 100644
index 00000000000..8934e5bbaa0
--- /dev/null
+++ b/gdb/unittests/next-iterator-selftests.c
@@ -0,0 +1,105 @@
+/* Self tests for the next_iterator class.
+
+ Copyright (C) 2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "gdbsupport/selftest.h"
+#include "gdbsupport/next-iterator.h"
+#include <vector>
+
+namespace selftests {
+namespace next_iterator {
+
+struct list;
+using list_iterator = ::next_iterator<struct list>;
+using list_range = next_range<struct list>;
+
+/* The next_iterator allows usage with an incomplete type, provided the type
+ is defined later in the same file. While not essential to its functioning,
+ we're currently using this property in the sources, so check/demonstrate
+ it. */
+
+static void
+test_next_iterator_incomplete_type (struct list *l)
+{
+ list_iterator begin (l);
+ list_iterator end;
+
+ unsigned cnt = 0;
+ list_iterator i;
+ for (i = begin; i != end; ++i)
+ cnt++;
+ SELF_CHECK (cnt == 3);
+}
+
+struct list
+{
+ int i;
+ struct list *next;
+};
+
+static void
+test_next_iterator ()
+{
+ struct list a = { 1, nullptr };
+ struct list b = { 2, &a };
+ struct list c = { 3, &b };
+
+ /* Constructor with parameter. */
+ list_iterator begin (&c);
+
+ /* Constructor without parameter. */
+ list_iterator end;
+
+ /* Operator*. */
+ SELF_CHECK (*begin == &c);
+ SELF_CHECK (*end == nullptr);
+
+ /* Operator==, operator!=. */
+ SELF_CHECK (begin == begin);
+ SELF_CHECK (end == end);
+ SELF_CHECK (begin != end);
+
+ /* Operator++. */
+ list_iterator i (&c);
+ ++i;
+ SELF_CHECK (*i == &b);
+
+ /* Loop using iterators. */
+ std::vector<int> expected = {3, 2, 1};
+ std::vector<int> v;
+ for (i = begin; i != end; ++i)
+ v.push_back ((*i)->i);
+ SELF_CHECK (v == expected);
+
+ /* Loop using range. */
+ v.clear ();
+ for (auto l : list_range (begin))
+ v.push_back (l->i);
+ SELF_CHECK (v == expected);
+
+ test_next_iterator_incomplete_type (&c);
+}
+
+} /* namespace next_iterator */
+} /* namespace selftests */
+
+INIT_GDB_FILE (next_iterator_selftests)
+{
+ selftests::register_test ("next-iterator",
+ selftests::next_iterator::test_next_iterator);
+}
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 05/10] [gdbsupport] Use using instead of typedef in next_iterator
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
` (3 preceding siblings ...)
2026-05-01 12:44 ` [PATCH 04/10] [gdb] Add unit test for next_iterator Tom de Vries
@ 2026-05-01 12:44 ` Tom de Vries
2026-05-01 12:45 ` [PATCH 06/10] [gdbsupport] Factor out base_next_iterator Tom de Vries
` (5 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
To: gdb-patches
Use using instead of typedef in next_iterator. While we're at it, do the same
in basic_safe_iterator.
Suggested-By: Simon Marchi <simon.marchi@polymtl.ca>
Co-Authored-By: Simon Marchi <simon.marchi@polymtl.ca>
---
gdbsupport/next-iterator.h | 12 ++++++------
gdbsupport/safe-iterator.h | 12 ++++++------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/gdbsupport/next-iterator.h b/gdbsupport/next-iterator.h
index 0c90428d349..9f0aba7f8c4 100644
--- a/gdbsupport/next-iterator.h
+++ b/gdbsupport/next-iterator.h
@@ -28,12 +28,12 @@
template<typename T>
struct next_iterator
{
- typedef next_iterator self_type;
- typedef T *value_type;
- typedef T *&reference;
- typedef T **pointer;
- typedef std::forward_iterator_tag iterator_category;
- typedef int difference_type;
+ using self_type = next_iterator;
+ using value_type = T *;
+ using reference = T *&;
+ using pointer = T **;
+ using iterator_category = std::forward_iterator_tag;
+ using difference_type = int;
explicit next_iterator (T *item)
: m_item (item)
diff --git a/gdbsupport/safe-iterator.h b/gdbsupport/safe-iterator.h
index 3e5d1140179..6c5a2901c7e 100644
--- a/gdbsupport/safe-iterator.h
+++ b/gdbsupport/safe-iterator.h
@@ -43,12 +43,12 @@ template<typename Iterator>
class basic_safe_iterator
{
public:
- typedef basic_safe_iterator self_type;
- typedef typename Iterator::value_type value_type;
- typedef typename Iterator::reference reference;
- typedef typename Iterator::pointer pointer;
- typedef typename Iterator::iterator_category iterator_category;
- typedef typename Iterator::difference_type difference_type;
+ using self_type = basic_safe_iterator;
+ using value_type = typename Iterator::value_type;
+ using reference = typename Iterator::reference;
+ using pointer = typename Iterator::pointer;
+ using iterator_category = typename Iterator::iterator_category;
+ using difference_type = typename Iterator::difference_type;
/* Construct the iterator using the underlying iterator BEGIN; the end
iterator is default constructed. */
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 06/10] [gdbsupport] Factor out base_next_iterator
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
` (4 preceding siblings ...)
2026-05-01 12:44 ` [PATCH 05/10] [gdbsupport] Use using instead of typedef in next_iterator Tom de Vries
@ 2026-05-01 12:45 ` Tom de Vries
2026-05-08 19:17 ` Tom Tromey
2026-05-01 12:45 ` [PATCH 07/10] [gdb] Add block::block_and_superblocks Tom de Vries
` (4 subsequent siblings)
10 siblings, 1 reply; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:45 UTC (permalink / raw)
To: gdb-patches
Template struct next_iterator<T> allows iterating over the "next" field of T.
I decided to generalize this to be able to use any field.
A first thought was to use macros, but nowadays we try to do things more in
native c++, so I didn't explore that further.
Instead, this patch factors out base_next_iterator, which contains all parts
not specific to "next", in other words, everything except the operator++.
I also explored using a pointer-to-member template argument T::next:
...
template<typename T, auto F = &T::next>
struct next_iterator
{
...
self_type &operator++ ()
{
m_item = m_item->*F;
return *this;
}
...
}
...
but that meant that using an incomplete T was no longer allowed (see
test_next_iterator_incomplete_type), so it's not a drop-in replacement.
---
gdbsupport/next-iterator.h | 36 ++++++++++++++++++++++++++----------
1 file changed, 26 insertions(+), 10 deletions(-)
diff --git a/gdbsupport/next-iterator.h b/gdbsupport/next-iterator.h
index 9f0aba7f8c4..feee2c2a7c7 100644
--- a/gdbsupport/next-iterator.h
+++ b/gdbsupport/next-iterator.h
@@ -21,27 +21,27 @@
#include "gdbsupport/iterator-range.h"
-/* An iterator that uses the 'next' field of a type to iterate. This
- can be used with various GDB types that are stored as linked
- lists. */
+/* An iterator base class for iterating over a field of a type. In order to
+ form a functioning iterator, classes inheriting this should define a next
+ function, which determines the actual field that is iterated over. */
-template<typename T>
-struct next_iterator
+template<typename T, class D>
+struct base_next_iterator
{
- using self_type = next_iterator;
+ using self_type = base_next_iterator;
using value_type = T *;
using reference = T *&;
using pointer = T **;
using iterator_category = std::forward_iterator_tag;
using difference_type = int;
- explicit next_iterator (T *item)
+ explicit base_next_iterator (T *item)
: m_item (item)
{
}
/* Create a one-past-the-end iterator. */
- next_iterator ()
+ base_next_iterator ()
: m_item (nullptr)
{
}
@@ -63,15 +63,31 @@ struct next_iterator
self_type &operator++ ()
{
- m_item = m_item->next;
+ m_item = static_cast<D *>(this)->next ();
return *this;
}
-private:
+protected:
T *m_item;
};
+/* An iterator that uses the 'next' field of a type to iterate. This
+ can be used with various GDB types that are stored as linked
+ lists. Note that we're using CRTP here. */
+
+template<typename T>
+struct next_iterator : base_next_iterator<T, next_iterator<T>>
+{
+ using base_next_iterator<T, next_iterator<T>>::base_next_iterator;
+ using base_next_iterator<T, next_iterator<T>>::m_item;
+
+ T *next ()
+ {
+ return m_item->next;
+ }
+};
+
/* A convenience wrapper to make a range type around a next_iterator. */
template <typename T>
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 07/10] [gdb] Add block::block_and_superblocks
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
` (5 preceding siblings ...)
2026-05-01 12:45 ` [PATCH 06/10] [gdbsupport] Factor out base_next_iterator Tom de Vries
@ 2026-05-01 12:45 ` Tom de Vries
2026-05-01 12:45 ` [PATCH 08/10] [gdb] Use block::block_and_superblocks Tom de Vries
` (3 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:45 UTC (permalink / raw)
To: gdb-patches
Add a function block::block_and_superblocks that can be used to transform:
...
while (block != NULL)
{
...
block = block->superblock ();
}
...
into:
...
for (auto b : block::block_and_superblocks (block))
{
...
}
...
---
gdb/block.h | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/gdb/block.h b/gdb/block.h
index b70b27f6509..ff5203ae4c6 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -108,6 +108,27 @@ struct blockranges
struct block : public allocate_on_obstack<block>
{
+ /* Variant of next_iterator using the superblock field instead of next. */
+ struct superblock_iterator
+ : base_next_iterator<const block, superblock_iterator>
+ {
+ typedef superblock_iterator self_type;
+
+ explicit superblock_iterator (value_type item)
+ : base_next_iterator (item)
+ {
+ }
+
+ superblock_iterator () = default;
+
+ value_type next ()
+ {
+ return m_item->superblock ();
+ }
+ };
+
+ using superblock_range = iterator_range<superblock_iterator>;
+
/* Return this block's start address. */
CORE_ADDR start () const
{ return m_start; }
@@ -311,6 +332,26 @@ struct block : public allocate_on_obstack<block>
struct dynamic_prop *static_link () const;
+ /* Return a range adapter that iterates over this block and its
+ superblocks. */
+
+ superblock_range block_and_superblocks () const
+ {
+ superblock_range::iterator begin (this);
+
+ return superblock_range (std::move (begin));
+ }
+
+ /* Return a range adapter that iterates over B and its superblocks. */
+
+ static superblock_range block_and_superblocks (const block *b)
+ {
+ if (b == nullptr)
+ return superblock_range ();
+
+ return b->block_and_superblocks ();
+ }
+
/* Return true if block A is lexically nested within this block, or
if A and this block have the same pc range. Return false
otherwise. If ALLOW_NESTED is true, then block A is considered
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 08/10] [gdb] Use block::block_and_superblocks
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
` (6 preceding siblings ...)
2026-05-01 12:45 ` [PATCH 07/10] [gdb] Add block::block_and_superblocks Tom de Vries
@ 2026-05-01 12:45 ` Tom de Vries
2026-05-08 19:41 ` Tom Tromey
2026-05-01 12:45 ` [PATCH 09/10] [gdb] Add block::block_and_superblocks_in_fn Tom de Vries
` (2 subsequent siblings)
10 siblings, 1 reply; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:45 UTC (permalink / raw)
To: gdb-patches
Add uses of block::block_and_superblocks.
---
gdb/ada-lang.c | 18 ++++------
gdb/blockframe.c | 11 +++---
gdb/compile/compile-object-load.c | 8 +++--
gdb/cp-namespace.c | 6 ++--
gdb/cp-support.c | 8 ++---
gdb/d-namespace.c | 6 ++--
gdb/dwarf2/line-program.c | 24 +++++--------
gdb/infrun.c | 10 +++---
gdb/inline-frame.c | 45 +++++++++++-------------
gdb/linespec.c | 7 ++--
gdb/symmisc.c | 9 +++--
gdb/symtab.c | 58 ++++++++++++++++++-------------
12 files changed, 101 insertions(+), 109 deletions(-)
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 71a338ce17e..6eb928b445d 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -5402,17 +5402,15 @@ ada_add_local_symbols (std::vector<struct block_symbol> &result,
const lookup_name_info &lookup_name,
const struct block *block, domain_search_flags domain)
{
- while (block != NULL)
+ for (auto b : block::block_and_superblocks (block))
{
- ada_add_block_symbols (result, block, lookup_name, domain, NULL);
+ ada_add_block_symbols (result, b, lookup_name, domain, nullptr);
/* If we found a non-function match, assume that's the one. We
only check this when finding a function boundary, so that we
can accumulate all results from intervening blocks first. */
- if (block->function () != nullptr && is_nonfunction (result))
+ if (b->function () != nullptr && is_nonfunction (result))
return;
-
- block = block->superblock ();
}
}
@@ -13825,9 +13823,7 @@ class ada_language : public language_defn
/* Search upwards from currently selected frame (so that we can
complete on local vars. */
- for (const block *b = get_selected_block (0);
- b != nullptr;
- b = b->superblock ())
+ for (auto b : block::block_and_superblocks (get_selected_block (0)))
{
if (b->is_static_block ())
surrounding_static_block = b; /* For elmin of dups */
@@ -13852,9 +13848,9 @@ class ada_language : public language_defn
auto callback = [&] (compunit_symtab *s)
{
QUIT;
- for (const block *b = s->blockvector ()->static_block ();
- b != nullptr;
- b = b->superblock ())
+ const struct block *static_block
+ = s->blockvector ()->static_block ();
+ for (auto b : block::block_and_superblocks (static_block))
{
/* Don't do this block twice. */
if (b == surrounding_static_block)
diff --git a/gdb/blockframe.c b/gdb/blockframe.c
index 8aafa6ffe57..5c981748cbc 100644
--- a/gdb/blockframe.c
+++ b/gdb/blockframe.c
@@ -69,13 +69,14 @@ get_frame_block (const frame_info_ptr &frame, CORE_ADDR *addr_in_block)
inline_count = frame_inlined_callees (frame);
- while (inline_count > 0)
+ auto range = bl->block_and_superblocks ();
+ for (auto b = range.begin (); b != range.end (); ++b, bl = *b)
{
- if (bl->inlined_p ())
- inline_count--;
+ if (inline_count <= 0)
+ break;
- bl = bl->superblock ();
- gdb_assert (bl != NULL);
+ if ((*b)->inlined_p ())
+ inline_count--;
}
return bl;
diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c
index 4ea924582fb..32c6fe0bacf 100644
--- a/gdb/compile/compile-object-load.c
+++ b/gdb/compile/compile-object-load.c
@@ -443,10 +443,12 @@ get_out_value_type (struct symbol *func_sym, struct objfile *objfile,
continue;
function_block = block;
- while (function_block != bv->static_block ()
- && function_block != bv->global_block ())
+ for (auto b : block::block_and_superblocks (block))
{
- function_block = function_block->superblock ();
+ if (b == bv->static_block () || b == bv->global_block ())
+ break;
+
+ function_block = b->superblock ();
function = function_block->function ();
if (function != NULL)
break;
diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index c8cd5c245aa..534f2d0b8f9 100644
--- a/gdb/cp-namespace.c
+++ b/gdb/cp-namespace.c
@@ -613,13 +613,11 @@ cp_lookup_symbol_via_all_imports (const char *scope, const char *name,
{
struct block_symbol sym;
- while (block != NULL)
+ for (auto b : block::block_and_superblocks (block))
{
- sym = cp_lookup_symbol_via_imports (scope, name, block, domain, 0, 1);
+ sym = cp_lookup_symbol_via_imports (scope, name, b, domain, 0, 1);
if (sym.symbol != nullptr)
return sym;
-
- block = block->superblock ();
}
return {};
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index d040ad79469..c04a5120380 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -1408,15 +1408,11 @@ add_symbol_overload_list_using (const char *func_name,
const char *the_namespace,
std::vector<symbol *> *overload_list)
{
- const struct block *block;
-
/* First, go through the using directives. If any of them apply,
look in the appropriate namespaces for new functions to match
on. */
- for (block = get_selected_block (0);
- block != NULL;
- block = block->superblock ())
+ for (auto block : block::block_and_superblocks (get_selected_block (0)))
for (using_direct *current : block->get_using ())
{
/* Prevent recursive calls. */
@@ -1459,7 +1455,7 @@ add_symbol_overload_list_qualified (const char *func_name,
/* Search upwards from currently selected frame (so that we can
complete on local vars. */
- for (const block *b = selected_block; b != nullptr; b = b->superblock ())
+ for (auto b : block::block_and_superblocks (selected_block))
add_symbol_overload_list_block (func_name, b, overload_list);
const block *surrounding_static_block = (selected_block == nullptr
diff --git a/gdb/d-namespace.c b/gdb/d-namespace.c
index 34b90c0ed93..a8bb90320c3 100644
--- a/gdb/d-namespace.c
+++ b/gdb/d-namespace.c
@@ -481,14 +481,12 @@ d_lookup_symbol_module (const char *scope, const char *name,
/* Search for name in modules imported to this and parent
blocks. */
- while (block != NULL)
+ for (auto b : block::block_and_superblocks (block))
{
- sym = d_lookup_symbol_imports (scope, name, block, domain);
+ sym = d_lookup_symbol_imports (scope, name, b, domain);
if (sym.symbol != NULL)
return sym;
-
- block = block->superblock ();
}
return {};
diff --git a/gdb/dwarf2/line-program.c b/gdb/dwarf2/line-program.c
index b9da1b4799f..227ec01aec9 100644
--- a/gdb/dwarf2/line-program.c
+++ b/gdb/dwarf2/line-program.c
@@ -373,21 +373,15 @@ dwarf_find_and_extend_inline_block_range (dwarf2_cu *cu,
the child of a non-inline block. This is new inline block is our
candidate for extending. */
struct block *block = nullptr;
- for (const struct block *b = it->second;
- b != nullptr;
- b = b->superblock ())
- {
- if (b->function () != nullptr && b->inlined_p ())
- {
- if (b->superblock () != nullptr
- && b->superblock ()->function () != nullptr
- && !b->superblock ()->inlined_p ())
- {
- block = const_cast<struct block *> (b);
- break;
- }
- }
- }
+ for (auto b : block::block_and_superblocks (it->second))
+ if (b->inlined_p ()
+ && b->superblock () != nullptr
+ && b->superblock ()->function () != nullptr
+ && !b->superblock ()->inlined_p ())
+ {
+ block = const_cast<struct block *> (b);
+ break;
+ }
/* If we didn't find a block, or the block we found wasn't called from
the expected LINE, then we're done. Maybe we should try harder to
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 11c5d5214d6..be57c521a0d 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -8261,13 +8261,15 @@ process_event_stop_test (struct execution_control_state *ecs)
const struct block *prev
= block_for_pc (ecs->event_thread->control.step_frame_id.code_addr);
const struct block *curr = block_for_pc (ecs->event_thread->stop_pc ());
- while (curr != nullptr && !curr->contains (prev))
+ for (auto b : block::block_and_superblocks (curr))
{
- if (curr->inlined_p ())
+ if (b->contains (prev))
+ break;
+
+ if (b->inlined_p ())
depth++;
- else if (curr->function () != nullptr)
+ else if (b->function () != nullptr)
break;
- curr = curr->superblock ();
}
while (inline_skipped_frames (ecs->event_thread) > depth)
step_into_inline_frame (ecs->event_thread);
diff --git a/gdb/inline-frame.c b/gdb/inline-frame.c
index a1ccd4ed0da..3aeaebffa2d 100644
--- a/gdb/inline-frame.c
+++ b/gdb/inline-frame.c
@@ -217,7 +217,7 @@ inline_frame_sniffer (const struct frame_unwind *self,
void **this_cache)
{
CORE_ADDR this_pc;
- const struct block *frame_block, *cur_block;
+ const struct block *frame_block;
int depth;
frame_info_ptr next_frame;
struct inline_state *state = find_inline_frame_state (inferior_thread ());
@@ -230,15 +230,15 @@ inline_frame_sniffer (const struct frame_unwind *self,
/* Calculate DEPTH, the number of inlined functions at this
location. */
depth = 0;
- cur_block = frame_block;
- while (cur_block->superblock ())
+ for (auto cur_block : frame_block->block_and_superblocks ())
{
+ if (cur_block->superblock () == nullptr)
+ break;
+
if (cur_block->inlined_p ())
depth++;
else if (cur_block->function () != NULL)
break;
-
- cur_block = cur_block->superblock ();
}
/* Check how many inlined functions already have frames. */
@@ -361,25 +361,22 @@ gather_inline_frames (CORE_ADDR this_pc)
return {};
std::vector<const symbol *> function_symbols;
- while (cur_block != nullptr)
- {
- if (cur_block->inlined_p ())
- {
- gdb_assert (cur_block->function () != nullptr);
-
- /* See comments in inline_frame_this_id about this use
- of BLOCK_ENTRY_PC. */
- if (cur_block->entry_pc () == this_pc
- || block_starting_point_at (bv, this_pc, cur_block))
- function_symbols.push_back (cur_block->function ());
- else
- break;
- }
- else if (cur_block->function () != nullptr)
- break;
-
- cur_block = cur_block->superblock ();
- }
+ auto range = block::block_and_superblocks (cur_block);
+ for (auto b = range.begin (); b != range.end (); ++b, cur_block = *b)
+ if (cur_block->inlined_p ())
+ {
+ gdb_assert (cur_block->function () != nullptr);
+
+ /* See comments in inline_frame_this_id about this use
+ of BLOCK_ENTRY_PC. */
+ if (cur_block->entry_pc () == this_pc
+ || block_starting_point_at (bv, this_pc, cur_block))
+ function_symbols.push_back (cur_block->function ());
+ else
+ break;
+ }
+ else if (cur_block->function () != nullptr)
+ break;
/* If we have a code region for which we have no function blocks,
possibly due to bad debug, or possibly just when some debug
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 6ed4b4553d3..c393e855a91 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -1194,11 +1194,10 @@ iterate_over_file_blocks
domain_search_flags domain,
for_each_symbol_callback_ftype callback)
{
- const struct block *block;
+ const struct block *static_block
+ = symtab->compunit ()->blockvector ()->static_block ();
- for (block = symtab->compunit ()->blockvector ()->static_block ();
- block != NULL;
- block = block->superblock ())
+ for (auto block : block::block_and_superblocks (static_block))
current_language->for_each_symbol (block, name, domain, callback);
}
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index 89374bd8a2f..f882f3add17 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -961,11 +961,10 @@ block_depth (const struct block *block)
{
int i = 0;
- while ((block = block->superblock ()) != NULL)
- {
- i++;
- }
- return i;
+ for (auto b [[maybe_unused]]: block::block_and_superblocks (block))
+ i++;
+
+ return i - 1;
}
\f
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 3c10e1fd750..d8e4e6375d9 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -2181,14 +2181,17 @@ lookup_local_symbol (const char *name,
const char *scope = block->scope ();
- while (!block->is_global_block () && !block->is_static_block ())
+ for (auto b : block->block_and_superblocks ())
{
+ if (b->is_global_block () || b->is_static_block ())
+ break;
+
struct symbol *sym = lookup_symbol_in_block (name, match_type,
- block, domain);
+ b, domain);
if (sym != NULL)
- return (struct block_symbol) {sym, block};
+ return (struct block_symbol) {sym, b};
- struct symbol *function = block->function ();
+ struct symbol *function = b->function ();
if (function != nullptr && function->is_template_function ())
{
struct template_symbol *templ = (struct template_symbol *) function;
@@ -2196,17 +2199,16 @@ lookup_local_symbol (const char *name,
templ->n_template_arguments,
templ->template_arguments);
if (sym != nullptr)
- return (struct block_symbol) {sym, block};
+ return (struct block_symbol) {sym, b};
}
struct block_symbol blocksym
- = langdef->lookup_symbol_local (scope, name, block, domain);
+ = langdef->lookup_symbol_local (scope, name, b, domain);
if (blocksym.symbol != nullptr)
return blocksym;
- if (block->inlined_p ())
+ if (b->inlined_p ())
break;
- block = block->superblock ();
}
/* We've reached the end of the function without finding a result. */
@@ -3829,13 +3831,17 @@ skip_prologue_sal (struct symtab_and_line *sal)
use the call site of the function instead. */
const block *function_block = nullptr;
- for (const block *b = block_for_pc_sect (sal->pc, sal->section);
- b != nullptr;
- b = b->superblock ())
- if (b->function () != NULL && b->inlined_p ())
- function_block = b;
- else if (b->function () != NULL)
- break;
+ const block *pc_block = block_for_pc_sect (sal->pc, sal->section);
+ for (auto b: block::block_and_superblocks (pc_block))
+ {
+ if (b->function () == nullptr)
+ continue;
+
+ if (b->inlined_p ())
+ function_block = b;
+ else
+ break;
+ }
if (function_block != NULL
&& function_block->function ()->line () != 0)
@@ -3929,7 +3935,8 @@ skip_prologue_using_sal (struct gdbarch *gdbarch, CORE_ADDR func_addr)
same function, not something inlined. If it's inlined,
then there is no point comparing the line numbers. */
bl = block_for_pc (prologue_sal.end);
- while (bl)
+ auto range = block::block_and_superblocks (bl);
+ for (auto b = range.begin (); b != range.end (); ++b, bl = *b)
{
if (bl->inlined_p ())
break;
@@ -3938,7 +3945,6 @@ skip_prologue_using_sal (struct gdbarch *gdbarch, CORE_ADDR func_addr)
bl = NULL;
break;
}
- bl = bl->superblock ();
}
if (bl != NULL)
break;
@@ -5868,7 +5874,7 @@ default_collect_symbol_completion_matches_break_on
frees them. I'm not going to worry about this; hopefully there
won't be that many. */
- const struct block *b;
+ const struct block *selected_block;
const struct block *surrounding_static_block, *surrounding_global_block;
/* The symbol we are completing on. Points in same buffer as text. */
const char *sym_text;
@@ -5977,12 +5983,17 @@ default_collect_symbol_completion_matches_break_on
this places which match our text string. Only complete on types
visible from current context. */
- b = get_selected_block (0);
- surrounding_static_block = b == nullptr ? nullptr : b->static_block ();
- surrounding_global_block = b == nullptr ? nullptr : b->global_block ();
+ selected_block = get_selected_block (0);
+ surrounding_static_block
+ = selected_block == nullptr ? nullptr : selected_block->static_block ();
+ surrounding_global_block
+ = selected_block == nullptr ? nullptr : selected_block->global_block ();
if (surrounding_static_block != NULL)
- while (b != surrounding_static_block)
+ for (auto b : block::block_and_superblocks (selected_block))
{
+ if (b == surrounding_static_block)
+ break;
+
QUIT;
for (struct symbol *sym : block_iterator_range (b))
@@ -6003,9 +6014,8 @@ default_collect_symbol_completion_matches_break_on
/* Stop when we encounter an enclosing function. Do not stop for
non-inlined functions - the locals of the enclosing function
are in scope for a nested function. */
- if (b->function () != NULL && b->inlined_p ())
+ if (b->inlined_p ())
break;
- b = b->superblock ();
}
/* Add fields from the file's types; symbols will be added below. */
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 09/10] [gdb] Add block::block_and_superblocks_in_fn
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
` (7 preceding siblings ...)
2026-05-01 12:45 ` [PATCH 08/10] [gdb] Use block::block_and_superblocks Tom de Vries
@ 2026-05-01 12:45 ` Tom de Vries
2026-05-01 12:45 ` [PATCH 10/10] [gdb] Use block::block_and_superblocks_in_fn Tom de Vries
2026-06-09 12:40 ` [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:45 UTC (permalink / raw)
To: gdb-patches
Add a function block::block_and_superblocks_in_fn that can be used to
transform:
...
while (block != NULL)
{
...
if (block->function () != nullptr)
break;
block = block->superblock ();
}
...
into:
...
for (auto b : block::block_and_superblocks_in_fn (block))
{
...
}
...
In fact the new loop is somewhat stricter, because it systematically ignores
the static and global blocks.
This means that the transformation is not strictly semantics-preserving. I'm
still on the fence about whether this is a good idea.
My assumption here is that these loops are written assuming a well-formed
block hierarchy:
...
global block <- static block <- function block <- in-function block
...
as well as assuming that the starting block is not the static or global block.
And for such loops, the stricter static/global blocks skipping behavior
doesn't matter.
---
gdb/block.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/gdb/block.h b/gdb/block.h
index ff5203ae4c6..c39425185aa 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -127,7 +127,42 @@ struct block : public allocate_on_obstack<block>
}
};
+ /* Variant of next_iterator using the superblock field instead of next. */
+ struct function_block_iterator
+ : base_next_iterator<const block, function_block_iterator>
+ {
+ typedef function_block_iterator self_type;
+
+ explicit function_block_iterator (value_type item)
+ : base_next_iterator (item->is_global_block () || item->is_static_block ()
+ ? nullptr : item)
+ {
+ }
+
+ function_block_iterator () = default;
+
+ value_type next ()
+ {
+ if (m_item->function () != nullptr)
+ return nullptr;
+
+ value_type next = m_item->superblock ();
+ if (next->is_global_block () || next->is_static_block ())
+ {
+ /* This shouldn't be reachable in well-formed block hierarchies, given
+ that we avoid global and static block in the constructor, and
+ stop iterating when encountering a function. But let's try to be
+ robust and ensure that this iterator never points to a static or
+ global block. */
+ return nullptr;
+ }
+
+ return next;
+ }
+ };
+
using superblock_range = iterator_range<superblock_iterator>;
+ using function_block_range = iterator_range<function_block_iterator>;
/* Return this block's start address. */
CORE_ADDR start () const
@@ -352,6 +387,27 @@ struct block : public allocate_on_obstack<block>
return b->block_and_superblocks ();
}
+ /* Return a range adapter that iterates over this block and its
+ superblocks in the same function. */
+
+ function_block_range block_and_superblocks_in_fn () const
+ {
+ function_block_range::iterator begin (this);
+
+ return function_block_range (std::move (begin));
+ }
+
+ /* Return a range adapter that iterates over B and its superblocks in the
+ same function. */
+
+ static function_block_range block_and_superblocks_in_fn (const block *b)
+ {
+ if (b == nullptr)
+ return function_block_range ();
+
+ return b->block_and_superblocks_in_fn ();
+ }
+
/* Return true if block A is lexically nested within this block, or
if A and this block have the same pc range. Return false
otherwise. If ALLOW_NESTED is true, then block A is considered
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 10/10] [gdb] Use block::block_and_superblocks_in_fn
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
` (8 preceding siblings ...)
2026-05-01 12:45 ` [PATCH 09/10] [gdb] Add block::block_and_superblocks_in_fn Tom de Vries
@ 2026-05-01 12:45 ` Tom de Vries
2026-06-09 12:40 ` [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:45 UTC (permalink / raw)
To: gdb-patches
Add uses of block::block_and_superblocks_in_fn.
---
gdb/ada-lang.c | 43 ++++-----
gdb/compile/compile-c-symbols.c | 10 +--
gdb/f-valprint.c | 19 ++--
gdb/mi/mi-cmd-stack.c | 155 +++++++++++++++-----------------
gdb/python/py-unwind.c | 2 +-
gdb/stack.c | 15 ++--
gdb/symtab.c | 11 +--
gdb/tracepoint.c | 9 +-
8 files changed, 114 insertions(+), 150 deletions(-)
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 6eb928b445d..400760be1ba 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -13118,32 +13118,27 @@ ada_add_exceptions_from_frame (compiled_regex *preg,
const frame_info_ptr &frame,
std::vector<ada_exc_info> *exceptions)
{
- const struct block *block = get_frame_block (frame, 0);
+ const struct block *frame_block = get_frame_block (frame, 0);
- while (block != 0)
- {
- for (struct symbol *sym : block_iterator_range (block))
- {
- switch (sym->loc_class ())
- {
- case LOC_TYPEDEF:
- case LOC_BLOCK:
- case LOC_CONST:
- break;
- default:
- if (ada_is_exception_sym (sym))
- {
- struct ada_exc_info info = {sym->print_name (),
- sym->value_address ()};
+ for (auto block : block::block_and_superblocks_in_fn (frame_block))
+ for (struct symbol *sym : block_iterator_range (block))
+ {
+ switch (sym->loc_class ())
+ {
+ case LOC_TYPEDEF:
+ case LOC_BLOCK:
+ case LOC_CONST:
+ break;
+ default:
+ if (ada_is_exception_sym (sym))
+ {
+ struct ada_exc_info info = {sym->print_name (),
+ sym->value_address ()};
- exceptions->push_back (info);
- }
- }
- }
- if (block->function () != NULL)
- break;
- block = block->superblock ();
- }
+ exceptions->push_back (info);
+ }
+ }
+ }
}
/* Add all exceptions defined globally whose name name match
diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
index dc0487d8f82..da8c6719fe5 100644
--- a/gdb/compile/compile-c-symbols.c
+++ b/gdb/compile/compile-c-symbols.c
@@ -588,20 +588,14 @@ generate_c_for_variable_locations (compile_instance *compiler,
reality of shadowing. */
gdb::unordered_set<std::string_view> symset;
- while (1)
+ for (auto b : block->block_and_superblocks_in_fn ())
{
/* Iterate over symbols in this block, generating code to
compute the location of each local variable. */
- for (struct symbol *sym : block_iterator_range (block))
+ for (struct symbol *sym : block_iterator_range (b))
if (symset.insert (sym->natural_name ()).second)
generate_c_for_for_one_variable (compiler, stream, gdbarch,
registers_used, pc, sym);
-
- /* If we just finished the outermost block of a function, we're
- done. */
- if (block->function () != NULL)
- break;
- block = block->superblock ();
}
return registers_used;
diff --git a/gdb/f-valprint.c b/gdb/f-valprint.c
index 13921c03a48..44b24d788d3 100644
--- a/gdb/f-valprint.c
+++ b/gdb/f-valprint.c
@@ -682,7 +682,7 @@ static void
info_common_command (const char *comname, int from_tty)
{
frame_info_ptr fi;
- const struct block *block;
+ const struct block *frame_block;
int values_printed = 0;
/* We have been told to display the contents of F77 COMMON
@@ -695,22 +695,17 @@ info_common_command (const char *comname, int from_tty)
/* The following is generally ripped off from stack.c's routine
print_frame_info(). */
- block = get_frame_block (fi, 0);
- if (block == NULL)
+ frame_block = get_frame_block (fi, 0);
+ if (frame_block == nullptr)
{
gdb_printf (_("No symbol table info available.\n"));
return;
}
- while (block)
- {
- info_common_command_for_block (block, comname, &values_printed);
- /* After handling the function's top-level block, stop. Don't
- continue to its superblock, the block of per-file symbols. */
- if (block->function ())
- break;
- block = block->superblock ();
- }
+ /* After handling the function's top-level block, stop. Don't
+ continue to its superblock, the block of per-file symbols. */
+ for (auto block : block::block_and_superblocks_in_fn (frame_block))
+ info_common_command_for_block (block, comname, &values_printed);
if (!values_printed)
{
diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c
index f2a4b3044b0..0f46033c9b4 100644
--- a/gdb/mi/mi-cmd-stack.c
+++ b/gdb/mi/mi-cmd-stack.c
@@ -573,11 +573,11 @@ list_args_or_locals (const frame_print_options &fp_opts,
enum what_to_list what, enum print_values values,
const frame_info_ptr &fi, int skip_unavailable)
{
- const struct block *block;
+ const struct block *frame_block;
const char *name_of_result;
struct ui_out *uiout = current_uiout;
- block = get_frame_block (fi, 0);
+ frame_block = get_frame_block (fi, 0);
switch (what)
{
@@ -596,88 +596,81 @@ list_args_or_locals (const frame_print_options &fp_opts,
ui_out_emit_list list_emitter (uiout, name_of_result);
- while (block != 0)
- {
- for (struct symbol *sym : block_iterator_range (block))
- {
- int print_me = 0;
-
- switch (sym->loc_class ())
- {
- default:
- case LOC_UNDEF: /* catches errors */
- case LOC_CONST: /* constant */
- case LOC_TYPEDEF: /* local typedef */
- case LOC_LABEL: /* local label */
- case LOC_BLOCK: /* local function */
- case LOC_CONST_BYTES: /* loc. byte seq. */
- case LOC_UNRESOLVED: /* unresolved static */
- case LOC_OPTIMIZED_OUT: /* optimized out */
- print_me = 0;
- break;
+ for (auto block : block::block_and_superblocks_in_fn (frame_block))
+ for (struct symbol *sym : block_iterator_range (block))
+ {
+ int print_me = 0;
+
+ switch (sym->loc_class ())
+ {
+ default:
+ case LOC_UNDEF: /* catches errors */
+ case LOC_CONST: /* constant */
+ case LOC_TYPEDEF: /* local typedef */
+ case LOC_LABEL: /* local label */
+ case LOC_BLOCK: /* local function */
+ case LOC_CONST_BYTES: /* loc. byte seq. */
+ case LOC_UNRESOLVED: /* unresolved static */
+ case LOC_OPTIMIZED_OUT: /* optimized out */
+ print_me = 0;
+ break;
- case LOC_ARG: /* argument */
- case LOC_REF_ARG: /* reference arg */
- case LOC_REGPARM_ADDR: /* indirect register arg */
- case LOC_LOCAL: /* stack local */
- case LOC_STATIC: /* static */
- case LOC_REGISTER: /* register */
- case LOC_COMPUTED: /* computed location */
- if (what == all)
- print_me = 1;
- else if (what == locals)
- print_me = !sym->is_argument ();
- else
- print_me = sym->is_argument ();
- break;
- }
- if (print_me)
- {
- struct symbol *sym2;
- struct frame_arg arg, entryarg;
-
- if (sym->is_argument ())
- sym2 = (lookup_symbol_search_name
- (sym->search_name (),
- block, SEARCH_VAR_DOMAIN).symbol);
- else
- sym2 = sym;
- gdb_assert (sym2 != NULL);
-
- arg.sym = sym2;
- arg.entry_kind = print_entry_values_no;
- entryarg.sym = sym2;
- entryarg.entry_kind = print_entry_values_no;
-
- switch (values)
- {
- case PRINT_SIMPLE_VALUES:
- if (!mi_simple_type_p (sym2->type ()))
- break;
- [[fallthrough]];
-
- case PRINT_ALL_VALUES:
- if (sym->is_argument ())
- read_frame_arg (fp_opts, sym2, fi, &arg, &entryarg);
- else
- read_frame_local (sym2, fi, &arg);
+ case LOC_ARG: /* argument */
+ case LOC_REF_ARG: /* reference arg */
+ case LOC_REGPARM_ADDR: /* indirect register arg */
+ case LOC_LOCAL: /* stack local */
+ case LOC_STATIC: /* static */
+ case LOC_REGISTER: /* register */
+ case LOC_COMPUTED: /* computed location */
+ if (what == all)
+ print_me = 1;
+ else if (what == locals)
+ print_me = !sym->is_argument ();
+ else
+ print_me = sym->is_argument ();
+ break;
+ }
+ if (print_me)
+ {
+ struct symbol *sym2;
+ struct frame_arg arg, entryarg;
+
+ if (sym->is_argument ())
+ sym2 = (lookup_symbol_search_name
+ (sym->search_name (),
+ block, SEARCH_VAR_DOMAIN).symbol);
+ else
+ sym2 = sym;
+ gdb_assert (sym2 != nullptr);
+
+ arg.sym = sym2;
+ arg.entry_kind = print_entry_values_no;
+ entryarg.sym = sym2;
+ entryarg.entry_kind = print_entry_values_no;
+
+ switch (values)
+ {
+ case PRINT_SIMPLE_VALUES:
+ if (!mi_simple_type_p (sym2->type ()))
break;
- }
-
- if (arg.entry_kind != print_entry_values_only)
- list_arg_or_local (&arg, what, values, skip_unavailable,
- fp_opts);
- if (entryarg.entry_kind != print_entry_values_no)
- list_arg_or_local (&entryarg, what, values, skip_unavailable,
- fp_opts);
- }
- }
+ [[fallthrough]];
- if (block->function ())
- break;
- else
- block = block->superblock ();
- }
+ case PRINT_ALL_VALUES:
+ if (sym->is_argument ())
+ read_frame_arg (fp_opts, sym2, fi, &arg, &entryarg);
+ else
+ read_frame_local (sym2, fi, &arg);
+ break;
+ }
+
+ if (arg.entry_kind != print_entry_values_only)
+ list_arg_or_local (&arg, what, values, skip_unavailable,
+ fp_opts);
+ if (entryarg.entry_kind != print_entry_values_no)
+ list_arg_or_local (&entryarg, what, values, skip_unavailable,
+ fp_opts);
+ }
+ }
}
/* Read a frame specification from FRAME_EXP and return the selected frame.
diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c
index 6dc5e11cf87..cb19496d46b 100644
--- a/gdb/python/py-unwind.c
+++ b/gdb/python/py-unwind.c
@@ -635,7 +635,7 @@ pending_framepy_block (PyObject *self, PyObject *args)
PENDING_FRAMEPY_REQUIRE_VALID (pending_frame);
frame_info_ptr frame = pending_frame->frame_info;
- const struct block *block = nullptr, *fn_block;
+ const struct block *block = nullptr;
try
{
diff --git a/gdb/stack.c b/gdb/stack.c
index 6fcc26417e2..e9a01d16a3b 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -2232,16 +2232,11 @@ void
iterate_over_block_local_vars (const struct block *block,
iterate_over_block_arg_local_vars_cb cb)
{
- while (block)
- {
- iterate_over_block_locals (block, cb);
- /* After handling the function's top-level block, stop. Don't
- continue to its superblock, the block of per-file
- symbols. */
- if (block->function ())
- break;
- block = block->superblock ();
- }
+ /* After handling the function's top-level block, stop. Don't
+ continue to its superblock, the block of per-file
+ symbols. */
+ for (auto b : block::block_and_superblocks_in_fn (block))
+ iterate_over_block_locals (b, cb);
}
/* Data to be passed around in the calls to the locals and args
diff --git a/gdb/symtab.c b/gdb/symtab.c
index d8e4e6375d9..9836a7abb38 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -2002,22 +2002,19 @@ lookup_language_this (const struct language_defn *lang,
lookup_name_info this_name (lang->name_of_this (),
symbol_name_match_type::SEARCH_NAME);
- while (block)
+ for (auto b : block::block_and_superblocks_in_fn (block))
{
struct symbol *sym;
- sym = block_lookup_symbol (block, this_name, SEARCH_VFT);
+ sym = block_lookup_symbol (b, this_name, SEARCH_VFT);
if (sym != NULL)
{
symbol_lookup_debug_printf_v
("lookup_language_this (...) = %s (%s, block %s)",
sym->print_name (), host_address_to_string (sym),
- host_address_to_string (block));
- return (struct block_symbol) {sym, block};
+ host_address_to_string (b));
+ return (struct block_symbol) {sym, b};
}
- if (block->function ())
- break;
- block = block->superblock ();
}
symbol_lookup_debug_printf_v ("lookup_language_this (...) = NULL");
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 7f078684b14..5608f81211a 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -2456,7 +2456,6 @@ tfind_outside_command (const char *args, int from_tty)
static void
info_scope_command (const char *args_in, int from_tty)
{
- const struct block *block;
const char *symname;
const char *save_args = args_in;
int j, count = 0;
@@ -2481,9 +2480,9 @@ info_scope_command (const char *args_in, int from_tty)
/* Resolve line numbers to PC. */
resolve_sal_pc (&sals[0]);
- block = block_for_pc (sals[0].pc);
+ const struct block *pc_block = block_for_pc (sals[0].pc);
- while (block != 0)
+ for (auto block : block::block_and_superblocks_in_fn (pc_block))
{
QUIT; /* Allow user to bail out with ^C. */
for (struct symbol *sym : block_iterator_range (block))
@@ -2607,10 +2606,6 @@ info_scope_command (const char *args_in, int from_tty)
gdb_printf (", length %s.\n", pulongest (t->length ()));
}
}
- if (block->function ())
- break;
- else
- block = block->superblock ();
}
if (count <= 0)
gdb_printf ("Scope for %s contains no locals or arguments.\n",
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 06/10] [gdbsupport] Factor out base_next_iterator
2026-05-01 12:45 ` [PATCH 06/10] [gdbsupport] Factor out base_next_iterator Tom de Vries
@ 2026-05-08 19:17 ` Tom Tromey
0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2026-05-08 19:17 UTC (permalink / raw)
To: Tom de Vries; +Cc: gdb-patches
>>>>> "Tom" == Tom de Vries <tdevries@suse.de> writes:
Tom> + m_item = static_cast<D *>(this)->next ();
Space before paren.
Tom
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 08/10] [gdb] Use block::block_and_superblocks
2026-05-01 12:45 ` [PATCH 08/10] [gdb] Use block::block_and_superblocks Tom de Vries
@ 2026-05-08 19:41 ` Tom Tromey
0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2026-05-08 19:41 UTC (permalink / raw)
To: Tom de Vries; +Cc: gdb-patches
>>>>> "Tom" == Tom de Vries <tdevries@suse.de> writes:
Tom> diff --git a/gdb/blockframe.c b/gdb/blockframe.c
Tom> index 8aafa6ffe57..5c981748cbc 100644
Tom> --- a/gdb/blockframe.c
Tom> +++ b/gdb/blockframe.c
Tom> @@ -69,13 +69,14 @@ get_frame_block (const frame_info_ptr &frame, CORE_ADDR *addr_in_block)
Tom> inline_count = frame_inlined_callees (frame);
Tom> - while (inline_count > 0)
Tom> + auto range = bl->block_and_superblocks ();
Tom> + for (auto b = range.begin (); b != range.end (); ++b, bl = *b)
Tom> {
Tom> - if (bl->inlined_p ())
Tom> - inline_count--;
Tom> + if (inline_count <= 0)
Tom> + break;
Tom> - bl = bl->superblock ();
Tom> - gdb_assert (bl != NULL);
Tom> + if ((*b)->inlined_p ())
Tom> + inline_count--;
Tom> }
Tom> return bl;
I think this particular change is less clear than the code it replaces.
Tom> diff --git a/gdb/dwarf2/line-program.c b/gdb/dwarf2/line-program.c
Tom> index b9da1b4799f..227ec01aec9 100644
Tom> --- a/gdb/dwarf2/line-program.c
Tom> +++ b/gdb/dwarf2/line-program.c
Tom> @@ -373,21 +373,15 @@ dwarf_find_and_extend_inline_block_range (dwarf2_cu *cu,
Tom> the child of a non-inline block. This is new inline block is our
Tom> candidate for extending. */
Tom> struct block *block = nullptr;
Tom> - for (const struct block *b = it->second;
Tom> - b != nullptr;
Tom> - b = b->superblock ())
Tom> - {
Tom> - if (b->function () != nullptr && b->inlined_p ())
Tom> - {
Tom> - if (b->superblock () != nullptr
Tom> - && b->superblock ()->function () != nullptr
Tom> - && !b->superblock ()->inlined_p ())
Tom> - {
Tom> - block = const_cast<struct block *> (b);
Tom> - break;
Tom> - }
Tom> - }
Tom> - }
Tom> + for (auto b : block::block_and_superblocks (it->second))
Tom> + if (b->inlined_p ()
Tom> + && b->superblock () != nullptr
Tom> + && b->superblock ()->function () != nullptr
Tom> + && !b->superblock ()->inlined_p ())
Tom> + {
Tom> + block = const_cast<struct block *> (b);
Tom> + break;
Tom> + }
It took me a while to figure out why you removed the check of
'function', but it's because inlined_p already does this check.
It's helpful to call out this kind of change or to put it in a separate
patch.
Tom> --- a/gdb/infrun.c
Tom> +++ b/gdb/infrun.c
Tom> @@ -8261,13 +8261,15 @@ process_event_stop_test (struct execution_control_state *ecs)
Tom> const struct block *prev
Tom> = block_for_pc (ecs->event_thread->control.step_frame_id.code_addr);
Tom> const struct block *curr = block_for_pc (ecs->event_thread->stop_pc ());
Tom> - while (curr != nullptr && !curr->contains (prev))
Tom> + for (auto b : block::block_and_superblocks (curr))
Tom> {
This code would be clearer if 'curr' were eliminated entirely.
In this case I had to go see if it was used after the loop.
Tom> + auto range = block::block_and_superblocks (cur_block);
Tom> + for (auto b = range.begin (); b != range.end (); ++b, cur_block = *b)
This is another case where the result is harder to reason about that the
earlier code.
Maybe it could be salvaged somehow by assigning at the breaks, not sure.
Tom> diff --git a/gdb/symmisc.c b/gdb/symmisc.c
Tom> index 89374bd8a2f..f882f3add17 100644
Tom> --- a/gdb/symmisc.c
Tom> +++ b/gdb/symmisc.c
Tom> @@ -961,11 +961,10 @@ block_depth (const struct block *block)
Tom> {
Tom> int i = 0;
Tom> - while ((block = block->superblock ()) != NULL)
Tom> - {
Tom> - i++;
Tom> - }
Tom> - return i;
Tom> + for (auto b [[maybe_unused]]: block::block_and_superblocks (block))
Tom> + i++;
Tom> +
Tom> + return i - 1;
Can this just be std::count?
Also this doesn't have to handle the case where the initial block is
nullptr.
Tom> + auto range = block::block_and_superblocks (bl);
Tom> + for (auto b = range.begin (); b != range.end (); ++b, bl = *b)
Like the earlier ones. I don't think multiple assignments like this
make it clearer or easier to work with.
Tom
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 00/10] [gdb] Add superblocks range loops
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
` (9 preceding siblings ...)
2026-05-01 12:45 ` [PATCH 10/10] [gdb] Use block::block_and_superblocks_in_fn Tom de Vries
@ 2026-06-09 12:40 ` Tom de Vries
10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-06-09 12:40 UTC (permalink / raw)
To: gdb-patches
On 5/1/26 2:44 PM, Tom de Vries wrote:
> [gdb] Add unit test for next_iterator
> [gdbsupport] Use using instead of typedef in next_iterator
I've committed these two patches.
I had Claude Code review these, and it complained about a magic constant
in the unit test, so I eliminated this. The change is so trivial that
it doesn't look worth the trouble of re-posting the patch.
Thanks,
- Tom
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-06-09 12:41 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
2026-05-01 12:44 ` [PATCH 01/10] [gdb] Use block::containing_function Tom de Vries
2026-05-01 12:44 ` [PATCH 02/10] [gdb] Factor out block::containing_function_block Tom de Vries
2026-05-01 12:44 ` [PATCH 03/10] [gdb] Use block::containing_function_block Tom de Vries
2026-05-01 12:44 ` [PATCH 04/10] [gdb] Add unit test for next_iterator Tom de Vries
2026-05-01 12:44 ` [PATCH 05/10] [gdbsupport] Use using instead of typedef in next_iterator Tom de Vries
2026-05-01 12:45 ` [PATCH 06/10] [gdbsupport] Factor out base_next_iterator Tom de Vries
2026-05-08 19:17 ` Tom Tromey
2026-05-01 12:45 ` [PATCH 07/10] [gdb] Add block::block_and_superblocks Tom de Vries
2026-05-01 12:45 ` [PATCH 08/10] [gdb] Use block::block_and_superblocks Tom de Vries
2026-05-08 19:41 ` Tom Tromey
2026-05-01 12:45 ` [PATCH 09/10] [gdb] Add block::block_and_superblocks_in_fn Tom de Vries
2026-05-01 12:45 ` [PATCH 10/10] [gdb] Use block::block_and_superblocks_in_fn Tom de Vries
2026-06-09 12:40 ` [PATCH 00/10] [gdb] Add superblocks range loops 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