diff options
author | Doug Evans <dje@google.com> | 2010-05-25 15:27:17 +0000 |
---|---|---|
committer | Doug Evans <dje@google.com> | 2010-05-25 15:27:17 +0000 |
commit | 07ca107c2d958b45633ef0cdcce7219a95f0cf01 (patch) | |
tree | 489e342ae66a8cac06bdb3d0106dbccb2b15010c /gdb/python | |
parent | 8e45593ff36c03d6f39e28a0a7947ce3d282794d (diff) | |
download | gdb-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.c | 95 | ||||
-rw-r--r-- | gdb/python/py-utils.c | 50 | ||||
-rw-r--r-- | gdb/python/python-internal.h | 6 | ||||
-rw-r--r-- | gdb/python/python.c | 11 |
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, |