X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fmi%2Fmi-cmd-var.c;h=f5219e0f9b2861ee1a646b978aece30fd4e8fb81;hb=381befeedf9316991d47f4213850545a96593d23;hp=37c87ff1da3ffa859896dfdd7c5c44b1ea229a3d;hpb=76bd6e0b6e6079d4da328e7fc8eec3897703b4af;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c index 37c87ff1da..f5219e0f9b 100644 --- a/gdb/mi/mi-cmd-var.c +++ b/gdb/mi/mi-cmd-var.c @@ -1,6 +1,5 @@ /* MI Command Set - varobj commands. - - Copyright (C) 2000, 2002, 2004, 2005, 2007 Free Software Foundation, Inc. + Copyright (C) 2000-2019 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). @@ -8,7 +7,7 @@ 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 2 of the License, or + 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, @@ -17,97 +16,105 @@ 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "mi-cmds.h" +#include "mi-main.h" #include "ui-out.h" #include "mi-out.h" #include "varobj.h" +#include "language.h" #include "value.h" #include -#include "gdb_string.h" - -const char mi_no_values[] = "--no-values"; -const char mi_simple_values[] = "--simple-values"; -const char mi_all_values[] = "--all-values"; +#include "mi-getopt.h" +#include "gdbthread.h" +#include "mi-parse.h" +#include "gdbsupport/gdb_optional.h" +#include "inferior.h" -extern int varobjdebug; /* defined in varobj.c. */ +extern unsigned int varobjdebug; /* defined in varobj.c. */ static void varobj_update_one (struct varobj *var, - enum print_values print_values, - int explicit); + enum print_values print_values, + bool is_explicit); -static int mi_print_value_p (struct type *type, enum print_values print_values); +static int mi_print_value_p (struct varobj *var, + enum print_values print_values); /* Print variable object VAR. The PRINT_VALUES parameter controls if the value should be printed. The PRINT_EXPRESSION parameter controls if the expression should be printed. */ + static void print_varobj (struct varobj *var, enum print_values print_values, int print_expression) { - char *type; + struct ui_out *uiout = current_uiout; + int thread_id; - ui_out_field_string (uiout, "name", varobj_get_objname (var)); + uiout->field_string ("name", varobj_get_objname (var)); if (print_expression) - ui_out_field_string (uiout, "exp", varobj_get_expression (var)); - ui_out_field_int (uiout, "numchild", varobj_get_num_children (var)); - - if (mi_print_value_p (varobj_get_gdb_type (var), print_values)) - ui_out_field_string (uiout, "value", varobj_get_value (var)); + { + std::string exp = varobj_get_expression (var); - type = varobj_get_type (var); - if (type != NULL) + uiout->field_string ("exp", exp.c_str ()); + } + uiout->field_signed ("numchild", varobj_get_num_children (var)); + + if (mi_print_value_p (var, print_values)) { - ui_out_field_string (uiout, "type", type); - xfree (type); + std::string val = varobj_get_value (var); + + uiout->field_string ("value", val.c_str ()); } + std::string type = varobj_get_type (var); + if (!type.empty ()) + uiout->field_string ("type", type.c_str ()); + + thread_id = varobj_get_thread_id (var); + if (thread_id > 0) + uiout->field_signed ("thread-id", thread_id); + if (varobj_get_frozen (var)) - ui_out_field_int (uiout, "frozen", 1); + uiout->field_signed ("frozen", 1); + + gdb::unique_xmalloc_ptr display_hint = varobj_get_display_hint (var); + if (display_hint) + uiout->field_string ("displayhint", display_hint.get ()); + + if (varobj_is_dynamic_p (var)) + uiout->field_signed ("dynamic", 1); } /* VAROBJ operations */ -enum mi_cmd_result -mi_cmd_var_create (char *command, char **argv, int argc) +void +mi_cmd_var_create (const char *command, char **argv, int argc) { + struct ui_out *uiout = current_uiout; CORE_ADDR frameaddr = 0; struct varobj *var; - char *name; char *frame; char *expr; - struct cleanup *old_cleanups; enum varobj_type var_type; if (argc != 3) - { - /* mi_error_message = xstrprintf ("mi_cmd_var_create: Usage: - ...."); return MI_CMD_ERROR; */ - error (_("mi_cmd_var_create: Usage: NAME FRAME EXPRESSION.")); - } + error (_("-var-create: Usage: NAME FRAME EXPRESSION.")); - name = xstrdup (argv[0]); - /* Add cleanup for name. Must be free_current_contents as - name can be reallocated */ - old_cleanups = make_cleanup (free_current_contents, &name); - - frame = xstrdup (argv[1]); - make_cleanup (xfree, frame); - - expr = xstrdup (argv[2]); - make_cleanup (xfree, expr); + frame = argv[1]; + expr = argv[2]; + const char *name = argv[0]; + std::string gen_name; if (strcmp (name, "-") == 0) { - xfree (name); - name = varobj_gen_name (); + gen_name = varobj_gen_name (); + name = gen_name.c_str (); } - else if (!isalpha (*name)) - error (_("mi_cmd_var_create: name of object must begin with a letter")); + else if (!isalpha (name[0])) + error (_("-var-create: name of object must begin with a letter")); if (strcmp (frame, "*") == 0) var_type = USE_CURRENT_FRAME; @@ -121,214 +128,201 @@ mi_cmd_var_create (char *command, char **argv, int argc) if (varobjdebug) fprintf_unfiltered (gdb_stdlog, - "Name=\"%s\", Frame=\"%s\" (0x%s), Expression=\"%s\"\n", - name, frame, paddr (frameaddr), expr); + "Name=\"%s\", Frame=\"%s\" (%s), Expression=\"%s\"\n", + name, frame, hex_string (frameaddr), expr); var = varobj_create (name, expr, frameaddr, var_type); if (var == NULL) - error (_("mi_cmd_var_create: unable to create variable object")); + error (_("-var-create: unable to create variable object")); print_varobj (var, PRINT_ALL_VALUES, 0 /* don't print expression */); - do_cleanups (old_cleanups); - return MI_CMD_DONE; + uiout->field_signed ("has_more", varobj_has_more (var, 0)); } -enum mi_cmd_result -mi_cmd_var_delete (char *command, char **argv, int argc) +void +mi_cmd_var_delete (const char *command, char **argv, int argc) { char *name; struct varobj *var; int numdel; int children_only_p = 0; - struct cleanup *old_cleanups; + struct ui_out *uiout = current_uiout; if (argc < 1 || argc > 2) - error (_("mi_cmd_var_delete: Usage: [-c] EXPRESSION.")); + error (_("-var-delete: Usage: [-c] EXPRESSION.")); - name = xstrdup (argv[0]); - /* Add cleanup for name. Must be free_current_contents as - name can be reallocated */ - old_cleanups = make_cleanup (free_current_contents, &name); + name = argv[0]; /* If we have one single argument it cannot be '-c' or any string - starting with '-'. */ + starting with '-'. */ if (argc == 1) { if (strcmp (name, "-c") == 0) - error (_("mi_cmd_var_delete: Missing required argument after '-c': variable object name")); + error (_("-var-delete: Missing required " + "argument after '-c': variable object name")); if (*name == '-') - error (_("mi_cmd_var_delete: Illegal variable object name")); + error (_("-var-delete: Illegal variable object name")); } /* If we have 2 arguments they must be '-c' followed by a string - which would be the variable name. */ + which would be the variable name. */ if (argc == 2) { if (strcmp (name, "-c") != 0) - error (_("mi_cmd_var_delete: Invalid option.")); + error (_("-var-delete: Invalid option.")); children_only_p = 1; - do_cleanups (old_cleanups); - name = xstrdup (argv[1]); - make_cleanup (free_current_contents, &name); + name = argv[1]; } /* If we didn't error out, now NAME contains the name of the - variable. */ + variable. */ var = varobj_get_handle (name); - if (var == NULL) - error (_("mi_cmd_var_delete: Variable object not found.")); + numdel = varobj_delete (var, children_only_p); - numdel = varobj_delete (var, NULL, children_only_p); + uiout->field_signed ("ndeleted", numdel); +} + +/* Parse a string argument into a format value. */ - ui_out_field_int (uiout, "ndeleted", numdel); +static enum varobj_display_formats +mi_parse_format (const char *arg) +{ + if (arg != NULL) + { + int len; + + len = strlen (arg); + + if (strncmp (arg, "natural", len) == 0) + return FORMAT_NATURAL; + else if (strncmp (arg, "binary", len) == 0) + return FORMAT_BINARY; + else if (strncmp (arg, "decimal", len) == 0) + return FORMAT_DECIMAL; + else if (strncmp (arg, "hexadecimal", len) == 0) + return FORMAT_HEXADECIMAL; + else if (strncmp (arg, "octal", len) == 0) + return FORMAT_OCTAL; + else if (strncmp (arg, "zero-hexadecimal", len) == 0) + return FORMAT_ZHEXADECIMAL; + } - do_cleanups (old_cleanups); - return MI_CMD_DONE; + error (_("Must specify the format as: \"natural\", " + "\"binary\", \"decimal\", \"hexadecimal\", \"octal\" or \"zero-hexadecimal\"")); } -enum mi_cmd_result -mi_cmd_var_set_format (char *command, char **argv, int argc) +void +mi_cmd_var_set_format (const char *command, char **argv, int argc) { enum varobj_display_formats format; - int len; struct varobj *var; - char *formspec; + struct ui_out *uiout = current_uiout; if (argc != 2) - error (_("mi_cmd_var_set_format: Usage: NAME FORMAT.")); + error (_("-var-set-format: Usage: NAME FORMAT.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); - if (var == NULL) - error (_("mi_cmd_var_set_format: Variable object not found")); - - formspec = xstrdup (argv[1]); - if (formspec == NULL) - error (_("mi_cmd_var_set_format: Must specify the format as: \"natural\", \"binary\", \"decimal\", \"hexadecimal\", or \"octal\"")); - - len = strlen (formspec); - - if (strncmp (formspec, "natural", len) == 0) - format = FORMAT_NATURAL; - else if (strncmp (formspec, "binary", len) == 0) - format = FORMAT_BINARY; - else if (strncmp (formspec, "decimal", len) == 0) - format = FORMAT_DECIMAL; - else if (strncmp (formspec, "hexadecimal", len) == 0) - format = FORMAT_HEXADECIMAL; - else if (strncmp (formspec, "octal", len) == 0) - format = FORMAT_OCTAL; - else - error (_("mi_cmd_var_set_format: Unknown display format: must be: \"natural\", \"binary\", \"decimal\", \"hexadecimal\", or \"octal\"")); - - /* Set the format of VAR to given format */ + format = mi_parse_format (argv[1]); + + /* Set the format of VAR to the given format. */ varobj_set_display_format (var, format); - /* Report the new current format */ - ui_out_field_string (uiout, "format", varobj_format_string[(int) format]); - return MI_CMD_DONE; + /* Report the new current format. */ + uiout->field_string ("format", varobj_format_string[(int) format]); + + /* Report the value in the new format. */ + std::string val = varobj_get_value (var); + uiout->field_string ("value", val.c_str ()); } -enum mi_cmd_result -mi_cmd_var_set_frozen (char *command, char **argv, int argc) +void +mi_cmd_var_set_visualizer (const char *command, char **argv, int argc) { struct varobj *var; - int frozen; if (argc != 2) - error (_("-var-set-format: Usage: NAME FROZEN_FLAG.")); + error (_("Usage: NAME VISUALIZER_FUNCTION.")); var = varobj_get_handle (argv[0]); + if (var == NULL) error (_("Variable object not found")); + varobj_set_visualizer (var, argv[1]); +} + +void +mi_cmd_var_set_frozen (const char *command, char **argv, int argc) +{ + struct varobj *var; + bool frozen; + + if (argc != 2) + error (_("-var-set-format: Usage: NAME FROZEN_FLAG.")); + + var = varobj_get_handle (argv[0]); + if (strcmp (argv[1], "0") == 0) - frozen = 0; + frozen = false; else if (strcmp (argv[1], "1") == 0) - frozen = 1; + frozen = true; else error (_("Invalid flag value")); varobj_set_frozen (var, frozen); - /* We don't automatically return the new value, or what varobjs got new - values during unfreezing. If this information is required, client - should call -var-update explicitly. */ - return MI_CMD_DONE; + /* We don't automatically return the new value, or what varobjs got + new values during unfreezing. If this information is required, + client should call -var-update explicitly. */ } - -enum mi_cmd_result -mi_cmd_var_show_format (char *command, char **argv, int argc) +void +mi_cmd_var_show_format (const char *command, char **argv, int argc) { + struct ui_out *uiout = current_uiout; enum varobj_display_formats format; struct varobj *var; if (argc != 1) - error (_("mi_cmd_var_show_format: Usage: NAME.")); + error (_("-var-show-format: Usage: NAME.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); - if (var == NULL) - error (_("mi_cmd_var_show_format: Variable object not found")); format = varobj_get_display_format (var); - /* Report the current format */ - ui_out_field_string (uiout, "format", varobj_format_string[(int) format]); - return MI_CMD_DONE; + /* Report the current format. */ + uiout->field_string ("format", varobj_format_string[(int) format]); } -enum mi_cmd_result -mi_cmd_var_info_num_children (char *command, char **argv, int argc) +void +mi_cmd_var_info_num_children (const char *command, char **argv, int argc) { + struct ui_out *uiout = current_uiout; struct varobj *var; if (argc != 1) - error (_("mi_cmd_var_info_num_children: Usage: NAME.")); + error (_("-var-info-num-children: Usage: NAME.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); - if (var == NULL) - error (_("mi_cmd_var_info_num_children: Variable object not found")); - ui_out_field_int (uiout, "numchild", varobj_get_num_children (var)); - return MI_CMD_DONE; -} - -/* Parse a string argument into a print_values value. */ - -static enum print_values -mi_parse_values_option (const char *arg) -{ - if (strcmp (arg, "0") == 0 - || strcmp (arg, mi_no_values) == 0) - return PRINT_NO_VALUES; - else if (strcmp (arg, "1") == 0 - || strcmp (arg, mi_all_values) == 0) - return PRINT_ALL_VALUES; - else if (strcmp (arg, "2") == 0 - || strcmp (arg, mi_simple_values) == 0) - return PRINT_SIMPLE_VALUES; - else - error (_("Unknown value for PRINT_VALUES\n\ -Must be: 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""), - mi_no_values, mi_simple_values, mi_all_values); + uiout->field_signed ("numchild", varobj_get_num_children (var)); } /* Return 1 if given the argument PRINT_VALUES we should display - a value of type TYPE. */ + the varobj VAR. */ static int -mi_print_value_p (struct type *type, enum print_values print_values) +mi_print_value_p (struct varobj *var, enum print_values print_values) { - if (type != NULL) - type = check_typedef (type); + struct type *type; if (print_values == PRINT_NO_VALUES) return 0; @@ -336,118 +330,155 @@ mi_print_value_p (struct type *type, enum print_values print_values) if (print_values == PRINT_ALL_VALUES) return 1; - /* For PRINT_SIMPLE_VALUES, only print the value if it has a type - and that type is not a compound type. */ + if (varobj_is_dynamic_p (var)) + return 1; + + type = varobj_get_gdb_type (var); + if (type == NULL) + return 1; + else + { + type = check_typedef (type); - return (TYPE_CODE (type) != TYPE_CODE_ARRAY - && TYPE_CODE (type) != TYPE_CODE_STRUCT - && TYPE_CODE (type) != TYPE_CODE_UNION); + /* For PRINT_SIMPLE_VALUES, only print the value if it has a type + and that type is not a compound type. */ + return (TYPE_CODE (type) != TYPE_CODE_ARRAY + && TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION); + } } -enum mi_cmd_result -mi_cmd_var_list_children (char *command, char **argv, int argc) +void +mi_cmd_var_list_children (const char *command, char **argv, int argc) { - struct varobj *var; - struct varobj **childlist; - struct varobj **cc; - struct cleanup *cleanup_children; - int numchild; + struct ui_out *uiout = current_uiout; + struct varobj *var; enum print_values print_values; + int from, to; - if (argc != 1 && argc != 2) - error (_("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME")); + if (argc < 1 || argc > 4) + error (_("-var-list-children: Usage: " + "[PRINT_VALUES] NAME [FROM TO]")); - /* Get varobj handle, if a valid var obj name was specified */ - if (argc == 1) + /* Get varobj handle, if a valid var obj name was specified. */ + if (argc == 1 || argc == 3) var = varobj_get_handle (argv[0]); else var = varobj_get_handle (argv[1]); - if (var == NULL) - error (_("Variable object not found")); - numchild = varobj_list_children (var, &childlist); - ui_out_field_int (uiout, "numchild", numchild); - if (argc == 2) - print_values = mi_parse_values_option (argv[0]); + if (argc > 2) + { + from = atoi (argv[argc - 2]); + to = atoi (argv[argc - 1]); + } else - print_values = PRINT_NO_VALUES; - - if (numchild <= 0) { - xfree (childlist); - return MI_CMD_DONE; + from = -1; + to = -1; } - if (mi_version (uiout) == 1) - cleanup_children = make_cleanup_ui_out_tuple_begin_end (uiout, "children"); + const std::vector &children + = varobj_list_children (var, &from, &to); + + uiout->field_signed ("numchild", to - from); + if (argc == 2 || argc == 4) + print_values = mi_parse_print_values (argv[0]); else - cleanup_children = make_cleanup_ui_out_list_begin_end (uiout, "children"); - cc = childlist; - while (*cc != NULL) + print_values = PRINT_NO_VALUES; + + gdb::unique_xmalloc_ptr display_hint = varobj_get_display_hint (var); + if (display_hint) + uiout->field_string ("displayhint", display_hint.get ()); + + if (from < to) { - struct cleanup *cleanup_child; - cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, "child"); - print_varobj (*cc, print_values, 1 /* print expression */); - cc++; - do_cleanups (cleanup_child); + /* For historical reasons this might emit a list or a tuple, so + we construct one or the other. */ + gdb::optional tuple_emitter; + gdb::optional list_emitter; + + if (mi_version (uiout) == 1) + tuple_emitter.emplace (uiout, "children"); + else + list_emitter.emplace (uiout, "children"); + for (int ix = from; ix < to && ix < children.size (); ix++) + { + ui_out_emit_tuple child_emitter (uiout, "child"); + + print_varobj (children[ix], print_values, 1 /* print expression */); + } } - do_cleanups (cleanup_children); - xfree (childlist); - return MI_CMD_DONE; + + uiout->field_signed ("has_more", varobj_has_more (var, to)); } -enum mi_cmd_result -mi_cmd_var_info_type (char *command, char **argv, int argc) +void +mi_cmd_var_info_type (const char *command, char **argv, int argc) { + struct ui_out *uiout = current_uiout; struct varobj *var; if (argc != 1) - error (_("mi_cmd_var_info_type: Usage: NAME.")); + error (_("-var-info-type: Usage: NAME.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); - if (var == NULL) - error (_("mi_cmd_var_info_type: Variable object not found")); - ui_out_field_string (uiout, "type", varobj_get_type (var)); - return MI_CMD_DONE; + std::string type_name = varobj_get_type (var); + uiout->field_string ("type", type_name.c_str ()); } -enum mi_cmd_result -mi_cmd_var_info_expression (char *command, char **argv, int argc) +void +mi_cmd_var_info_path_expression (const char *command, char **argv, int argc) { - enum varobj_languages lang; + struct ui_out *uiout = current_uiout; struct varobj *var; if (argc != 1) - error (_("mi_cmd_var_info_expression: Usage: NAME.")); + error (_("Usage: NAME.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ + var = varobj_get_handle (argv[0]); + + const char *path_expr = varobj_get_path_expr (var); + + uiout->field_string ("path_expr", path_expr); +} + +void +mi_cmd_var_info_expression (const char *command, char **argv, int argc) +{ + struct ui_out *uiout = current_uiout; + const struct language_defn *lang; + struct varobj *var; + + if (argc != 1) + error (_("-var-info-expression: Usage: NAME.")); + + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); - if (var == NULL) - error (_("mi_cmd_var_info_expression: Variable object not found")); lang = varobj_get_language (var); - ui_out_field_string (uiout, "lang", varobj_language_string[(int) lang]); - ui_out_field_string (uiout, "exp", varobj_get_expression (var)); - return MI_CMD_DONE; + uiout->field_string ("lang", lang->la_natural_name); + + std::string exp = varobj_get_expression (var); + uiout->field_string ("exp", exp.c_str ()); } -enum mi_cmd_result -mi_cmd_var_show_attributes (char *command, char **argv, int argc) +void +mi_cmd_var_show_attributes (const char *command, char **argv, int argc) { + struct ui_out *uiout = current_uiout; int attr; - char *attstr; + const char *attstr; struct varobj *var; if (argc != 1) - error (_("mi_cmd_var_show_attributes: Usage: NAME.")); + error (_("-var-show-attributes: Usage: NAME.")); /* Get varobj handle, if a valid var obj name was specified */ var = varobj_get_handle (argv[0]); - if (var == NULL) - error (_("mi_cmd_var_show_attributes: Variable object not found")); attr = varobj_get_attributes (var); /* FIXME: define masks for attributes */ @@ -456,178 +487,299 @@ mi_cmd_var_show_attributes (char *command, char **argv, int argc) else attstr = "noneditable"; - ui_out_field_string (uiout, "attr", attstr); - return MI_CMD_DONE; + uiout->field_string ("attr", attstr); } -enum mi_cmd_result -mi_cmd_var_evaluate_expression (char *command, char **argv, int argc) +void +mi_cmd_var_evaluate_expression (const char *command, char **argv, int argc) { + struct ui_out *uiout = current_uiout; struct varobj *var; - if (argc != 1) - error (_("mi_cmd_var_evaluate_expression: Usage: NAME.")); + enum varobj_display_formats format; + int formatFound; + int oind; + char *oarg; + + enum opt + { + OP_FORMAT + }; + static const struct mi_opt opts[] = + { + {"f", OP_FORMAT, 1}, + { 0, 0, 0 } + }; + + /* Parse arguments. */ + format = FORMAT_NATURAL; + formatFound = 0; + oind = 0; + while (1) + { + int opt = mi_getopt ("-var-evaluate-expression", argc, argv, + opts, &oind, &oarg); - /* Get varobj handle, if a valid var obj name was specified */ - var = varobj_get_handle (argv[0]); - if (var == NULL) - error (_("mi_cmd_var_evaluate_expression: Variable object not found")); + if (opt < 0) + break; + switch ((enum opt) opt) + { + case OP_FORMAT: + if (formatFound) + error (_("Cannot specify format more than once")); + + format = mi_parse_format (oarg); + formatFound = 1; + break; + } + } + + if (oind >= argc) + error (_("Usage: [-f FORMAT] NAME")); + + if (oind < argc - 1) + error (_("Garbage at end of command")); + + /* Get varobj handle, if a valid var obj name was specified. */ + var = varobj_get_handle (argv[oind]); + + if (formatFound) + { + std::string val = varobj_get_formatted_value (var, format); - ui_out_field_string (uiout, "value", varobj_get_value (var)); - return MI_CMD_DONE; + uiout->field_string ("value", val.c_str ()); + } + else + { + std::string val = varobj_get_value (var); + + uiout->field_string ("value", val.c_str ()); + } } -enum mi_cmd_result -mi_cmd_var_assign (char *command, char **argv, int argc) +void +mi_cmd_var_assign (const char *command, char **argv, int argc) { + struct ui_out *uiout = current_uiout; struct varobj *var; - char *expression; if (argc != 2) - error (_("mi_cmd_var_assign: Usage: NAME EXPRESSION.")); + error (_("-var-assign: Usage: NAME EXPRESSION.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); - if (var == NULL) - error (_("mi_cmd_var_assign: Variable object not found")); - /* FIXME: define masks for attributes */ - if (!(varobj_get_attributes (var) & 0x00000001)) - error (_("mi_cmd_var_assign: Variable object is not editable")); + if (!varobj_editable_p (var)) + error (_("-var-assign: Variable object is not editable")); + + const char *expression = argv[1]; - expression = xstrdup (argv[1]); + /* MI command '-var-assign' may write memory, so suppress memory + changed notification if it does. */ + scoped_restore save_suppress + = make_scoped_restore (&mi_suppress_notification.memory, 1); if (!varobj_set_value (var, expression)) - error (_("mi_cmd_var_assign: Could not assign expression to variable object")); + error (_("-var-assign: Could not assign " + "expression to variable object")); - ui_out_field_string (uiout, "value", varobj_get_value (var)); - return MI_CMD_DONE; + std::string val = varobj_get_value (var); + uiout->field_string ("value", val.c_str ()); } -enum mi_cmd_result -mi_cmd_var_update (char *command, char **argv, int argc) +/* Type used for parameters passing to mi_cmd_var_update_iter. */ + +struct mi_cmd_var_update + { + int only_floating; + enum print_values print_values; + }; + +/* Helper for mi_cmd_var_update - update each VAR. */ + +static void +mi_cmd_var_update_iter (struct varobj *var, void *data_pointer) { - struct varobj *var; - struct varobj **rootlist; - struct varobj **cr; - struct cleanup *cleanup; + struct mi_cmd_var_update *data = (struct mi_cmd_var_update *) data_pointer; + bool thread_stopped; + + int thread_id = varobj_get_thread_id (var); + + if (thread_id == -1) + { + thread_stopped = (inferior_ptid == null_ptid + || inferior_thread ()->state == THREAD_STOPPED); + } + else + { + thread_info *tp = find_thread_global_id (thread_id); + + thread_stopped = (tp == NULL + || tp->state == THREAD_STOPPED); + } + + if (thread_stopped + && (!data->only_floating || varobj_floating_p (var))) + varobj_update_one (var, data->print_values, false /* implicit */); +} + +void +mi_cmd_var_update (const char *command, char **argv, int argc) +{ + struct ui_out *uiout = current_uiout; char *name; - int nv; enum print_values print_values; if (argc != 1 && argc != 2) - error (_("mi_cmd_var_update: Usage: [PRINT_VALUES] NAME.")); + error (_("-var-update: Usage: [PRINT_VALUES] NAME.")); if (argc == 1) name = argv[0]; else - name = (argv[1]); + name = argv[1]; if (argc == 2) - print_values = mi_parse_values_option (argv[0]); + print_values = mi_parse_print_values (argv[0]); else print_values = PRINT_NO_VALUES; - /* Check if the parameter is a "*" which means that we want - to update all variables */ + /* For historical reasons this might emit a list or a tuple, so we + construct one or the other. */ + gdb::optional tuple_emitter; + gdb::optional list_emitter; + + if (mi_version (uiout) <= 1) + tuple_emitter.emplace (uiout, "changelist"); + else + list_emitter.emplace (uiout, "changelist"); + + /* Check if the parameter is a "*", which means that we want to + update all variables. */ - if ((*name == '*') && (*(name + 1) == '\0')) + if ((*name == '*' || *name == '@') && (*(name + 1) == '\0')) { - nv = varobj_list (&rootlist); - cleanup = make_cleanup (xfree, rootlist); - if (mi_version (uiout) <= 1) - make_cleanup_ui_out_tuple_begin_end (uiout, "changelist"); - else - make_cleanup_ui_out_list_begin_end (uiout, "changelist"); - if (nv <= 0) - { - do_cleanups (cleanup); - return MI_CMD_DONE; - } - cr = rootlist; - while (*cr != NULL) - { - varobj_update_one (*cr, print_values, 0 /* implicit */); - cr++; - } - do_cleanups (cleanup); + struct mi_cmd_var_update data; + + data.only_floating = (*name == '@'); + data.print_values = print_values; + + /* varobj_update_one automatically updates all the children of + VAROBJ. Therefore update each VAROBJ only once by iterating + only the root VAROBJs. */ + + all_root_varobjs (mi_cmd_var_update_iter, &data); } else { - /* Get varobj handle, if a valid var obj name was specified */ - var = varobj_get_handle (name); - if (var == NULL) - error (_("mi_cmd_var_update: Variable object not found")); + /* Get varobj handle, if a valid var obj name was specified. */ + struct varobj *var = varobj_get_handle (name); - if (mi_version (uiout) <= 1) - cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, "changelist"); - else - cleanup = make_cleanup_ui_out_list_begin_end (uiout, "changelist"); - varobj_update_one (var, print_values, 1 /* explicit */); - do_cleanups (cleanup); + varobj_update_one (var, print_values, true /* explicit */); } - return MI_CMD_DONE; } /* Helper for mi_cmd_var_update(). */ static void varobj_update_one (struct varobj *var, enum print_values print_values, - int explicit) + bool is_explicit) { - struct varobj **changelist; - struct varobj **cc; - struct cleanup *cleanup = NULL; - int nc; + struct ui_out *uiout = current_uiout; - nc = varobj_update (&var, &changelist, explicit); - - /* nc >= 0 represents the number of changes reported into changelist. - nc < 0 means that an error occured or the the variable has - changed type (TYPE_CHANGED). */ + std::vector changes = varobj_update (&var, is_explicit); - if (nc == 0) - return; - else if (nc < 0) + for (const varobj_update_result &r : changes) { + int from, to; + + gdb::optional tuple_emitter; if (mi_version (uiout) > 1) - cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - ui_out_field_string (uiout, "name", varobj_get_objname(var)); + tuple_emitter.emplace (uiout, nullptr); + uiout->field_string ("name", varobj_get_objname (r.varobj)); - switch (nc) - { - case NOT_IN_SCOPE: - ui_out_field_string (uiout, "in_scope", "false"); + switch (r.status) + { + case VAROBJ_IN_SCOPE: + if (mi_print_value_p (r.varobj, print_values)) + { + std::string val = varobj_get_value (r.varobj); + + uiout->field_string ("value", val.c_str ()); + } + uiout->field_string ("in_scope", "true"); break; - case INVALID: - ui_out_field_string (uiout, "in_scope", "invalid"); - break; - case TYPE_CHANGED: - ui_out_field_string (uiout, "in_scope", "true"); - ui_out_field_string (uiout, "new_type", varobj_get_type(var)); - ui_out_field_int (uiout, "new_num_children", - varobj_get_num_children(var)); + case VAROBJ_NOT_IN_SCOPE: + uiout->field_string ("in_scope", "false"); break; - } - if (mi_version (uiout) > 1) - do_cleanups (cleanup); - } - else - { - cc = changelist; - while (*cc != NULL) + case VAROBJ_INVALID: + uiout->field_string ("in_scope", "invalid"); + break; + } + + if (r.status != VAROBJ_INVALID) { - if (mi_version (uiout) > 1) - cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - ui_out_field_string (uiout, "name", varobj_get_objname (*cc)); - if (mi_print_value_p (varobj_get_gdb_type (*cc), print_values)) - ui_out_field_string (uiout, "value", varobj_get_value (*cc)); - ui_out_field_string (uiout, "in_scope", "true"); - ui_out_field_string (uiout, "type_changed", "false"); - if (mi_version (uiout) > 1) - do_cleanups (cleanup); - cc++; + if (r.type_changed) + uiout->field_string ("type_changed", "true"); + else + uiout->field_string ("type_changed", "false"); + } + + if (r.type_changed) + { + std::string type_name = varobj_get_type (r.varobj); + + uiout->field_string ("new_type", type_name.c_str ()); + } + + if (r.type_changed || r.children_changed) + uiout->field_signed ("new_num_children", + varobj_get_num_children (r.varobj)); + + gdb::unique_xmalloc_ptr display_hint + = varobj_get_display_hint (r.varobj); + if (display_hint) + uiout->field_string ("displayhint", display_hint.get ()); + + if (varobj_is_dynamic_p (r.varobj)) + uiout->field_signed ("dynamic", 1); + + varobj_get_child_range (r.varobj, &from, &to); + uiout->field_signed ("has_more", varobj_has_more (r.varobj, to)); + + if (!r.newobj.empty ()) + { + ui_out_emit_list list_emitter (uiout, "new_children"); + + for (varobj *child : r.newobj) + { + ui_out_emit_tuple inner_tuple_emitter (uiout, NULL); + print_varobj (child, print_values, 1 /* print_expression */); + } } - xfree (changelist); } } + +void +mi_cmd_enable_pretty_printing (const char *command, char **argv, int argc) +{ + if (argc != 0) + error (_("-enable-pretty-printing: no arguments allowed")); + + varobj_enable_pretty_printing (); +} + +void +mi_cmd_var_set_update_range (const char *command, char **argv, int argc) +{ + struct varobj *var; + int from, to; + + if (argc != 3) + error (_("-var-set-update-range: Usage: VAROBJ FROM TO")); + + var = varobj_get_handle (argv[0]); + from = atoi (argv[1]); + to = atoi (argv[2]); + + varobj_set_child_range (var, from, to); +}