Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Tom Tromey <tom@tromey.com>
To: gdb-patches@sourceware.org
Cc: Tom Tromey <tom@tromey.com>
Subject: [RFC 4/4] Convert some Python code to new-style
Date: Sun, 22 Feb 2026 12:49:37 -0700	[thread overview]
Message-ID: <20260222200759.1587070-5-tom@tromey.com> (raw)
In-Reply-To: <20260222200759.1587070-1-tom@tromey.com>

This converts various spots in the gdb Python layer to use the
new-style 'safety' approach.  py-arch.c and py-frame.c are essentially
completely converted.  Some other spots are touched on an ad hoc
basis.
---
 gdb/python/py-arch.c         | 222 +++++--------
 gdb/python/py-frame.c        | 617 +++++++++++------------------------
 gdb/python/py-registers.c    |  39 +--
 gdb/python/py-tui.c          |  56 ++--
 gdb/python/python-internal.h |  15 +-
 gdb/python/python.c          |  12 +-
 6 files changed, 342 insertions(+), 619 deletions(-)

diff --git a/gdb/python/py-arch.c b/gdb/python/py-arch.c
index f40d7da1763..aa99dc34329 100644
--- a/gdb/python/py-arch.c
+++ b/gdb/python/py-arch.c
@@ -30,18 +30,6 @@ struct arch_object : public PyObject
 static const registry<gdbarch>::key<PyObject, gdb::noop_deleter<PyObject>>
      arch_object_data;
 
-/* Require a valid Architecture.  */
-#define ARCHPY_REQUIRE_VALID(arch_obj, arch)			\
-  do {								\
-    arch = arch_object_to_gdbarch (arch_obj);			\
-    if (arch == NULL)						\
-      {								\
-	PyErr_SetString (PyExc_RuntimeError,			\
-			 _("Architecture is invalid."));	\
-	return NULL;						\
-      }								\
-  } while (0)
-
 extern PyTypeObject arch_object_type;
 
 /* Associates an arch_object with GDBARCH as gdbarch_data via the gdbarch
@@ -72,6 +60,18 @@ arch_object_to_gdbarch (PyObject *obj)
   return py_arch->gdbarch;
 }
 
+/* Return the gdbarch associated with OBJ.  Throws an exception on
+   error.  */
+
+static gdbarch *
+require_arch (gdbpy_borrowed_ref obj)
+{
+  gdbarch *result = arch_object_to_gdbarch (obj);
+  if (result == nullptr)
+    gdbpy_err_set_string (PyExc_RuntimeError, _("Architecture is invalid."));
+  return result;
+}
+
 /* See python-internal.h.  */
 
 bool
@@ -103,16 +103,11 @@ gdbarch_to_arch_object (struct gdbarch *gdbarch)
 /* Implementation of gdb.Architecture.name (self) -> String.
    Returns the name of the architecture as a string value.  */
 
-static PyObject *
-archpy_name (PyObject *self, PyObject *args)
+static const char *
+archpy_name (gdbpy_borrowed_ref self)
 {
-  struct gdbarch *gdbarch = NULL;
-  const char *name;
-
-  ARCHPY_REQUIRE_VALID (self, gdbarch);
-
-  name = (gdbarch_bfd_arch_info (gdbarch))->printable_name;
-  return PyUnicode_FromString (name);
+  gdbarch *gdbarch = require_arch (self);
+  return gdbarch_bfd_arch_info (gdbarch)->printable_name;
 }
 
 /* Implementation of
@@ -121,56 +116,45 @@ archpy_name (PyObject *self, PyObject *args)
    in the list is a Python dict object.
 */
 
-static PyObject *
-archpy_disassemble (PyObject *self, PyObject *args, PyObject *kw)
+static gdbpy_ref<>
+archpy_disassemble (gdbpy_borrowed_ref self, gdbpy_borrowed_ref args,
+		    gdbpy_borrowed_ref kw)
 {
   static const char *keywords[] = { "start_pc", "end_pc", "count", NULL };
   CORE_ADDR start = 0, end = 0;
   CORE_ADDR pc;
   long count = 0, i;
   PyObject *start_obj = nullptr, *end_obj = nullptr, *count_obj = nullptr;
-  struct gdbarch *gdbarch = NULL;
 
-  ARCHPY_REQUIRE_VALID (self, gdbarch);
+  struct gdbarch *gdbarch = require_arch (self);
 
-  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "O|OO",
-					keywords, &start_obj, &end_obj,
-					&count_obj))
-    return NULL;
+  gdbpy_arg_parse_tuple_and_keywords (args, kw, "O|OO",
+				      keywords, &start_obj, &end_obj,
+				      &count_obj);
 
   if (get_addr_from_python (start_obj, &start) < 0)
-    return nullptr;
+    throw gdb_python_exception (); /* FIXME */
 
   if (end_obj != nullptr)
     {
       if (get_addr_from_python (end_obj, &end) < 0)
-	return nullptr;
+	throw gdb_python_exception (); /* FIXME */
 
       if (end < start)
-	{
-	  PyErr_SetString (PyExc_ValueError,
-			   _("Argument 'end_pc' should be greater than or "
-			     "equal to the argument 'start_pc'."));
-
-	  return NULL;
-	}
+	gdbpy_err_set_string (PyExc_ValueError,
+			      _("Argument 'end_pc' should be greater than or "
+				"equal to the argument 'start_pc'."));
     }
   if (count_obj)
     {
-      count = PyLong_AsLong (count_obj);
-      if (PyErr_Occurred () || count < 0)
-	{
-	  PyErr_SetString (PyExc_TypeError,
-			   _("Argument 'count' should be an non-negative "
-			     "integer."));
-
-	  return NULL;
-	}
+      count = gdbpy_long_as_long (count_obj);
+      if (count < 0)
+	gdbpy_err_set_string (PyExc_TypeError,
+			      _("Argument 'count' should be an non-negative "
+				"integer."));
     }
 
-  gdbpy_ref<> result_list (PyList_New (0));
-  if (result_list == NULL)
-    return NULL;
+  gdbpy_ref<> result_list = gdbpy_new_list (0);
 
   for (pc = start, i = 0;
        /* All args are specified.  */
@@ -182,68 +166,52 @@ archpy_disassemble (PyObject *self, PyObject *args, PyObject *kw)
        /* Both end_pc and count are not specified.  */
        || (end_obj == NULL && count_obj == NULL && pc == start);)
     {
-      int insn_len = 0;
-      gdbpy_ref<> insn_dict (PyDict_New ());
+      gdbpy_ref<> insn_dict = gdbpy_new_dict ();
 
-      if (insn_dict == NULL)
-	return NULL;
-      if (PyList_Append (result_list.get (), insn_dict.get ()))
-	return NULL;  /* PyList_Append Sets the exception.  */
+      gdbpy_list_append (result_list, insn_dict);
 
       string_file stb;
-
-      try
-	{
-	  insn_len = gdb_print_insn (gdbarch, pc, &stb, NULL);
-	}
-      catch (const gdb_exception &except)
-	{
-	  return gdbpy_handle_gdb_exception (nullptr, except);
-	}
+      int insn_len = gdb_print_insn (gdbarch, pc, &stb, NULL);
 
       gdbpy_ref<> pc_obj = gdb_py_object_from_ulongest (pc);
       if (pc_obj == nullptr)
-	return nullptr;
+	throw gdb_python_exception (); /* FIXME */
 
-      gdbpy_ref<> asm_obj
-	(PyUnicode_FromString (!stb.empty () ? stb.c_str () : "<unknown>"));
-      if (asm_obj == nullptr)
-	return nullptr;
+      gdbpy_ref<> asm_obj = gdbpy_unicode_from_string (!stb.empty ()
+						       ? stb.c_str ()
+						       : "<unknown>");
 
       gdbpy_ref<> len_obj = gdb_py_object_from_longest (insn_len);
       if (len_obj == nullptr)
-	return nullptr;
+	throw gdb_python_exception (); /* FIXME */
 
-      if (PyDict_SetItemString (insn_dict.get (), "addr", pc_obj.get ())
-	  || PyDict_SetItemString (insn_dict.get (), "asm", asm_obj.get ())
-	  || PyDict_SetItemString (insn_dict.get (), "length", len_obj.get ()))
-	return NULL;
+      gdbpy_dict_set_item_string (insn_dict, "addr", pc_obj);
+      gdbpy_dict_set_item_string (insn_dict, "asm", asm_obj);
+      gdbpy_dict_set_item_string (insn_dict, "length", len_obj);
 
       pc += insn_len;
       i++;
     }
 
-  return result_list.release ();
+  return result_list;
 }
 
 /* Implementation of gdb.Architecture.registers (self, reggroup) -> Iterator.
    Returns an iterator over register descriptors for registers in GROUP
    within the architecture SELF.  */
 
-static PyObject *
-archpy_registers (PyObject *self, PyObject *args, PyObject *kw)
+static gdbpy_ref<>
+archpy_registers (gdbpy_borrowed_ref self, gdbpy_borrowed_ref args,
+		  gdbpy_borrowed_ref kw)
 {
   static const char *keywords[] = { "reggroup", NULL };
-  struct gdbarch *gdbarch = NULL;
   const char *group_name = NULL;
 
   /* Parse method arguments.  */
-  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "|s", keywords,
-					&group_name))
-    return NULL;
+  gdbpy_arg_parse_tuple_and_keywords (args, kw, "|s", keywords, &group_name);
 
   /* Extract the gdbarch from the self object.  */
-  ARCHPY_REQUIRE_VALID (self, gdbarch);
+  struct gdbarch *gdbarch = require_arch (self);
 
   return gdbpy_new_register_descriptor_iterator (gdbarch, group_name);
 }
@@ -252,35 +220,30 @@ archpy_registers (PyObject *self, PyObject *args, PyObject *kw)
    Returns an iterator that will give up all valid register groups in the
    architecture SELF.  */
 
-static PyObject *
-archpy_register_groups (PyObject *self, PyObject *args)
+static gdbpy_ref<>
+archpy_register_groups (gdbpy_borrowed_ref self)
 {
-  struct gdbarch *gdbarch = NULL;
-
-  /* Extract the gdbarch from the self object.  */
-  ARCHPY_REQUIRE_VALID (self, gdbarch);
+  struct gdbarch *gdbarch = require_arch (self);
   return gdbpy_new_reggroup_iterator (gdbarch);
 }
 
 /* Implementation of gdb.integer_type.  */
-static PyObject *
-archpy_integer_type (PyObject *self, PyObject *args, PyObject *kw)
+static gdbpy_ref<>
+archpy_integer_type (gdbpy_borrowed_ref self, gdbpy_borrowed_ref args,
+		     gdbpy_borrowed_ref kw)
 {
   static const char *keywords[] = { "size", "signed", NULL };
   int size;
   PyObject *is_signed_obj = Py_True;
 
-  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "i|O!", keywords,
-					&size,
-					&PyBool_Type, &is_signed_obj))
-    return nullptr;
+  gdbpy_arg_parse_tuple_and_keywords (args, kw, "i|O!", keywords, &size,
+				      &PyBool_Type, &is_signed_obj);
 
   /* Assume signed by default.  */
   gdb_assert (PyBool_Check (is_signed_obj));
   bool is_signed = is_signed_obj == Py_True;
 
-  struct gdbarch *gdbarch;
-  ARCHPY_REQUIRE_VALID (self, gdbarch);
+  struct gdbarch *gdbarch = require_arch (self);
 
   const struct builtin_type *builtins = builtin_type (gdbarch);
   struct type *type = nullptr;
@@ -309,22 +272,19 @@ archpy_integer_type (PyObject *self, PyObject *args, PyObject *kw)
       break;
 
     default:
-      PyErr_SetString (PyExc_ValueError,
-		       _("no integer type of that size is available"));
-      return nullptr;
+      gdbpy_err_set_string (PyExc_ValueError,
+			    _("no integer type of that size is available"));
     }
 
-  return type_to_type_object (type).release ();
+  return type_to_type_object (type);
 }
 
 /* Implementation of gdb.void_type.  */
-static PyObject *
-archpy_void_type (PyObject *self, PyObject *args)
+static gdbpy_ref<>
+archpy_void_type (gdbpy_borrowed_ref self)
 {
-  struct gdbarch *gdbarch;
-  ARCHPY_REQUIRE_VALID (self, gdbarch);
-
-  return type_to_type_object (builtin_type (gdbarch)->builtin_void).release ();
+  struct gdbarch *gdbarch = require_arch (self);
+  return type_to_type_object (builtin_type (gdbarch)->builtin_void);
 }
 
 /* __repr__ implementation for gdb.Architecture.  */
@@ -345,24 +305,16 @@ archpy_repr (PyObject *self)
 /* Implementation of gdb.architecture_names().  Return a list of all the
    BFD architecture names that GDB understands.  */
 
-PyObject *
-gdbpy_all_architecture_names (PyObject *self, PyObject *args)
+gdbpy_ref<>
+gdbpy_all_architecture_names (gdbpy_borrowed_ref self)
 {
-  gdbpy_ref<> list (PyList_New (0));
-  if (list == nullptr)
-    return nullptr;
+  gdbpy_ref<> list = gdbpy_new_list (0);
 
   std::vector<const char *> name_list = gdbarch_printable_names ();
   for (const char *name : name_list)
-    {
-      gdbpy_ref <> py_name (PyUnicode_FromString (name));
-      if (py_name == nullptr)
-	return nullptr;
-      if (PyList_Append (list.get (), py_name.get ()) < 0)
-	return nullptr;
-    }
+    gdbpy_list_append (list, gdbpy_unicode_from_string (name));
 
- return list.release ();
+ return list;
 }
 
 /* Initializes the Architecture class in the gdb module.  */
@@ -379,32 +331,26 @@ GDBPY_INITIALIZE_FILE (gdbpy_initialize_arch);
 \f
 
 static PyMethodDef arch_object_methods [] = {
-  { "name", archpy_name, METH_NOARGS,
-    "name () -> String.\n\
-Return the name of the architecture as a string value." },
-  { "disassemble", (PyCFunction) archpy_disassemble,
-    METH_VARARGS | METH_KEYWORDS,
+  wrap_noargs<archpy_name> ("name", "name () -> String.\n\
+Return the name of the architecture as a string value."),
+  wrap_varargs<archpy_disassemble> ("disassemble",
     "disassemble (start_pc [, end_pc [, count]]) -> List.\n\
 Return a list of at most COUNT disassembled instructions from START_PC to\n\
-END_PC." },
-  { "integer_type", (PyCFunction) archpy_integer_type,
-    METH_VARARGS | METH_KEYWORDS,
+END_PC."),
+  wrap_varargs<archpy_integer_type> ("integer_type",
     "integer_type (size [, signed]) -> type\n\
 Return an integer Type corresponding to the given bitsize and signed-ness.\n\
-If not specified, the type defaults to signed." },
-  { "void_type", (PyCFunction) archpy_void_type,
-    METH_NOARGS,
+If not specified, the type defaults to signed."),
+  wrap_noargs<archpy_void_type> ("void_type",
     "void_type () -> type\n\
-Return a void Type." },
-  { "registers", (PyCFunction) archpy_registers,
-    METH_VARARGS | METH_KEYWORDS,
+Return a void Type."),
+  wrap_varargs<archpy_registers> ("registers",
     "registers ([ group-name ]) -> Iterator.\n\
 Return an iterator of register descriptors for the registers in register\n\
-group GROUP-NAME." },
-  { "register_groups", archpy_register_groups,
-    METH_NOARGS,
+group GROUP-NAME."),
+  wrap_noargs<archpy_register_groups> ("register_groups",
     "register_groups () -> Iterator.\n\
-Return an iterator over all of the register groups in this architecture." },
+Return an iterator over all of the register groups in this architecture."),
   {NULL}  /* Sentinel */
 };
 
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 592a1d5a2b5..247b3419b9a 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -42,16 +42,9 @@ struct frame_object : public PyObject
      ID as the  previous frame).  Whenever get_prev_frame returns NULL, we
      record the frame_id of the next frame and set FRAME_ID_IS_NEXT to 1.  */
   int frame_id_is_next;
-};
 
-/* Require a valid frame.  This must be called inside a TRY_CATCH, or
-   another context in which a gdb exception is allowed.  */
-#define FRAPY_REQUIRE_VALID(frame_obj, frame)		\
-    do {						\
-      frame = frame_object_to_frame_info (frame_obj);	\
-      if (frame == NULL)				\
-	error (_("Frame is invalid."));			\
-    } while (0)
+  static PyTypeObject *corresponding_object_type;
+};
 
 /* Returns the frame_info object corresponding to the given Python Frame
    object.  If the frame doesn't exist anymore (the frame id doesn't
@@ -73,6 +66,18 @@ frame_object_to_frame_info (PyObject *obj)
   return frame;
 }
 
+/* Return the frame associated with OBJ.  Throws an exception on
+   error.  */
+
+static frame_info_ptr
+require_frame (gdbpy_borrowed_ref obj)
+{
+  frame_info_ptr frame = frame_object_to_frame_info (obj);
+  if (frame == nullptr)
+    gdbpy_err_format (PyExc_RuntimeError, _("Frame is invalid."));
+  return frame;
+}
+
 /* Called by the Python interpreter to obtain string representation
    of the object.  */
 
@@ -104,257 +109,142 @@ frapy_repr (PyObject *self)
    Returns True if the frame corresponding to the frame_id of this
    object still exists in the inferior.  */
 
-static PyObject *
-frapy_is_valid (PyObject *self, PyObject *args)
+static bool
+frapy_is_valid (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr frame = NULL;
-
-  try
-    {
-      frame = frame_object_to_frame_info (self);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  if (frame == NULL)
-    Py_RETURN_FALSE;
-
-  Py_RETURN_TRUE;
+  return frame_object_to_frame_info (self) != nullptr;
 }
 
 /* Implementation of gdb.Frame.name (self) -> String.
    Returns the name of the function corresponding to this frame.  */
 
-static PyObject *
-frapy_name (PyObject *self, PyObject *args)
+static gdbpy_ref<>
+frapy_name (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr frame;
-  gdb::unique_xmalloc_ptr<char> name;
+  frame_info_ptr frame = require_frame (self);
   enum language lang;
-  PyObject *result;
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, frame);
+  gdb::unique_xmalloc_ptr<char> name = find_frame_funname (frame, &lang,
+							   nullptr);
+  if (name != nullptr)
+    return host_string_to_python_string (name.get ());
 
-      name = find_frame_funname (frame, &lang, NULL);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  if (name)
-    {
-      result = PyUnicode_Decode (name.get (), strlen (name.get ()),
-				 host_charset (), NULL);
-    }
-  else
-    {
-      result = Py_None;
-      Py_INCREF (Py_None);
-    }
-
-  return result;
+  return gdbpy_ref<>::new_reference (Py_None);
 }
 
 /* Implementation of gdb.Frame.type (self) -> Integer.
    Returns the frame type, namely one of the gdb.*_FRAME constants.  */
 
-static PyObject *
-frapy_type (PyObject *self, PyObject *args)
+static ULONGEST
+frapy_type (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr frame;
-  enum frame_type type = NORMAL_FRAME;/* Initialize to appease gcc warning.  */
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, frame);
-
-      type = get_frame_type (frame);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  return gdb_py_object_from_longest (type).release ();
+  frame_info_ptr frame = require_frame (self);
+  enum frame_type type = get_frame_type (frame);
+  return type;
 }
 
 /* Implementation of gdb.Frame.architecture (self) -> gdb.Architecture.
    Returns the frame's architecture as a gdb.Architecture object.  */
 
-static PyObject *
-frapy_arch (PyObject *self, PyObject *args)
+static gdbpy_ref<>
+frapy_arch (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr frame = NULL;    /* Initialize to appease gcc warning.  */
-  frame_object *obj = (frame_object *) self;
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, frame);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  return gdbarch_to_arch_object (obj->gdbarch).release ();
+  require_frame (self);
+  frame_object *obj = self;
+  return gdbarch_to_arch_object (obj->gdbarch);
 }
 
 /* Implementation of gdb.Frame.unwind_stop_reason (self) -> Integer.
    Returns one of the gdb.FRAME_UNWIND_* constants.  */
 
-static PyObject *
-frapy_unwind_stop_reason (PyObject *self, PyObject *args)
+static int
+frapy_unwind_stop_reason (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr frame = NULL;    /* Initialize to appease gcc warning.  */
-  enum unwind_stop_reason stop_reason;
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, frame);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  stop_reason = get_frame_unwind_stop_reason (frame);
-
-  return gdb_py_object_from_longest (stop_reason).release ();
+  frame_info_ptr frame = require_frame (self);
+  return get_frame_unwind_stop_reason (frame);
 }
 
 /* Implementation of gdb.Frame.pc (self) -> Long.
    Returns the frame's resume address.  */
 
-static PyObject *
-frapy_pc (PyObject *self, PyObject *args)
+static ULONGEST
+frapy_pc (gdbpy_borrowed_ref self)
 {
-  CORE_ADDR pc = 0;	      /* Initialize to appease gcc warning.  */
-  frame_info_ptr frame;
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, frame);
-
-      pc = get_frame_pc (frame);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  return gdb_py_object_from_ulongest (pc).release ();
+  frame_info_ptr frame = require_frame (self);
+  return get_frame_pc (frame);
 }
 
 /* Implementation of gdb.Frame.read_register (self, register) -> gdb.Value.
    Returns the value of a register in this frame.  */
 
-static PyObject *
-frapy_read_register (PyObject *self, PyObject *args, PyObject *kw)
+static gdbpy_ref<>
+frapy_read_register (gdbpy_borrowed_ref self, gdbpy_borrowed_ref args,
+		     gdbpy_borrowed_ref kw)
 {
   PyObject *pyo_reg_id;
-  gdbpy_ref<> result;
 
   static const char *keywords[] = { "register", nullptr };
-  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "O", keywords, &pyo_reg_id))
-    return nullptr;
+  gdbpy_arg_parse_tuple_and_keywords (args, kw, "O", keywords, &pyo_reg_id);
 
-  try
-    {
-      scoped_value_mark free_values;
-      frame_info_ptr frame;
-      int regnum;
-
-      FRAPY_REQUIRE_VALID (self, frame);
-
-      if (!gdbpy_parse_register_id (get_frame_arch (frame), pyo_reg_id,
-				    &regnum))
-	return nullptr;
-
-      gdb_assert (regnum >= 0);
-      value *val
-	= value_of_register (regnum, get_next_frame_sentinel_okay (frame));
+  scoped_value_mark free_values;
+  frame_info_ptr frame = require_frame (self);
 
-      if (val == NULL)
-	PyErr_SetString (PyExc_ValueError, _("Can't read register."));
-      else
-	result = value_to_value_object (val);
-    }
-  catch (const gdb_exception &except)
+  int regnum;
+  if (!gdbpy_parse_register_id (get_frame_arch (frame), pyo_reg_id, &regnum))
     {
-      return gdbpy_handle_gdb_exception (nullptr, except);
+      // FIXME future conversion
+      throw gdb_python_exception ();
     }
 
-  return result.release ();
+  gdb_assert (regnum >= 0);
+  value *val
+    = value_of_register (regnum, get_next_frame_sentinel_okay (frame));
+
+  if (val == nullptr)
+    gdbpy_err_set_string (PyExc_ValueError, _("Can't read register."));
+
+  return value_to_value_object (val);
 }
 
 /* Implementation of gdb.Frame.block (self) -> gdb.Block.
    Returns the frame's code block.  */
 
-static PyObject *
-frapy_block (PyObject *self, PyObject *args)
+static gdbpy_ref<>
+frapy_block (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr frame;
-  const struct block *block = NULL, *fn_block;
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, frame);
-      block = get_frame_block (frame, NULL);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
+  frame_info_ptr frame = require_frame (self);
+  const struct block *block = get_frame_block (frame, nullptr);
 
+  const struct block *fn_block;
   for (fn_block = block;
        fn_block != NULL && fn_block->function () == NULL;
        fn_block = fn_block->superblock ())
     ;
 
   if (block == NULL || fn_block == NULL || fn_block->function () == NULL)
-    {
-      PyErr_SetString (PyExc_RuntimeError,
-		       _("Cannot locate block for frame."));
-      return NULL;
-    }
+    gdbpy_err_set_string (PyExc_RuntimeError,
+			  _("Cannot locate block for frame."));
 
-  return block_to_block_object (block,
-				fn_block->function ()->objfile ()).release ();
+  return block_to_block_object (block, fn_block->function ()->objfile ());
 }
 
 
 /* Implementation of gdb.Frame.function (self) -> gdb.Symbol.
    Returns the symbol for the function corresponding to this frame.  */
 
-static PyObject *
-frapy_function (PyObject *self, PyObject *args)
+static gdbpy_ref<>
+frapy_function (gdbpy_borrowed_ref self)
 {
-  struct symbol *sym = NULL;
-  frame_info_ptr frame;
+  frame_info_ptr frame = require_frame (self);
 
-  try
-    {
-      enum language funlang;
+  struct symbol *sym = nullptr;
+  enum language funlang;
+  gdb::unique_xmalloc_ptr<char> funname
+    = find_frame_funname (frame, &funlang, &sym);
 
-      FRAPY_REQUIRE_VALID (self, frame);
+  if (sym != nullptr)
+    return symbol_to_symbol_object (sym);
 
-      gdb::unique_xmalloc_ptr<char> funname
-	= find_frame_funname (frame, &funlang, &sym);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  if (sym)
-    return symbol_to_symbol_object (sym).release ();
-
-  Py_RETURN_NONE;
+  return gdbpy_ref<>::new_reference (Py_None);
 }
 
 /* Convert a frame_info struct to a Python Frame object.
@@ -400,82 +290,43 @@ frame_info_to_frame_object (const frame_info_ptr &frame)
    Returns the frame immediately older (outer) to this frame, or None if
    there isn't one.  */
 
-static PyObject *
-frapy_older (PyObject *self, PyObject *args)
+static gdbpy_ref<>
+frapy_older (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr frame, prev = NULL;
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, frame);
-
-      prev = get_prev_frame (frame);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
+  frame_info_ptr frame = require_frame (self);
+  frame_info_ptr prev = get_prev_frame (frame);
 
-  gdbpy_ref<> prev_obj;
   if (prev)
-    prev_obj = frame_info_to_frame_object (prev);
-  else
-    prev_obj = gdbpy_ref<>::new_reference (Py_None);
+    return frame_info_to_frame_object (prev);
 
-  return prev_obj.release ();
+  return gdbpy_ref<>::new_reference (Py_None);
 }
 
 /* Implementation of gdb.Frame.newer (self) -> gdb.Frame.
    Returns the frame immediately newer (inner) to this frame, or None if
    there isn't one.  */
 
-static PyObject *
-frapy_newer (PyObject *self, PyObject *args)
+static gdbpy_ref<>
+frapy_newer (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr frame, next = NULL;
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, frame);
+  frame_info_ptr frame = require_frame (self);
+  frame_info_ptr next = get_next_frame (frame);
 
-      next = get_next_frame (frame);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  gdbpy_ref<> next_obj;
   if (next)
-    next_obj = frame_info_to_frame_object (next);
-  else
-    next_obj = gdbpy_ref<>::new_reference (Py_None);
+    return frame_info_to_frame_object (next);
 
-  return next_obj.release ();
+  return gdbpy_ref<>::new_reference (Py_None);
 }
 
 /* Implementation of gdb.Frame.find_sal (self) -> gdb.Symtab_and_line.
    Returns the frame's symtab and line.  */
 
-static PyObject *
-frapy_find_sal (PyObject *self, PyObject *args)
+static gdbpy_ref<>
+frapy_find_sal (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr frame;
-  gdbpy_ref<> sal_obj;
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, frame);
-
-      symtab_and_line sal = find_frame_sal (frame);
-      sal_obj = symtab_and_line_to_sal_object (sal);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  return sal_obj.release ();
+  frame_info_ptr frame = require_frame (self);
+  symtab_and_line sal = find_frame_sal (frame);
+  return symtab_and_line_to_sal_object (sal);
 }
 
 /* Implementation of gdb.Frame.read_var_value (self, variable,
@@ -485,20 +336,19 @@ frapy_find_sal (PyObject *self, PyObject *args)
    frame).  The variable argument must be a string or an instance of a
    gdb.Symbol.  The block argument must be an instance of gdb.Block.  Returns
    NULL on error, with a python exception set.  */
-static PyObject *
-frapy_read_var (PyObject *self, PyObject *args, PyObject *kw)
+static gdbpy_ref<>
+frapy_read_var (gdbpy_borrowed_ref self, gdbpy_borrowed_ref args,
+		gdbpy_borrowed_ref kw)
 {
-  frame_info_ptr frame;
   PyObject *sym_obj, *block_obj = NULL;
-  struct symbol *var = NULL;	/* gcc-4.3.2 false warning.  */
-  const struct block *block = NULL;
 
   static const char *keywords[] = { "variable", "block", nullptr };
-  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "O|O!", keywords,
-					&sym_obj, &block_object_type,
-					&block_obj))
-    return nullptr;
+  gdbpy_arg_parse_tuple_and_keywords (args, kw, "O|O!", keywords,
+				      &sym_obj, &block_object_type,
+				      &block_obj);
 
+  const struct block *block = NULL;
+  struct symbol *var = NULL;	/* gcc-4.3.2 false warning.  */
   if (PyObject_TypeCheck (sym_obj, &symbol_object_type))
     var = symbol_object_to_symbol (sym_obj);
   else if (gdbpy_is_string (sym_obj))
@@ -506,8 +356,9 @@ frapy_read_var (PyObject *self, PyObject *args, PyObject *kw)
       gdb::unique_xmalloc_ptr<char>
 	var_name (python_string_to_target_string (sym_obj));
 
-      if (!var_name)
-	return NULL;
+      // FIXME future conversion
+      if (var_name == nullptr)
+	throw gdb_python_exception ();
 
       if (block_obj != nullptr)
 	{
@@ -518,183 +369,93 @@ frapy_read_var (PyObject *self, PyObject *args, PyObject *kw)
 	  gdb_assert (block != nullptr);
 	}
 
-      try
-	{
-	  struct block_symbol lookup_sym;
-	  FRAPY_REQUIRE_VALID (self, frame);
-
-	  if (!block)
-	    block = get_frame_block (frame, NULL);
-	  lookup_sym = lookup_symbol (var_name.get (), block,
-				      SEARCH_VFT, nullptr);
-	  var = lookup_sym.symbol;
-	  block = lookup_sym.block;
-	}
-      catch (const gdb_exception &except)
-	{
-	  return gdbpy_handle_gdb_exception (nullptr, except);
-	}
+      frame_info_ptr frame = require_frame (self);
 
-      if (!var)
-	{
-	  PyErr_Format (PyExc_ValueError,
-			_("Variable '%s' not found."), var_name.get ());
+      if (!block)
+	block = get_frame_block (frame, NULL);
+      block_symbol lookup_sym = lookup_symbol (var_name.get (), block,
+					       SEARCH_VFT, nullptr);
+      var = lookup_sym.symbol;
+      block = lookup_sym.block;
 
-	  return NULL;
-	}
+      if (var == nullptr)
+	gdbpy_err_format (PyExc_ValueError,
+			  _("Variable '%s' not found."), var_name.get ());
     }
   else
-    {
-      PyErr_Format (PyExc_TypeError,
-		    _("argument 1 must be gdb.Symbol or str, not %s"),
-		    Py_TYPE (sym_obj)->tp_name);
-      return NULL;
-    }
-
-  gdbpy_ref<> result;
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, frame);
-
-      scoped_value_mark free_values;
-      struct value *val = read_var_value (var, block, frame);
-      result = value_to_value_object (val);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  return result.release ();
+    gdbpy_err_format (PyExc_TypeError,
+		      _("argument 1 must be gdb.Symbol or str, not %s"),
+		      Py_TYPE (sym_obj)->tp_name);
+
+  frame_info_ptr frame = require_frame (self);
+  scoped_value_mark free_values;
+  struct value *val = read_var_value (var, block, frame);
+  return value_to_value_object (val);
 }
 
 /* Select this frame.  */
 
-static PyObject *
-frapy_select (PyObject *self, PyObject *args)
+static void
+frapy_select (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr fi;
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, fi);
-
-      select_frame (fi);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  Py_RETURN_NONE;
+  frame_info_ptr fi = require_frame (self);
+  select_frame (fi);
 }
 
 /* The stack frame level for this frame.  */
 
-static PyObject *
-frapy_level (PyObject *self, PyObject *args)
+static int
+frapy_level (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr fi;
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, fi);
-
-      return gdb_py_object_from_longest (frame_relative_level (fi)).release ();
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  Py_RETURN_NONE;
+  frame_info_ptr fi = require_frame (self);
+  return frame_relative_level (fi);
 }
 
 /* The language for this frame.  */
 
-static PyObject *
-frapy_language (PyObject *self, PyObject *args)
+static const char *
+frapy_language (gdbpy_borrowed_ref self)
 {
-  try
-    {
-      frame_info_ptr fi;
-      FRAPY_REQUIRE_VALID (self, fi);
+  frame_info_ptr fi = require_frame (self);
 
-      enum language lang = get_frame_language (fi);
-      const language_defn *lang_def = language_def (lang);
+  enum language lang = get_frame_language (fi);
+  const language_defn *lang_def = language_def (lang);
 
-      return host_string_to_python_string (lang_def->name ()).release ();
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  Py_RETURN_NONE;
+  return lang_def->name ();
 }
 
 /* The static link for this frame.  */
 
-static PyObject *
-frapy_static_link (PyObject *self, PyObject *args)
+static gdbpy_ref<>
+frapy_static_link (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr link;
-
-  try
-    {
-      FRAPY_REQUIRE_VALID (self, link);
-
-      link = frame_follow_static_link (link);
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
+  frame_info_ptr link = require_frame (self);
+  link = frame_follow_static_link (link);
 
   if (link == nullptr)
-    Py_RETURN_NONE;
+    return gdbpy_ref<>::new_reference (Py_None);
 
-  return frame_info_to_frame_object (link).release ();
+  return frame_info_to_frame_object (link);
 }
 
 /* Implementation of gdb.newest_frame () -> gdb.Frame.
    Returns the newest frame object.  */
 
-PyObject *
-gdbpy_newest_frame (PyObject *self, PyObject *args)
+gdbpy_ref<>
+gdbpy_newest_frame (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr frame = NULL;
-
-  try
-    {
-      frame = get_current_frame ();
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  return frame_info_to_frame_object (frame).release ();
+  return frame_info_to_frame_object (get_current_frame ());
 }
 
 /* Implementation of gdb.selected_frame () -> gdb.Frame.
    Returns the selected frame object.  */
 
-PyObject *
-gdbpy_selected_frame (PyObject *self, PyObject *args)
+gdbpy_ref<>
+gdbpy_selected_frame (gdbpy_borrowed_ref self)
 {
-  frame_info_ptr frame = NULL;
-
-  try
-    {
-      frame = get_selected_frame ("No frame is currently selected.");
-    }
-  catch (const gdb_exception &except)
-    {
-      return gdbpy_handle_gdb_exception (nullptr, except);
-    }
-
-  return frame_info_to_frame_object (frame).release ();
+  frame_info_ptr frame
+    = get_selected_frame ("No frame is currently selected.");
+  return frame_info_to_frame_object (frame);
 }
 
 /* Implementation of gdb.stop_reason_string (Integer) -> String.
@@ -788,54 +549,53 @@ GDBPY_INITIALIZE_FILE (gdbpy_initialize_frames);
 \f
 
 static PyMethodDef frame_object_methods[] = {
-  { "is_valid", frapy_is_valid, METH_NOARGS,
+  wrap_noargs<frapy_is_valid> ("is_valid",
     "is_valid () -> Boolean.\n\
-Return true if this frame is valid, false if not." },
-  { "name", frapy_name, METH_NOARGS,
+Return true if this frame is valid, false if not."),
+  wrap_noargs<frapy_name> ("name",
     "name () -> String.\n\
-Return the function name of the frame, or None if it can't be determined." },
-  { "type", frapy_type, METH_NOARGS,
+Return the function name of the frame, or None if it can't be determined."),
+  wrap_noargs<frapy_type> ("type",
     "type () -> Integer.\n\
-Return the type of the frame." },
-  { "architecture", frapy_arch, METH_NOARGS,
+Return the type of the frame."),
+  wrap_noargs<frapy_arch> ("architecture",
     "architecture () -> gdb.Architecture.\n\
-Return the architecture of the frame." },
-  { "unwind_stop_reason", frapy_unwind_stop_reason, METH_NOARGS,
+Return the architecture of the frame."),
+  wrap_noargs<frapy_unwind_stop_reason> ("unwind_stop_reason",
     "unwind_stop_reason () -> Integer.\n\
-Return the reason why it's not possible to find frames older than this." },
-  { "pc", frapy_pc, METH_NOARGS,
+Return the reason why it's not possible to find frames older than this."),
+  wrap_noargs<frapy_pc> ("pc",
     "pc () -> Long.\n\
-Return the frame's resume address." },
-  { "read_register", (PyCFunction) frapy_read_register,
-    METH_VARARGS | METH_KEYWORDS,
+Return the frame's resume address."),
+  wrap_varargs<frapy_read_register> ("read_register",
     "read_register (register_name) -> gdb.Value\n\
-Return the value of the register in the frame." },
-  { "block", frapy_block, METH_NOARGS,
+Return the value of the register in the frame."),
+  wrap_noargs<frapy_block> ("block",
     "block () -> gdb.Block.\n\
-Return the frame's code block." },
-  { "function", frapy_function, METH_NOARGS,
+Return the frame's code block."),
+  wrap_noargs<frapy_function> ("function",
     "function () -> gdb.Symbol.\n\
-Returns the symbol for the function corresponding to this frame." },
-  { "older", frapy_older, METH_NOARGS,
+Returns the symbol for the function corresponding to this frame."),
+  wrap_noargs<frapy_older> ("older",
     "older () -> gdb.Frame.\n\
-Return the frame that called this frame." },
-  { "newer", frapy_newer, METH_NOARGS,
+Return the frame that called this frame."),
+  wrap_noargs<frapy_newer> ("newer",
     "newer () -> gdb.Frame.\n\
-Return the frame called by this frame." },
-  { "find_sal", frapy_find_sal, METH_NOARGS,
+Return the frame called by this frame."),
+  wrap_noargs<frapy_find_sal> ("find_sal",
     "find_sal () -> gdb.Symtab_and_line.\n\
-Return the frame's symtab and line." },
-  { "read_var", (PyCFunction) frapy_read_var, METH_VARARGS | METH_KEYWORDS,
+Return the frame's symtab and line."),
+  wrap_varargs<frapy_read_var> ("read_var",
     "read_var (variable) -> gdb.Value.\n\
-Return the value of the variable in this frame." },
-  { "select", frapy_select, METH_NOARGS,
-    "Select this frame as the user's current frame." },
-  { "level", frapy_level, METH_NOARGS,
-    "The stack level of this frame." },
-  { "language", frapy_language, METH_NOARGS,
-    "The language of this frame." },
-  { "static_link", frapy_static_link, METH_NOARGS,
-    "The static link of this frame, or None." },
+Return the value of the variable in this frame."),
+  wrap_noargs<frapy_select> ("select",
+    "Select this frame as the user's current frame."),
+  wrap_noargs<frapy_level> ("level",
+    "The stack level of this frame."),
+  wrap_noargs<frapy_language> ("language",
+    "The language of this frame."),
+  wrap_noargs<frapy_static_link> ("static_link",
+    "The static link of this frame, or None."),
   {NULL}  /* Sentinel */
 };
 
@@ -878,3 +638,6 @@ PyTypeObject frame_object_type = {
   0,				  /* tp_init */
   0,				  /* tp_alloc */
 };
+
+PyTypeObject *frame_object::corresponding_object_type
+    = &frame_object_type;
diff --git a/gdb/python/py-registers.c b/gdb/python/py-registers.c
index 44bc53e6a9d..c24154b64d1 100644
--- a/gdb/python/py-registers.c
+++ b/gdb/python/py-registers.c
@@ -43,6 +43,8 @@ struct register_descriptor_iterator_object : public PyObject
 
   /* Pointer back to the architecture we're finding registers for.  */
   struct gdbarch *gdbarch;
+
+  static PyTypeObject *corresponding_object_type;
 };
 
 extern PyTypeObject register_descriptor_iterator_object_type;
@@ -67,6 +69,8 @@ struct reggroup_iterator_object : public PyObject
 
   /* Pointer back to the architecture we're finding registers for.  */
   struct gdbarch *gdbarch;
+
+  static PyTypeObject *corresponding_object_type;
 };
 
 extern PyTypeObject reggroup_iterator_object_type;
@@ -222,20 +226,17 @@ gdbpy_reggroup_iter_next (PyObject *self)
 /* Return a new gdb.RegisterGroupsIterator over all the register groups in
    GDBARCH.  */
 
-PyObject *
+gdbpy_ref<>
 gdbpy_new_reggroup_iterator (struct gdbarch *gdbarch)
 {
   gdb_assert (gdbarch != nullptr);
 
   /* Create a new object and fill in its internal state.  */
-  reggroup_iterator_object *iter
-    = PyObject_New (reggroup_iterator_object,
-		    &reggroup_iterator_object_type);
-  if (iter == NULL)
-    return NULL;
+  gdbpy_ref<reggroup_iterator_object> iter
+    = gdbpy_new<reggroup_iterator_object> ();
   iter->index = 0;
   iter->gdbarch = gdbarch;
-  return (PyObject *) iter;
+  return iter;
 }
 
 /* Create and return a new gdb.RegisterDescriptorIterator object which
@@ -246,7 +247,7 @@ gdbpy_new_reggroup_iterator (struct gdbarch *gdbarch)
 
    This function can return NULL if GROUP_NAME isn't found.  */
 
-PyObject *
+gdbpy_ref<>
 gdbpy_new_register_descriptor_iterator (struct gdbarch *gdbarch,
 					const char *group_name)
 {
@@ -259,25 +260,19 @@ gdbpy_new_register_descriptor_iterator (struct gdbarch *gdbarch,
     {
       grp = reggroup_find (gdbarch, group_name);
       if (grp == NULL)
-	{
-	  PyErr_SetString (PyExc_ValueError,
-			   _("Unknown register group name."));
-	  return NULL;
-	}
+	gdbpy_err_set_string (PyExc_ValueError,
+			      _("Unknown register group name."));
     }
   /* Create a new iterator object initialised for this architecture and
      fill in all of the details.  */
-  register_descriptor_iterator_object *iter
-    = PyObject_New (register_descriptor_iterator_object,
-		    &register_descriptor_iterator_object_type);
-  if (iter == NULL)
-    return NULL;
+  gdbpy_ref<register_descriptor_iterator_object> iter
+    = gdbpy_new<register_descriptor_iterator_object> ();
   iter->regnum = 0;
   iter->gdbarch = gdbarch;
   gdb_assert (grp != NULL);
   iter->reggroup = grp;
 
-  return (PyObject *) iter;
+  return iter;
 }
 
 /* Return a reference to the gdb.RegisterDescriptorIterator object.  */
@@ -477,6 +472,9 @@ PyTypeObject register_descriptor_iterator_object_type = {
   register_descriptor_iterator_object_methods		/*tp_methods */
 };
 
+PyTypeObject *register_descriptor_iterator_object::corresponding_object_type
+  = &register_descriptor_iterator_object_type;
+
 static gdb_PyGetSetDef gdbpy_register_descriptor_getset[] = {
   { "name", gdbpy_register_descriptor_name, NULL,
     "The name of this register.", NULL },
@@ -547,6 +545,9 @@ PyTypeObject reggroup_iterator_object_type = {
   0				  /*tp_methods */
 };
 
+PyTypeObject *reggroup_iterator_object::corresponding_object_type
+  = &reggroup_iterator_object_type;
+
 static gdb_PyGetSetDef gdbpy_reggroup_getset[] = {
   { "name", gdbpy_reggroup_name, NULL,
     "The name of this register group.", NULL },
diff --git a/gdb/python/py-tui.c b/gdb/python/py-tui.c
index be19193770f..d5173656f8d 100644
--- a/gdb/python/py-tui.c
+++ b/gdb/python/py-tui.c
@@ -51,6 +51,8 @@ struct gdbpy_tui_window: public PyObject
 
   /* Return true if this object is valid.  */
   bool is_valid () const;
+
+  static PyTypeObject *corresponding_object_type;
 };
 
 extern PyTypeObject gdbpy_tui_window_object_type;
@@ -435,11 +437,14 @@ gdbpy_register_tui_window (PyObject *self, PyObject *args, PyObject *kw)
 
 /* Require that "Window" be a valid window.  */
 
-#define REQUIRE_WINDOW(Window)					\
-    do {							\
-      if (!(Window)->is_valid ())				\
-	return PyErr_Format (PyExc_RuntimeError,		\
-			     _("TUI window is invalid."));	\
+#define REQUIRE_WINDOW(Window)				\
+    do {						\
+      if (!(Window)->is_valid ())			\
+	{						\
+	  PyErr_Format (PyExc_RuntimeError,		\
+			_("TUI window is invalid."));	\
+	  return nullptr;					\
+	}						\
     } while (0)
 
 /* Require that "Window" be a valid window.  */
@@ -456,27 +461,30 @@ gdbpy_register_tui_window (PyObject *self, PyObject *args, PyObject *kw)
 
 /* Python function which checks the validity of a TUI window
    object.  */
-static PyObject *
-gdbpy_tui_is_valid (PyObject *self, PyObject *args)
+static bool
+gdbpy_tui_is_valid (gdbpy_borrowed_ref self)
 {
-  gdbpy_tui_window *win = (gdbpy_tui_window *) self;
+  gdbpy_tui_window *win = self;
+  return win->is_valid ();
+}
 
-  if (win->is_valid ())
-    Py_RETURN_TRUE;
-  Py_RETURN_FALSE;
+static void
+require_window (gdbpy_tui_window *win)
+{
+  if (!win->is_valid ())
+    {
+      PyErr_Format (PyExc_RuntimeError, _("TUI window is invalid."));
+      throw gdb_python_exception ();
+    }
 }
 
 /* Python function that erases the TUI window.  */
-static PyObject *
-gdbpy_tui_erase (PyObject *self, PyObject *args)
+static void
+gdbpy_tui_erase (gdbpy_borrowed_ref self)
 {
-  gdbpy_tui_window *win = (gdbpy_tui_window *) self;
-
-  REQUIRE_WINDOW (win);
-
+  gdbpy_tui_window *win = self;
+  require_window (win);
   win->window->erase ();
-
-  Py_RETURN_NONE;
 }
 
 /* Python function that writes some text to a TUI window.  */
@@ -565,11 +573,10 @@ static gdb_PyGetSetDef tui_object_getset[] =
 
 static PyMethodDef tui_object_methods[] =
 {
-  { "is_valid", gdbpy_tui_is_valid, METH_NOARGS,
+  wrap_noargs<gdbpy_tui_is_valid> ("is_valid",
     "is_valid () -> Boolean\n\
-Return true if this TUI window is valid, false if not." },
-  { "erase", gdbpy_tui_erase, METH_NOARGS,
-    "Erase the TUI window." },
+Return true if this TUI window is valid, false if not."),
+  wrap_noargs<gdbpy_tui_erase> ("erase", "Erase the TUI window."),
   { "write", (PyCFunction) gdbpy_tui_write, METH_VARARGS | METH_KEYWORDS,
     "Append a string to the TUI window." },
   { NULL } /* Sentinel.  */
@@ -616,6 +623,9 @@ PyTypeObject gdbpy_tui_window_object_type =
   0,				  /* tp_alloc */
 };
 
+PyTypeObject *gdbpy_tui_window::corresponding_object_type
+    = &gdbpy_tui_window_object_type;
+
 /* Called when TUI is enabled or disabled.  */
 
 static void
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index fdd353ffbeb..289e7a8ea23 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -470,8 +470,8 @@ PyObject *gdbpy_lookup_static_symbols (PyObject *self, PyObject *args,
 PyObject *gdbpy_start_recording (PyObject *self, PyObject *args);
 PyObject *gdbpy_current_recording (PyObject *self, PyObject *args);
 PyObject *gdbpy_stop_recording (PyObject *self, PyObject *args);
-PyObject *gdbpy_newest_frame (PyObject *self, PyObject *args);
-PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args);
+gdbpy_ref<> gdbpy_newest_frame (gdbpy_borrowed_ref self);
+gdbpy_ref<> gdbpy_selected_frame (gdbpy_borrowed_ref self);
 PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw);
 int gdbpy_is_field (PyObject *obj);
 PyObject *gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
@@ -518,11 +518,11 @@ PyObject *objfpy_get_xmethods (PyObject *, void *);
 PyObject *gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw);
 
 gdbpy_ref<> gdbarch_to_arch_object (struct gdbarch *gdbarch);
-PyObject *gdbpy_all_architecture_names (PyObject *self, PyObject *args);
+gdbpy_ref<> gdbpy_all_architecture_names (gdbpy_borrowed_ref self);
 
-PyObject *gdbpy_new_register_descriptor_iterator (struct gdbarch *gdbarch,
-						  const char *group_name);
-PyObject *gdbpy_new_reggroup_iterator (struct gdbarch *gdbarch);
+gdbpy_ref<> gdbpy_new_register_descriptor_iterator (struct gdbarch *gdbarch,
+						    const char *group_name);
+gdbpy_ref<> gdbpy_new_reggroup_iterator (struct gdbarch *gdbarch);
 
 gdbpy_ref<thread_object> create_thread_object (struct thread_info *tp);
 gdbpy_ref<> thread_to_thread_object (thread_info *thr);;
@@ -1332,4 +1332,7 @@ class gdbpy_memoizing_registry_storage
 extern int eval_python_command (const char *command, int start_symbol,
 				const char *filename = nullptr);
 
+#include "py-wrappers.h"
+#include "py-safety.h"
+
 #endif /* GDB_PYTHON_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 8739864a861..5ee434167db 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -3036,12 +3036,12 @@ Arguments (also strings) are passed to the command." },
   { "current_objfile", gdbpy_get_current_objfile, METH_NOARGS,
     "Return the current Objfile being loaded, or None." },
 
-  { "newest_frame", gdbpy_newest_frame, METH_NOARGS,
+  wrap_noargs<gdbpy_newest_frame> ("newest_frame",
     "newest_frame () -> gdb.Frame.\n\
-Return the newest frame object." },
-  { "selected_frame", gdbpy_selected_frame, METH_NOARGS,
+Return the newest frame object."),
+  wrap_noargs<gdbpy_selected_frame> ("selected_frame",
     "selected_frame () -> gdb.Frame.\n\
-Return the selected frame object." },
+Return the selected frame object."),
   { "frame_stop_reason_string", gdbpy_frame_stop_reason_string, METH_VARARGS,
     "stop_reason_string (Integer) -> String.\n\
 Return a string explaining unwind stop reason." },
@@ -3157,9 +3157,9 @@ Set the value of the convenience variable $NAME." },
 Register a TUI window constructor." },
 #endif	/* TUI */
 
-  { "architecture_names", gdbpy_all_architecture_names, METH_NOARGS,
+  wrap_noargs<gdbpy_all_architecture_names> ("architecture_names",
     "architecture_names () -> List.\n\
-Return a list of all the architecture names GDB understands." },
+Return a list of all the architecture names GDB understands."),
 
   { "connections", gdbpy_connections, METH_NOARGS,
     "connections () -> List.\n\
-- 
2.49.0


  parent reply	other threads:[~2026-02-22 20:09 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-22 19:49 [RFC 0/4] Better Python safety Tom Tromey
2026-02-22 19:49 ` [RFC 1/4] Add gdbpy_borrowed_ref Tom Tromey
2026-02-24  4:57   ` Simon Marchi
2026-02-25  3:55     ` Tom Tromey
2026-02-25 15:24       ` Simon Marchi
2026-02-26  1:38       ` Tom Tromey
2026-02-22 19:49 ` [RFC 2/4] Add wrappers for some Python APIs Tom Tromey
2026-02-22 19:49 ` [RFC 3/4] Add constexpr functions to create PyMethodDef entries Tom Tromey
2026-02-22 19:49 ` Tom Tromey [this message]
2026-02-23 20:28 ` [RFC 0/4] Better Python safety Simon Marchi
2026-02-23 21:00 ` Simon Marchi
2026-02-23 23:23   ` Tom Tromey
2026-02-23 23:56     ` Tom Tromey
2026-02-24  1:05       ` Simon Marchi
2026-02-24 16:29         ` Tom Tromey
2026-02-23 21:22 ` Tom Tromey
2026-03-04 17:39 ` Matthieu Longo
2026-03-04 21:02   ` Tom Tromey

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=20260222200759.1587070-5-tom@tromey.com \
    --to=tom@tromey.com \
    --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