[RFC PATCH 3/3] gdb: Add support for writing overlay managers in python
Craig Blackmore
craig.blackmore@embecosm.com
Mon May 9 21:51:24 GMT 2022
Adds gdb_py_overlay_manager class which overrides most of the
public gdb_overlay_manager methods, deferring to python code to
implement them.
This allows the overlay manager support to be written in a python script
which implements the required hooks and likely contains internal details
of a specific overlay system. The script can then be shipped alongside
the overlay system.
GDB python has no concept of obj_section, therefore, it is not currently
possible to support python overlay managers that need to manipulate
sections.
---
gdb/Makefile.in | 1 +
gdb/python/py-overlay.c | 409 +++++++++++++++++++++++++++++++++++
gdb/python/python-internal.h | 3 +
gdb/python/python.c | 4 +-
4 files changed, 416 insertions(+), 1 deletion(-)
create mode 100644 gdb/python/py-overlay.c
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index d86ba85ccbc..2662958d017 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -412,6 +412,7 @@ SUBDIR_PYTHON_SRCS = \
python/py-micmd.c \
python/py-newobjfileevent.c \
python/py-objfile.c \
+ python/py-overlay.c \
python/py-param.c \
python/py-prettyprint.c \
python/py-progspace.c \
diff --git a/gdb/python/py-overlay.c b/gdb/python/py-overlay.c
new file mode 100644
index 00000000000..5ad7dbcab63
--- /dev/null
+++ b/gdb/python/py-overlay.c
@@ -0,0 +1,409 @@
+/* Python interface to overlay manager
+
+ Copyright (C) 2022 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 "defs.h"
+#include "python-internal.h"
+#include "python.h"
+#include "overlay.h"
+
+/* Constants for method names defined on a Python class. */
+#define PC_IN_UNMAPPED_RANGE_METHOD "pc_in_unmapped_range"
+#define PC_IN_MAPPED_RANGE_METHOD "pc_in_mapped_range"
+#define OVERLAY_UNMAPPED_ADDRESS_METHOD "overlay_unmapped_address"
+#define OVERLAY_MAPPED_ADDRESS_METHOD "overlay_mapped_address"
+#define SYMBOL_OVERLAYED_ADDRESS_METHOD "symbol_overlayed_address"
+#define HANDLE_OVERLAY_BP_EVENT_METHOD "handle_overlay_bp_event"
+#define OVERLAY_UPDATE_METHOD "overlay_update"
+#define OVERLAY_ADDRESS_FOR_SAL_METHOD "overlay_address_for_sal"
+#define LIST_OVERLAYS_COMMAND_METHOD "list_overlays_command"
+#define MAP_OVERLAY_COMMAND_METHOD "map_overlay_command"
+#define UNMAP_OVERLAY_COMMAND_METHOD "unmap_overlay_command"
+
+/* Declare. */
+struct gdbpy_ovly_mgr_object;
+
+/* An implementation of an overlay manager that delegates out to Python
+ code that the user can easily override. */
+
+class gdb_py_overlay_manager : public gdb_overlay_manager
+{
+public:
+ /* Constructor. */
+ gdb_py_overlay_manager (gdbpy_ovly_mgr_object *obj)
+ : gdb_overlay_manager (),
+ m_obj (obj)
+ {
+ Py_INCREF (m_obj);
+ }
+
+ /* Destructor. */
+ ~gdb_py_overlay_manager ()
+ {
+ gdb_assert (gdb_python_initialized);
+ gdbpy_enter enter_py;
+
+ Py_DECREF (m_obj);
+ }
+
+private:
+
+ /* Generic method for calling a python method which is expected to take a
+ CORE_ADDR. If the method is implemented return its result, else raise an
+ error.
+ */
+
+ PyObject *
+ call_python (CORE_ADDR addr, const char *method_name)
+ {
+ gdb_assert (gdb_python_initialized);
+ gdbpy_enter enter_py;
+
+ PyObject *obj = (PyObject *) m_obj;
+
+ /* If this method is not implemented, return addr. */
+ PyObject *match_method_name
+ = PyUnicode_FromString (method_name);
+ if (!PyObject_HasAttr ((PyObject *) obj, match_method_name))
+ error (_("could not find method %s"), method_name);
+
+ gdbpy_ref<> addr_arg (gdb_py_object_from_ulongest (addr));
+ if (addr_arg == nullptr)
+ {
+ gdbpy_print_stack ();
+ error (_("failed to convert addr to pass to %s"), method_name);
+ }
+
+ gdbpy_ref<> result (PyObject_CallMethodObjArgs (obj, match_method_name,
+ addr_arg.get (), NULL));
+ if (result == NULL)
+ {
+ gdbpy_print_stack ();
+ error (_("missing result object from %s"), method_name);
+ }
+
+ if (result == Py_None)
+ {
+ gdbpy_print_stack ();
+ error (_("%s returned None"), method_name);
+ }
+
+ return result.get ();
+ }
+
+ /* Generic method for calling a python method which is expected to take a
+ CORE_ADDR and return a bool.
+ */
+
+ bool
+ call_python_bool (CORE_ADDR addr, const char *method_name)
+ {
+ PyObject *result = call_python (addr, method_name);
+
+ return PyObject_IsTrue (result);
+ }
+
+ /* Generic method for calling a python method which is expected to take a
+ CORE_ADDR and return a CORE_ADDR.
+ */
+
+ CORE_ADDR
+ call_python_addr (CORE_ADDR addr, const char *method_name)
+ {
+ PyObject *result = call_python (addr, method_name);
+
+ if (get_addr_from_python (result, &addr) != 0)
+ {
+ gdbpy_print_stack ();
+ error (_("failed to convert address returned by %s"), method_name);
+ }
+
+ return addr;
+ }
+
+ /* Generic method for calling a python method, if implemented, which is
+ expected to take no arguments and return void. Raise an error if the
+ method is not implemented. */
+
+ void
+ call_python_void (const char *method_name)
+ {
+ gdb_assert (gdb_python_initialized);
+ gdbpy_enter enter_py;
+
+ PyObject *obj = (PyObject *) m_obj;
+
+ /* If this method is not implemented, return. */
+ if (!PyObject_HasAttrString (obj, method_name))
+ error (_("could not find method %s"), method_name);
+
+ gdbpy_ref<> result (PyObject_CallMethod (obj, method_name, NULL));
+
+ if (result == NULL)
+ {
+ gdbpy_print_stack ();
+ error (_("missing result object from %s"), method_name);
+ }
+ }
+
+ /* Return the result of calling HANDLE_OVERLAY_BP_EVENT_METHOD. */
+
+ void
+ handle_overlay_bp_event () override
+ {
+ call_python_void (HANDLE_OVERLAY_BP_EVENT_METHOD);
+ }
+
+ /* Return result of calling PC_IN_UNMAPPED_RANGE_METHOD.
+
+ We cannot pass section to PC_IN_UNMAPPED_RANGE_METHOD because GDB's python
+ support currently has no concept of obj_section. If an overlay manager
+ needed to access sections then obj_section would first need to be
+ supported. */
+
+ bool
+ pc_in_unmapped_range (CORE_ADDR addr,
+ ATTRIBUTE_UNUSED struct obj_section *section) override
+ {
+ return call_python_bool (addr, PC_IN_UNMAPPED_RANGE_METHOD);
+ }
+
+ /* Return result of calling PC_IN_MAPPED_RANGE_METHOD.
+
+ See pc_in_unmapped_range above regarding unused section parameter. */
+
+ bool
+ pc_in_mapped_range (CORE_ADDR addr,
+ ATTRIBUTE_UNUSED struct obj_section *section) override
+ {
+ return call_python_bool (addr, PC_IN_MAPPED_RANGE_METHOD);
+ }
+
+ /* Return result of calling OVERLAY_UNMAPPED_ADDRESS_METHOD.
+
+ See pc_in_unmapped_range above regarding unused section parameter. */
+
+ CORE_ADDR
+ overlay_unmapped_address (CORE_ADDR addr,
+ ATTRIBUTE_UNUSED struct obj_section *section)
+ override
+ {
+ return call_python_addr (addr, OVERLAY_UNMAPPED_ADDRESS_METHOD);
+ }
+
+ /* Return result of calling OVERLAY_MAPPED_ADDRESS_METHOD.
+
+ See pc_in_unmapped_range above regarding unused section parameter. */
+
+ CORE_ADDR
+ overlay_mapped_address (CORE_ADDR addr,
+ ATTRIBUTE_UNUSED struct obj_section *section)
+ override
+ {
+ return call_python_addr (addr, OVERLAY_MAPPED_ADDRESS_METHOD);
+ }
+
+ /* Return result of calling SYMBOL_OVERLAYED_ADDRESS_METHOD.
+
+ See pc_in_unmapped_range above regarding unused section parameter. */
+
+ CORE_ADDR
+ symbol_overlayed_address (CORE_ADDR addr,
+ ATTRIBUTE_UNUSED struct obj_section *section)
+ override
+ {
+ return call_python_addr (addr, SYMBOL_OVERLAYED_ADDRESS_METHOD);
+ }
+
+ /* Return result of calling OVERLAY_UPDATE_METHOD.
+
+ See pc_in_unmapped_range above regarding unused section parameter. */
+
+ void
+ overlay_update (ATTRIBUTE_UNUSED obj_section *) override
+ {
+ call_python_void (OVERLAY_UPDATE_METHOD);
+ }
+
+ /* Return result of calling OVERLAY_ADDRESS_FOR_SAL_METHOD. */
+
+ CORE_ADDR
+ overlay_address_for_sal (CORE_ADDR addr) override
+ {
+ return call_python_addr (addr, OVERLAY_ADDRESS_FOR_SAL_METHOD);
+ }
+
+ /* Since GDB python has no concept of sections, we cannot currently support
+ python overlay managers that need to deal with overlay sections. The
+ following methods are not required for non-section based managers so they
+ simply return nullptr or false.
+ */
+
+ struct obj_section *
+ find_pc_mapped_section (CORE_ADDR) override
+ {
+ return nullptr;
+ }
+
+ struct obj_section *
+ find_pc_overlay (CORE_ADDR) override
+ {
+ return nullptr;
+ }
+
+ bool
+ section_is_overlay (ATTRIBUTE_UNUSED struct obj_section *) override
+ {
+ return false;
+ }
+
+ bool
+ section_is_mapped (ATTRIBUTE_UNUSED struct obj_section *) override
+ {
+ return false;
+ }
+
+ void list_overlays_command (const char *args, int from_tty) override
+ {
+ call_python_void (LIST_OVERLAYS_COMMAND_METHOD);
+ }
+
+ void map_overlay_command (const char *args, int from_tty) override
+ {
+ call_python_void (MAP_OVERLAY_COMMAND_METHOD);
+ }
+
+ void unmap_overlay_command (const char *args, int from_tty) override
+ {
+ call_python_void (UNMAP_OVERLAY_COMMAND_METHOD);
+ }
+
+ void overlay_load_command (const char *args, int from_tty) override
+ {
+ overlay_update (nullptr);
+ }
+
+ /* The Python object associated with this overlay manager. */
+ gdbpy_ovly_mgr_object *m_obj;
+};
+
+/* Wrapper around a Python object, provides a mechanism to find the overlay
+ manager object from the Python object. */
+
+struct gdbpy_ovly_mgr_object {
+ /* Python boilerplate, must come first. */
+ PyObject_HEAD
+
+ /* Point at the actual overlay manager we created when this Python object
+ was created. This object is owned by the generic overlay management
+ code within GDB. */
+ gdb_py_overlay_manager *manager;
+};
+
+/* Initializer for OverlayManager object, it takes no parameters. */
+
+static int
+ovlpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ gdbpy_ovly_mgr_object *obj = (gdbpy_ovly_mgr_object *) self;
+ std::unique_ptr <gdb_py_overlay_manager> mgr
+ (new gdb_py_overlay_manager (obj));
+ obj->manager = mgr.get ();
+ overlay_manager_register (std::move (mgr));
+ return 0;
+}
+
+/* Deallocate OverlayManager object. */
+
+static void
+ovlpy_dealloc (PyObject *self)
+{
+ /* TODO: Should ensure that this object is no longer registered as the
+ overlay manager for GDB otherwise bad things will happen. */
+
+ /* Set this pointer to null not because we have to, but to protect
+ against any uses after we deallocate. */
+ gdbpy_ovly_mgr_object *obj = (gdbpy_ovly_mgr_object *) self;
+ obj->manager = nullptr;
+
+ /* Now ask Python to free this object. */
+ Py_TYPE (self)->tp_free (self);
+}
+
+void
+gdbpy_finalize_overlay (void)
+{
+ overlay_manager_register (nullptr);
+}
+
+/* Structure defining an OverlayManager object type. */
+
+PyTypeObject overlay_manager_object_type =
+{
+ PyVarObject_HEAD_INIT (NULL, 0)
+ "gdb.OverlayManager", /*tp_name*/
+ sizeof (gdbpy_ovly_mgr_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ ovlpy_dealloc, /*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 | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "GDB overlay manager object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ ovlpy_init, /* tp_init */
+ 0, /* tp_alloc */
+};
+
+/* Initialize the Python overlay code. */
+int
+gdbpy_initialize_overlay (void)
+{
+ overlay_manager_object_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&overlay_manager_object_type) < 0)
+ return -1;
+
+ if (gdb_pymodule_addobject (gdb_module, "OverlayManager",
+ (PyObject *) &overlay_manager_object_type) < 0)
+ return -1;
+ return 0;
+}
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index d947b96033b..e898017690c 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -540,6 +540,9 @@ int gdbpy_initialize_connection ()
int gdbpy_initialize_micommands (void)
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
void gdbpy_finalize_micommands ();
+int gdbpy_initialize_overlay (void)
+ CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+void gdbpy_finalize_overlay (void);
/* A wrapper for PyErr_Fetch that handles reference counting for the
caller. */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 7a9c8c1b66e..f2e03a5769e 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1892,6 +1892,7 @@ finalize_python (void *ignore)
gdbpy_enter::finalize ();
gdbpy_finalize_micommands ();
+ gdbpy_finalize_overlay ();
Py_Finalize ();
@@ -2072,7 +2073,8 @@ do_start_initialization ()
|| gdbpy_initialize_membuf () < 0
|| gdbpy_initialize_connection () < 0
|| gdbpy_initialize_tui () < 0
- || gdbpy_initialize_micommands () < 0)
+ || gdbpy_initialize_micommands () < 0
+ || gdbpy_initialize_overlay () < 0)
return false;
#define GDB_PY_DEFINE_EVENT_TYPE(name, py_name, doc, base) \
--
2.17.1
More information about the Gdb-patches
mailing list