diff options
| author | Matthieu Longo <matthieu.longo@arm.com> | 2025-07-17 18:36:41 +0100 |
|---|---|---|
| committer | Matthieu Longo <matthieu.longo@arm.com> | 2026-01-29 16:46:14 +0000 |
| commit | 9a84753aa7f8b8939cf4eea9c7f1db4b42e171e1 (patch) | |
| tree | 027a0af3564eff86d5d6800a436d757945e91cec /gdb/python/py-objfile.c | |
| parent | 8b0f0d5fbf8d870c433dc62ceaaf740740af9923 (diff) | |
| download | binutils-9a84753aa7f8b8939cf4eea9c7f1db4b42e171e1.tar.gz binutils-9a84753aa7f8b8939cf4eea9c7f1db4b42e171e1.tar.bz2 binutils-9a84753aa7f8b8939cf4eea9c7f1db4b42e171e1.zip | |
gdb: new setters and getters for __dict__, and attributes
GDB is currently using the Python unlimited API. Migrating the codebase
to the Python limited API would have for benefit to make a GDB build
artifacts compatible with older and newer versions of Python that they
were built with.
This patch prepares the ground for migrating the existing C extension
types from static types to heap-allocated ones, by removing the
dependency on tp_dictoffset, which is unavailable when using the limited
API.
One of the most common incompatibilities in the current static type
declarations is the tp_dictoffset slot, which specifies the dictionary
offset within the instance structure. Historically, the unlimited
API has provided two approaches to supply a dictionary for __dict__:
* A managed dictionary.
Setting Py_TPFLAGS_MANAGED_DICT in tp_flags indicates that the
instances of the type have a __dict__ attribute, and that the
dictionary is managed by Python.
According to the Python documentation, this is the recommended approach.
However, this flag was introduced in 3.12, together with
PyObject_VisitManagedDict() and PyObject_ClearManagedDict(), neither
of which is part of the limited API (at least for now). As a result,
this recommended approach is not viable in the context of the limited
API.
* An instance dictionary, for which the offset in the instance is
provided via tp_dictoffset.
According to the Python documentation, this "tp slot" is on the
deprecation path, and Py_TPFLAGS_MANAGED_DICT should be used instead.
Given the age of the GDB codebase and the requirement to support older
Python versions (>= 3.4), no need to argue that today, the implementation
of __dict__ relies on tp_dictoffset. However, in the context of the
limited API, PyType_Slot does not provide a Py_tp_dictoffset member, so
another approach is needed to provide __dict__ to instances of C extension
types.
Given the constraints of the limited API, the proposed solution consists
in providing a dictionary through a common base class, gdbpy__dict__wrapper.
This helper class owns a dictionary member corresponding to __dict__, and
any C extension type requiring a __dict__ must inherit from it. Since
extension object must also be convertible to PyObject, this wrapper class
publicly inherits from PyObject as well.
Access to the dictionary is provided via a custom getter defined in a
PyGetSetDef, similarily to what was previously done with gdb_py_generic_dict().
Because __dict__ participates in attribute look-up, and since this dictionary
is neither managed by Python nor exposed via tp_dictoffset, custom
implementations of tp_getattro and tp_setattro are required to correctly
redirect attribute look-ups to the dictionary. These custom implementations
— equivalent to PyObject_GenericGetAttr() and PyObject_GenericSetAttr() —
must be installed via tp_getattro / tp_setattro for static types, or
Py_tp_getattro / Py_tp_setattro for heap-allocated types.
- gdbpy__dict__wrapper: a base class for C extension objects that own a
__dict__.
- gdb_py_generic_dict_getter: a __dict__ getter for extension types
derived from gdbpy__dict__wrapper.
- gdb_py_generic_getattro: equivalent of PyObject_GenericGetAttr, but
fixes the look-up of __dict__.
- gdb_py_generic_setattro: equivalent of PyObject_GenericSetAttr, but
fixes the look-up of __dict__.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
Approved-By: Tom Tromey <tom@tromey.com>
Diffstat (limited to 'gdb/python/py-objfile.c')
| -rw-r--r-- | gdb/python/py-objfile.c | 18 |
1 files changed, 6 insertions, 12 deletions
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c index 8cf365a27dc..36acdb06a25 100644 --- a/gdb/python/py-objfile.c +++ b/gdb/python/py-objfile.c @@ -26,17 +26,11 @@ #include "python.h" #include "inferior.h" -struct objfile_object +struct objfile_object : public gdbpy_dict_wrapper { - PyObject_HEAD - /* The corresponding objfile. */ struct objfile *objfile; - /* Dictionary holding user-added attributes. - This is the __dict__ attribute of the object. */ - PyObject *dict; - /* The pretty-printer list of functions. */ PyObject *printers; @@ -739,8 +733,8 @@ Look up a static-linkage global symbol in this objfile and return it." }, static gdb_PyGetSetDef objfile_getset[] = { - { "__dict__", gdb_py_generic_dict, NULL, - "The __dict__ for this objfile.", &objfile_object_type }, + { "__dict__", gdb_py_generic_dict_getter, NULL, + "The __dict__ for this objfile.", NULL }, { "filename", objfpy_get_filename, NULL, "The objfile's filename, or None.", NULL }, { "username", objfpy_get_username, NULL, @@ -785,8 +779,8 @@ PyTypeObject objfile_object_type = 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ + gdb_py_generic_getattro, /*tp_getattro*/ + gdb_py_generic_setattro, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "GDB objfile object", /* tp_doc */ @@ -803,7 +797,7 @@ PyTypeObject objfile_object_type = 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - offsetof (objfile_object, dict), /* tp_dictoffset */ + 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ objfpy_new, /* tp_new */ |
