/* Python reference-holding class Copyright (C) 2016-2026 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 . */ #ifndef GDB_PYTHON_PY_REF_H #define GDB_PYTHON_PY_REF_H #include "gdbsupport/gdb_ref_ptr.h" #include "python-traits.h" /* A policy class for gdb::ref_ptr for Python reference counting. */ struct gdbpy_ref_policy { static void incref (PyObject *ptr) { Py_INCREF (ptr); } static void decref (PyObject *ptr) { Py_DECREF (ptr); } }; /* A gdb::ref_ptr that has been specialized for Python objects or their "subclasses". */ template using gdbpy_ref = gdb::ref_ptr; /* A wrapper class for Python extension objects that have a __dict__ attribute. Any Python C object extension needing __dict__ should inherit from this class. Given that the C extension object must also be convertible to PyObject, this wrapper class publicly inherits from PyObject as well. Access to the dict requires a custom getter defined via PyGetSetDef. gdb_PyGetSetDef my_object_getset[] = { gdbpy_dict_wrapper_cfg_dict_getter ("object"), ... { nullptr } }; It is also important to note that __dict__ is used during the attribute look-up. Since this dictionary is not managed by Python and is not exposed via tp_dictoffset, custom attribute getter (tp_getattro) and setter (tp_setattro) are required to correctly redirect attribute access to the dictionary: - gdb_py_generic_getattro (), assigned to tp_getattro for static types, or Py_tp_getattro for heap-allocated types. - gdb_py_generic_setattro (), assigned to tp_setattro for static types, or Py_tp_setattro for heap-allocated types. */ struct gdbpy_dict_wrapper : public PyObject { /* Dictionary holding user-added attributes. This is the __dict__ attribute of the object. */ PyObject *dict; /* Compute the address of the __dict__ attribute for the given PyObject. */ static PyObject **compute_addr (PyObject *self) { auto *wrapper = reinterpret_cast (self); return &wrapper->dict; } #define gdbpy_dict_wrapper_cfg_dict_getter(object_name) \ { \ "__dict__", /* name */ \ (getter) gdb_py_generic_dict_getter, \ (setter) nullptr, \ "The __dict__ for this " object_name ".", /* doc */ \ nullptr, /* closure */ \ } #define gdbpy_dict_wrapper_getsetattro \ /*tp_getattro*/ \ gdb_py_generic_getattro, \ /*tp_setattro*/ \ gdb_py_generic_setattro /* Allocate the dictionary pointed by 'dict'. Note: this method should be called once the object was allocated, when setting its attributes. */ bool allocate_dict () { dict = PyDict_New (); return dict != nullptr; } }; static_assert (gdb::is_python_allocatable_v); #endif /* GDB_PYTHON_PY_REF_H */