[pushed] gdb/python: add property ranges to gdb.Block object

Message ID 20260325150756.2619246-1-jan@vrany.io
State New
Headers
Series [pushed] gdb/python: add property ranges to gdb.Block object |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 fail Patch failed to apply
linaro-tcwg-bot/tcwg_gdb_build--master-arm fail Patch failed to apply

Commit Message

Jan Vrany March 25, 2026, 3:08 p.m. UTC
  This commit adds a new property - ranges - to gdb.Block object. It holds
a tuple of ranges for that block. Each range is a tuple of (start, end)
address. For contiguous blocks it contains only one range.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Tom Tromey <tom@tromey.com>
---
 gdb/NEWS                              |  4 +++
 gdb/doc/python.texi                   |  8 ++++++
 gdb/python/py-block.c                 | 39 +++++++++++++++++++++++++++
 gdb/testsuite/gdb.python/py-block.exp |  3 +++
 4 files changed, 54 insertions(+)
  

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 03f46df5400..4cf91053c95 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -234,6 +234,10 @@  qExecAndArgs
      strings in the disassembler output can contain ANSI escape
      sequences to indicate styling.
 
+  ** New gdb.Block.ranges attribute.  This read only attribute contains
+     a tuple of pairs each representing a single range.  Contiguous blocks
+     have only one range.
+
 * Guile API
 
   ** Procedures 'memory-port-read-buffer-size',
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index d7718818def..e1e983726e8 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -6342,6 +6342,14 @@  One past the last address that appears in the block.  This attribute
 is not writable.
 @end defvar
 
+@defvar Block.ranges
+A tuple representing address ranges of the block.  Each range is represented
+as a pair (two-element tuple) where the first element is the start of the
+range and the second element is one past the last address that appears in
+the range. The order of ranges is unspecified.  Contiguous blocks have only
+one range.  This attribute is not writable.
+@end defvar
+
 @defvar Block.function
 The name of the block represented as a @code{gdb.Symbol}.  If the
 block is not named, then this attribute holds @code{None}.  This
diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c
index 4d77242ca0d..6e4b662cc51 100644
--- a/gdb/python/py-block.c
+++ b/gdb/python/py-block.c
@@ -117,6 +117,43 @@  blpy_get_end (PyObject *self, void *closure)
   return gdb_py_object_from_ulongest (block->end ()).release ();
 }
 
+/* Implementation of gdb.Block.ranges.  */
+
+static PyObject *
+blpy_get_ranges (PyObject *self, void *closure)
+{
+  const struct block *block = nullptr;
+
+  BLPY_REQUIRE_VALID (self, block);
+
+  auto ranges = block->ranges ();
+
+  if (ranges.size () == 0)
+    return Py_BuildValue ("((" GDB_PY_LLU_ARG GDB_PY_LLU_ARG "))",
+			  (gdb_py_ulongest) block->start (),
+			  (gdb_py_ulongest) block->end ());
+  else
+    {
+      gdbpy_ref<> ranges_obj (PyTuple_New (ranges.size ()));
+      if (ranges_obj == nullptr)
+	return nullptr;
+
+      for (int i = 0; i < ranges.size (); i++)
+	{
+	  gdbpy_ref<> range_obj
+	    (Py_BuildValue ("(" GDB_PY_LLU_ARG GDB_PY_LLU_ARG ")",
+			    (gdb_py_ulongest) ranges[i].start (),
+			    (gdb_py_ulongest) ranges[i].end ()));
+	  if (range_obj == nullptr)
+	    return nullptr;
+
+	  PyTuple_SetItem (ranges_obj.get (), i, range_obj.release ());
+	}
+
+      return ranges_obj.release ();
+    }
+}
+
 static PyObject *
 blpy_get_function (PyObject *self, void *closure)
 {
@@ -564,6 +601,8 @@  static gdb_PyGetSetDef block_object_getset[] = {
     "Whether this block is a global block.", NULL },
   { "subblocks", blpy_get_subblocks, nullptr,
     "List of blocks contained in this block.", nullptr },
+  { "ranges", blpy_get_ranges, nullptr,
+    "List of address ranges for this block.", nullptr },
   { NULL }  /* Sentinel */
 };
 
diff --git a/gdb/testsuite/gdb.python/py-block.exp b/gdb/testsuite/gdb.python/py-block.exp
index b483d4b8a92..e4e309da05f 100644
--- a/gdb/testsuite/gdb.python/py-block.exp
+++ b/gdb/testsuite/gdb.python/py-block.exp
@@ -43,6 +43,9 @@  gdb_test "python print (block)" "<gdb.Block <anonymous> \{i, f, b\}>" \
 gdb_test "python print (block.function)" "None" "first anonymous block"
 gdb_test "python print (block.start)" "${decimal}" "check start not None"
 gdb_test "python print (block.end)" "${decimal}" "check end not None"
+gdb_test "python print (block.ranges)" \
+	 "\\(\\(${decimal}, ${decimal}\\)(,|(, (\\(${decimal}, ${decimal}\\))+))\\)" \
+	 "check ranges contains tuple of tuples"
 gdb_test "python print (block\['f'\].name == 'f')" "True" "check variable access"
 gdb_test "python print (block\['nonexistent'\])" ".*KeyError.*: 'nonexistent'.*" \
 	 "check nonexistent variable"