/* Convenience functions implemented in Python.
- Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2008-2017 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include "value.h"
-#include "exceptions.h"
#include "python-internal.h"
#include "charset.h"
#include "gdbcmd.h"
#include "completer.h"
#include "expression.h"
#include "language.h"
+#include "py-ref.h"
-static PyTypeObject fnpy_object_type;
+extern PyTypeObject fnpy_object_type
+ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("PyObject");
\f
convert_values_to_python (int argc, struct value **argv)
{
int i;
- PyObject *result = PyTuple_New (argc);
+ gdbpy_ref<> result (PyTuple_New (argc));
+
+ if (result == NULL)
+ return NULL;
for (i = 0; i < argc; ++i)
{
- PyObject *elt = value_to_value_object (argv[i]);
- if (! elt)
- {
- Py_DECREF (result);
- error (_("Could not convert value to Python object."));
- }
- PyTuple_SetItem (result, i, elt);
+ gdbpy_ref<> elt (value_to_value_object (argv[i]));
+ if (elt == NULL)
+ return NULL;
+ PyTuple_SetItem (result.get (), i, elt.release ());
}
- return result;
+ return result.release ();
}
/* Call a Python function object's invoke method. */
fnpy_call (struct gdbarch *gdbarch, const struct language_defn *language,
void *cookie, int argc, struct value **argv)
{
- struct value *value = NULL;
- PyObject *result, *callable, *args;
- struct cleanup *cleanup;
-
- cleanup = ensure_python_env (gdbarch, language);
+ /* The gdbpy_enter object needs to be placed first, so that it's the last to
+ be destroyed. */
+ gdbpy_enter enter_py (gdbarch, language);
+ struct value *value;
+ gdbpy_ref<> result;
+ gdbpy_ref<> args (convert_values_to_python (argc, argv));
+
+ /* convert_values_to_python can return NULL on error. If we
+ encounter this, do not call the function, but allow the Python ->
+ error code conversion below to deal with the Python exception.
+ Note, that this is different if the function simply does not
+ have arguments. */
+
+ if (args != NULL)
+ {
+ gdbpy_ref<> callable (PyObject_GetAttrString ((PyObject *) cookie,
+ "invoke"));
+ if (callable == NULL)
+ error (_("No method named 'invoke' in object."));
- args = convert_values_to_python (argc, argv);
+ result.reset (PyObject_Call (callable.get (), args.get (), NULL));
+ }
- callable = PyObject_GetAttrString ((PyObject *) cookie, "invoke");
- if (! callable)
+ if (result == NULL)
{
- Py_DECREF (args);
- error (_("No method named 'invoke' in object."));
- }
+ PyObject *ptype, *pvalue, *ptraceback;
- result = PyObject_Call (callable, args, NULL);
- Py_DECREF (callable);
- Py_DECREF (args);
+ PyErr_Fetch (&ptype, &pvalue, &ptraceback);
- if (!result)
- {
- gdbpy_print_stack ();
- error (_("Error while executing Python code."));
+ /* Try to fetch an error message contained within ptype, pvalue.
+ When fetching the error message we need to make our own copy,
+ we no longer own ptype, pvalue after the call to PyErr_Restore. */
+
+ gdb::unique_xmalloc_ptr<char>
+ msg (gdbpy_exception_to_string (ptype, pvalue));
+
+ if (msg == NULL)
+ {
+ /* An error occurred computing the string representation of the
+ error message. This is rare, but we should inform the user. */
+
+ printf_filtered (_("An error occurred in a Python "
+ "convenience function\n"
+ "and then another occurred computing the "
+ "error message.\n"));
+ gdbpy_print_stack ();
+ }
+
+ /* Don't print the stack for gdb.GdbError exceptions.
+ It is generally used to flag user errors.
+
+ We also don't want to print "Error occurred in Python command"
+ for user errors. However, a missing message for gdb.GdbError
+ exceptions is arguably a bug, so we flag it as such. */
+
+ if (!PyErr_GivenExceptionMatches (ptype, gdbpy_gdberror_exc)
+ || msg == NULL || *msg == '\0')
+ {
+ PyErr_Restore (ptype, pvalue, ptraceback);
+ gdbpy_print_stack ();
+ if (msg != NULL && *msg != '\0')
+ error (_("Error occurred in Python convenience function: %s"),
+ msg.get ());
+ else
+ error (_("Error occurred in Python convenience function."));
+ }
+ else
+ {
+ Py_XDECREF (ptype);
+ Py_XDECREF (pvalue);
+ Py_XDECREF (ptraceback);
+ error ("%s", msg.get ());
+ }
}
- value = convert_value_from_python (result);
+ value = convert_value_from_python (result.get ());
if (value == NULL)
{
- Py_DECREF (result);
gdbpy_print_stack ();
error (_("Error while executing Python code."));
}
- Py_DECREF (result);
- do_cleanups (cleanup);
-
return value;
}
static int
fnpy_init (PyObject *self, PyObject *args, PyObject *kwds)
{
- char *name, *docstring = NULL;
+ const char *name;
+ gdb::unique_xmalloc_ptr<char> docstring;
if (! PyArg_ParseTuple (args, "s", &name))
return -1;
if (PyObject_HasAttrString (self, "__doc__"))
{
- PyObject *ds_obj = PyObject_GetAttrString (self, "__doc__");
- if (ds_obj && gdbpy_is_string (ds_obj))
+ gdbpy_ref<> ds_obj (PyObject_GetAttrString (self, "__doc__"));
+ if (ds_obj != NULL)
{
- docstring = python_string_to_host_string (ds_obj);
- if (docstring == NULL)
+ if (gdbpy_is_string (ds_obj.get ()))
{
- Py_DECREF (self);
- return -1;
+ docstring = python_string_to_host_string (ds_obj.get ());
+ if (docstring == NULL)
+ {
+ Py_DECREF (self);
+ return -1;
+ }
}
}
}
if (! docstring)
- docstring = xstrdup (_("This function is not documented."));
+ docstring.reset (xstrdup (_("This function is not documented.")));
- add_internal_function (name, docstring, fnpy_call, self);
+ add_internal_function (name, docstring.release (), fnpy_call, self);
return 0;
}
/* Initialize internal function support. */
-void
+int
gdbpy_initialize_functions (void)
{
+ fnpy_object_type.tp_new = PyType_GenericNew;
if (PyType_Ready (&fnpy_object_type) < 0)
- return;
+ return -1;
- Py_INCREF (&fnpy_object_type);
- PyModule_AddObject (gdb_module, "Function", (PyObject *) &fnpy_object_type);
+ return gdb_pymodule_addobject (gdb_module, "Function",
+ (PyObject *) &fnpy_object_type);
}
\f
-static PyTypeObject fnpy_object_type =
+PyTypeObject fnpy_object_type =
{
- PyObject_HEAD_INIT (NULL)
- 0, /*ob_size*/
+ PyVarObject_HEAD_INIT (NULL, 0)
"gdb.Function", /*tp_name*/
sizeof (PyObject), /*tp_basicsize*/
0, /*tp_itemsize*/
0, /* tp_dictoffset */
fnpy_init, /* tp_init */
0, /* tp_alloc */
- PyType_GenericNew /* tp_new */
};