aboutsummaryrefslogtreecommitdiff
path: root/gdb/python
diff options
context:
space:
mode:
authorDoug Evans <dje@google.com>2010-05-25 15:27:17 +0000
committerDoug Evans <dje@google.com>2010-05-25 15:27:17 +0000
commit07ca107c2d958b45633ef0cdcce7219a95f0cf01 (patch)
tree489e342ae66a8cac06bdb3d0106dbccb2b15010c /gdb/python
parent8e45593ff36c03d6f39e28a0a7947ce3d282794d (diff)
downloadgdb-07ca107c2d958b45633ef0cdcce7219a95f0cf01.zip
gdb-07ca107c2d958b45633ef0cdcce7219a95f0cf01.tar.gz
gdb-07ca107c2d958b45633ef0cdcce7219a95f0cf01.tar.bz2
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.
Diffstat (limited to 'gdb/python')
-rw-r--r--gdb/python/py-cmd.c95
-rw-r--r--gdb/python/py-utils.c50
-rw-r--r--gdb/python/python-internal.h6
-rw-r--r--gdb/python/python.c11
4 files changed, 152 insertions, 10 deletions
diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
index f9a4130..2cff4ba 100644
--- a/gdb/python/py-cmd.c
+++ b/gdb/python/py-cmd.c
@@ -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);
- PyErr_Restore (ptype, pvalue, ptraceback);
+ 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 ();
- error (_("Error occurred in Python command: %s"), copy);
}
- else
+
+ /* 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."));
+ if (msg != NULL && *msg != '\0')
+ error (_("Error occurred in Python command: %s"), msg);
+ else
+ error (_("Error occurred in Python command."));
}
+ else
+ 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;
+}
diff --git a/gdb/python/py-utils.c b/gdb/python/py-utils.c
index cd11834..944e6b4 100644
--- a/gdb/python/py-utils.c
+++ b/gdb/python/py-utils.c
@@ -222,3 +222,53 @@ gdbpy_is_string (PyObject *obj)
{
return PyString_Check (obj) || PyUnicode_Check (obj);
}
+
+/* Return the string representation of OBJ, i.e., str (obj).
+ Space for the result is malloc'd, the caller must free.
+ If the result is NULL a python error occurred, the caller must clear it. */
+
+char *
+gdbpy_obj_to_string (PyObject *obj)
+{
+ PyObject *str_obj = PyObject_Str (obj);
+
+ if (str_obj != NULL)
+ {
+ char *msg = xstrdup (PyString_AsString (str_obj));
+
+ Py_DECREF (str_obj);
+ return msg;
+ }
+
+ return NULL;
+}
+
+/* Return the string representation of the exception represented by
+ TYPE, VALUE which is assumed to have been obtained with PyErr_Fetch,
+ i.e., the error indicator is currently clear.
+ Space for the result is malloc'd, the caller must free.
+ If the result is NULL a python error occurred, the caller must clear it. */
+
+char *
+gdbpy_exception_to_string (PyObject *ptype, PyObject *pvalue)
+{
+ PyObject *str_obj = PyObject_Str (pvalue);
+ char *str;
+
+ /* There are a few cases to consider.
+ For example:
+ pvalue is a string when PyErr_SetString is used.
+ pvalue is not a string when raise "foo" is used, instead it is None
+ and ptype is "foo".
+ So the algorithm we use is to print `str (pvalue)' if it's not
+ None, otherwise we print `str (ptype)'.
+ Using str (aka PyObject_Str) will fetch the error message from
+ gdb.GdbError ("message"). */
+
+ if (pvalue && pvalue != Py_None)
+ str = gdbpy_obj_to_string (pvalue);
+ else
+ str = gdbpy_obj_to_string (ptype);
+
+ return str;
+}
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index f41f32a..bc07b5d 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -92,6 +92,7 @@ PyObject *gdbpy_block_for_pc (PyObject *self, PyObject *args);
PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw);
PyObject *gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
const char *encoding, struct type *type);
+PyObject *gdbpy_string_to_argv (PyObject *self, PyObject *args);
PyObject *gdbpy_get_hook_function (const char *);
PyObject *gdbpy_parameter (PyObject *self, PyObject *args);
PyObject *gdbpy_parameter_value (enum var_types type, void *var);
@@ -179,6 +180,9 @@ PyObject *python_string_to_target_python_string (PyObject *obj);
char *python_string_to_host_string (PyObject *obj);
PyObject *target_string_to_unicode (const gdb_byte *str, int length);
int gdbpy_is_string (PyObject *obj);
+char *gdbpy_obj_to_string (PyObject *obj);
+char *gdbpy_exception_to_string (PyObject *ptype, PyObject *pvalue);
+
int gdbpy_is_lazy_string (PyObject *result);
gdb_byte *gdbpy_extract_lazy_string (PyObject *string,
struct type **str_type,
@@ -197,4 +201,6 @@ extern PyObject *gdbpy_children_cst;
extern PyObject *gdbpy_to_string_cst;
extern PyObject *gdbpy_display_hint_cst;
+extern PyObject *gdbpy_gdberror_exc;
+
#endif /* GDB_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 3110328..288c701 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -57,6 +57,8 @@ PyObject *gdbpy_children_cst;
PyObject *gdbpy_display_hint_cst;
PyObject *gdbpy_doc_cst;
+/* The GdbError exception. */
+PyObject *gdbpy_gdberror_exc;
/* Architecture and language to be used in callbacks from
the Python interpreter. */
@@ -655,6 +657,9 @@ Enables or disables printing of Python stack traces."),
PyModule_AddStringConstant (gdb_module, "HOST_CONFIG", (char*) host_name);
PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name);
+ gdbpy_gdberror_exc = PyErr_NewException ("gdb.GdbError", NULL, NULL);
+ PyModule_AddObject (gdb_module, "GdbError", gdbpy_gdberror_exc);
+
gdbpy_initialize_auto_load ();
gdbpy_initialize_values ();
gdbpy_initialize_frames ();
@@ -771,6 +776,12 @@ Return the name of the current target charset." },
"target_wide_charset () -> string.\n\
Return the name of the current target wide charset." },
+ { "string_to_argv", gdbpy_string_to_argv, METH_VARARGS,
+ "string_to_argv (String) -> Array.\n\
+Parse String and return an argv-like array.\n\
+Arguments are separate by spaces and may be quoted."
+ },
+
{ "write", gdbpy_write, METH_VARARGS,
"Write a string using gdb's filtered stream." },
{ "flush", gdbpy_flush, METH_NOARGS,