diff options
author | Tom Tromey <tromey@redhat.com> | 2009-05-28 01:09:20 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2009-05-28 01:09:20 +0000 |
commit | b6313243984b74ee6772dd8273b0e6073ad1815b (patch) | |
tree | 79db018823e681990855f3c379c40e2cc7de9f6e /gdb/varobj.c | |
parent | a6bac58e84001d33b9540e208e9ca6d6ab265bf3 (diff) | |
download | gdb-b6313243984b74ee6772dd8273b0e6073ad1815b.zip gdb-b6313243984b74ee6772dd8273b0e6073ad1815b.tar.gz gdb-b6313243984b74ee6772dd8273b0e6073ad1815b.tar.bz2 |
gdb
2009-05-27 Vladimir Prus <vladimir@codesourcery.com>
Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
* mi/mi-main.c (mi_cmd_list_features): List "python" feature.
* varobj.h (varobj_set_visualizer): Declare.
(varobj_get_display_hint): Likewise.
(varobj_update_result_t) <children_changed, value_installed>: New
fields.
* mi/mi-cmds.c (mi_cmds): Add var-set-visualizer.
* mi/mi-cmds.h (mi_cmd_var_set_visualizer,
mi_cmd_var_set_child_range): Declare.
* mi/mi-cmd-var.c (mi_cmd_var_set_visualizer): New function.
(mi_cmd_var_list_children): Emit display hint.
(varobj_update_one): Emit display hint. Handle dynamic children.
* python/python.c (GdbMethods): Add "default_visualizer".
* python/python-internal.h (apply_varobj_pretty_printer,
gdbpy_get_varobj_pretty_printer, gdbpy_get_display_hint):
Declare.
(gdbpy_default_visualizer): Likewise.
* varobj.c: Include python.h, python-internal.h.
(PyObject): New typedef.
(struct varobj) <children_requested, pretty_printer>: New fields.
(varobj_create): Call install_default_visualizer.
(instantiate_pretty_printer): New function.
(varobj_set_display_format): Update.
(varobj_get_display_hint): New function.
(update_dynamic_varobj_children): New function.
(varobj_get_num_children): Handle dynamic children.
(varobj_list_children): Likewise.
(install_new_value): Likewise.
(varobj_add_child): New function.
(install_visualizer): Likewise.
(install_default_visualizer): Likewise.
(varobj_set_visualizer): Likewise.
(varobj_update): Handle dynamic children.
(create_child): Use create_child_with_value.
(create_child_with_value): New function.
(value_get_print_value): Call pretty printer. Add value_formatter
argument.
(c_value_of_variable): Update.
(varobj_invalidate): Always free all_rootvarobj.
* python/python-prettyprint.c (apply_varobj_pretty_printer): New
function.
(gdbpy_get_varobj_pretty_printer): Likewise.
(gdbpy_default_visualizer): Likewise.
gdb/doc
2009-05-27 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (GDB/MI Miscellaneous Commands): Document "python"
feature.
(GDB/MI Variable Objects): Document -var-set-visualizer.
gdb/testsuite
2009-05-27 Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
* lib/mi-support.exp (mi_varobj_update_dynamic): New proc.
(mi_child_regexp): Likewise.
(mi_list_varobj_children_range): Likewise.
(mi_get_features): Likewise.
(mi_list_varobj_children): Rewrite.
* gdb.python/python-mi.exp: New file.
Diffstat (limited to 'gdb/varobj.c')
-rw-r--r-- | gdb/varobj.c | 534 |
1 files changed, 497 insertions, 37 deletions
diff --git a/gdb/varobj.c b/gdb/varobj.c index e8556d7..ca698dc 100644 --- a/gdb/varobj.c +++ b/gdb/varobj.c @@ -35,6 +35,13 @@ #include "gdbthread.h" #include "inferior.h" +#if HAVE_PYTHON +#include "python/python.h" +#include "python/python-internal.h" +#else +typedef int PyObject; +#endif + /* Non-zero if we want to see trace of varobj level stuff. */ int varobjdebug = 0; @@ -138,6 +145,12 @@ struct varobj /* Children of this object. */ VEC (varobj_p) *children; + /* Whether the children of this varobj were requested. This field is + used to decide if dynamic varobj should recompute their children. + In the event that the frontend never asked for the children, we + can avoid that. */ + int children_requested; + /* Description of the root variable. Points to root variable for children. */ struct varobj_root *root; @@ -159,6 +172,10 @@ struct varobj not fetched if either the variable is frozen, or any parents is frozen. */ int not_fetched; + + /* The pretty-printer that has been constructed. If NULL, then a + new printer object is needed, and one will be constructed. */ + PyObject *pretty_printer; }; struct cpstack @@ -190,6 +207,10 @@ static void uninstall_variable (struct varobj *); static struct varobj *create_child (struct varobj *, int, char *); +static struct varobj * +create_child_with_value (struct varobj *parent, int index, const char *name, + struct value *value); + /* Utility routines */ static struct varobj *new_variable (void); @@ -215,6 +236,8 @@ static char *cppop (struct cpstack **pstack); static int install_new_value (struct varobj *var, struct value *value, int initial); +static void install_default_visualizer (struct varobj *var); + /* Language-specific routines. */ static enum varobj_languages variable_language (struct varobj *var); @@ -233,12 +256,16 @@ static char *my_value_of_variable (struct varobj *var, enum varobj_display_formats format); static char *value_get_print_value (struct value *value, - enum varobj_display_formats format); + enum varobj_display_formats format, + PyObject *value_formatter); static int varobj_value_is_changeable_p (struct varobj *var); static int is_root_p (struct varobj *var); +static struct varobj * +varobj_add_child (struct varobj *var, const char *name, struct value *value); + /* C implementation */ static int c_number_of_children (struct varobj *var); @@ -570,6 +597,7 @@ varobj_create (char *objname, } } + install_default_visualizer (var); discard_cleanups (old_chain); return var; } @@ -676,6 +704,33 @@ varobj_delete (struct varobj *var, char ***dellist, int only_children) return delcount; } +/* Convenience function for varobj_set_visualizer. Instantiate a + pretty-printer for a given value. */ +static PyObject * +instantiate_pretty_printer (PyObject *constructor, struct value *value) +{ +#if HAVE_PYTHON + PyObject *val_obj = NULL; + PyObject *printer; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + value = value_copy (value); + } + GDB_PY_HANDLE_EXCEPTION (except); + val_obj = value_to_value_object (value); + + if (! val_obj) + return NULL; + + printer = PyObject_CallFunctionObjArgs (constructor, val_obj, NULL); + Py_DECREF (val_obj); + return printer; +#endif + return NULL; +} + /* Set/Get variable object display format */ enum varobj_display_formats @@ -700,7 +755,8 @@ varobj_set_display_format (struct varobj *var, && var->value && !value_lazy (var->value)) { xfree (var->print_value); - var->print_value = value_get_print_value (var->value, var->format); + var->print_value = value_get_print_value (var->value, var->format, + var->pretty_printer); } return var->format; @@ -712,6 +768,21 @@ varobj_get_display_format (struct varobj *var) return var->format; } +char * +varobj_get_display_hint (struct varobj *var) +{ + char *result = NULL; + +#if HAVE_PYTHON + PyGILState_STATE state = PyGILState_Ensure (); + if (var->pretty_printer) + result = gdbpy_get_display_hint (var->pretty_printer); + PyGILState_Release (state); +#endif + + return result; +} + /* If the variable object is bound to a specific thread, that is its evaluation can always be done in context of a frame inside that thread, returns GDB id of the thread -- which @@ -744,12 +815,141 @@ varobj_get_frozen (struct varobj *var) return var->frozen; } +static int +update_dynamic_varobj_children (struct varobj *var, + VEC (varobj_p) **changed, + VEC (varobj_p) **new_and_unchanged, + int *cchanged) + +{ +#if HAVE_PYTHON + /* FIXME: we *might* want to provide this functionality as + a standalone function, so that other interested parties + than varobj code can benefit for this. */ + struct cleanup *back_to; + PyObject *children; + PyObject *iterator; + int i; + int children_changed = 0; + PyObject *printer = var->pretty_printer; + PyGILState_STATE state; + + state = PyGILState_Ensure (); + back_to = make_cleanup_py_restore_gil (&state); + + *cchanged = 0; + if (!PyObject_HasAttr (printer, gdbpy_children_cst)) + { + do_cleanups (back_to); + return 0; + } + + children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst, + NULL); + + if (!children) + { + gdbpy_print_stack (); + error ("Null value returned for children"); + } + + make_cleanup_py_decref (children); + + if (!PyIter_Check (children)) + error ("Returned value is not iterable"); + + iterator = PyObject_GetIter (children); + if (!iterator) + { + gdbpy_print_stack (); + error ("Could not get children iterator"); + } + make_cleanup_py_decref (iterator); + + for (i = 0; ; ++i) + { + PyObject *item = PyIter_Next (iterator); + PyObject *py_v; + struct value *v; + char *name; + struct cleanup *inner; + + if (!item) + break; + inner = make_cleanup_py_decref (item); + + if (!PyArg_ParseTuple (item, "sO", &name, &py_v)) + error ("Invalid item from the child list"); + + if (PyObject_TypeCheck (py_v, &value_object_type)) + { + /* If we just call convert_value_from_python for this type, + we won't know who owns the result. For this one case we + need to copy the resulting value. */ + v = value_object_to_value (py_v); + v = value_copy (v); + } + else + v = convert_value_from_python (py_v); + + /* TODO: This assume the name of the i-th child never changes. */ + + /* Now see what to do here. */ + if (VEC_length (varobj_p, var->children) < i + 1) + { + /* There's no child yet. */ + struct varobj *child = varobj_add_child (var, name, v); + if (new_and_unchanged) + VEC_safe_push (varobj_p, *new_and_unchanged, child); + children_changed = 1; + } + else + { + varobj_p existing = VEC_index (varobj_p, var->children, i); + if (install_new_value (existing, v, 0) && changed) + { + if (changed) + VEC_safe_push (varobj_p, *changed, existing); + } + else + { + if (new_and_unchanged) + VEC_safe_push (varobj_p, *new_and_unchanged, existing); + } + } + + do_cleanups (inner); + } + + if (i < VEC_length (varobj_p, var->children)) + { + int i; + children_changed = 1; + for (i = 0; i < VEC_length (varobj_p, var->children); ++i) + varobj_delete (VEC_index (varobj_p, var->children, i), NULL, 0); + } + VEC_truncate (varobj_p, var->children, i); + var->num_children = VEC_length (varobj_p, var->children); + + do_cleanups (back_to); + + *cchanged = children_changed; + return 1; +#else + gdb_assert (0 && "should never be called if Python is not enabled"); +#endif +} int varobj_get_num_children (struct varobj *var) { if (var->num_children == -1) - var->num_children = number_of_children (var); + { + int changed; + if (!var->pretty_printer + || !update_dynamic_varobj_children (var, NULL, NULL, &changed)) + var->num_children = number_of_children (var); + } return var->num_children; } @@ -762,7 +962,16 @@ varobj_list_children (struct varobj *var) { struct varobj *child; char *name; - int i; + int i, children_changed; + + var->children_requested = 1; + + if (var->pretty_printer + /* This, in theory, can result in the number of children changing without + frontend noticing. But well, calling -var-list-children on the same + varobj twice is not something a sane frontend would do. */ + && update_dynamic_varobj_children (var, NULL, NULL, &children_changed)) + return var->children; if (var->num_children == -1) var->num_children = number_of_children (var); @@ -788,12 +997,24 @@ varobj_list_children (struct varobj *var) name = name_of_child (var, i); existing = create_child (var, i, name); VEC_replace (varobj_p, var->children, i, existing); + install_default_visualizer (existing); } } return var->children; } +static struct varobj * +varobj_add_child (struct varobj *var, const char *name, struct value *value) +{ + varobj_p v = create_child_with_value (var, + VEC_length (varobj_p, var->children), + name, value); + VEC_safe_push (varobj_p, var->children, v); + install_default_visualizer (v); + return v; +} + /* Obtain the type of an object Variable as a string similar to the one gdb prints on the console */ @@ -1003,6 +1224,13 @@ install_new_value (struct varobj *var, struct value *value, int initial) a type. */ gdb_assert (var->type || CPLUS_FAKE_CHILD (var)); changeable = varobj_value_is_changeable_p (var); + + /* If the type has custom visualizer, we consider it to be always + changeable. FIXME: need to make sure this behaviour will not + mess up read-sensitive values. */ + if (var->pretty_printer) + changeable = 1; + need_to_fetch = changeable; /* We are not interested in the address of references, and given @@ -1054,12 +1282,14 @@ install_new_value (struct varobj *var, struct value *value, int initial) } } + /* Below, we'll be comparing string rendering of old and new values. Don't get string rendering if the value is lazy -- if it is, the code above has decided that the value should not be fetched. */ if (value && !value_lazy (value)) - print_value = value_get_print_value (value, var->format); + print_value = value_get_print_value (value, var->format, + var->pretty_printer); /* If the type is changeable, compare the old and the new values. If this is the initial assignment, we don't have any old value @@ -1133,6 +1363,114 @@ install_new_value (struct varobj *var, struct value *value, int initial) return changed; } +static void +install_visualizer (struct varobj *var, PyObject *visualizer) +{ +#if HAVE_PYTHON + /* If there are any children now, wipe them. */ + varobj_delete (var, NULL, 1 /* children only */); + var->num_children = -1; + + Py_XDECREF (var->pretty_printer); + var->pretty_printer = visualizer; + + install_new_value (var, var->value, 1); + + /* If we removed the visualizer, and the user ever requested the + object's children, then we must compute the list of children. + Note that we needn't do this when installing a visualizer, + because updating will recompute dynamic children. */ + if (!visualizer && var->children_requested) + varobj_list_children (var); +#else + error ("Python support required"); +#endif +} + +static void +install_default_visualizer (struct varobj *var) +{ +#if HAVE_PYTHON + struct cleanup *cleanup; + PyGILState_STATE state; + PyObject *pretty_printer = NULL; + + state = PyGILState_Ensure (); + cleanup = make_cleanup_py_restore_gil (&state); + + if (var->value) + { + pretty_printer = gdbpy_get_varobj_pretty_printer (var->value); + if (! pretty_printer) + { + gdbpy_print_stack (); + error (_("Cannot instantiate printer for default visualizer")); + } + } + + if (pretty_printer == Py_None) + { + Py_DECREF (pretty_printer); + pretty_printer = NULL; + } + + install_visualizer (var, pretty_printer); + do_cleanups (cleanup); +#else + /* No error is right as this function is inserted just as a hook. */ +#endif +} + +void +varobj_set_visualizer (struct varobj *var, const char *visualizer) +{ +#if HAVE_PYTHON + PyObject *mainmod, *globals, *pretty_printer, *constructor; + struct cleanup *back_to, *value; + PyGILState_STATE state; + + + state = PyGILState_Ensure (); + back_to = make_cleanup_py_restore_gil (&state); + + mainmod = PyImport_AddModule ("__main__"); + globals = PyModule_GetDict (mainmod); + Py_INCREF (globals); + make_cleanup_py_decref (globals); + + constructor = PyRun_String (visualizer, Py_eval_input, globals, globals); + + /* Do not instantiate NoneType. */ + if (constructor == Py_None) + { + pretty_printer = Py_None; + Py_INCREF (pretty_printer); + } + else + pretty_printer = instantiate_pretty_printer (constructor, var->value); + + Py_XDECREF (constructor); + + if (! pretty_printer) + { + gdbpy_print_stack (); + error ("Could not evaluate visualizer expression: %s", visualizer); + } + + if (pretty_printer == Py_None) + { + Py_DECREF (pretty_printer); + pretty_printer = NULL; + } + + install_visualizer (var, pretty_printer); + + do_cleanups (back_to); +#else + error ("Python support required"); +#endif +} + /* Update the values for a variable and its children. This is a two-pronged attack. First, re-parse the value for the root's expression to see if it's changed. Then go all the way @@ -1158,7 +1496,7 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit) struct varobj **cv; struct varobj **templist = NULL; struct value *new; - VEC (varobj_p) *stack = NULL; + VEC (varobj_update_result) *stack = NULL; VEC (varobj_update_result) *result = NULL; struct frame_info *fi; @@ -1197,20 +1535,85 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit) if (new == NULL) r.status = VAROBJ_NOT_IN_SCOPE; - - if (r.type_changed || r.changed) - VEC_safe_push (varobj_update_result, result, &r); + r.value_installed = 1; if (r.status == VAROBJ_NOT_IN_SCOPE) - return result; + { + VEC_safe_push (varobj_update_result, result, &r); + return result; + } + + VEC_safe_push (varobj_update_result, stack, &r); + } + else + { + varobj_update_result r = {*varp}; + VEC_safe_push (varobj_update_result, stack, &r); } - - VEC_safe_push (varobj_p, stack, *varp); /* Walk through the children, reconstructing them all. */ - while (!VEC_empty (varobj_p, stack)) + while (!VEC_empty (varobj_update_result, stack)) { - v = VEC_pop (varobj_p, stack); + varobj_update_result r = *(VEC_last (varobj_update_result, stack)); + struct varobj *v = r.varobj; + + VEC_pop (varobj_update_result, stack); + + /* Update this variable, unless it's a root, which is already + updated. */ + if (!r.value_installed) + { + new = value_of_child (v->parent, v->index); + if (install_new_value (v, new, 0 /* type not changed */)) + { + r.changed = 1; + v->updated = 0; + } + } + + /* We probably should not get children of a varobj that has a + pretty-printer, but for which -var-list-children was never + invoked. Presumably, such varobj is not yet expanded in the + UI, so we need not bother getting it. */ + if (v->pretty_printer) + { + VEC (varobj_p) *changed = 0, *new_and_unchanged = 0; + int i, children_changed; + varobj_p tmp; + + if (!v->children_requested) + continue; + + if (v->frozen) + continue; + + /* If update_dynamic_varobj_children returns 0, then we have + a non-conforming pretty-printer, so we skip it. */ + if (update_dynamic_varobj_children (v, &changed, &new_and_unchanged, + &children_changed)) + { + if (children_changed) + r.children_changed = 1; + for (i = 0; VEC_iterate (varobj_p, changed, i, tmp); ++i) + { + varobj_update_result r = {tmp}; + r.changed = 1; + r.value_installed = 1; + VEC_safe_push (varobj_update_result, stack, &r); + } + for (i = 0; + VEC_iterate (varobj_p, new_and_unchanged, i, tmp); + ++i) + { + varobj_update_result r = {tmp}; + r.value_installed = 1; + VEC_safe_push (varobj_update_result, stack, &r); + } + if (r.changed || r.children_changed) + VEC_safe_push (varobj_update_result, result, &r); + continue; + } + } /* Push any children. Use reverse order so that the first child is popped from the work stack first, and so @@ -1221,26 +1624,18 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit) varobj_p c = VEC_index (varobj_p, v->children, i); /* Child may be NULL if explicitly deleted by -var-delete. */ if (c != NULL && !c->frozen) - VEC_safe_push (varobj_p, stack, c); - } - - /* Update this variable, unless it's a root, which is already - updated. */ - if (v->root->rootvar != v) - { - new = value_of_child (v->parent, v->index); - if (install_new_value (v, new, 0 /* type not changed */)) { - /* Note that it's changed */ - varobj_update_result r = {v}; - r.changed = 1; - VEC_safe_push (varobj_update_result, result, &r); - v->updated = 0; + varobj_update_result r = {c}; + VEC_safe_push (varobj_update_result, stack, &r); } } + + if (r.changed || r.type_changed) + VEC_safe_push (varobj_update_result, result, &r); } - VEC_free (varobj_p, stack); + VEC_free (varobj_update_result, stack); + return result; } @@ -1439,16 +1834,23 @@ uninstall_variable (struct varobj *var) static struct varobj * create_child (struct varobj *parent, int index, char *name) { + return create_child_with_value (parent, index, name, + value_of_child (parent, index)); +} + +static struct varobj * +create_child_with_value (struct varobj *parent, int index, const char *name, + struct value *value) +{ struct varobj *child; char *childs_name; - struct value *value; child = new_variable (); /* name is allocated by name_of_child */ - child->name = name; + /* FIXME: xstrdup should not be here. */ + child->name = xstrdup (name); child->index = index; - value = value_of_child (parent, index); child->parent = parent; child->root = parent->root; childs_name = xstrprintf ("%s.%s", parent->obj_name, name); @@ -1497,6 +1899,8 @@ new_variable (void) var->print_value = NULL; var->frozen = 0; var->not_fetched = 0; + var->children_requested = 0; + var->pretty_printer = 0; return var; } @@ -1531,6 +1935,14 @@ free_variable (struct varobj *var) xfree (var->root); } +#if HAVE_PYTHON + { + PyGILState_STATE state = PyGILState_Ensure (); + Py_XDECREF (var->pretty_printer); + PyGILState_Release (state); + } +#endif + xfree (var->name); xfree (var->obj_name); xfree (var->print_value); @@ -1804,23 +2216,65 @@ my_value_of_variable (struct varobj *var, enum varobj_display_formats format) } static char * -value_get_print_value (struct value *value, enum varobj_display_formats format) +value_get_print_value (struct value *value, enum varobj_display_formats format, + PyObject *value_formatter) { long dummy; struct ui_file *stb; struct cleanup *old_chain; - char *thevalue; + char *thevalue = NULL; struct value_print_options opts; if (value == NULL) return NULL; +#if HAVE_PYTHON + { + PyGILState_STATE state = PyGILState_Ensure (); + if (value_formatter && PyObject_HasAttr (value_formatter, + gdbpy_to_string_cst)) + { + char *hint; + struct value *replacement; + int string_print = 0; + + hint = gdbpy_get_display_hint (value_formatter); + if (hint) + { + if (!strcmp (hint, "string")) + string_print = 1; + xfree (hint); + } + + thevalue = apply_varobj_pretty_printer (value_formatter, + &replacement); + if (thevalue && !string_print) + { + PyGILState_Release (state); + return thevalue; + } + if (replacement) + value = replacement; + } + PyGILState_Release (state); + } +#endif + stb = mem_fileopen (); old_chain = make_cleanup_ui_file_delete (stb); get_formatted_print_options (&opts, format_code[(int) format]); opts.deref_ref = 0; - common_val_print (value, stb, 0, &opts, current_language); + opts.raw = 1; + if (thevalue) + { + make_cleanup (xfree, thevalue); + LA_PRINT_STRING (stb, builtin_type (current_gdbarch)->builtin_char, + (gdb_byte *) thevalue, strlen (thevalue), + 0, &opts); + } + else + common_val_print (value, stb, 0, &opts, current_language); thevalue = ui_file_xstrdup (stb, &dummy); do_cleanups (old_chain); @@ -1911,7 +2365,7 @@ varobj_floating_p (struct varobj *var) value is not known. If WAS_PTR is not NULL, set *WAS_PTR to 0 or 1 - depending on whether pointer was deferenced + depending on whether pointer was dereferenced in this function. */ static void adjust_value_for_child_access (struct value **value, @@ -2277,6 +2731,11 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format) catch that case explicitly. */ struct type *type = get_type (var); + /* If we have a custom formatter, return whatever string it has + produced. */ + if (var->pretty_printer && var->print_value) + return xstrdup (var->print_value); + /* Strip top-level references. */ while (TYPE_CODE (type) == TYPE_CODE_REF) type = check_typedef (TYPE_TARGET_TYPE (type)); @@ -2321,7 +2780,8 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format) if (format == var->format) return xstrdup (var->print_value); else - return value_get_print_value (var->value, format); + return value_get_print_value (var->value, format, + var->pretty_printer); } } } |