From: Jan Vrany <jan.vrany@labware.com>
To: gdb-patches@sourceware.org
Cc: Jan Vrany <jan.vrany@labware.com>, Eli Zaretskii <eliz@gnu.org>
Subject: [RFC v5 07/18] gdb/python: add gdb.Compunit
Date: Mon, 23 Jun 2025 17:10:02 +0100 [thread overview]
Message-ID: <20250623161013.650814-8-jan.vrany@labware.com> (raw)
In-Reply-To: <20250623161013.650814-1-jan.vrany@labware.com>
This commit introduces gdb.Compunit - a representation of struct
compunit_symtab in Python.
It also adds method gdb.Objfile.compunits() to get a list of compunits
for an objfile and adds compunit attribute to gdb.Block and gdb.Symtab
to access compunit containing given block or symbol table.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
gdb/Makefile.in | 1 +
gdb/NEWS | 2 +
gdb/doc/python.texi | 75 ++++++
gdb/python/py-block.c | 14 +
gdb/python/py-compunit.c | 311 ++++++++++++++++++++++
gdb/python/py-objfile.c | 31 +++
gdb/python/py-symtab.c | 14 +
gdb/python/python-internal.h | 3 +
gdb/testsuite/gdb.python/py-block.exp | 2 +
gdb/testsuite/gdb.python/py-compunit-1.c | 24 ++
gdb/testsuite/gdb.python/py-compunit-2.c | 28 ++
gdb/testsuite/gdb.python/py-compunit.exp | 83 ++++++
gdb/testsuite/gdb.python/py-compunit.link | 10 +
gdb/testsuite/gdb.python/py-symtab.exp | 8 +
14 files changed, 606 insertions(+)
create mode 100644 gdb/python/py-compunit.c
create mode 100644 gdb/testsuite/gdb.python/py-compunit-1.c
create mode 100644 gdb/testsuite/gdb.python/py-compunit-2.c
create mode 100644 gdb/testsuite/gdb.python/py-compunit.exp
create mode 100644 gdb/testsuite/gdb.python/py-compunit.link
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 998203ce1e2..c74031891be 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -440,6 +440,7 @@ SUBDIR_PYTHON_SRCS = \
python/py-value.c \
python/py-varobj.c \
python/py-xmethods.c \
+ python/py-compunit.c \
python/python.c
SUBDIR_PYTHON_OBS = $(patsubst %.c,%.o,$(SUBDIR_PYTHON_SRCS))
diff --git a/gdb/NEWS b/gdb/NEWS
index e8e32a5dd5c..8e381329f9a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -333,6 +333,8 @@ vFile:stat
** Added gdb.Type.function. Returns a new gdb.Type representing a function
returning that type. Parameter types can be specified too.
+ ** Added class gdb.Compunit.
+
* Debugger Adapter Protocol changes
** The "scopes" request will now return a scope holding global
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 633526dc875..3ef3699d355 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -220,6 +220,7 @@ optional arguments while skipping others. Example:
* Blocks In Python:: Accessing blocks from Python.
* Symbols In Python:: Python representation of symbols.
* Symbol Tables In Python:: Python representation of symbol tables.
+* Compunits In Python:: Python representation of compunits.
* Line Tables In Python:: Python representation of line tables.
* Breakpoints In Python:: Manipulating breakpoints using Python.
* Finish Breakpoints in Python:: Setting Breakpoints on function return
@@ -5828,6 +5829,11 @@ Like @code{Objfile.lookup_global_symbol}, but searches for a global
symbol with static linkage named @var{name} in this objfile.
@end defun
+@defun Objfile.compunits ()
+Return a sequence of @code{gdb.Compunit} associated with this objfile.
+@xref{Compunits In Python}.
+@end defun
+
@node Frames In Python
@subsubsection Accessing inferior stack frames from Python
@@ -6180,6 +6186,11 @@ have a superblock that is not the static block -- for instance this
happens for an inlined function.
@end defvar
+@defvar Block.compunit
+The @code{gdb.Compunit} containing this block. @xref{Compunits In Python}.
+This attribute is not writable.
+@end defvar
+
@defvar Block.superblock
The block containing this block. If this parent block does not exist,
this attribute holds @code{None}. This attribute is not writable.
@@ -6613,6 +6624,11 @@ If no producer information is available then @code{None} is returned.
This attribute is not writable.
@end defvar
+@defvar Symtab.compunit
+The @code{gdb.Compunit} this symbol table belongs to.
+@xref{Compunits In Python}. This attribute is not writable.
+@end defvar
+
A @code{gdb.Symtab} object has the following methods:
@defun Symtab.is_valid ()
@@ -6642,6 +6658,65 @@ Return the line table associated with the symbol table.
@xref{Line Tables In Python}.
@end defun
+@node Compunits In Python
+@subsubsection Compunits representation in Python
+
+@cindex compunits in python
+@tindex gdb.Compunit
+
+A compilation unit -- compunit for short -- represents a piece of code
+compiled by compiler independently of the rest. It is a result of compiling
+(parts of) one or more source files.
+
+Access to compunits maintained by @value{GDBN} on objfiles
+is exposed to Python via @code{gdb.Compunit}. Compunit for a symbol table can
+be accessed via @code{compunit} property of @code{gdb.Symtab} object.
+@xref{Symbol Tables In Python}. Method @code{compunits} of
+@code{gdb.Objfile} can be used to get a list of all compunits belonging to
+that objfile. @xref{Objfiles In Python}.
+
+A @code{gdb.Compunit} object has the following attributes:
+
+@defvar Compunit.objfile
+The @code{gdb.Objfile} from which the compunit was extracted.
+@xref{Objfiles In Python}. This attribute is not writable.
+@end defvar
+
+@defvar Compunit.producer
+The name and possibly version number of the program that
+compiled the code in the compunit.
+The contents of this string is up to the compiler.
+If no producer information is available then @code{None} is returned.
+This attribute is not writable.
+@end defvar
+
+@defvar Compunit.symtabs
+The sequence of @code{gdb.Symtab} objects associated with this compunit.
+@xref{Symbol Tables In Python}. This attribute is not writable.
+@end defvar
+
+A @code{gdb.Compunit} object has the following methods:
+
+@defun Compunit.is_valid ()
+Returns @code{True} if the @code{gdb.Compunit} object is valid,
+@code{False} if not. A @code{gdb.Compunit} object can become invalid if
+the compunit it refers to does not exist in @value{GDBN} any
+longer. All other @code{gdb.Compunit} methods will throw an exception
+if it is invalid at the time the method is called. Similarly, accessing
+any of the attributes will throw an exception if it is invalid at the time
+the attribute is accessed.
+@end defun
+
+@defun Compunit.global_block ()
+Return @code{gdb.Block} object representing the global block of the
+underlying compunit. @xref{Blocks In Python}.
+@end defun
+
+@defun Compunit.static_block ()
+Return @code{gdb.Block} object representing the static block of the
+underlying compunit. @xref{Blocks In Python}.
+@end defun
+
@node Line Tables In Python
@subsubsection Manipulating line tables using Python
diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c
index fa7dd192280..89315ebf866 100644
--- a/gdb/python/py-block.c
+++ b/gdb/python/py-block.c
@@ -218,6 +218,18 @@ blpy_get_static_block (PyObject *self, void *closure)
return block_to_block_object (static_block, self_obj->objfile);
}
+/* Getter function for Block.compunit. */
+
+static PyObject *
+blpy_get_compunit (PyObject *self, void *closure)
+{
+ const struct block *block;
+
+ BLPY_REQUIRE_VALID (self, block);
+
+ return compunit_to_compunit_object (block->global_block ()->compunit ());
+}
+
/* Implementation of gdb.Block.is_global (self) -> Boolean.
Returns True if this block object is a global block. */
@@ -556,6 +568,8 @@ static gdb_PyGetSetDef block_object_getset[] = {
"Block containing the global block.", NULL },
{ "static_block", blpy_get_static_block, NULL,
"Block containing the static block.", NULL },
+ { "compunit", blpy_get_compunit, nullptr,
+ "Compunit containing this block.", nullptr },
{ "is_static", blpy_is_static, NULL,
"Whether this block is a static block.", NULL },
{ "is_global", blpy_is_global, NULL,
diff --git a/gdb/python/py-compunit.c b/gdb/python/py-compunit.c
new file mode 100644
index 00000000000..a2d7620f483
--- /dev/null
+++ b/gdb/python/py-compunit.c
@@ -0,0 +1,311 @@
+/* Python interface to compunits.
+
+ Copyright (C) 2025-2025 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 "charset.h"
+#include "symtab.h"
+#include "source.h"
+#include "python-internal.h"
+#include "objfiles.h"
+#include "block.h"
+
+struct compunit_object {
+ PyObject_HEAD
+
+ /* The GDB compunit structure. */
+ struct compunit_symtab *compunit;
+
+ /* A compunit object is associated with an objfile, so keep track with
+ a single-linked list, rooted in the objfile. This allows
+ invalidation of the underlying struct compunit_symtab when the objfile is
+ deleted. */
+ compunit_object *next;
+};
+
+/* This function is called when an objfile is about to be freed.
+ Invalidate the compunit as further actions on the compunit
+ would result in bad data. All access to obj->compunit should be
+ gated by CUPY_REQUIRE_VALID which will raise an exception on
+ compunits. */
+struct cupy_deleter
+{
+ void operator() (compunit_object *obj)
+ {
+ gdbpy_enter enter_py;
+
+ while (obj != nullptr)
+ {
+ compunit_object *next = obj->next;
+
+ obj->compunit = nullptr;
+ obj->next = nullptr;
+ Py_DECREF (obj);
+
+ obj = next;
+ }
+ }
+};
+
+extern PyTypeObject compunit_object_type
+ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("compunit_object");
+static const registry<objfile>::key<compunit_object, cupy_deleter>
+ cupy_objfile_data_key;
+
+/* Require a valid compunit. All access to compunit_object->compunit
+ should be gated by this call. */
+
+#define CUPY_REQUIRE_VALID(compunit_obj, compunit) \
+ do { \
+ compunit = compunit_object_to_compunit (compunit_obj); \
+ if (compunit == nullptr) \
+ { \
+ PyErr_SetString (PyExc_RuntimeError, \
+ _("Compunit object is invalid.")); \
+ return nullptr; \
+ } \
+ } while (0)
+
+
+/* Getter function for gdb.Compunit.objfile. */
+
+static PyObject *
+cupy_get_objfile (PyObject *self, void *closure)
+{
+ struct compunit_symtab *compunit = nullptr;
+
+ CUPY_REQUIRE_VALID (self, compunit);
+
+ return objfile_to_objfile_object (compunit->objfile ()).release ();
+}
+
+/* Getter function for gdb.Compunit.producer. */
+
+static PyObject *
+cupy_get_producer (PyObject *self, void *closure)
+{
+ struct compunit_symtab *compunit = nullptr;
+
+ CUPY_REQUIRE_VALID (self, compunit);
+ if (compunit->producer () != nullptr)
+ {
+ const char *producer = compunit->producer ();
+
+ return host_string_to_python_string (producer).release ();
+ }
+
+ Py_RETURN_NONE;
+}
+
+/* Implementation of gdb.Compunit.is_valid (self) -> Boolean.
+ Returns True if this Symbol table still exists in GDB. */
+
+static PyObject *
+cupy_is_valid (PyObject *self, PyObject *args)
+{
+ struct compunit_symtab *compunit = nullptr;
+
+ compunit = compunit_object_to_compunit (self);
+ if (compunit == nullptr)
+ Py_RETURN_FALSE;
+
+ Py_RETURN_TRUE;
+}
+
+/* Return the GLOBAL_BLOCK of the underlying compunit. */
+
+static PyObject *
+cupy_global_block (PyObject *self, PyObject *args)
+{
+ struct compunit_symtab *compunit = nullptr;
+
+ CUPY_REQUIRE_VALID (self, compunit);
+
+ const struct blockvector *blockvector = compunit->blockvector ();
+ const struct block *block = blockvector->global_block ();
+
+ return block_to_block_object (block, compunit->objfile ());
+}
+
+/* Return the STATIC_BLOCK of the underlying compunit. */
+
+static PyObject *
+cupy_static_block (PyObject *self, PyObject *args)
+{
+ struct compunit_symtab *compunit = nullptr;
+
+ CUPY_REQUIRE_VALID (self, compunit);
+
+ const struct blockvector *blockvector = compunit->blockvector ();
+ const struct block *block = blockvector->static_block ();
+
+ return block_to_block_object (block, compunit->objfile ());
+}
+
+/* Return a list of gdb.Symtab objects associated with the underlying
+ compunit. */
+
+static PyObject *
+cupy_get_symtabs (PyObject *self, void *closure)
+{
+ struct compunit_symtab *compunit = nullptr;
+
+ CUPY_REQUIRE_VALID (self, compunit);
+
+ gdbpy_ref<> list (PyList_New (0));
+ if (list == nullptr)
+ return nullptr;
+
+ for (struct symtab *each : compunit->filetabs ())
+ {
+ gdbpy_ref<> item (symtab_to_symtab_object (each));
+ if (item.get () == nullptr
+ || PyList_Append (list.get (), item.get ()) == -1)
+ {
+ return nullptr;
+ }
+ }
+
+ return list.release ();
+}
+
+/* Given a compunit, and a compunit_object that has previously been
+ allocated and initialized, populate the compunit_object with the
+ struct compunit_symtab data. Also, register the compunit_object life-cycle
+ with the life-cycle of the object file associated with this
+ compunit, if needed. */
+static void
+set_compunit (compunit_object *obj, struct compunit_symtab *compunit)
+{
+ obj->compunit = compunit;
+ obj->next = cupy_objfile_data_key.get (compunit->objfile ());
+ cupy_objfile_data_key.set (compunit->objfile (), obj);
+
+ Py_INCREF (obj);
+}
+
+/* Return a new reference to gdb.Compunit Python object representing
+ COMPUNIT. Return NULL and set the Python error on failure. */
+PyObject *
+compunit_to_compunit_object (struct compunit_symtab *compunit)
+{
+ gdb_assert (compunit != nullptr);
+
+ compunit_object *compunit_obj
+ = cupy_objfile_data_key.get (compunit->objfile ());
+ while (compunit_obj != nullptr)
+ {
+ if (compunit_obj->compunit == compunit)
+ {
+ Py_INCREF (compunit_obj);
+ return (PyObject*)compunit_obj;
+ }
+ compunit_obj = compunit_obj->next;
+ }
+
+ compunit_obj = PyObject_New (compunit_object, &compunit_object_type);
+ if (compunit_obj)
+ set_compunit (compunit_obj, compunit);
+
+ return (PyObject * )compunit_obj;
+}
+
+/* Return struct compunit_symtab reference that is wrapped by this object. */
+struct compunit_symtab *
+compunit_object_to_compunit (PyObject *obj)
+{
+ if (! PyObject_TypeCheck (obj, &compunit_object_type))
+ return nullptr;
+ return ((compunit_object *) obj)->compunit;
+}
+
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
+gdbpy_initialize_compunits (void)
+{
+ if (gdbpy_type_ready (&compunit_object_type) < 0)
+ return -1;
+
+ return 0;
+}
+
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_compunits);
+
+\f
+
+static gdb_PyGetSetDef compunit_object_getset[] = {
+ { "objfile", cupy_get_objfile, nullptr, "The compunit's objfile.",
+ nullptr },
+ { "producer", cupy_get_producer, nullptr,
+ "The name/version of the program that compiled this compunit.", nullptr },
+ { "symtabs", cupy_get_symtabs, nullptr,
+ "List of symbol tables associated with this compunit", nullptr },
+ {nullptr} /* Sentinel */
+};
+
+static PyMethodDef compunit_object_methods[] = {
+ { "is_valid", cupy_is_valid, METH_NOARGS,
+ "is_valid () -> Boolean.\n\
+Return true if this compunit is valid, false if not." },
+ { "global_block", cupy_global_block, METH_NOARGS,
+ "global_block () -> gdb.Block.\n\
+Return the global block of the compunit." },
+ { "static_block", cupy_static_block, METH_NOARGS,
+ "static_block () -> gdb.Block.\n\
+Return the static block of the compunit." },
+ {nullptr} /* Sentinel */
+};
+
+PyTypeObject compunit_object_type = {
+ PyVarObject_HEAD_INIT (nullptr, 0)
+ "gdb.Compunit", /*tp_name*/
+ sizeof (compunit_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB compunit object", /*tp_doc */
+ 0, /*tp_traverse */
+ 0, /*tp_clear */
+ 0, /*tp_richcompare */
+ 0, /*tp_weaklistoffset */
+ 0, /*tp_iter */
+ 0, /*tp_iternext */
+ compunit_object_methods, /*tp_methods */
+ 0, /*tp_members */
+ compunit_object_getset, /*tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew /* tp_new */
+};
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index 1c6f5697302..b76f57e818d 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -544,6 +544,33 @@ objfpy_repr (PyObject *self_)
objfile_name (obj));
}
+/* Implementation of gdb.Objfile.compunits() -> List */
+
+static PyObject *
+objfpy_compunits (PyObject *self_, PyObject *args)
+{
+ objfile_object *self = (objfile_object *) self_;
+
+ OBJFPY_REQUIRE_VALID (self);
+
+ gdbpy_ref<> list (PyList_New (0));
+ if (list == nullptr)
+ return nullptr;
+
+ self->objfile->expand_all_symtabs ();
+
+ for (struct compunit_symtab *compunit : self->objfile->compunits ())
+ {
+ PyObject *item = compunit_to_compunit_object (compunit);
+
+ if (item == nullptr
+ || PyList_Append (list.get (), item) == -1)
+ return nullptr;
+ }
+
+ return list.release ();
+}
+
/* Subroutine of gdbpy_lookup_objfile_by_build_id to simplify it.
Return non-zero if STRING is a potentially valid build id. */
@@ -737,6 +764,10 @@ Look up a global symbol in this objfile and return it." },
"lookup_static_symbol (name [, domain]).\n\
Look up a static-linkage global symbol in this objfile and return it." },
+ { "compunits", objfpy_compunits, METH_NOARGS,
+ "compunits () -> List.\n\
+Return a sequence of compunits associated to this objfile." },
+
{ NULL }
};
diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
index 9f7bdb0f132..806a6efa4fd 100644
--- a/gdb/python/py-symtab.c
+++ b/gdb/python/py-symtab.c
@@ -149,6 +149,18 @@ stpy_get_producer (PyObject *self, void *closure)
Py_RETURN_NONE;
}
+/* Getter function for Symtab.compunit. */
+
+static PyObject *
+stpy_get_compunit (PyObject *self, void *closure)
+{
+ struct symtab *symtab = nullptr;
+
+ STPY_REQUIRE_VALID (self, symtab);
+
+ return compunit_to_compunit_object (symtab->compunit ());
+}
+
static PyObject *
stpy_fullname (PyObject *self, PyObject *args)
{
@@ -448,6 +460,8 @@ static gdb_PyGetSetDef symtab_object_getset[] = {
NULL },
{ "producer", stpy_get_producer, NULL,
"The name/version of the program that compiled this symtab.", NULL },
+ { "compunit", stpy_get_compunit, nullptr,
+ "The compunit this symtab belongs to.", nullptr },
{NULL} /* Sentinel */
};
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 7f4237eecc2..99e362c5221 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -548,6 +548,8 @@ gdbpy_ref<thread_object> create_thread_object (struct thread_info *tp);
gdbpy_ref<> thread_to_thread_object (thread_info *thr);;
gdbpy_ref<inferior_object> inferior_to_inferior_object (inferior *inf);
+PyObject *compunit_to_compunit_object (struct compunit_symtab *compunit);
+
PyObject *gdbpy_buffer_to_membuf (gdb::unique_xmalloc_ptr<gdb_byte> buffer,
CORE_ADDR address, ULONGEST length);
@@ -564,6 +566,7 @@ struct symtab *symtab_object_to_symtab (PyObject *obj);
struct symtab_and_line *sal_object_to_symtab_and_line (PyObject *obj);
frame_info_ptr frame_object_to_frame_info (PyObject *frame_obj);
struct gdbarch *arch_object_to_gdbarch (PyObject *obj);
+struct compunit_symtab *compunit_object_to_compunit (PyObject *obj);
extern PyObject *gdbpy_execute_mi_command (PyObject *self, PyObject *args,
PyObject *kw);
diff --git a/gdb/testsuite/gdb.python/py-block.exp b/gdb/testsuite/gdb.python/py-block.exp
index ce3f7ce04c4..11c2de8fc6f 100644
--- a/gdb/testsuite/gdb.python/py-block.exp
+++ b/gdb/testsuite/gdb.python/py-block.exp
@@ -104,6 +104,8 @@ gdb_test "python print (repr (block))" \
"Check block in many_locals_func"
gdb_test "python print (block.function)" "many_locals_func" \
"many_locals_func block"
+gdb_test "python print(block.compunit)" "<gdb\.Compunit object at .*>" \
+ "test compunit property"
# Switch frames, then test for main block.
gdb_test "up" ".*"
diff --git a/gdb/testsuite/gdb.python/py-compunit-1.c b/gdb/testsuite/gdb.python/py-compunit-1.c
new file mode 100644
index 00000000000..f0f43fdd4ff
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-compunit-1.c
@@ -0,0 +1,24 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2025-2025 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+int give_me_zero ();
+
+int
+main ()
+{
+ return give_me_zero ();
+}
diff --git a/gdb/testsuite/gdb.python/py-compunit-2.c b/gdb/testsuite/gdb.python/py-compunit-2.c
new file mode 100644
index 00000000000..f38a49ea30f
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-compunit-2.c
@@ -0,0 +1,28 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2025-2025 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+int __attribute__ ((section (".text_give_me_one"))) __attribute__((noinline))
+give_me_one ()
+{
+ return 1;
+}
+
+int __attribute__ ((section (".text_give_me_zero")))
+give_me_zero ()
+{
+ return give_me_one() - 1;
+}
diff --git a/gdb/testsuite/gdb.python/py-compunit.exp b/gdb/testsuite/gdb.python/py-compunit.exp
new file mode 100644
index 00000000000..9e5c4dc6e03
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-compunit.exp
@@ -0,0 +1,83 @@
+# Copyright (C) 2025-2025 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite. It tests the compunit
+# support in Python.
+
+load_lib gdb-python.exp
+
+require allow_python_tests
+
+# The test executable is compiled using two source files and uses custom
+# linker script. This is to force creation of two interleaved compunits
+# (py-compunit-1.c) with one function (main) and the other (py-compunit-2.c)
+# with two functions (get_me_one and get_me_zero) which are placed "before"
+# and "after" the main function.
+
+standard_testfile py-compunit-1.c py-compunit-2.c
+
+set ld_flags "-static -T${srcdir}/${subdir}/py-compunit.link"
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+ [list $srcfile $srcfile2] \
+ [list debug additional_flags=$ld_flags]]} {
+ return -1
+}
+
+if {![runto_main]} {
+ return 0
+}
+
+set python_error_text "Error occurred in Python.*"
+
+gdb_py_test_silent_cmd "python sym = gdb.lookup_symbol(\"main\")" \
+ "Find a symbol in objfile" 1
+gdb_py_test_silent_cmd "python objfile = sym\[0\].symtab.objfile" \
+ "Get backing object file" 1
+
+gdb_test "python print (len(objfile.compunits()) > 0)" \
+ "True" \
+ "Get objfile compunits"
+gdb_test "python print (objfile.compunits())" \
+ "\\\[<gdb\.Compunit object at .*>\\\]" \
+ "Objfile compunits return a sequence of gdb.Compunit"
+gdb_py_test_silent_cmd "python compunit = objfile.compunits()\[0\]" \
+ "Get first compunit" 1
+gdb_test "python print (compunit.is_valid())" \
+ "True" \
+ "Compunit is valid"
+gdb_test "python print (compunit == compunit)" \
+ "True" \
+ "Compunits are comparable"
+gdb_test "python print (compunit is objfile.compunits()\[0\])" \
+ "True" \
+ "Compunits are identical"
+gdb_test "python print (len(objfile.compunits()\[0\].symtabs) > 0)" \
+ "True" \
+ "Get compunit symtabs"
+gdb_test "python print (objfile.compunits()\[0\].symtabs)" \
+ "\\\[<gdb\.Symtab.*>\\\]" \
+ "Compunit symtabs return a sequence of gdb.Symtab"
+
+
+gdb_unload "unload 1"
+
+gdb_test "python print (objfile.is_valid())" "False" \
+"Get objfile validity after unload"
+gdb_test "python print (compunit.is_valid())" "False" \
+"Get compunit validity after unload"
+gdb_py_test_silent_cmd "python compunit = None" \
+"Test compunit deallocation" 1
+gdb_test "python print (objfile.compunits())" "RuntimeError.*: Objfile no longer exists.*" \
+"Get objfile compunits after unload"
diff --git a/gdb/testsuite/gdb.python/py-compunit.link b/gdb/testsuite/gdb.python/py-compunit.link
new file mode 100644
index 00000000000..5b219acf916
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-compunit.link
@@ -0,0 +1,10 @@
+SECTIONS
+{
+ .text_give_me_zero 0x00080000 : { }
+} INSERT BEFORE .text;
+
+SECTIONS
+{
+ .text_give_me_one 0x00F00000 : { }
+}
+INSERT AFTER .text;
diff --git a/gdb/testsuite/gdb.python/py-symtab.exp b/gdb/testsuite/gdb.python/py-symtab.exp
index a4891f31288..4828a0a33b6 100644
--- a/gdb/testsuite/gdb.python/py-symtab.exp
+++ b/gdb/testsuite/gdb.python/py-symtab.exp
@@ -68,6 +68,8 @@ gdb_test "python print (sal.is_valid())" "True" "test sal.is_valid"
gdb_test "python print (symtab.filename)" ".*${py_symbol_c}" "test symtab.filename"
gdb_test "python print (symtab.objfile)" \
"<gdb.Objfile filename=.*${testfile}.*>" "test symtab.objfile"
+gdb_test "python print (symtab.compunit)" \
+ "<gdb.Compunit .*>" "test symtab.compunit"
gdb_test "python print (symtab.fullname())" ".*${full_py_symbol_c}" "test symtab.fullname"
gdb_test "python print (symtab.is_valid())" "True" "test symtab.is_valid()"
gdb_test "python print (\"qq\" in global_symbols)" "True" "test qq in global symbols"
@@ -89,6 +91,12 @@ gdb_test_multiple "python print (\"simple_struct\" in static_symbols)" \
}
}
}
+gdb_test "python print (symtab.compunit in symtab.objfile.compunits())" \
+ "True" "Test symtab.compunit in symtab.objfile.compunits()"
+gdb_test "python print (symtab.compunit.global_block() is symtab.global_block())" \
+ "True" "Test symtab.compunit.global_block() is symtab.global_block()"
+gdb_test "python print (symtab.compunit.static_block() is symtab.static_block())" \
+ "True" "Test symtab.compunit.static_block() is symtab.static_block()"
# Test symtab identity
gdb_test "python print (symtab is symtab)"\
--
2.47.2
next prev parent reply other threads:[~2025-06-23 16:13 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-23 16:09 [RFC v5 00/19] Add Python "JIT" API Jan Vrany
2025-06-23 16:09 ` [RFC v5 01/18] gdb: introduce expand_symtabs_maybe_overlapping Jan Vrany
2025-06-24 15:22 ` Tom Tromey
2025-06-26 15:05 ` Jan Vraný
2025-06-23 16:09 ` [RFC v5 02/18] gdb: introduce compunit_symtab::maybe_contains Jan Vrany
2025-06-23 16:09 ` [RFC v5 03/18] gdb: update is_addr_in_objfile to support "dynamic" objfiles Jan Vrany
2025-06-23 16:09 ` [RFC v5 04/18] gdb: introduce new function create_function_type Jan Vrany
2025-06-24 15:29 ` Tom Tromey
2025-06-26 11:12 ` Jan Vraný
2025-06-27 14:21 ` Tom Tromey
2025-06-27 14:30 ` Jan Vraný
2025-06-23 16:10 ` [RFC v5 05/18] gdb/python: add function () method to gdb.Type object Jan Vrany
2025-06-24 16:11 ` Tom Tromey
2025-06-26 11:13 ` Jan Vraný
2025-06-23 16:10 ` [RFC v5 06/18] gdb: use std::vector<> to hold on blocks in struct blockvector Jan Vrany
2025-06-23 16:10 ` Jan Vrany [this message]
2025-06-23 16:10 ` [RFC v5 08/18] gdb/python: allow instantiation of gdb.Objfile from Python Jan Vrany
2025-06-23 16:10 ` [RFC v5 09/18] gdb/python: add unlink () method to gdb.Objfile object Jan Vrany
2025-06-23 16:10 ` [RFC v5 10/18] gdb/python: allow instantiation of gdb.Compunit from Python Jan Vrany
2025-06-23 16:10 ` [RFC v5 11/18] gdb/python: allow instantiation of gdb.Symtab " Jan Vrany
2025-06-23 16:10 ` [RFC v5 12/18] gdb/python: allow instantiation of gdb.Block " Jan Vrany
2025-06-23 16:10 ` [RFC v5 13/18] gdb/python: allow instantiation of gdb.Symbol " Jan Vrany
2025-06-23 16:10 ` [RFC v5 14/18] gdb/python: add add_symbol () method to gdb.Block Jan Vrany
2025-08-29 14:10 ` Andrew Burgess
2025-08-29 14:14 ` Andrew Burgess
2025-06-23 16:10 ` [RFC v5 15/18] gdb/python: add more attributes to gdb.LinetableEntry objects Jan Vrany
2025-08-29 14:00 ` Andrew Burgess
2025-09-02 11:03 ` Jan Vraný
2025-06-23 16:10 ` [RFC v5 16/18] gdb/python: allow instantiation of gdb.LineTableEntry objects Jan Vrany
2025-06-23 16:10 ` [RFC v5 17/18] gdb/python: allow instantiation of gdb.LineTable objects Jan Vrany
2025-06-23 16:10 ` [RFC v5 18/18] gdb/python: add section in documentation on implementing JIT interface Jan Vrany
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250623161013.650814-8-jan.vrany@labware.com \
--to=jan.vrany@labware.com \
--cc=eliz@gnu.org \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox