python/py-micmd.c \
python/py-newobjfileevent.c \
python/py-objfile.c \
+ python/py-obj-type.c \
python/py-param.c \
python/py-prettyprint.c \
python/py-progspace.c \
if test "$enable_py_limited_api" = yes; then
- # The minimal Python limited API version is currently set to 3.11 for the
- # support of PyBuffer_FillInfo and PyBuffer_Release.
+ # The minimal Python limited API version is currently set to 3.14 for the
+ # support of Py_TYPE().
# The choice of the minimal version for the Python limited API won't be
# frozen until the end of the migration.
old_CFLAGS="$CFLAGS"
#ifndef PY_VERSION_HEX
#error "PY_VERSION_HEX is not defined"
#endif
-#if PY_VERSION_HEX < 0x030b0000
-#error "Python limited API support requires at least Python version 3.11"
+#if PY_VERSION_HEX < 0x030e0000
+#error "Python limited API support requires at least Python version 3.14"
#endif
int
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
-$as_echo "#define Py_LIMITED_API 0x030b0000" >>confdefs.h
+$as_echo "#define Py_LIMITED_API 0x030e0000" >>confdefs.h
else
- as_fn_error $? "Python limited API support requires at least Python version 3.11" "$LINENO" 5
+ as_fn_error $? "Python limited API support requires at least Python version 3.14" "$LINENO" 5
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
[enable_py_limited_api=no])
if test "$enable_py_limited_api" = yes; then
- # The minimal Python limited API version is currently set to 3.11 for the
- # support of PyBuffer_FillInfo and PyBuffer_Release.
+ # The minimal Python limited API version is currently set to 3.14 for the
+ # support of Py_TYPE().
# The choice of the minimal version for the Python limited API won't be
# frozen until the end of the migration.
old_CFLAGS="$CFLAGS"
#ifndef PY_VERSION_HEX
#error "PY_VERSION_HEX is not defined"
#endif
-#if PY_VERSION_HEX < 0x030b0000
-#error "Python limited API support requires at least Python version 3.11"
+#if PY_VERSION_HEX < 0x030e0000
+#error "Python limited API support requires at least Python version 3.14"
#endif
]],[[]])],
- [AC_DEFINE(Py_LIMITED_API, 0x030b0000,
+ [AC_DEFINE(Py_LIMITED_API, 0x030e0000,
[Define if GDB should be built against the Python limited C API.])
],[
- AC_MSG_ERROR([Python limited API support requires at least Python version 3.11])
+ AC_MSG_ERROR([Python limited API support requires at least Python version 3.14])
])
CFLAGS="$old_CFLAGS"
CPPFLAGS="$old_CPPFLAGS"
auto arch_info = gdbarch_bfd_arch_info (gdbarch);
return PyUnicode_FromFormat ("<%s arch_name=%s printable_name=%s>",
- Py_TYPE (self)->tp_name, arch_info->arch_name,
+ gdbpy_py_obj_tp_name (self),
+ arch_info->arch_name,
arch_info->printable_name);
}
if (++written_symbols < len)
str += ", ";
}
- return PyUnicode_FromFormat ("<%s %s {%s}>", Py_TYPE (self)->tp_name,
+ return PyUnicode_FromFormat ("<%s %s {%s}>",
+ gdbpy_py_obj_tp_name (self),
name, str.c_str ());
}
static PyObject *
bppy_repr (PyObject *self)
{
+ const char *tp_name = gdbpy_py_obj_tp_name (self);
+
const auto bp = (struct gdbpy_breakpoint_object*) self;
if (bp->bp == nullptr)
- return PyUnicode_FromFormat ("<%s (invalid)>", Py_TYPE (self)->tp_name);
+ return PyUnicode_FromFormat ("<%s (invalid)>", tp_name);
std::string str = " ";
if (bp->bp->thread != -1)
str.pop_back ();
return PyUnicode_FromFormat ("<%s%s number=%d hits=%d%s>",
- Py_TYPE (self)->tp_name,
+ tp_name,
(bp->bp->enable_state == bp_enabled
? "" : " disabled"), bp->bp->number,
bp->bp->hit_count, str.c_str ());
str += fn_name;
}
- return PyUnicode_FromFormat ("<%s %s>", Py_TYPE (self)->tp_name,
+ return PyUnicode_FromFormat ("<%s %s>",
+ gdbpy_py_obj_tp_name (py_self),
str.c_str ());
}
return gdb_py_invalid_object_repr (obj);
return PyUnicode_FromFormat ("<%s num=%d, what=\"%s\">",
- Py_TYPE (obj)->tp_name,
+ gdbpy_py_obj_tp_name (obj),
target->connection_number,
make_target_connection_string (target).c_str ());
}
bfd *core_bfd = get_inferior_core_bfd (obj->inferior);
gdb_assert (core_bfd != nullptr);
return PyUnicode_FromFormat ("<%s inferior=%d filename='%s'>",
- Py_TYPE (self)->tp_name,
+ gdbpy_py_obj_tp_name (self),
obj->inferior->num,
bfd_get_filename (core_bfd));
}
const char *arch_name
= (gdbarch_bfd_arch_info (obj->gdbarch))->printable_name;
return PyUnicode_FromFormat ("<%s address=%s architecture=%s>",
- Py_TYPE (obj)->tp_name,
+ gdbpy_py_obj_tp_name (self),
core_addr_to_string_nz (obj->address),
arch_name);
}
{
PyErr_Format (PyExc_ValueError,
_("Cannot use 'string' and 'parts' when creating %s."),
- Py_TYPE (self)->tp_name);
+ gdbpy_py_obj_tp_name (self));
return -1;
}
gdb_assert (obj->parts != nullptr);
return PyUnicode_FromFormat ("<%s length=%d string=\"%U\">",
- Py_TYPE (obj)->tp_name,
+ gdbpy_py_obj_tp_name (self),
obj->length,
disasmpy_result_str (self));
}
PyErr_Format
(PyExc_TypeError,
_("Result from Disassembler must be gdb.DisassemblerResult, not %s."),
- Py_TYPE (result.get ())->tp_name);
+ gdbpy_py_obj_tp_name (result.get ()));
gdbpy_print_stack ();
return std::optional<int> (-1);
}
static int
disasmpy_part_init (PyObject *self, PyObject *args, PyObject *kwargs)
{
- PyErr_SetString (PyExc_RuntimeError,
- _("Cannot create instances of DisassemblerPart."));
+ PyErr_Format (PyExc_RuntimeError,
+ _("Cannot create instances of %s."),
+ gdbpy_py_obj_tp_name (self));
return -1;
}
gdb_assert (obj->string != nullptr);
return PyUnicode_FromFormat ("<%s string='%s', style='%s'>",
- Py_TYPE (obj)->tp_name,
+ gdbpy_py_obj_tp_name (self),
obj->string->c_str (),
get_style_name (obj->style));
}
disasm_addr_part_object *obj = (disasm_addr_part_object *) self;
return PyUnicode_FromFormat ("<%s address='%s'>",
- Py_TYPE (obj)->tp_name,
+ gdbpy_py_obj_tp_name (self),
core_addr_to_string_nz (obj->address));
}
const frame_id &fid = frame_obj->frame_id;
return PyUnicode_FromFormat ("<%s level=%d frame-id=%s>",
- Py_TYPE (self)->tp_name,
+ gdbpy_py_obj_tp_name (self),
frame_relative_level (f_info),
fid.to_string ().c_str ());
}
{
PyErr_Format (PyExc_TypeError,
_("argument 1 must be gdb.Symbol or str, not %s"),
- Py_TYPE (sym_obj)->tp_name);
+ gdbpy_py_obj_tp_name (sym_obj));
return NULL;
}
thread_info *thr = thread_obj->thread;
return PyUnicode_FromFormat ("<%s id=%s target-id=\"%s\">",
- Py_TYPE (self)->tp_name,
+ gdbpy_py_obj_tp_name (self),
print_full_thread_id (thr),
target_pid_to_str (thr->ptid).c_str ());
}
PyErr_Format
(PyExc_ValueError,
_("MI notification data must be either None or a dictionary, not %s"),
- Py_TYPE (data)->tp_name);
+ gdbpy_py_obj_tp_name (data));
return nullptr;
}
{
PyErr_Format (PyExc_TypeError,
_("gdb.MICommand.installed must be set to a bool, not %s"),
- newvalue == Py_None ? "None" : Py_TYPE(newvalue)->tp_name);
+ newvalue == Py_None ? "None" : gdbpy_py_obj_tp_name (newvalue));
return -1;
}
--- /dev/null
+/* Helpers related to Python object type
+
+ Copyright (C) 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 <http://www.gnu.org/licenses/>. */
+
+#include "python-internal.h"
+#include "py-obj-type.h"
+
+/* Return the type's fully qualified name from a PyTypeObject. */
+const char *
+gdb_py_tp_name (PyTypeObject *py_type) noexcept
+{
+#if PY_VERSION_HEX >= 0x030d0000
+ /* Note: PyType_GetFullyQualifiedName() was added in version 3.13, and is
+ part of the stable ABI since version 3.13. */
+ PyObject *fully_qualified_name = PyType_GetFullyQualifiedName (py_type);
+ if (fully_qualified_name == nullptr)
+ return nullptr;
+
+ return PyUnicode_AsUTF8AndSize (fully_qualified_name, nullptr);
+
+#else /* PY_VERSION_HEX < 0x030d0000 && ! defined (Py_LIMITED_API) */
+ /* For non-heap types, the fully qualified name corresponds to tp_name. */
+ if (! (PyType_GetFlags (py_type) & Py_TPFLAGS_HEAPTYPE))
+ return py_type->tp_name;
+
+ /* In the absence of PyType_GetFullyQualifiedName(), we fallback using
+ __qualname__ instead. However, the result may differ slightly in some
+ cases, e.g. the module name may be missing. */
+
+# if PY_VERSION_HEX >= 0x030b0000
+ /* Note: PyType_GetQualName() was added in version 3.11. */
+ PyObject *qualname = PyType_GetQualName (py_type);
+ if (qualname == nullptr)
+ return nullptr;
+
+ return PyUnicode_AsUTF8AndSize (qualname, nullptr);
+
+# else
+ /* In the absence of PyType_GetQualName(), fallback on using PyHeapTypeObject
+ which is not part of the public API.
+ Tested on 3.10 which is the oldest supported version at the time of this
+ writing, i.e. February 2026. Hopefully, this workaround should go away
+ when the minimum supported Python version is increased above 3.10. */
+ PyHeapTypeObject *ht = (PyHeapTypeObject *) py_type;
+ if (ht->ht_qualname == nullptr)
+ return nullptr;
+
+ return PyUnicode_AsUTF8AndSize (ht->ht_qualname, nullptr);
+# endif
+#endif
+}
+
+/* Return the type's fully qualified name from a PyObject. */
+const char *
+gdbpy_py_obj_tp_name (PyObject *self) noexcept
+{
+ /* Note: Py_TYPE () is part of the stable ABI since version 3.14. */
+ return gdb_py_tp_name (Py_TYPE (self));
+}
--- /dev/null
+/* Helpers related to Python object type
+
+ Copyright (C) 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 <http://www.gnu.org/licenses/>. */
+
+#ifndef GDB_PYTHON_PY_OBJ_TYPE_H
+#define GDB_PYTHON_PY_OBJ_TYPE_H
+
+/* Return the type's fully qualified name from a PyTypeObject. */
+extern const char *gdb_py_tp_name (PyTypeObject *py_type) noexcept;
+
+/* Return the type's fully qualified name from a PyObject. */
+extern const char *gdbpy_py_obj_tp_name (PyObject *self) noexcept;
+
+#endif /* GDB_PYTHON_PY_OBJ_TYPE_H */
PyErr_Format
(PyExc_TypeError,
_("'foreground' argument must be gdb.Color or None, not %s."),
- Py_TYPE (fg)->tp_name);
+ gdbpy_py_obj_tp_name (fg));
return -1;
}
PyErr_Format
(PyExc_TypeError,
_("'background' argument must be gdb.Color or None, not %s."),
- Py_TYPE (bg)->tp_name);
+ gdbpy_py_obj_tp_name (bg));
return -1;
}
if (!gdbpy_is_color (newvalue))
{
PyErr_Format (PyExc_TypeError, _("value must be gdb.Color, not %s"),
- Py_TYPE (newvalue)->tp_name);
+ gdbpy_py_obj_tp_name (newvalue));
return -1;
}
if (!gdbpy_is_color (newvalue))
{
PyErr_Format (PyExc_TypeError, _("value must be gdb.Color, not %s"),
- Py_TYPE (newvalue)->tp_name);
+ gdbpy_py_obj_tp_name (newvalue));
return -1;
}
PyErr_Format
(PyExc_TypeError,
_("value must be a Long (a gdb.INTENSITY constant), not %s"),
- Py_TYPE (newvalue)->tp_name);
+ gdbpy_py_obj_tp_name (newvalue));
return -1;
}
if (style_obj->style_name == nullptr)
return PyUnicode_FromFormat ("<%s fg=%s, bg=%s, intensity=%s>",
- Py_TYPE (self)->tp_name,
+ gdbpy_py_obj_tp_name (self),
fg_str.get (), bg_str.get (),
intensity_str);
else
return PyUnicode_FromFormat ("<%s name='%s', fg=%s, bg=%s, intensity=%s>",
- Py_TYPE (self)->tp_name,
+ gdbpy_py_obj_tp_name (self),
style_obj->style_name, fg_str.get (),
bg_str.get (), intensity_str);
}
if (symbol == nullptr)
return gdb_py_invalid_object_repr (self);
- return PyUnicode_FromFormat ("<%s print_name=%s>", Py_TYPE (self)->tp_name,
+ return PyUnicode_FromFormat ("<%s print_name=%s>",
+ gdbpy_py_obj_tp_name (self),
symbol->print_name ());
}
auto py_typename = PyUnicode_Decode (type_name.c_str (), type_name.size (),
host_charset (), NULL);
- return PyUnicode_FromFormat ("<%s code=%s name=%U>", Py_TYPE (self)->tp_name,
+ return PyUnicode_FromFormat ("<%s code=%s name=%U>",
+ gdbpy_py_obj_tp_name (self),
code, py_typename);
}
if (frame == nullptr)
return PyUnicode_FromFormat ("<%s for an invalid frame>",
- Py_TYPE (self)->tp_name);
+ gdbpy_py_obj_tp_name (self));
std::string saved_reg_names;
struct gdbarch *gdbarch = pending_frame->gdbarch;
}
return PyUnicode_FromFormat ("<%s frame #%d, saved_regs=(%s)>",
- Py_TYPE (self)->tp_name,
+ gdbpy_py_obj_tp_name (self),
frame_relative_level (frame),
saved_reg_names.c_str ());
}
}
return PyUnicode_FromFormat ("<%s level=%d, sp=%s, pc=%s>",
- Py_TYPE (self)->tp_name,
+ gdbpy_py_obj_tp_name (self),
frame_relative_level (frame),
sp_str,
pc_str);
gdb_assert (pyo_unwind_info != nullptr);
if (!PyObject_TypeCheck (pyo_unwind_info, &unwind_info_object_type))
error (_("an Unwinder should return gdb.UnwindInfo, not %s."),
- Py_TYPE (pyo_unwind_info)->tp_name);
+ gdbpy_py_obj_tp_name (pyo_unwind_info));
{
unwind_info_object *unwind_info =
Therefore, we must explicitly raise an AttributeError in this case. */
PyErr_Format (PyExc_AttributeError,
"'%s' object has no attribute '%s'",
- Py_TYPE (self)->tp_name,
+ gdbpy_py_obj_tp_name (self),
PyUnicode_AsUTF8AndSize (attr, nullptr));
return nullptr;
}
PyObject *
gdb_py_invalid_object_repr (PyObject *self)
{
- return PyUnicode_FromFormat ("<%s (invalid)>", Py_TYPE (self)->tp_name);
+ return PyUnicode_FromFormat ("<%s (invalid)>", gdbpy_py_obj_tp_name (self));
}
#include <Python.h>
#include <frameobject.h>
#include "py-ref.h"
+#include "py-obj-type.h"
static_assert (PY_VERSION_HEX >= 0x03040000);
{
if (PyType_Ready (type) < 0)
return -1;
+ const char *tp_name = gdb_py_tp_name (type);
if (mod == nullptr)
{
- gdb_assert (startswith (type->tp_name, "gdb."));
+ gdb_assert (startswith (tp_name, "gdb."));
mod = gdb_module;
}
- const char *dot = strrchr (type->tp_name, '.');
+ const char *dot = strrchr (tp_name, '.');
gdb_assert (dot != nullptr);
return gdb_pymodule_addobject (mod, dot + 1, (PyObject *) type);
}
PyErr_Format
(PyExc_TypeError,
_("'style' argument must be gdb.Style or None, not %s."),
- Py_TYPE (style_obj)->tp_name);
+ gdbpy_py_obj_tp_name (style_obj));
return nullptr;
}
[list "" "${base_pattern}\r\n.*"] \
[list "GlobalNullDisassembler" "${base_pattern}\r\n.*"] \
[list "ShowInfoRepr" "${base_pattern}\\s+## <gdb.disassembler.DisassembleInfo address=$hex architecture=\[^>\]+>\r\n.*"] \
- [list "ShowInfoSubClassRepr" "${base_pattern}\\s+## <MyInfo address=$hex architecture=\[^>\]+>\r\n.*"] \
+ [list "ShowInfoSubClassRepr" "${base_pattern}\\s+## <ShowInfoSubClassRepr.MyInfo address=$hex architecture=\[^>\]+>\r\n.*"] \
[list "ShowResultRepr" "${base_pattern}\\s+## <gdb.disassembler.DisassemblerResult length=$decimal string=\"\[^\r\n\]+\">\r\n.*"] \
[list "ShowResultStr" "${base_pattern}\\s+## ${nop}\r\n.*"] \
[list "GlobalPreInfoDisassembler" "${base_pattern}\\s+## ad = $hex, ar = ${curr_arch}\r\n.*"] \
"Buffer returned from read_memory is sized $decimal instead of the expected $decimal"]] \
[list "ResultOfWrongType" \
[make_exception_pattern "TypeError" \
- "Result from Disassembler must be gdb.DisassemblerResult, not Blah."]] \
+ "Result from Disassembler must be gdb.DisassemblerResult, not ResultOfWrongType.Blah."]] \
[list "ResultOfVeryWrongType" \
[make_exception_pattern "TypeError" \
- "Result from Disassembler must be gdb.DisassemblerResult, not Blah."]] \
+ "Result from Disassembler must be gdb.DisassemblerResult, not ResultOfVeryWrongType.Blah."]] \
[list "ErrorCreatingTextPart_NoArgs" \
[make_exception_pattern "TypeError" \
[missing_arg_pattern "style" 1]]] \
foreach type {DisassemblerTextPart DisassemblerAddressPart} {
gdb_test "python result = gdb.disassembler.${type}()" \
[multi_line \
- "RuntimeError.*: Cannot create instances of DisassemblerPart\\." \
+ "RuntimeError.*: Cannot create instances of gdb.disassembler.${type}\\." \
"Error occurred in Python.*"] \
"try to create an instance of ${type}"
}
gdb_test_no_output "python obj = bad_object_unwinder(\"bad-object\")"
gdb_test_no_output "python gdb.unwinder.register_unwinder(None, obj, replace=True)"
gdb_test "backtrace" \
- "Python Exception <class 'gdb.error'>: an Unwinder should return gdb.UnwindInfo, not Blah\\.\r\n.*"
+ "Python Exception <class 'gdb.error'>: an Unwinder should return gdb.UnwindInfo, not bad_object_unwinder.+Blah\\.\r\n.*"
}
# Gather information about every frame.