diff options
author | Tom Tromey <tromey@redhat.com> | 2009-05-28 01:05:14 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2009-05-28 01:05:14 +0000 |
commit | a6bac58e84001d33b9540e208e9ca6d6ab265bf3 (patch) | |
tree | 6dc1ea1483f42b9b0995046c029dad43ad45e05c /gdb/python | |
parent | 42ae523077b469c09e83845d30ee137a844aacb8 (diff) | |
download | gdb-a6bac58e84001d33b9540e208e9ca6d6ab265bf3.zip gdb-a6bac58e84001d33b9540e208e9ca6d6ab265bf3.tar.gz gdb-a6bac58e84001d33b9540e208e9ca6d6ab265bf3.tar.bz2 |
gdb
2009-05-27 Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
Phil Muldoon <pmuldoon@redhat.com>
Paul Pluzhnikov <ppluzhnikov@google.com>
Vladimir Prus <vladimir@codesourcery.com>
* python/python-value.c (value_object_to_value): New function.
* python/python-internal.h: Include frameobject.h.
(gdbpy_children_cst, gdbpy_to_string_cst, gdbpy_display_hint_cst):
Declare.
(value_object_to_value): Declare.
* printcmd.c (struct format_data) <raw>: New field.
(last_format): Default to 0.
(decode_format): Initialize val.raw. Handle /r flag.
(print_command_1): Initialize fmt.raw and opts.raw.
(output_command): Likewise.
(x_command): Fix initialization of fmt.format. Initialize
fmt.raw.
(display_command): Initialize fmt.raw.
(do_one_display): Set opts.raw.
* python/python.c (gdbpy_to_string_cst, gdbpy_children_cst,
gdbpy_display_hint_cst): New globals.
(_initialize_python): Initialize them. Set gdb.pretty_printers.
* cp-valprint.c: Include python.h.
(cp_print_value): Call apply_val_pretty_printer.
* python/python.h (apply_val_pretty_printer): Declare.
* stack.c (print_this_frame_argument_p): Remove.
(print_frame_args): Compute summary flag. Don't use
print_this_frame_argument_p.
* valprint.c: Include python.h.
(user_print_options): Initialize new fields.
(scalar_type_p): New function.
(val_print): Handle 'raw' and 'summary' modes. Call
apply_val_pretty_printer.
(value_print): Handle 'raw' mode.
* valprint.h (struct value_print_options) <raw, summary>: New
fields.
* Makefile.in (SUBDIR_PYTHON_OBS): Add python-prettyprint.o
(SUBDIR_PYTHON_SRCS): Add python-prettyprint.c.
(python-prettyprint.o): New target.
* python/python-prettyprint.c: New file.
gdb/doc
2009-05-27 Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
Phil Muldoon <pmuldoon@redhat.com>
* gdb.texinfo (Objfiles In Python): Reference pretty printing.
(Pretty Printing): New node.
(Selecting Pretty-Printers): Likewise.
(Python API): Update.
(Output Formats): Document /r format.
gdb/testsuite
2009-05-27 Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
Phil Muldoon <pmuldoon@redhat.com>
Paul Pluzhnikov <ppluzhnikov@google.com>
* gdb.python/python-prettyprint.exp: New file.
* gdb.python/python-prettyprint.c: New file.
* gdb.python/python-prettyprint.py: New file.
* gdb.base/display.exp: print/r is now valid.
Diffstat (limited to 'gdb/python')
-rw-r--r-- | gdb/python/python-internal.h | 7 | ||||
-rw-r--r-- | gdb/python/python-prettyprint.c | 524 | ||||
-rw-r--r-- | gdb/python/python-value.c | 11 | ||||
-rw-r--r-- | gdb/python/python.c | 8 | ||||
-rw-r--r-- | gdb/python/python.h | 6 |
5 files changed, 556 insertions, 0 deletions
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 819867f..983d24d 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -33,6 +33,7 @@ #if HAVE_LIBPYTHON2_4 #include "python2.4/Python.h" +#include "python2.4/frameobject.h" /* Py_ssize_t is not defined until 2.5. Logical type for Py_ssize_t is Py_intptr_t, but that fails in 64-bit compilation due to several apparent mistakes in python2.4 API, so we @@ -40,8 +41,10 @@ typedef int Py_ssize_t; #elif HAVE_LIBPYTHON2_5 #include "python2.5/Python.h" +#include "python2.5/frameobject.h" #elif HAVE_LIBPYTHON2_6 #include "python2.6/Python.h" +#include "python2.6/frameobject.h" #else #error "Unable to find usable Python.h" #endif @@ -74,6 +77,7 @@ PyObject *objfile_to_objfile_object (struct objfile *); PyObject *objfpy_get_printers (PyObject *, void *); +struct value *value_object_to_value (PyObject *self); struct value *convert_value_from_python (PyObject *obj); struct type *type_object_to_type (PyObject *obj); @@ -108,5 +112,8 @@ PyObject *target_string_to_unicode (const gdb_byte *str, int length); int gdbpy_is_string (PyObject *obj); extern PyObject *gdbpy_doc_cst; +extern PyObject *gdbpy_children_cst; +extern PyObject *gdbpy_to_string_cst; +extern PyObject *gdbpy_display_hint_cst; #endif /* GDB_PYTHON_INTERNAL_H */ diff --git a/gdb/python/python-prettyprint.c b/gdb/python/python-prettyprint.c new file mode 100644 index 0000000..5be4f36 --- /dev/null +++ b/gdb/python/python-prettyprint.c @@ -0,0 +1,524 @@ +/* Python pretty-printing + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "exceptions.h" +#include "objfiles.h" +#include "symtab.h" +#include "language.h" +#include "valprint.h" +#include "python.h" +#include "python-internal.h" + +#ifdef HAVE_PYTHON + +/* Helper function for find_pretty_printer which iterates over a list, + calls each function and inspects output. This will return a + printer object if one recognizes VALUE. If no printer is found, it + will return None. On error, it will set the Python error and + return NULL. */ +static PyObject * +search_pp_list (PyObject *list, PyObject *value) +{ + Py_ssize_t pp_list_size, list_index; + PyObject *function, *printer = NULL; + + pp_list_size = PyList_Size (list); + for (list_index = 0; list_index < pp_list_size; list_index++) + { + function = PyList_GetItem (list, list_index); + if (! function) + return NULL; + + printer = PyObject_CallFunctionObjArgs (function, value, NULL); + if (! printer) + return NULL; + else if (printer != Py_None) + return printer; + + Py_DECREF (printer); + } + + Py_RETURN_NONE; +} + +/* Find the pretty-printing constructor function for VALUE. If no + pretty-printer exists, return None. If one exists, return a new + reference. On error, set the Python error and return NULL. */ +static PyObject * +find_pretty_printer (PyObject *value) +{ + PyObject *pp_list = NULL; + PyObject *function = NULL; + struct objfile *obj; + volatile struct gdb_exception except; + + /* Look at the pretty-printer dictionary for each objfile. */ + ALL_OBJFILES (obj) + { + PyObject *objf = objfile_to_objfile_object (obj); + if (!objf) + { + /* Ignore the error and continue. */ + PyErr_Clear (); + continue; + } + + pp_list = objfpy_get_printers (objf, NULL); + function = search_pp_list (pp_list, value); + + /* If there is an error in any objfile list, abort the search and + exit. */ + if (! function) + { + Py_XDECREF (pp_list); + return NULL; + } + + if (function != Py_None) + goto done; + + Py_DECREF (function); + Py_XDECREF (pp_list); + } + + pp_list = NULL; + /* Fetch the global pretty printer dictionary. */ + if (! PyObject_HasAttrString (gdb_module, "pretty_printers")) + { + function = Py_None; + Py_INCREF (function); + goto done; + } + pp_list = PyObject_GetAttrString (gdb_module, "pretty_printers"); + if (! pp_list) + goto done; + if (! PyList_Check (pp_list)) + goto done; + + function = search_pp_list (pp_list, value); + + done: + Py_XDECREF (pp_list); + + return function; +} + +/* Pretty-print a single value, via the printer object PRINTER. If + the function returns a string, an xmalloc()d copy is returned. + Otherwise, if the function returns a value, a *OUT_VALUE is set to + the value, and NULL is returned. On error, *OUT_VALUE is set to + NULL and NULL is returned. */ +static char * +pretty_print_one_value (PyObject *printer, struct value **out_value) +{ + char *output = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + PyObject *result; + + result = PyObject_CallMethodObjArgs (printer, gdbpy_to_string_cst, NULL); + if (result) + { + if (gdbpy_is_string (result)) + output = python_string_to_host_string (result); + else + *out_value = convert_value_from_python (result); + Py_DECREF (result); + } + } + + return output; +} + +/* Return the display hint for the object printer, PRINTER. Return + NULL if there is no display_hint method, or if the method did not + return a string. On error, print stack trace and return NULL. On + success, return an xmalloc()d string. */ +char * +gdbpy_get_display_hint (PyObject *printer) +{ + PyObject *hint; + char *result = NULL; + + if (! PyObject_HasAttr (printer, gdbpy_display_hint_cst)) + return NULL; + + hint = PyObject_CallMethodObjArgs (printer, gdbpy_display_hint_cst, NULL); + if (gdbpy_is_string (hint)) + result = python_string_to_host_string (hint); + if (hint) + Py_DECREF (hint); + else + gdbpy_print_stack (); + + return result; +} + +/* Helper for apply_val_pretty_printer which calls to_string and + formats the result. */ +static void +print_string_repr (PyObject *printer, const char *hint, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language) +{ + char *output; + struct value *replacement = NULL; + + output = pretty_print_one_value (printer, &replacement); + if (output) + { + if (hint && !strcmp (hint, "string")) + LA_PRINT_STRING (stream, builtin_type (current_gdbarch)->builtin_char, + (gdb_byte *) output, strlen (output), + 0, options); + else + fputs_filtered (output, stream); + xfree (output); + } + else if (replacement) + common_val_print (replacement, stream, recurse, options, language); + else + gdbpy_print_stack (); +} + +static void +py_restore_tstate (void *p) +{ + PyFrameObject *frame = p; + PyThreadState *tstate = PyThreadState_GET (); + tstate->frame = frame; +} + +/* Create a dummy PyFrameObject, needed to work around + a Python-2.4 bug with generators. */ +static PyObject * +push_dummy_python_frame () +{ + PyObject *empty_string, *null_tuple, *globals; + PyCodeObject *code; + PyFrameObject *frame; + PyThreadState *tstate; + + empty_string = PyString_FromString (""); + if (!empty_string) + return NULL; + + null_tuple = PyTuple_New (0); + if (!null_tuple) + { + Py_DECREF (empty_string); + return NULL; + } + + code = PyCode_New (0, /* argcount */ + 0, /* nlocals */ + 0, /* stacksize */ + 0, /* flags */ + empty_string, /* code */ + null_tuple, /* consts */ + null_tuple, /* names */ + null_tuple, /* varnames */ +#if PYTHON_API_VERSION >= 1010 + null_tuple, /* freevars */ + null_tuple, /* cellvars */ +#endif + empty_string, /* filename */ + empty_string, /* name */ + 1, /* firstlineno */ + empty_string /* lnotab */ + ); + + Py_DECREF (empty_string); + Py_DECREF (null_tuple); + + if (!code) + return NULL; + + globals = PyDict_New (); + if (!globals) + { + Py_DECREF (code); + return NULL; + } + + tstate = PyThreadState_GET (); + + frame = PyFrame_New (tstate, code, globals, NULL); + + Py_DECREF (globals); + Py_DECREF (code); + + if (!frame) + return NULL; + + tstate->frame = frame; + make_cleanup (py_restore_tstate, frame->f_back); + return (PyObject *) frame; +} + +/* Helper for apply_val_pretty_printer that formats children of the + printer, if any exist. */ +static void +print_children (PyObject *printer, const char *hint, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language) +{ + int is_map, is_array, done_flag, pretty; + unsigned int i; + PyObject *children, *iter, *frame; + struct cleanup *cleanups; + + if (! PyObject_HasAttr (printer, gdbpy_children_cst)) + return; + + /* If we are printing a map or an array, we want some special + formatting. */ + is_map = hint && ! strcmp (hint, "map"); + is_array = hint && ! strcmp (hint, "array"); + + children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst, + NULL); + if (! children) + { + gdbpy_print_stack (); + return; + } + + cleanups = make_cleanup_py_decref (children); + + iter = PyObject_GetIter (children); + if (!iter) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (iter); + + /* Use the prettyprint_arrays option if we are printing an array, + and the pretty option otherwise. */ + pretty = is_array ? options->prettyprint_arrays : options->pretty; + + /* Manufacture a dummy Python frame to work around Python 2.4 bug, + where it insists on having a non-NULL tstate->frame when + a generator is called. */ + frame = push_dummy_python_frame (); + if (!frame) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (frame); + + done_flag = 0; + for (i = 0; i < options->print_max; ++i) + { + PyObject *py_v, *item = PyIter_Next (iter); + char *name; + struct cleanup *inner_cleanup; + + if (! item) + { + if (PyErr_Occurred ()) + gdbpy_print_stack (); + /* Set a flag so we can know whether we printed all the + available elements. */ + else + done_flag = 1; + break; + } + + if (! PyArg_ParseTuple (item, "sO", &name, &py_v)) + { + gdbpy_print_stack (); + Py_DECREF (item); + continue; + } + inner_cleanup = make_cleanup_py_decref (item); + + /* Print initial "{". For other elements, there are three + cases: + 1. Maps. Print a "," after each value element. + 2. Arrays. Always print a ",". + 3. Other. Always print a ",". */ + if (i == 0) + fputs_filtered (" = {", stream); + else if (! is_map || i % 2 == 0) + fputs_filtered (pretty ? "," : ", ", stream); + + /* In summary mode, we just want to print "= {...}" if there is + a value. */ + if (options->summary) + { + /* This increment tricks the post-loop logic to print what + we want. */ + ++i; + /* Likewise. */ + pretty = 0; + break; + } + + if (! is_map || i % 2 == 0) + { + if (pretty) + { + fputs_filtered ("\n", stream); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + wrap_here (n_spaces (2 + 2 *recurse)); + } + + if (is_map && i % 2 == 0) + fputs_filtered ("[", stream); + else if (is_array) + { + /* We print the index, not whatever the child method + returned as the name. */ + if (options->print_array_indexes) + fprintf_filtered (stream, "[%d] = ", i); + } + else if (! is_map) + { + fputs_filtered (name, stream); + fputs_filtered (" = ", stream); + } + + if (gdbpy_is_string (py_v)) + { + char *text = python_string_to_host_string (py_v); + if (! text) + gdbpy_print_stack (); + else + { + fputs_filtered (text, stream); + xfree (text); + } + } + else + { + struct value *value = convert_value_from_python (py_v); + + if (value == NULL) + { + gdbpy_print_stack (); + error (_("Error while executing Python code.")); + } + else + common_val_print (value, stream, recurse + 1, options, language); + } + + if (is_map && i % 2 == 0) + fputs_filtered ("] = ", stream); + + do_cleanups (inner_cleanup); + } + + if (i) + { + if (!done_flag) + { + if (pretty) + { + fputs_filtered ("\n", stream); + print_spaces_filtered (2 + 2 * recurse, stream); + } + fputs_filtered ("...", stream); + } + if (pretty) + { + fputs_filtered ("\n", stream); + print_spaces_filtered (2 * recurse, stream); + } + fputs_filtered ("}", stream); + } + + done: + do_cleanups (cleanups); +} + +int +apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language) +{ + PyObject *printer = NULL; + PyObject *val_obj = NULL; + struct value *value; + char *hint = NULL; + struct cleanup *cleanups; + int result = 0; + PyGILState_STATE state; + + state = PyGILState_Ensure (); + cleanups = make_cleanup_py_restore_gil (&state); + + /* Instantiate the printer. */ + if (valaddr) + valaddr += embedded_offset; + value = value_from_contents_and_address (type, valaddr, address); + + val_obj = value_to_value_object (value); + if (! val_obj) + goto done; + + /* Find the constructor. */ + printer = find_pretty_printer (val_obj); + Py_DECREF (val_obj); + make_cleanup_py_decref (printer); + if (! printer || printer == Py_None) + goto done; + + /* If we are printing a map, we want some special formatting. */ + hint = gdbpy_get_display_hint (printer); + make_cleanup (free_current_contents, &hint); + + /* Print the section */ + print_string_repr (printer, hint, stream, recurse, options, language); + print_children (printer, hint, stream, recurse, options, language); + result = 1; + + + done: + if (PyErr_Occurred ()) + gdbpy_print_stack (); + do_cleanups (cleanups); + return result; +} + +#else /* HAVE_PYTHON */ + +int +apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + struct ui_file *stream, int format, + int deref_ref, int recurse, + enum val_prettyprint pretty, + const struct language_defn *language) +{ + return 0; +} + +#endif /* HAVE_PYTHON */ diff --git a/gdb/python/python-value.c b/gdb/python/python-value.c index 76f5cde..46af318 100644 --- a/gdb/python/python-value.c +++ b/gdb/python/python-value.c @@ -805,6 +805,17 @@ value_to_value_object (struct value *val) return (PyObject *) val_obj; } +/* Returns value structure corresponding to the given value object. */ +struct value * +value_object_to_value (PyObject *self) +{ + value_object *real; + if (! PyObject_TypeCheck (self, &value_object_type)) + return NULL; + real = (value_object *) self; + return real->value; +} + /* Try to convert a Python value to a gdb value. If the value cannot be converted, set a Python exception and return NULL. */ diff --git a/gdb/python/python.c b/gdb/python/python.c index 701a931..19098cc 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -52,6 +52,10 @@ static PyMethodDef GdbMethods[]; PyObject *gdb_module; +/* Some string constants we may wish to use. */ +PyObject *gdbpy_to_string_cst; +PyObject *gdbpy_children_cst; +PyObject *gdbpy_display_hint_cst; PyObject *gdbpy_doc_cst; /* Given a command_line, return a command string suitable for passing @@ -556,9 +560,13 @@ Enables or disables auto-loading of Python code when an object is opened."), gdbpy_initialize_objfile (); PyRun_SimpleString ("import gdb"); + PyRun_SimpleString ("gdb.pretty_printers = []"); observer_attach_new_objfile (gdbpy_new_objfile); + gdbpy_to_string_cst = PyString_FromString ("to_string"); + gdbpy_children_cst = PyString_FromString ("children"); + gdbpy_display_hint_cst = PyString_FromString ("display_hint"); gdbpy_doc_cst = PyString_FromString ("__doc__"); /* Create a couple objects which are used for Python's stdout and diff --git a/gdb/python/python.h b/gdb/python/python.h index e63c447..33b0437 100644 --- a/gdb/python/python.h +++ b/gdb/python/python.h @@ -26,4 +26,10 @@ extern struct value *values_in_python; void eval_python_from_control_command (struct command_line *); +int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language); + #endif /* GDB_PYTHON_H */ |