Add python gdb.GdbError and gdb.string_to_argv.
* NEWS: Document them. * python/py-cmd.c (cmdpy_function): Don't print a traceback if the exception is gdb.GdbError. Print a second traceback if there's an error computing the error message. (gdbpy_string_to_argv): New function. * python/py-utils.c (gdbpy_obj_to_string): New function. (gdbpy_exception_to_string): New function. * python/python-internal.h (gdbpy_string_to_argv): Declare. (gdbpy_obj_to_string, gdbpy_exception_to_string): Declare. (gdbpy_gdberror_exc): Declare. * python/python.c (gdbpy_gdberror_exc): New global. (_initialize_python): Initialize gdbpy_gdberror_exc and create gdb.GdbError. (GdbMethods): Add string_to_argv. doc/ * gdb.texinfo (Exception Handling): Document gdb.GdbError. (Commands In Python): Document gdb.string_to_argv. testsuite/ * gdb.python/py-cmd.exp: Add tests for gdb.GdbError and gdb.string_to_argv.
This commit is contained in:
parent
8e45593ff3
commit
07ca107c2d
10 changed files with 255 additions and 13 deletions
|
@ -88,6 +88,7 @@ cmdpy_dont_repeat (PyObject *self, PyObject *args)
|
|||
|
||||
|
||||
/* Called if the gdb cmd_list_element is destroyed. */
|
||||
|
||||
static void
|
||||
cmdpy_destroyer (struct cmd_list_element *self, void *context)
|
||||
{
|
||||
|
@ -111,6 +112,7 @@ cmdpy_destroyer (struct cmd_list_element *self, void *context)
|
|||
}
|
||||
|
||||
/* Called by gdb to invoke the command. */
|
||||
|
||||
static void
|
||||
cmdpy_function (struct cmd_list_element *command, char *args, int from_tty)
|
||||
{
|
||||
|
@ -145,30 +147,51 @@ cmdpy_function (struct cmd_list_element *command, char *args, int from_tty)
|
|||
ttyobj, NULL);
|
||||
Py_DECREF (argobj);
|
||||
Py_DECREF (ttyobj);
|
||||
|
||||
if (! result)
|
||||
{
|
||||
PyObject *ptype, *pvalue, *ptraceback;
|
||||
char *msg;
|
||||
|
||||
PyErr_Fetch (&ptype, &pvalue, &ptraceback);
|
||||
|
||||
if (pvalue && PyString_Check (pvalue))
|
||||
{
|
||||
/* Make a temporary copy of the string data. */
|
||||
char *s = PyString_AsString (pvalue);
|
||||
char *copy = alloca (strlen (s) + 1);
|
||||
/* 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. */
|
||||
|
||||
strcpy (copy, s);
|
||||
msg = gdbpy_exception_to_string (ptype, pvalue);
|
||||
make_cleanup (xfree, msg);
|
||||
|
||||
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 command\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 ();
|
||||
error (_("Error occurred in Python command: %s"), copy);
|
||||
if (msg != NULL && *msg != '\0')
|
||||
error (_("Error occurred in Python command: %s"), msg);
|
||||
else
|
||||
error (_("Error occurred in Python command."));
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_Restore (ptype, pvalue, ptraceback);
|
||||
gdbpy_print_stack ();
|
||||
error (_("Error occurred in Python command."));
|
||||
}
|
||||
error ("%s", msg);
|
||||
}
|
||||
|
||||
Py_DECREF (result);
|
||||
do_cleanups (cleanup);
|
||||
}
|
||||
|
@ -589,3 +612,55 @@ static PyTypeObject cmdpy_object_type =
|
|||
0, /* tp_alloc */
|
||||
PyType_GenericNew /* tp_new */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Utility to build a buildargv-like result from ARGS.
|
||||
This intentionally parses arguments the way libiberty/argv.c:buildargv
|
||||
does. It splits up arguments in a reasonable way, and we want a standard
|
||||
way of parsing arguments. Several gdb commands use buildargv to parse their
|
||||
arguments. Plus we want to be able to write compatible python
|
||||
implementations of gdb commands. */
|
||||
|
||||
PyObject *
|
||||
gdbpy_string_to_argv (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *py_argv;
|
||||
char *input;
|
||||
|
||||
if (!PyArg_ParseTuple (args, "s", &input))
|
||||
return NULL;
|
||||
|
||||
py_argv = PyList_New (0);
|
||||
|
||||
/* buildargv uses NULL to represent an empty argument list, but we can't use
|
||||
that in Python. Instead, if ARGS is "" then return an empty list.
|
||||
This undoes the NULL -> "" conversion that cmdpy_function does. */
|
||||
|
||||
if (*input != '\0')
|
||||
{
|
||||
char **c_argv = gdb_buildargv (input);
|
||||
int i;
|
||||
|
||||
for (i = 0; c_argv[i] != NULL; ++i)
|
||||
{
|
||||
PyObject *argp = PyString_FromString (c_argv[i]);
|
||||
|
||||
if (argp == NULL
|
||||
|| PyList_Append (py_argv, argp) < 0)
|
||||
{
|
||||
if (argp != NULL)
|
||||
{
|
||||
Py_DECREF (argp);
|
||||
}
|
||||
Py_DECREF (py_argv);
|
||||
freeargv (c_argv);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
freeargv (c_argv);
|
||||
}
|
||||
|
||||
return py_argv;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue