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 08/18] gdb/python: allow instantiation of gdb.Objfile from Python
Date: Mon, 23 Jun 2025 17:10:03 +0100 [thread overview]
Message-ID: <20250623161013.650814-9-jan.vrany@labware.com> (raw)
In-Reply-To: <20250623161013.650814-1-jan.vrany@labware.com>
This commit adds code to allow user extension to instantiate
gdb.Objfile. This is a step towards a Python support for dynamically
generated code (JIT) in GDB.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
gdb/doc/python.texi | 13 +++
gdb/python/py-inferior.c | 10 +++
gdb/python/py-objfile.c | 111 +++++++++++++++++++++++-
gdb/python/python-internal.h | 1 +
gdb/testsuite/gdb.python/py-objfile.exp | 38 +++++++-
5 files changed, 169 insertions(+), 4 deletions(-)
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 3ef3699d355..ad9d65636b7 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -5793,6 +5793,19 @@ Reading symbols from ./hello...
A @code{gdb.Objfile} object has the following methods:
+@defun Objfile.__init__ (filename @r{[}, inferior @r{][}, arch @r{]})
+Create a new objfile with given @var{filename}.
+
+The optional @var{inferior} argument specifies the inferior to which the newly
+created objfile is added. Defaults to currently selected inferior.
+@pxref{Inferiors In Python}.
+
+The optional @var{arch} argument specifies the architectore to associate with
+the newly created objfile. Defaults to inferior's architecture.
+@xref{Architectures In Python}.
+
+@end defun
+
@defun Objfile.is_valid ()
Returns @code{True} if the @code{gdb.Objfile} object is valid,
@code{False} if not. A @code{gdb.Objfile} object can become invalid
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index 2aa11d3160d..250e16fa0d0 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -225,6 +225,16 @@ python_free_objfile (struct objfile *objfile)
gdbpy_print_stack ();
}
+/* Return inferior reference that is wrapped by this object. */
+
+inferior *
+inferior_object_to_inferior (PyObject *obj)
+{
+ if (! PyObject_TypeCheck (obj, &inferior_object_type))
+ return nullptr;
+ return ((inferior_object *) obj)->inferior;
+}
+
/* Return a reference to the Python object of type Inferior
representing INFERIOR. If the object has already been created,
return it and increment the reference count, otherwise, create it.
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index b76f57e818d..6403db583a7 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -25,6 +25,7 @@
#include "symtab.h"
#include "python.h"
#include "inferior.h"
+#include "observable.h"
struct objfile_object
{
@@ -251,6 +252,84 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
return (PyObject *) self.release ();
}
+/* Object initializer; creates new a objfile.
+
+ Use: __init__(FILENAME [, INFERIOR [,ARCH]]). */
+
+static int
+objfpy_init (PyObject *zelf, PyObject *args, PyObject *kw)
+{
+ struct objfile_object *self = (struct objfile_object*) zelf;
+
+ if (self->objfile)
+ {
+ PyErr_Format (PyExc_RuntimeError,
+ _("Objfile object already initialized."));
+ return -1;
+ }
+
+ static const char *keywords[] = { "filename", "inferior", "arch", nullptr };
+ const char *filename;
+ PyObject* inf_obj = nullptr;
+ PyObject* arch_obj = nullptr;
+
+
+ if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|OO", keywords,
+ &filename, &inf_obj, &arch_obj))
+ return -1;
+
+ inferior *inf = nullptr;
+ if (inf_obj)
+ {
+ inf = inferior_object_to_inferior (inf_obj);
+ if (! inf)
+ {
+ PyErr_Format (PyExc_TypeError,
+ _("The inferior argument is not gdb.Inferior object"));
+ return -1;
+ }
+ }
+ else
+ {
+ inf = current_inferior ();
+ }
+
+ gdbarch *arch = nullptr;
+ if (arch_obj)
+ {
+ if (! gdbpy_is_architecture (arch_obj))
+ {
+ PyErr_Format (PyExc_TypeError,
+ _("The arch argument is not gdb.Architecture object"));
+ return -1;
+ }
+ arch = arch_object_to_gdbarch (arch_obj);
+ }
+ else
+ {
+ arch = inf->arch ();
+ }
+
+ if (!objfpy_initialize (self))
+ {
+ PyErr_Format (PyExc_RuntimeError,
+ _("Failed to initialize Objfile object."));
+ return -1;
+ }
+
+ struct objfile *objfile;
+
+ objfile = objfile::make (nullptr, inf->pspace, filename, OBJF_NOT_FILENAME | OBJF_READNOW);
+ objfile->per_bfd->gdbarch = arch;
+
+ self->objfile = objfile;
+ objfpy_objfile_data_key.set(objfile, self);
+ /* Increment refcount on self as it is now referenced from objfile! */
+ Py_INCREF (self);
+
+ return 0;
+}
+
PyObject *
objfpy_get_printers (PyObject *o, void *ignore)
{
@@ -733,6 +812,32 @@ objfile_to_objfile_object (struct objfile *objfile)
return gdbpy_ref<>::new_reference (result);
}
+/* This function remove any dynamic objfiles left over when the
+ inferior exits. */
+
+static void
+objfpy_inferior_exit_hook (struct inferior *inf)
+{
+ for (objfile *objf : current_program_space->objfiles_safe ())
+ {
+ if (objf->obfd == nullptr)
+ {
+ /* Following check is to only unlink dynamic objfiles created by
+ Python code. Dynamic objfiles created by JIT reader API are
+ unlinked in jit_inferior_exit_hook (). */
+ if (objf->jited_data == nullptr || objf->jited_data->addr != 0)
+ objf->unlink ();
+ }
+ }
+}
+
+void _initialize_py_objfile ();
+void
+_initialize_py_objfile ()
+{
+ gdb::observers::inferior_exit.attach (objfpy_inferior_exit_hook, "py-objfile");
+}
+
static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_objfile (void)
{
@@ -837,8 +942,8 @@ PyTypeObject objfile_object_type =
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
- offsetof (objfile_object, dict), /* tp_dictoffset */
- 0, /* tp_init */
+ offsetof (objfile_object, dict),/* tp_dictoffset */
+ objfpy_init, /* tp_init */
0, /* tp_alloc */
- objfpy_new, /* tp_new */
+ objfpy_new, /* tp_new */
};
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 99e362c5221..18b78a7d235 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -567,6 +567,7 @@ 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);
+inferior *inferior_object_to_inferior(PyObject *obj);
extern PyObject *gdbpy_execute_mi_command (PyObject *self, PyObject *args,
PyObject *kw);
diff --git a/gdb/testsuite/gdb.python/py-objfile.exp b/gdb/testsuite/gdb.python/py-objfile.exp
index 8d1102896fa..055a35cea41 100644
--- a/gdb/testsuite/gdb.python/py-objfile.exp
+++ b/gdb/testsuite/gdb.python/py-objfile.exp
@@ -173,4 +173,40 @@ if ![ishost *-*-mingw*] {
gdb_py_test_silent_cmd "python objfile = gdb.objfiles()\[0\]" \
"get first objfile" 1
gdb_file_cmd ${binfile}
-gdb_test "python print(objfile)" "<gdb.Objfile \\\(invalid\\\)>"
+gdb_test "python print(objfile)" "<gdb.Objfile \\\(invalid\\\)>" "print invalid objfile"
+
+# Test creating objfile dynamically from Python
+gdb_py_test_silent_cmd "python objfile = gdb.Objfile(\"Test objfile\")" \
+ "create objfile" 1
+
+gdb_test "python print(objfile)" \
+ "<gdb.Objfile filename=Test objfile>" \
+ "print dynamic objfile"
+
+gdb_test "python print(objfile.is_file)" \
+ "False" \
+ "(dynamic) objfile.is_file"
+
+gdb_test "python print(objfile.is_valid())" \
+ "True" \
+ "(dynamic) objfile.is_valid()"
+
+gdb_test "python print(objfile in gdb.objfiles())" \
+ "True" \
+ "(dynamic) objfile in gdb.objfiles()"
+
+gdb_test "python print( gdb.Objfile(\"Test objfile 2\", gdb.selected_inferior()))" \
+ "<gdb.Objfile filename=Test objfile 2>" \
+ "create objfile with inferior"
+
+gdb_test "python print( gdb.Objfile(\"Test objfile 3\", gdb.selected_inferior(), gdb.selected_inferior().architecture()))" \
+ "<gdb.Objfile filename=Test objfile 3>" \
+ "create objfile with inferior and arch"
+
+gdb_test "python print( gdb.Objfile(\"Test objfile 4\", gdb))" \
+ "TypeError.*:.*" \
+ "create objfile with invalid inferior"
+
+gdb_test "python print( gdb.Objfile(\"Test objfile 5\", gdb.selected_inferior(), gdb.selected_inferior()))" \
+ "TypeError.*:.*" \
+ "create objfile with valid inferior but invalid arch"
--
2.47.2
next prev parent reply other threads:[~2025-06-23 16:14 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 ` [RFC v5 07/18] gdb/python: add gdb.Compunit Jan Vrany
2025-06-23 16:10 ` Jan Vrany [this message]
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-9-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