* [RCF 0/3 V3] MI notification of command parameter change
@ 2012-08-03 11:22 Yao Qi
2012-08-03 11:22 ` [PATCH 1/3] new observer command_param_changed Yao Qi
` (3 more replies)
0 siblings, 4 replies; 15+ messages in thread
From: Yao Qi @ 2012-08-03 11:22 UTC (permalink / raw)
To: gdb-patches
Hi,
This is the V3, and V2 can be found here,
[RCF 0/6 V2] MI notification of command option change
http://sourceware.org/ml/gdb-patches/2012-07/msg00689.html
In this version, GDB will emit MI notification for all 'set'
commands (except 'maint set' commands). The difference of V3
is described in each patch. Code indentatoin patch is not
posted, as I think it is obvious if this series is approved.
Regression tested on x86_64-linux.
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 1/3] new observer command_param_changed. 2012-08-03 11:22 [RCF 0/3 V3] MI notification of command parameter change Yao Qi @ 2012-08-03 11:22 ` Yao Qi 2012-08-03 17:35 ` Tom Tromey 2012-08-03 11:22 ` [PATCH 2/3] attach to command_param_changed observer Yao Qi ` (2 subsequent siblings) 3 siblings, 1 reply; 15+ messages in thread From: Yao Qi @ 2012-08-03 11:22 UTC (permalink / raw) To: gdb-patches Hi, This patch is to teach GDB to check the change of command option, and notify observer. Compared with V2, V3 has following changes, 1. Move notifying 'command_option_changed' observer at the end of do_set_command to make sure the command is correctly executed, 2. Add a field 'prefix' to track the prefix command in order to get the whole command options in multi-word command. 3. Split do_setshow_command to do_set_command and do_show_command. 4. Don't call observer for command of class class_maintenance and class_deprecated. Note that in order to make patch easier to read, the indnetation is not adjusted. Indentation is fixed in a separate patch. gdb: 2012-08-03 Yao Qi <yao@codesourcery.com> * cli/cli-setshow.c (notify_command_param_changed_p): New. (add_setshow_auto_boolean_cmd): Move auto_boolean_enums out. Remove 'static'. (lookup_cmd_for_prefixlist): New. (add_setshow_cmd_full): Set field 'prefix'. * cli/cli-decode.h (struct cmd_list_element) <prefix>: New field. Declare 'auto_boolean_enums'. * cli/cli-setshow.c: Include "observer.h". (do_setshow_command): Split it to ... (do_set_command, do_show_command): ... them. New. (do_set_command): Call observer_notify_command_param_changed if notify_command_param_changed_p returns true. (cmd_show_list): Caller update. * auto-load.c (set_auto_load_cmd): Likewise. * remote.c (show_remote_cmd): Likewise. * cli/cli-setshow.h: Update declarations. * top.c (execute_command): Call do_set_command and do_show_command. gdb/doc: 2012-08-03 Yao Qi <yao@codesourcery.com> * observer.texi: New observer command_param_changed. --- gdb/auto-load.c | 2 +- gdb/cli/cli-decode.c | 51 ++++++++++- gdb/cli/cli-decode.h | 4 + gdb/cli/cli-setshow.c | 260 +++++++++++++++++++++++++++++++++++++++++------- gdb/cli/cli-setshow.h | 10 +- gdb/doc/observer.texi | 8 ++ gdb/remote.c | 2 +- gdb/top.c | 6 +- 8 files changed, 294 insertions(+), 49 deletions(-) diff --git a/gdb/auto-load.c b/gdb/auto-load.c index 2cc52c6..03a7539 100644 --- a/gdb/auto-load.c +++ b/gdb/auto-load.c @@ -1022,7 +1022,7 @@ set_auto_load_cmd (char *args, int from_tty) if (list->var_type == var_boolean) { gdb_assert (list->type == set_cmd); - do_setshow_command (args, from_tty, list); + do_set_command (args, from_tty, list); } } diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index c337b43..a0f1017 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -52,6 +52,32 @@ static struct cmd_list_element *find_cmd (char *command, static void help_all (struct ui_file *stream); +/* Look up a command whose 'prefixlist' is KEY. Return the command if found, + otherwise return NULL. */ + +static struct cmd_list_element * +lookup_cmd_for_prefixlist (struct cmd_list_element **key, + struct cmd_list_element *list) +{ + struct cmd_list_element *p = NULL; + + for (p = list; p != NULL; p = p->next) + { + struct cmd_list_element *q; + + if (p->prefixlist == NULL) + continue; + else if (p->prefixlist == key) + return p; + + q = lookup_cmd_for_prefixlist (key, *(p->prefixlist)); + if (q != NULL) + return q; + } + + return NULL; +} + static void print_help_for_command (struct cmd_list_element *c, char *prefix, int recurse, struct ui_file *stream); @@ -193,6 +219,7 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int), c->prefixlist = NULL; c->prefixname = NULL; c->allow_unknown = 0; + c->prefix = NULL; c->abbrev_flag = 0; set_cmd_completer (c, make_symbol_completion_list_fn); c->destroyer = NULL; @@ -392,6 +419,27 @@ add_setshow_cmd_full (char *name, full_set_doc, set_list); if (set_func != NULL) set_cmd_sfunc (set, set_func); + + + { + struct cmd_list_element *p; + /* Check to see if *SET_LIST contains any element other than SET. */ + for (p = *set_list; p != NULL; p = p->next) + if (p != set) + break; + + if (p == NULL) + { + /* *SET_LIST only contains SET. */ + p = lookup_cmd_for_prefixlist (set_list, setlist); + + set->prefix = p ? (p->cmd_pointer ? p->cmd_pointer : p) : p; + } + else + set->prefix = p->prefix; + } + + show = add_set_or_show_cmd (name, show_cmd, class, var_type, var, full_show_doc, show_list); show->show_value_func = show_func; @@ -430,6 +478,8 @@ add_setshow_enum_cmd (char *name, c->enums = enumlist; } +const char * const auto_boolean_enums[] = { "on", "off", "auto", NULL }; + /* Add an auto-boolean command named NAME to both the set and show command list lists. CLASS is as in add_cmd. VAR is address of the variable which will contain the value. DOC is the documentation @@ -445,7 +495,6 @@ add_setshow_auto_boolean_cmd (char *name, struct cmd_list_element **set_list, struct cmd_list_element **show_list) { - static const char *auto_boolean_enums[] = { "on", "off", "auto", NULL }; struct cmd_list_element *c; add_setshow_cmd_full (name, class, var_auto_boolean, var, diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h index b5e0790..edae6e8 100644 --- a/gdb/cli/cli-decode.h +++ b/gdb/cli/cli-decode.h @@ -149,6 +149,9 @@ struct cmd_list_element recognized; call the prefix's own function in that case. */ char allow_unknown; + /* The prefix command of this command. */ + struct cmd_list_element *prefix; + /* Nonzero says this is an abbreviation, and should not be mentioned in lists of commands. This allows "br<tab>" to complete to "break", which it @@ -232,5 +235,6 @@ extern void not_just_help_class_command (char *arg, int from_tty); extern void print_doc_line (struct ui_file *, char *); +extern const char * const auto_boolean_enums[]; #endif /* !defined (CLI_DECODE_H) */ diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c index 7ffb89e..64a447c 100644 --- a/gdb/cli/cli-setshow.c +++ b/gdb/cli/cli-setshow.c @@ -21,6 +21,7 @@ #include <ctype.h> #include "gdb_string.h" #include "arch-utils.h" +#include "observer.h" #include "ui-out.h" @@ -32,6 +33,20 @@ static int parse_binary_operation (char *); +/* Return true if the change of command parameter should be notified. */ + +static int +notify_command_param_changed_p (int param_changed, struct cmd_list_element *c) +{ + if (param_changed == 0) + return 0; + + if (c->class == class_maintenance || c->class == class_deprecated) + return 0; + + return 1; +} + \f static enum auto_boolean parse_auto_binary_operation (const char *arg) @@ -116,18 +131,19 @@ deprecated_show_value_hack (struct ui_file *ignore_file, } } -/* Do a "set" or "show" command. ARG is NULL if no argument, or the +/* Do a "set" command. ARG is NULL if no argument, or the text of the argument, and FROM_TTY is nonzero if this command is being entered directly by the user (i.e. these are just like any other command). C is the command list element for the command. */ void -do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) +do_set_command (char *arg, int from_tty, struct cmd_list_element *c) { - struct ui_out *uiout = current_uiout; + /* A flag to indicate the option is changed or not. */ + int option_changed = 0; + + gdb_assert (c->type == set_cmd); - if (c->type == set_cmd) - { switch (c->var_type) { case var_string: @@ -170,50 +186,106 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) #endif *q++ = '\0'; new = (char *) xrealloc (new, q - new); - xfree (*(char **) c->var); - *(char **) c->var = new; + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, new) != 0) + { + xfree (*(char **) c->var); + *(char **) c->var = new; + + option_changed = 1; + } + else + xfree (new); } break; case var_string_noescape: if (arg == NULL) arg = ""; - xfree (*(char **) c->var); - *(char **) c->var = xstrdup (arg); + + if (*(char **) c->var == NULL || strcmp (*(char **) c->var, arg) != 0) + { + xfree (*(char **) c->var); + *(char **) c->var = xstrdup (arg); + + option_changed = 1; + } break; case var_filename: if (arg == NULL) error_no_arg (_("filename to set it to.")); /* FALLTHROUGH */ case var_optional_filename: - xfree (*(char **) c->var); + { + char *val = NULL; - if (arg != NULL) - { - /* Clear trailing whitespace of filename. */ - char *ptr = arg + strlen (arg) - 1; + if (arg != NULL) + { + /* Clear trailing whitespace of filename. */ + char *ptr = arg + strlen (arg) - 1; - while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) - ptr--; - *(ptr + 1) = '\0'; + while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) + ptr--; + *(ptr + 1) = '\0'; - *(char **) c->var = tilde_expand (arg); - } - else - *(char **) c->var = xstrdup (""); + val = tilde_expand (arg); + } + else + val = xstrdup (""); + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, val) != 0) + { + xfree (*(char **) c->var); + *(char **) c->var = val; + + option_changed = 1; + } + else + xfree (val); + } break; case var_boolean: - *(int *) c->var = parse_binary_operation (arg); + { + int val = parse_binary_operation (arg); + + if (val != *(int *) c->var) + { + *(int *) c->var = val; + + option_changed = 1; + } + } break; case var_auto_boolean: - *(enum auto_boolean *) c->var = parse_auto_binary_operation (arg); + { + enum auto_boolean val = parse_auto_binary_operation (arg); + + if (*(enum auto_boolean *) c->var != val) + { + *(enum auto_boolean *) c->var = val; + + option_changed = 1; + } + } break; case var_uinteger: case var_zuinteger: if (arg == NULL) error_no_arg (_("integer to set it to.")); - *(unsigned int *) c->var = parse_and_eval_long (arg); - if (c->var_type == var_uinteger && *(unsigned int *) c->var == 0) - *(unsigned int *) c->var = UINT_MAX; + { + unsigned int val = parse_and_eval_long (arg); + + if (c->var_type == var_uinteger && val == 0) + val = UINT_MAX; + + if (*(unsigned int *) c->var != val) + { + *(unsigned int *) c->var = val; + + option_changed = 1; + } + } break; case var_integer: case var_zinteger: @@ -224,11 +296,17 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) error_no_arg (_("integer to set it to.")); val = parse_and_eval_long (arg); if (val == 0 && c->var_type == var_integer) - *(int *) c->var = INT_MAX; + val = INT_MAX; else if (val >= INT_MAX) error (_("integer %u out of range"), val); - else - *(int *) c->var = val; + + + if (*(int *) c->var != val) + { + *(int *) c->var = val; + + option_changed = 1; + } break; } case var_enum: @@ -293,15 +371,124 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) if (nmatches > 1) error (_("Ambiguous item \"%s\"."), arg); - *(const char **) c->var = match; + if (*(const char **) c->var != match) + { + *(const char **) c->var = match; + + option_changed = 1; + } } break; default: error (_("gdb internal error: bad var_type in do_setshow_command")); } - } - else if (c->type == show_cmd) + c->func (c, NULL, from_tty); + if (deprecated_set_hook) + deprecated_set_hook (c); + + if (notify_command_param_changed_p (option_changed, c)) { + char name[64]; + + /* Compute the whole multi-word command options. If user types command + 'set foo bar baz on', c->name is 'baz', and GDB can't pass "bar" to + command option change notification, because it is confusing. We can + trace back through field 'prefix' to compute the whole options, + and pass "foo bar baz" to notification. */ + { + /* Assume that the number of command option is less than 6. */ + struct cmd_list_element *cmds[6]; + struct cmd_list_element *p = c; + int i = 0; + int length = 0; + char *cp; + + /* Track back through filed 'prefix' and cache them in CMDS. */ + do + { + if (p == NULL) + break; + + cmds[i++] = p; + length += strlen (p->name); + length++; + + p = p->prefix; + } + while (i < (sizeof (cmds) / sizeof (struct cmd_list_element *))); + + cp = name; + /* Traverse them in the reversed order, and copy their names into + NAME. */ + for (i--; i >= 0; i--) + { + strcpy (cp, cmds[i]->name); + cp += strlen (cmds[i]->name); + + cp[0] = ' '; + cp++; + } + cp--; + cp[0] = 0; + } + + switch (c->var_type) + { + case var_string: + case var_string_noescape: + case var_filename: + case var_optional_filename: + case var_enum: + observer_notify_command_param_changed (name, *(char **) c->var); + break; + case var_boolean: + { + char *opt = *(int *) c->var ? "on" : "off"; + + observer_notify_command_param_changed (name, opt); + } + break; + case var_auto_boolean: + { + const char *s = auto_boolean_enums[*(enum auto_boolean *) c->var]; + + observer_notify_command_param_changed (name, s); + } + break; + case var_uinteger: + case var_zuinteger: + { + char s[64]; + + xsnprintf (s, sizeof s, "%u", *(unsigned int *) c->var); + observer_notify_command_param_changed (name, s); + } + break; + case var_integer: + case var_zinteger: + { + char s[64]; + + xsnprintf (s, sizeof s, "%d", *(int *) c->var); + observer_notify_command_param_changed (name, s); + } + break; + } + } +} + +/* Do a "show" command. ARG is NULL if no argument, or the + text of the argument, and FROM_TTY is nonzero if this command is + being entered directly by the user (i.e. these are just like any + other command). C is the command list element for the command. */ + +void +do_show_command (char *arg, int from_tty, struct cmd_list_element *c) +{ + struct ui_out *uiout = current_uiout; + + gdb_assert (c->type == show_cmd); + { struct cleanup *old_chain; struct ui_file *stb; @@ -387,12 +574,9 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) deprecated_show_value_hack (gdb_stdout, from_tty, c, value); } do_cleanups (old_chain); - } - else - error (_("gdb internal error: bad cmd_type in do_setshow_command")); + c->func (c, NULL, from_tty); - if (c->type == set_cmd && deprecated_set_hook) - deprecated_set_hook (c); + } } /* Show all the settings in a list of show commands. */ @@ -431,7 +615,7 @@ cmd_show_list (struct cmd_list_element *list, int from_tty, char *prefix) ui_out_field_string (uiout, "name", list->name); ui_out_text (uiout, ": "); if (list->type == show_cmd) - do_setshow_command ((char *) NULL, from_tty, list); + do_show_command ((char *) NULL, from_tty, list); else cmd_func (list, NULL, from_tty); /* Close the tuple. */ diff --git a/gdb/cli/cli-setshow.h b/gdb/cli/cli-setshow.h index cb8d2c5..ffe9abd 100644 --- a/gdb/cli/cli-setshow.h +++ b/gdb/cli/cli-setshow.h @@ -21,12 +21,10 @@ struct cmd_list_element; /* Exported to cli/cli-cmds.c and gdb/top.c */ -/* Do a "set" or "show" command. ARG is NULL if no argument, or the - text of the argument, and FROM_TTY is nonzero if this command is - being entered directly by the user (i.e. these are just like any - other command). C is the command list element for the command. */ -extern void do_setshow_command (char *arg, int from_tty, - struct cmd_list_element *c); +extern void do_set_command (char *arg, int from_tty, + struct cmd_list_element *c); +extern void do_show_command (char *arg, int from_tty, + struct cmd_list_element *c); /* Exported to cli/cli-cmds.c and gdb/top.c, language.c and valprint.c */ diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi index 14d4ac3..bf84820 100644 --- a/gdb/doc/observer.texi +++ b/gdb/doc/observer.texi @@ -234,6 +234,14 @@ the current top-level prompt. Variable gdb_datadir has been set. The value may not necessarily change. @end deftypefun +@deftypefun void command_param_changed (const char *@var{param}, const char *@var{value}) +The parameter of some @code{set} commands in console are changed. This +method is called after a command @code{set @var{param} @var{value}}. +@var{param} is the parameter of @code{set} command, and @var{value} +is the value of changed parameter. + +@end deftypefun + @deftypefun void test_notification (int @var{somearg}) This observer is used for internal testing. Do not use. See testsuite/gdb.gdb/observer.exp. diff --git a/gdb/remote.c b/gdb/remote.c index fa514dc..87b8921 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -11270,7 +11270,7 @@ show_remote_cmd (char *args, int from_tty) ui_out_field_string (uiout, "name", list->name); ui_out_text (uiout, ": "); if (list->type == show_cmd) - do_setshow_command ((char *) NULL, from_tty, list); + do_show_command ((char *) NULL, from_tty, list); else cmd_func (list, NULL, from_tty); /* Close the tuple. */ diff --git a/gdb/top.c b/gdb/top.c index 213c68c..8251d1b 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -474,8 +474,10 @@ execute_command (char *p, int from_tty) /* c->user_commands would be NULL in the case of a python command. */ if (c->class == class_user && c->user_commands) execute_user_command (c, arg); - else if (c->type == set_cmd || c->type == show_cmd) - do_setshow_command (arg, from_tty, c); + else if (c->type == set_cmd) + do_set_command (arg, from_tty, c); + else if (c->type == show_cmd) + do_show_command (arg, from_tty, c); else if (!cmd_func_p (c)) error (_("That is not a command, just a help topic.")); else if (deprecated_call_command_hook) -- 1.7.7.6 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] new observer command_param_changed. 2012-08-03 11:22 ` [PATCH 1/3] new observer command_param_changed Yao Qi @ 2012-08-03 17:35 ` Tom Tromey 2012-08-06 15:44 ` Yao Qi 0 siblings, 1 reply; 15+ messages in thread From: Tom Tromey @ 2012-08-03 17:35 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> +static struct cmd_list_element * Yao> +lookup_cmd_for_prefixlist (struct cmd_list_element **key, Yao> + struct cmd_list_element *list) It seems to me that this function relies on add_prefix_cmd being invoked before any of the sub-commands are added. But, I think this is not guaranteed by gdb's order-agnostic initialization approach. This, IIUC, is why the prefix list variables are global rather than being stored in the prefix command itself. If that is correct, then I think a different approach is needed. Yao> + if (notify_command_param_changed_p (option_changed, c)) Yao> { Yao> + char name[64]; It is better not to have a statically-sized buffer. This can easily be overrun by making new parameters from Python. Yao> + /* Assume that the number of command option is less than 6. */ Yao> + struct cmd_list_element *cmds[6]; Likewise. The rest looks good. Thanks for changing it to report all options. Tom ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] new observer command_param_changed. 2012-08-03 17:35 ` Tom Tromey @ 2012-08-06 15:44 ` Yao Qi 2012-08-06 20:21 ` Tom Tromey 0 siblings, 1 reply; 15+ messages in thread From: Yao Qi @ 2012-08-06 15:44 UTC (permalink / raw) To: gdb-patches; +Cc: Tom Tromey On Friday, August 03, 2012 11:34:55 AM Tom Tromey wrote: > It seems to me that this function relies on add_prefix_cmd being invoked > before any of the sub-commands are added. > > But, I think this is not guaranteed by gdb's order-agnostic > initialization approach. This, IIUC, is why the prefix list variables > are global rather than being stored in the prefix command itself. Yes, I go through the GDB source, and find there are some prefix_cmds are registered later than their sub-commands, maint_cplus_cmd_list unsetlist maintenancelist setlist in printcmd.c cmdpy_init in python/py-cmd.c thread_cmd_list setprintlist although most of prefix_cmds are registered before their sub-commands. > > If that is correct, then I think a different approach is needed. > We can't get correct the chain of 'c->prefix' if the command c is registered before its prefix cmd. However, this problem can be fixed by the following code added in add_prefix_cmd, + /* Update the field 'prefix' of each cmd_list_element in *PREFIXLIST. */ + for (p = *prefixlist; p != NULL; p = p->next) + p->prefix = c; This is the major change in this version. > Yao> + if (notify_command_param_changed_p (option_changed, c)) > Yao> { > Yao> + char name[64]; > > It is better not to have a statically-sized buffer. > This can easily be overrun by making new parameters from Python. > > Yao> + /* Assume that the number of command option is less than 6. */ > Yao> + struct cmd_list_element *cmds[6]; > > Likewise. They are switched to dynamic array. -- Yao (齐尧) gdb: 2012-08-06 Yao Qi <yao@codesourcery.com> * cli/cli-decode.c (set_cmd_prefix): New. (lookup_cmd_for_prefixlist): New. (add_prefix_cmd): Call set_cmd_prefix and update field 'prefix' of each cmd_list_element in *prefixlist. (add_setshow_cmd_full): set_cmd_prefix. (add_alias_cmd): Likewise. * cli/cli-decode.h (struct cmd_list_element) <prefix>: New field. Declare 'auto_boolean_enums'. * cli/cli-setshow.c: Include "observer.h". (notify_command_param_changed_p): New. (add_setshow_auto_boolean_cmd): Move auto_boolean_enums out. Remove 'static'. (do_setshow_command): Split it to ... (do_set_command, do_show_command): ... them. New. (do_set_command): Call observer_notify_command_param_changed if notify_command_param_changed_p returns true. (cmd_show_list): Caller update. * auto-load.c (set_auto_load_cmd): Likewise. * remote.c (show_remote_cmd): Likewise. * cli/cli-setshow.h: Update declarations. * top.c (execute_command): Call do_set_command and do_show_command. gdb/doc: 2012-08-06 Yao Qi <yao@codesourcery.com> * observer.texi: New observer command_param_changed. --- gdb/auto-load.c | 2 +- gdb/cli/cli-decode.c | 67 ++++++++++++- gdb/cli/cli-decode.h | 4 + gdb/cli/cli-setshow.c | 270 ++++++++++++++++++++++++++++++++++++++++++------- gdb/cli/cli-setshow.h | 10 +- gdb/doc/observer.texi | 8 ++ gdb/remote.c | 2 +- gdb/top.c | 6 +- 8 files changed, 320 insertions(+), 49 deletions(-) diff --git a/gdb/auto-load.c b/gdb/auto-load.c index 2cc52c6..03a7539 100644 --- a/gdb/auto-load.c +++ b/gdb/auto-load.c @@ -1022,7 +1022,7 @@ set_auto_load_cmd (char *args, int from_tty) if (list->var_type == var_boolean) { gdb_assert (list->type == set_cmd); - do_setshow_command (args, from_tty, list); + do_set_command (args, from_tty, list); } } diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index c337b43..3c2e152 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -52,6 +52,53 @@ static struct cmd_list_element *find_cmd (char *command, static void help_all (struct ui_file *stream); +/* Look up a command whose 'prefixlist' is KEY. Return the command if found, + otherwise return NULL. */ + +static struct cmd_list_element * +lookup_cmd_for_prefixlist (struct cmd_list_element **key, + struct cmd_list_element *list) +{ + struct cmd_list_element *p = NULL; + + for (p = list; p != NULL; p = p->next) + { + struct cmd_list_element *q; + + if (p->prefixlist == NULL) + continue; + else if (p->prefixlist == key) + return p; + + q = lookup_cmd_for_prefixlist (key, *(p->prefixlist)); + if (q != NULL) + return q; + } + + return NULL; +} + +static void +set_cmd_prefix (struct cmd_list_element *c, struct cmd_list_element **list) +{ + struct cmd_list_element *p; + + /* Check to see if *LIST contains any element other than C. */ + for (p = *list; p != NULL; p = p->next) + if (p != c) + break; + + if (p == NULL) + { + /* *SET_LIST only contains SET. */ + p = lookup_cmd_for_prefixlist (list, setlist); + + c->prefix = p ? (p->cmd_pointer ? p->cmd_pointer : p) : p; + } + else + c->prefix = p->prefix; +} + static void print_help_for_command (struct cmd_list_element *c, char *prefix, int recurse, struct ui_file *stream); @@ -193,6 +240,7 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int), c->prefixlist = NULL; c->prefixname = NULL; c->allow_unknown = 0; + c->prefix = NULL; c->abbrev_flag = 0; set_cmd_completer (c, make_symbol_completion_list_fn); c->destroyer = NULL; @@ -268,6 +316,8 @@ add_alias_cmd (char *name, char *oldname, enum command_class class, c->cmd_pointer = old; c->alias_chain = old->aliases; old->aliases = c; + + set_cmd_prefix (c, list); return c; } @@ -284,10 +334,21 @@ add_prefix_cmd (char *name, enum command_class class, struct cmd_list_element **list) { struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + struct cmd_list_element *p; c->prefixlist = prefixlist; c->prefixname = prefixname; c->allow_unknown = allow_unknown; + + if (list == &cmdlist) + c->prefix = NULL; + else + set_cmd_prefix (c, list); + + /* Update the field 'prefix' of each cmd_list_element in *PREFIXLIST. */ + for (p = *prefixlist; p != NULL; p = p->next) + p->prefix = c; + return c; } @@ -392,6 +453,9 @@ add_setshow_cmd_full (char *name, full_set_doc, set_list); if (set_func != NULL) set_cmd_sfunc (set, set_func); + + set_cmd_prefix (set, set_list); + show = add_set_or_show_cmd (name, show_cmd, class, var_type, var, full_show_doc, show_list); show->show_value_func = show_func; @@ -430,6 +494,8 @@ add_setshow_enum_cmd (char *name, c->enums = enumlist; } +const char * const auto_boolean_enums[] = { "on", "off", "auto", NULL }; + /* Add an auto-boolean command named NAME to both the set and show command list lists. CLASS is as in add_cmd. VAR is address of the variable which will contain the value. DOC is the documentation @@ -445,7 +511,6 @@ add_setshow_auto_boolean_cmd (char *name, struct cmd_list_element **set_list, struct cmd_list_element **show_list) { - static const char *auto_boolean_enums[] = { "on", "off", "auto", NULL }; struct cmd_list_element *c; add_setshow_cmd_full (name, class, var_auto_boolean, var, diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h index b5e0790..edae6e8 100644 --- a/gdb/cli/cli-decode.h +++ b/gdb/cli/cli-decode.h @@ -149,6 +149,9 @@ struct cmd_list_element recognized; call the prefix's own function in that case. */ char allow_unknown; + /* The prefix command of this command. */ + struct cmd_list_element *prefix; + /* Nonzero says this is an abbreviation, and should not be mentioned in lists of commands. This allows "br<tab>" to complete to "break", which it @@ -232,5 +235,6 @@ extern void not_just_help_class_command (char *arg, int from_tty); extern void print_doc_line (struct ui_file *, char *); +extern const char * const auto_boolean_enums[]; #endif /* !defined (CLI_DECODE_H) */ diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c index 7ffb89e..19172c2 100644 --- a/gdb/cli/cli-setshow.c +++ b/gdb/cli/cli-setshow.c @@ -21,6 +21,7 @@ #include <ctype.h> #include "gdb_string.h" #include "arch-utils.h" +#include "observer.h" #include "ui-out.h" @@ -32,6 +33,21 @@ static int parse_binary_operation (char *); +/* Return true if the change of command parameter should be notified. */ + +static int +notify_command_param_changed_p (int param_changed, struct cmd_list_element *c) +{ + if (param_changed == 0) + return 0; + + if (c->class == class_maintenance || c->class == class_deprecated + || c->class == class_obscure) + return 0; + + return 1; +} + \f static enum auto_boolean parse_auto_binary_operation (const char *arg) @@ -116,18 +132,19 @@ deprecated_show_value_hack (struct ui_file *ignore_file, } } -/* Do a "set" or "show" command. ARG is NULL if no argument, or the +/* Do a "set" command. ARG is NULL if no argument, or the text of the argument, and FROM_TTY is nonzero if this command is being entered directly by the user (i.e. these are just like any other command). C is the command list element for the command. */ void -do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) +do_set_command (char *arg, int from_tty, struct cmd_list_element *c) { - struct ui_out *uiout = current_uiout; + /* A flag to indicate the option is changed or not. */ + int option_changed = 0; + + gdb_assert (c->type == set_cmd); - if (c->type == set_cmd) - { switch (c->var_type) { case var_string: @@ -170,50 +187,106 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) #endif *q++ = '\0'; new = (char *) xrealloc (new, q - new); - xfree (*(char **) c->var); - *(char **) c->var = new; + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, new) != 0) + { + xfree (*(char **) c->var); + *(char **) c->var = new; + + option_changed = 1; + } + else + xfree (new); } break; case var_string_noescape: if (arg == NULL) arg = ""; - xfree (*(char **) c->var); - *(char **) c->var = xstrdup (arg); + + if (*(char **) c->var == NULL || strcmp (*(char **) c->var, arg) != 0) + { + xfree (*(char **) c->var); + *(char **) c->var = xstrdup (arg); + + option_changed = 1; + } break; case var_filename: if (arg == NULL) error_no_arg (_("filename to set it to.")); /* FALLTHROUGH */ case var_optional_filename: - xfree (*(char **) c->var); + { + char *val = NULL; - if (arg != NULL) - { - /* Clear trailing whitespace of filename. */ - char *ptr = arg + strlen (arg) - 1; + if (arg != NULL) + { + /* Clear trailing whitespace of filename. */ + char *ptr = arg + strlen (arg) - 1; - while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) - ptr--; - *(ptr + 1) = '\0'; + while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) + ptr--; + *(ptr + 1) = '\0'; - *(char **) c->var = tilde_expand (arg); - } - else - *(char **) c->var = xstrdup (""); + val = tilde_expand (arg); + } + else + val = xstrdup (""); + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, val) != 0) + { + xfree (*(char **) c->var); + *(char **) c->var = val; + + option_changed = 1; + } + else + xfree (val); + } break; case var_boolean: - *(int *) c->var = parse_binary_operation (arg); + { + int val = parse_binary_operation (arg); + + if (val != *(int *) c->var) + { + *(int *) c->var = val; + + option_changed = 1; + } + } break; case var_auto_boolean: - *(enum auto_boolean *) c->var = parse_auto_binary_operation (arg); + { + enum auto_boolean val = parse_auto_binary_operation (arg); + + if (*(enum auto_boolean *) c->var != val) + { + *(enum auto_boolean *) c->var = val; + + option_changed = 1; + } + } break; case var_uinteger: case var_zuinteger: if (arg == NULL) error_no_arg (_("integer to set it to.")); - *(unsigned int *) c->var = parse_and_eval_long (arg); - if (c->var_type == var_uinteger && *(unsigned int *) c->var == 0) - *(unsigned int *) c->var = UINT_MAX; + { + unsigned int val = parse_and_eval_long (arg); + + if (c->var_type == var_uinteger && val == 0) + val = UINT_MAX; + + if (*(unsigned int *) c->var != val) + { + *(unsigned int *) c->var = val; + + option_changed = 1; + } + } break; case var_integer: case var_zinteger: @@ -224,11 +297,17 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) error_no_arg (_("integer to set it to.")); val = parse_and_eval_long (arg); if (val == 0 && c->var_type == var_integer) - *(int *) c->var = INT_MAX; + val = INT_MAX; else if (val >= INT_MAX) error (_("integer %u out of range"), val); - else - *(int *) c->var = val; + + + if (*(int *) c->var != val) + { + *(int *) c->var = val; + + option_changed = 1; + } break; } case var_enum: @@ -293,15 +372,133 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) if (nmatches > 1) error (_("Ambiguous item \"%s\"."), arg); - *(const char **) c->var = match; + if (*(const char **) c->var != match) + { + *(const char **) c->var = match; + + option_changed = 1; + } } break; default: error (_("gdb internal error: bad var_type in do_setshow_command")); } - } - else if (c->type == show_cmd) + c->func (c, NULL, from_tty); + if (deprecated_set_hook) + deprecated_set_hook (c); + + if (notify_command_param_changed_p (option_changed, c)) { + char *name; + + /* Compute the whole multi-word command options. If user types command + 'set foo bar baz on', c->name is 'baz', and GDB can't pass "bar" to + command option change notification, because it is confusing. We can + trace back through field 'prefix' to compute the whole options, + and pass "foo bar baz" to notification. */ + { + struct cmd_list_element **cmds; + struct cmd_list_element *p; + int i; + int length = 0; + char *cp; + + for (i = 0, p = c; p != NULL; i++) + { + length += strlen (p->name); + length++; + + p = p->prefix; + } + cp = name = xmalloc (length); + cmds = xmalloc (sizeof (struct cmd_list_element *) * i); + + /* Track back through filed 'prefix' and cache them in CMDS. */ + for (i = 0, p = c; p != NULL; i++) + { + cmds[i] = p; + p = p->prefix; + } + + /* Skip the command 'set' in CMDS. */ + i--; + gdb_assert (cmds[i]->prefixlist == &setlist); + /* Traverse them in the reversed order, and copy their names into + NAME. */ + for (i--; i >= 0; i--) + { + memcpy (cp, cmds[i]->name, strlen (cmds[i]->name)); + cp += strlen (cmds[i]->name); + + if (i != 0) + { + cp[0] = ' '; + cp++; + } + } + cp[0] = 0; + + xfree (cmds); + } + + switch (c->var_type) + { + case var_string: + case var_string_noescape: + case var_filename: + case var_optional_filename: + case var_enum: + observer_notify_command_param_changed (name, *(char **) c->var); + break; + case var_boolean: + { + char *opt = *(int *) c->var ? "on" : "off"; + + observer_notify_command_param_changed (name, opt); + } + break; + case var_auto_boolean: + { + const char *s = auto_boolean_enums[*(enum auto_boolean *) c->var]; + + observer_notify_command_param_changed (name, s); + } + break; + case var_uinteger: + case var_zuinteger: + { + char s[64]; + + xsnprintf (s, sizeof s, "%u", *(unsigned int *) c->var); + observer_notify_command_param_changed (name, s); + } + break; + case var_integer: + case var_zinteger: + { + char s[64]; + + xsnprintf (s, sizeof s, "%d", *(int *) c->var); + observer_notify_command_param_changed (name, s); + } + break; + } + xfree (name); + } +} + +/* Do a "show" command. ARG is NULL if no argument, or the + text of the argument, and FROM_TTY is nonzero if this command is + being entered directly by the user (i.e. these are just like any + other command). C is the command list element for the command. */ + +void +do_show_command (char *arg, int from_tty, struct cmd_list_element *c) +{ + struct ui_out *uiout = current_uiout; + + gdb_assert (c->type == show_cmd); + { struct cleanup *old_chain; struct ui_file *stb; @@ -387,12 +584,9 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) deprecated_show_value_hack (gdb_stdout, from_tty, c, value); } do_cleanups (old_chain); - } - else - error (_("gdb internal error: bad cmd_type in do_setshow_command")); + c->func (c, NULL, from_tty); - if (c->type == set_cmd && deprecated_set_hook) - deprecated_set_hook (c); + } } /* Show all the settings in a list of show commands. */ @@ -431,7 +625,7 @@ cmd_show_list (struct cmd_list_element *list, int from_tty, char *prefix) ui_out_field_string (uiout, "name", list->name); ui_out_text (uiout, ": "); if (list->type == show_cmd) - do_setshow_command ((char *) NULL, from_tty, list); + do_show_command ((char *) NULL, from_tty, list); else cmd_func (list, NULL, from_tty); /* Close the tuple. */ diff --git a/gdb/cli/cli-setshow.h b/gdb/cli/cli-setshow.h index cb8d2c5..ffe9abd 100644 --- a/gdb/cli/cli-setshow.h +++ b/gdb/cli/cli-setshow.h @@ -21,12 +21,10 @@ struct cmd_list_element; /* Exported to cli/cli-cmds.c and gdb/top.c */ -/* Do a "set" or "show" command. ARG is NULL if no argument, or the - text of the argument, and FROM_TTY is nonzero if this command is - being entered directly by the user (i.e. these are just like any - other command). C is the command list element for the command. */ -extern void do_setshow_command (char *arg, int from_tty, - struct cmd_list_element *c); +extern void do_set_command (char *arg, int from_tty, + struct cmd_list_element *c); +extern void do_show_command (char *arg, int from_tty, + struct cmd_list_element *c); /* Exported to cli/cli-cmds.c and gdb/top.c, language.c and valprint.c */ diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi index 14d4ac3..bf84820 100644 --- a/gdb/doc/observer.texi +++ b/gdb/doc/observer.texi @@ -234,6 +234,14 @@ the current top-level prompt. Variable gdb_datadir has been set. The value may not necessarily change. @end deftypefun +@deftypefun void command_param_changed (const char *@var{param}, const char *@var{value}) +The parameter of some @code{set} commands in console are changed. This +method is called after a command @code{set @var{param} @var{value}}. +@var{param} is the parameter of @code{set} command, and @var{value} +is the value of changed parameter. + +@end deftypefun + @deftypefun void test_notification (int @var{somearg}) This observer is used for internal testing. Do not use. See testsuite/gdb.gdb/observer.exp. diff --git a/gdb/remote.c b/gdb/remote.c index fa514dc..87b8921 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -11270,7 +11270,7 @@ show_remote_cmd (char *args, int from_tty) ui_out_field_string (uiout, "name", list->name); ui_out_text (uiout, ": "); if (list->type == show_cmd) - do_setshow_command ((char *) NULL, from_tty, list); + do_show_command ((char *) NULL, from_tty, list); else cmd_func (list, NULL, from_tty); /* Close the tuple. */ diff --git a/gdb/top.c b/gdb/top.c index 213c68c..8251d1b 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -474,8 +474,10 @@ execute_command (char *p, int from_tty) /* c->user_commands would be NULL in the case of a python command. */ if (c->class == class_user && c->user_commands) execute_user_command (c, arg); - else if (c->type == set_cmd || c->type == show_cmd) - do_setshow_command (arg, from_tty, c); + else if (c->type == set_cmd) + do_set_command (arg, from_tty, c); + else if (c->type == show_cmd) + do_show_command (arg, from_tty, c); else if (!cmd_func_p (c)) error (_("That is not a command, just a help topic.")); else if (deprecated_call_command_hook) -- 1.7.7.6 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] new observer command_param_changed. 2012-08-06 15:44 ` Yao Qi @ 2012-08-06 20:21 ` Tom Tromey 2012-08-07 2:58 ` Yao Qi 0 siblings, 1 reply; 15+ messages in thread From: Tom Tromey @ 2012-08-06 20:21 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> They are switched to dynamic array. Thanks. Yao> + /* Update the field 'prefix' of each cmd_list_element in *PREFIXLIST. */ Yao> + for (p = *prefixlist; p != NULL; p = p->next) Yao> + p->prefix = c; Super. Yao> { Yao> + char *name; Yao> + Yao> + /* Compute the whole multi-word command options. If user types command Yao> + 'set foo bar baz on', c->name is 'baz', and GDB can't pass "bar" to Yao> + command option change notification, because it is confusing. We can Yao> + trace back through field 'prefix' to compute the whole options, Yao> + and pass "foo bar baz" to notification. */ Yao> + { Two blocks separated only by a declaration seems unusual. I would suggest just a single block. Yao> + /* Skip the command 'set' in CMDS. */ Yao> + i--; Yao> + gdb_assert (cmds[i]->prefixlist == &setlist); I wonder if this can trigger somehow. For example, if a Python programmer makes a Parameter under 'maint set' that is in an unexpected command class. I think it would be safer perhaps to just avoid the notification if the prefixlist is not setlist. Tom ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] new observer command_param_changed. 2012-08-06 20:21 ` Tom Tromey @ 2012-08-07 2:58 ` Yao Qi 2012-08-08 18:11 ` Tom Tromey 0 siblings, 1 reply; 15+ messages in thread From: Yao Qi @ 2012-08-07 2:58 UTC (permalink / raw) To: gdb-patches; +Cc: Tom Tromey On Monday, August 06, 2012 02:20:47 PM Tom Tromey wrote: > Yao> { > Yao> + char *name; > Yao> + > Yao> + /* Compute the whole multi-word command options. If user types > command Yao> + 'set foo bar baz on', c->name is 'baz', and GDB can't pass > "bar" to Yao> + command option change notification, because it is > confusing. We can Yao> + trace back through field 'prefix' to compute > the whole options, Yao> + and pass "foo bar baz" to notification. */ > Yao> + { > > Two blocks separated only by a declaration seems unusual. > I would suggest just a single block. OK, fixed. > > Yao> + /* Skip the command 'set' in CMDS. */ > Yao> + i--; > Yao> + gdb_assert (cmds[i]->prefixlist == &setlist); > > I wonder if this can trigger somehow. For example, if a Python > programmer makes a Parameter under 'maint set' that is in an unexpected > command class. Yes, this case will trigger this assertion failure here. > I think it would be safer perhaps to just avoid the notification if the > prefixlist is not setlist. OK, replace the assertion with the following condition check. + /* Don't trigger any observer notification if prefixlist is not + setlist. */ + i--; + if (cmds[i]->prefixlist != &setlist) + { + xfree (cmds); + xfree (name); + + return; + } The rest is unchanged. -- Yao (齐尧) gdb: 2012-08-07 Yao Qi <yao@codesourcery.com> * cli/cli-decode.c (set_cmd_prefix): New. (lookup_cmd_for_prefixlist): New. (add_prefix_cmd): Call set_cmd_prefix and update field 'prefix' of each cmd_list_element in *prefixlist. (add_setshow_cmd_full): set_cmd_prefix. (add_alias_cmd): Likewise. * cli/cli-decode.h (struct cmd_list_element) <prefix>: New field. Declare 'auto_boolean_enums'. * cli/cli-setshow.c: Include "observer.h". (notify_command_param_changed_p): New. (add_setshow_auto_boolean_cmd): Move auto_boolean_enums out. Remove 'static'. (do_setshow_command): Split it to ... (do_set_command, do_show_command): ... them. New. (do_set_command): Call observer_notify_command_param_changed if notify_command_param_changed_p returns true. (cmd_show_list): Caller update. * auto-load.c (set_auto_load_cmd): Likewise. * remote.c (show_remote_cmd): Likewise. * cli/cli-setshow.h: Update declarations. * top.c (execute_command): Call do_set_command and do_show_command. gdb/doc: 2012-08-07 Yao Qi <yao@codesourcery.com> * observer.texi: New observer command_param_changed. --- gdb/auto-load.c | 2 +- gdb/cli/cli-decode.c | 67 ++++++++++++- gdb/cli/cli-decode.h | 4 + gdb/cli/cli-setshow.c | 274 ++++++++++++++++++++++++++++++++++++++++++------- gdb/cli/cli-setshow.h | 10 +- gdb/doc/observer.texi | 8 ++ gdb/remote.c | 2 +- gdb/top.c | 6 +- 8 files changed, 324 insertions(+), 49 deletions(-) diff --git a/gdb/auto-load.c b/gdb/auto-load.c index 2cc52c6..03a7539 100644 --- a/gdb/auto-load.c +++ b/gdb/auto-load.c @@ -1022,7 +1022,7 @@ set_auto_load_cmd (char *args, int from_tty) if (list->var_type == var_boolean) { gdb_assert (list->type == set_cmd); - do_setshow_command (args, from_tty, list); + do_set_command (args, from_tty, list); } } diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index c337b43..3c2e152 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -52,6 +52,53 @@ static struct cmd_list_element *find_cmd (char *command, static void help_all (struct ui_file *stream); +/* Look up a command whose 'prefixlist' is KEY. Return the command if found, + otherwise return NULL. */ + +static struct cmd_list_element * +lookup_cmd_for_prefixlist (struct cmd_list_element **key, + struct cmd_list_element *list) +{ + struct cmd_list_element *p = NULL; + + for (p = list; p != NULL; p = p->next) + { + struct cmd_list_element *q; + + if (p->prefixlist == NULL) + continue; + else if (p->prefixlist == key) + return p; + + q = lookup_cmd_for_prefixlist (key, *(p->prefixlist)); + if (q != NULL) + return q; + } + + return NULL; +} + +static void +set_cmd_prefix (struct cmd_list_element *c, struct cmd_list_element **list) +{ + struct cmd_list_element *p; + + /* Check to see if *LIST contains any element other than C. */ + for (p = *list; p != NULL; p = p->next) + if (p != c) + break; + + if (p == NULL) + { + /* *SET_LIST only contains SET. */ + p = lookup_cmd_for_prefixlist (list, setlist); + + c->prefix = p ? (p->cmd_pointer ? p->cmd_pointer : p) : p; + } + else + c->prefix = p->prefix; +} + static void print_help_for_command (struct cmd_list_element *c, char *prefix, int recurse, struct ui_file *stream); @@ -193,6 +240,7 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int), c->prefixlist = NULL; c->prefixname = NULL; c->allow_unknown = 0; + c->prefix = NULL; c->abbrev_flag = 0; set_cmd_completer (c, make_symbol_completion_list_fn); c->destroyer = NULL; @@ -268,6 +316,8 @@ add_alias_cmd (char *name, char *oldname, enum command_class class, c->cmd_pointer = old; c->alias_chain = old->aliases; old->aliases = c; + + set_cmd_prefix (c, list); return c; } @@ -284,10 +334,21 @@ add_prefix_cmd (char *name, enum command_class class, struct cmd_list_element **list) { struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + struct cmd_list_element *p; c->prefixlist = prefixlist; c->prefixname = prefixname; c->allow_unknown = allow_unknown; + + if (list == &cmdlist) + c->prefix = NULL; + else + set_cmd_prefix (c, list); + + /* Update the field 'prefix' of each cmd_list_element in *PREFIXLIST. */ + for (p = *prefixlist; p != NULL; p = p->next) + p->prefix = c; + return c; } @@ -392,6 +453,9 @@ add_setshow_cmd_full (char *name, full_set_doc, set_list); if (set_func != NULL) set_cmd_sfunc (set, set_func); + + set_cmd_prefix (set, set_list); + show = add_set_or_show_cmd (name, show_cmd, class, var_type, var, full_show_doc, show_list); show->show_value_func = show_func; @@ -430,6 +494,8 @@ add_setshow_enum_cmd (char *name, c->enums = enumlist; } +const char * const auto_boolean_enums[] = { "on", "off", "auto", NULL }; + /* Add an auto-boolean command named NAME to both the set and show command list lists. CLASS is as in add_cmd. VAR is address of the variable which will contain the value. DOC is the documentation @@ -445,7 +511,6 @@ add_setshow_auto_boolean_cmd (char *name, struct cmd_list_element **set_list, struct cmd_list_element **show_list) { - static const char *auto_boolean_enums[] = { "on", "off", "auto", NULL }; struct cmd_list_element *c; add_setshow_cmd_full (name, class, var_auto_boolean, var, diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h index b5e0790..edae6e8 100644 --- a/gdb/cli/cli-decode.h +++ b/gdb/cli/cli-decode.h @@ -149,6 +149,9 @@ struct cmd_list_element recognized; call the prefix's own function in that case. */ char allow_unknown; + /* The prefix command of this command. */ + struct cmd_list_element *prefix; + /* Nonzero says this is an abbreviation, and should not be mentioned in lists of commands. This allows "br<tab>" to complete to "break", which it @@ -232,5 +235,6 @@ extern void not_just_help_class_command (char *arg, int from_tty); extern void print_doc_line (struct ui_file *, char *); +extern const char * const auto_boolean_enums[]; #endif /* !defined (CLI_DECODE_H) */ diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c index 7ffb89e..d0cf211 100644 --- a/gdb/cli/cli-setshow.c +++ b/gdb/cli/cli-setshow.c @@ -21,6 +21,7 @@ #include <ctype.h> #include "gdb_string.h" #include "arch-utils.h" +#include "observer.h" #include "ui-out.h" @@ -32,6 +33,21 @@ static int parse_binary_operation (char *); +/* Return true if the change of command parameter should be notified. */ + +static int +notify_command_param_changed_p (int param_changed, struct cmd_list_element *c) +{ + if (param_changed == 0) + return 0; + + if (c->class == class_maintenance || c->class == class_deprecated + || c->class == class_obscure) + return 0; + + return 1; +} + \f static enum auto_boolean parse_auto_binary_operation (const char *arg) @@ -116,18 +132,19 @@ deprecated_show_value_hack (struct ui_file *ignore_file, } } -/* Do a "set" or "show" command. ARG is NULL if no argument, or the +/* Do a "set" command. ARG is NULL if no argument, or the text of the argument, and FROM_TTY is nonzero if this command is being entered directly by the user (i.e. these are just like any other command). C is the command list element for the command. */ void -do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) +do_set_command (char *arg, int from_tty, struct cmd_list_element *c) { - struct ui_out *uiout = current_uiout; + /* A flag to indicate the option is changed or not. */ + int option_changed = 0; + + gdb_assert (c->type == set_cmd); - if (c->type == set_cmd) - { switch (c->var_type) { case var_string: @@ -170,50 +187,106 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) #endif *q++ = '\0'; new = (char *) xrealloc (new, q - new); - xfree (*(char **) c->var); - *(char **) c->var = new; + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, new) != 0) + { + xfree (*(char **) c->var); + *(char **) c->var = new; + + option_changed = 1; + } + else + xfree (new); } break; case var_string_noescape: if (arg == NULL) arg = ""; - xfree (*(char **) c->var); - *(char **) c->var = xstrdup (arg); + + if (*(char **) c->var == NULL || strcmp (*(char **) c->var, arg) != 0) + { + xfree (*(char **) c->var); + *(char **) c->var = xstrdup (arg); + + option_changed = 1; + } break; case var_filename: if (arg == NULL) error_no_arg (_("filename to set it to.")); /* FALLTHROUGH */ case var_optional_filename: - xfree (*(char **) c->var); + { + char *val = NULL; - if (arg != NULL) - { - /* Clear trailing whitespace of filename. */ - char *ptr = arg + strlen (arg) - 1; + if (arg != NULL) + { + /* Clear trailing whitespace of filename. */ + char *ptr = arg + strlen (arg) - 1; - while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) - ptr--; - *(ptr + 1) = '\0'; + while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) + ptr--; + *(ptr + 1) = '\0'; - *(char **) c->var = tilde_expand (arg); - } - else - *(char **) c->var = xstrdup (""); + val = tilde_expand (arg); + } + else + val = xstrdup (""); + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, val) != 0) + { + xfree (*(char **) c->var); + *(char **) c->var = val; + + option_changed = 1; + } + else + xfree (val); + } break; case var_boolean: - *(int *) c->var = parse_binary_operation (arg); + { + int val = parse_binary_operation (arg); + + if (val != *(int *) c->var) + { + *(int *) c->var = val; + + option_changed = 1; + } + } break; case var_auto_boolean: - *(enum auto_boolean *) c->var = parse_auto_binary_operation (arg); + { + enum auto_boolean val = parse_auto_binary_operation (arg); + + if (*(enum auto_boolean *) c->var != val) + { + *(enum auto_boolean *) c->var = val; + + option_changed = 1; + } + } break; case var_uinteger: case var_zuinteger: if (arg == NULL) error_no_arg (_("integer to set it to.")); - *(unsigned int *) c->var = parse_and_eval_long (arg); - if (c->var_type == var_uinteger && *(unsigned int *) c->var == 0) - *(unsigned int *) c->var = UINT_MAX; + { + unsigned int val = parse_and_eval_long (arg); + + if (c->var_type == var_uinteger && val == 0) + val = UINT_MAX; + + if (*(unsigned int *) c->var != val) + { + *(unsigned int *) c->var = val; + + option_changed = 1; + } + } break; case var_integer: case var_zinteger: @@ -224,11 +297,17 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) error_no_arg (_("integer to set it to.")); val = parse_and_eval_long (arg); if (val == 0 && c->var_type == var_integer) - *(int *) c->var = INT_MAX; + val = INT_MAX; else if (val >= INT_MAX) error (_("integer %u out of range"), val); - else - *(int *) c->var = val; + + + if (*(int *) c->var != val) + { + *(int *) c->var = val; + + option_changed = 1; + } break; } case var_enum: @@ -293,15 +372,137 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) if (nmatches > 1) error (_("Ambiguous item \"%s\"."), arg); - *(const char **) c->var = match; + if (*(const char **) c->var != match) + { + *(const char **) c->var = match; + + option_changed = 1; + } } break; default: error (_("gdb internal error: bad var_type in do_setshow_command")); } - } - else if (c->type == show_cmd) + c->func (c, NULL, from_tty); + if (deprecated_set_hook) + deprecated_set_hook (c); + + if (notify_command_param_changed_p (option_changed, c)) { + char *name, *cp; + struct cmd_list_element **cmds; + struct cmd_list_element *p; + int i; + int length = 0; + + /* Compute the whole multi-word command options. If user types command + 'set foo bar baz on', c->name is 'baz', and GDB can't pass "bar" to + command option change notification, because it is confusing. We can + trace back through field 'prefix' to compute the whole options, + and pass "foo bar baz" to notification. */ + + for (i = 0, p = c; p != NULL; i++) + { + length += strlen (p->name); + length++; + + p = p->prefix; + } + cp = name = xmalloc (length); + cmds = xmalloc (sizeof (struct cmd_list_element *) * i); + + /* Track back through filed 'prefix' and cache them in CMDS. */ + for (i = 0, p = c; p != NULL; i++) + { + cmds[i] = p; + p = p->prefix; + } + + /* Don't trigger any observer notification if prefixlist is not + setlist. */ + i--; + if (cmds[i]->prefixlist != &setlist) + { + xfree (cmds); + xfree (name); + + return; + } + /* Traverse them in the reversed order, and copy their names into + NAME. */ + for (i--; i >= 0; i--) + { + memcpy (cp, cmds[i]->name, strlen (cmds[i]->name)); + cp += strlen (cmds[i]->name); + + if (i != 0) + { + cp[0] = ' '; + cp++; + } + } + cp[0] = 0; + + xfree (cmds); + + switch (c->var_type) + { + case var_string: + case var_string_noescape: + case var_filename: + case var_optional_filename: + case var_enum: + observer_notify_command_param_changed (name, *(char **) c->var); + break; + case var_boolean: + { + char *opt = *(int *) c->var ? "on" : "off"; + + observer_notify_command_param_changed (name, opt); + } + break; + case var_auto_boolean: + { + const char *s = auto_boolean_enums[*(enum auto_boolean *) c->var]; + + observer_notify_command_param_changed (name, s); + } + break; + case var_uinteger: + case var_zuinteger: + { + char s[64]; + + xsnprintf (s, sizeof s, "%u", *(unsigned int *) c->var); + observer_notify_command_param_changed (name, s); + } + break; + case var_integer: + case var_zinteger: + { + char s[64]; + + xsnprintf (s, sizeof s, "%d", *(int *) c->var); + observer_notify_command_param_changed (name, s); + } + break; + } + xfree (name); + } +} + +/* Do a "show" command. ARG is NULL if no argument, or the + text of the argument, and FROM_TTY is nonzero if this command is + being entered directly by the user (i.e. these are just like any + other command). C is the command list element for the command. */ + +void +do_show_command (char *arg, int from_tty, struct cmd_list_element *c) +{ + struct ui_out *uiout = current_uiout; + + gdb_assert (c->type == show_cmd); + { struct cleanup *old_chain; struct ui_file *stb; @@ -387,12 +588,9 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) deprecated_show_value_hack (gdb_stdout, from_tty, c, value); } do_cleanups (old_chain); - } - else - error (_("gdb internal error: bad cmd_type in do_setshow_command")); + c->func (c, NULL, from_tty); - if (c->type == set_cmd && deprecated_set_hook) - deprecated_set_hook (c); + } } /* Show all the settings in a list of show commands. */ @@ -431,7 +629,7 @@ cmd_show_list (struct cmd_list_element *list, int from_tty, char *prefix) ui_out_field_string (uiout, "name", list->name); ui_out_text (uiout, ": "); if (list->type == show_cmd) - do_setshow_command ((char *) NULL, from_tty, list); + do_show_command ((char *) NULL, from_tty, list); else cmd_func (list, NULL, from_tty); /* Close the tuple. */ diff --git a/gdb/cli/cli-setshow.h b/gdb/cli/cli-setshow.h index cb8d2c5..ffe9abd 100644 --- a/gdb/cli/cli-setshow.h +++ b/gdb/cli/cli-setshow.h @@ -21,12 +21,10 @@ struct cmd_list_element; /* Exported to cli/cli-cmds.c and gdb/top.c */ -/* Do a "set" or "show" command. ARG is NULL if no argument, or the - text of the argument, and FROM_TTY is nonzero if this command is - being entered directly by the user (i.e. these are just like any - other command). C is the command list element for the command. */ -extern void do_setshow_command (char *arg, int from_tty, - struct cmd_list_element *c); +extern void do_set_command (char *arg, int from_tty, + struct cmd_list_element *c); +extern void do_show_command (char *arg, int from_tty, + struct cmd_list_element *c); /* Exported to cli/cli-cmds.c and gdb/top.c, language.c and valprint.c */ diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi index 14d4ac3..bf84820 100644 --- a/gdb/doc/observer.texi +++ b/gdb/doc/observer.texi @@ -234,6 +234,14 @@ the current top-level prompt. Variable gdb_datadir has been set. The value may not necessarily change. @end deftypefun +@deftypefun void command_param_changed (const char *@var{param}, const char *@var{value}) +The parameter of some @code{set} commands in console are changed. This +method is called after a command @code{set @var{param} @var{value}}. +@var{param} is the parameter of @code{set} command, and @var{value} +is the value of changed parameter. + +@end deftypefun + @deftypefun void test_notification (int @var{somearg}) This observer is used for internal testing. Do not use. See testsuite/gdb.gdb/observer.exp. diff --git a/gdb/remote.c b/gdb/remote.c index fa514dc..87b8921 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -11270,7 +11270,7 @@ show_remote_cmd (char *args, int from_tty) ui_out_field_string (uiout, "name", list->name); ui_out_text (uiout, ": "); if (list->type == show_cmd) - do_setshow_command ((char *) NULL, from_tty, list); + do_show_command ((char *) NULL, from_tty, list); else cmd_func (list, NULL, from_tty); /* Close the tuple. */ diff --git a/gdb/top.c b/gdb/top.c index 213c68c..8251d1b 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -474,8 +474,10 @@ execute_command (char *p, int from_tty) /* c->user_commands would be NULL in the case of a python command. */ if (c->class == class_user && c->user_commands) execute_user_command (c, arg); - else if (c->type == set_cmd || c->type == show_cmd) - do_setshow_command (arg, from_tty, c); + else if (c->type == set_cmd) + do_set_command (arg, from_tty, c); + else if (c->type == show_cmd) + do_show_command (arg, from_tty, c); else if (!cmd_func_p (c)) error (_("That is not a command, just a help topic.")); else if (deprecated_call_command_hook) -- 1.7.7.6 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] new observer command_param_changed. 2012-08-07 2:58 ` Yao Qi @ 2012-08-08 18:11 ` Tom Tromey 0 siblings, 0 replies; 15+ messages in thread From: Tom Tromey @ 2012-08-08 18:11 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> OK, replace the assertion with the following condition check. [...] Yao> The rest is unchanged. Thanks. This is ok. Tom ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 2/3] attach to command_param_changed observer. 2012-08-03 11:22 [RCF 0/3 V3] MI notification of command parameter change Yao Qi 2012-08-03 11:22 ` [PATCH 1/3] new observer command_param_changed Yao Qi @ 2012-08-03 11:22 ` Yao Qi 2012-08-03 11:30 ` Eli Zaretskii 2012-08-03 17:36 ` Tom Tromey 2012-08-03 11:22 ` [PATCH 3/3] test case Yao Qi 2012-08-10 0:57 ` [committed]: [RCF 0/3 V3] MI notification of command parameter change Yao Qi 3 siblings, 2 replies; 15+ messages in thread From: Yao Qi @ 2012-08-03 11:22 UTC (permalink / raw) To: gdb-patches Hi, 'mi_suppress_breakpoint_notifications' is used to suppress mi breakpoint notifications. This patch is to change this variable to an array so that multiple mi notifications can be suppressed. The following patch will use it to suppress other MI notifications. This patch is to attach function 'mi_command_param_changed' to observer 'command_param_changed', so that a MI notification "=cmd-param-changed" is sent to MI frontend. If the command param change is requested from MI, the notification is suppressed. Compared with V2, V3 has the following changes, - Rename MI notification to "=cmd-param-changed". - Update doc especially for multi-word commands. - Rename some functions from "optoin" to "param". gdb: 2012-08-03 Yao Qi <yao@codesourcery.com> * NEWS: Mention new MI notification. * mi/mi-interp.c: Declare mi_command_param_changed. (mi_interpreter_init): Attach mi_command_param_changed to observer command_param_changed. (mi_command_param_changed): New. Remove mi_suppress_breakpoint_notifications. Define global variable mi_suppress_notification. (mi_breakpoint_created): Update. (mi_breakpoint_deleted): Likewise. (mi_breakpoint_modified): Likewise. * mi/mi-main.c (mi_cmd_execute): Likewise. Check command 'gdb-set' and set mi_suppress_notification. * mi/mi-main.h: (mi_suppress_notification): New struct. gdb/doc: 2012-08-03 Yao Qi <yao@codesourcery.com> * gdb.texinfo (GDB/MI Async Records): Doc for '=cmd-param-changed'. --- gdb/NEWS | 5 +++++ gdb/doc/gdb.texinfo | 6 ++++++ gdb/mi/mi-interp.c | 44 ++++++++++++++++++++++++++++++++++++++------ gdb/mi/mi-main.c | 11 +++++++++-- gdb/mi/mi-main.h | 10 +++++++++- 5 files changed, 67 insertions(+), 9 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index a590bee..e30bd1a 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -17,6 +17,11 @@ maint info bfds List the BFDs known to GDB. +* MI changes + + ** Command parameter changes are now notified using new async record + "=cmd-param-changed". + *** Changes in GDB 7.5 * GDB now supports x32 ABI. Visit <http://sites.google.com/site/x32abi/> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 15a9efd..2d8d7d6 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -27618,6 +27618,12 @@ breakpoint commands; @xref{GDB/MI Breakpoint Commands}. Note that if a breakpoint is emitted in the result record of a command, then it will not also be emitted in an async record. +@item =cmd-param-changed,param=@var{param},value=@var{value} +Reports that a parameter of the command @code{set @var{param}} is +changed to @var{value}. In the multi-word @code{set} command, +the @var{param} is the whole parameter list to @code{set} command. +For example, In command @code{set check type on}, @var{param} +is @code{check type} and @var{value} is @code{on}. @end table @node GDB/MI Frame Information diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index b487136..94df818 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -71,6 +71,7 @@ static void mi_about_to_proceed (void); static void mi_breakpoint_created (struct breakpoint *b); static void mi_breakpoint_deleted (struct breakpoint *b); static void mi_breakpoint_modified (struct breakpoint *b); +static void mi_command_param_changed (const char *param, const char *value); static int report_initial_inferior (struct inferior *inf, void *closure); @@ -128,6 +129,7 @@ mi_interpreter_init (struct interp *interp, int top_level) observer_attach_breakpoint_created (mi_breakpoint_created); observer_attach_breakpoint_deleted (mi_breakpoint_deleted); observer_attach_breakpoint_modified (mi_breakpoint_modified); + observer_attach_command_param_changed (mi_command_param_changed); /* The initial inferior is created before this function is called, so we need to report it explicitly. Use iteration in @@ -501,10 +503,14 @@ mi_about_to_proceed (void) mi_proceeded = 1; } -/* When non-zero, no MI notifications will be emitted in - response to breakpoint change observers. */ +/* When the element is non-zero, no MI notifications will be emitted in + response to the corresponding observers. */ -int mi_suppress_breakpoint_notifications = 0; +struct mi_suppress_notification mi_suppress_notification = + { + 0, + 0, + }; /* Emit notification about a created breakpoint. */ @@ -515,7 +521,7 @@ mi_breakpoint_created (struct breakpoint *b) struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); volatile struct gdb_exception e; - if (mi_suppress_breakpoint_notifications) + if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) @@ -546,7 +552,7 @@ mi_breakpoint_deleted (struct breakpoint *b) { struct mi_interp *mi = top_level_interpreter_data (); - if (mi_suppress_breakpoint_notifications) + if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) @@ -569,7 +575,7 @@ mi_breakpoint_modified (struct breakpoint *b) struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); volatile struct gdb_exception e; - if (mi_suppress_breakpoint_notifications) + if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) @@ -730,6 +736,32 @@ mi_solib_unloaded (struct so_list *solib) gdb_flush (mi->event_channel); } +/* Emit notification about the command parameter change. */ + +static void +mi_command_param_changed (const char *param, const char *value) +{ + struct mi_interp *mi = top_level_interpreter_data (); + struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); + + if (mi_suppress_notification.cmd_param_changed) + return; + + target_terminal_ours (); + + fprintf_unfiltered (mi->event_channel, + "cmd-param-changed"); + + ui_out_redirect (mi_uiout, mi->event_channel); + + ui_out_field_string (mi_uiout, "param", param); + ui_out_field_string (mi_uiout, "value", value); + + ui_out_redirect (mi_uiout, NULL); + + gdb_flush (mi->event_channel); +} + static int report_initial_inferior (struct inferior *inf, void *closure) { diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index dfb4892..4db3652 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -2099,8 +2099,15 @@ mi_cmd_execute (struct mi_parse *parse) if (strncmp (parse->command, "break-", sizeof ("break-") - 1 ) == 0) { - make_cleanup_restore_integer (&mi_suppress_breakpoint_notifications); - mi_suppress_breakpoint_notifications = 1; + make_cleanup_restore_integer (&mi_suppress_notification.breakpoint); + mi_suppress_notification.breakpoint = 1; + } + else if (strncmp (parse->command, "gdb-set", sizeof ("gdb-set") - 1) == 0) + { + int *p = &mi_suppress_notification.cmd_param_changed; + + make_cleanup_restore_integer (p); + mi_suppress_notification.cmd_param_changed = 1; } if (parse->cmd->argv_func != NULL) diff --git a/gdb/mi/mi-main.h b/gdb/mi/mi-main.h index beac2cd..f4268c2 100644 --- a/gdb/mi/mi-main.h +++ b/gdb/mi/mi-main.h @@ -32,7 +32,15 @@ extern char *current_token; extern int running_result_record_printed; extern int mi_proceeded; -extern int mi_suppress_breakpoint_notifications; + +struct mi_suppress_notification +{ + /* Breakpoint notification suppressed? */ + int breakpoint; + /* Command param changed notification suppressed? */ + int cmd_param_changed; +}; +extern struct mi_suppress_notification mi_suppress_notification; #endif -- 1.7.7.6 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] attach to command_param_changed observer. 2012-08-03 11:22 ` [PATCH 2/3] attach to command_param_changed observer Yao Qi @ 2012-08-03 11:30 ` Eli Zaretskii 2012-08-03 17:36 ` Tom Tromey 1 sibling, 0 replies; 15+ messages in thread From: Eli Zaretskii @ 2012-08-03 11:30 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches > From: Yao Qi <yao@codesourcery.com> > Date: Fri, 3 Aug 2012 19:21:43 +0800 > > 'mi_suppress_breakpoint_notifications' is used to suppress mi > breakpoint notifications. This patch is to change this variable > to an array so that multiple mi notifications can be suppressed. > The following patch will use it to suppress other MI notifications. > > This patch is to attach function 'mi_command_param_changed' to > observer 'command_param_changed', so that a MI notification > "=cmd-param-changed" is sent to MI frontend. If the command param > change is requested from MI, the notification is suppressed. > > Compared with V2, V3 has the following changes, > > - Rename MI notification to "=cmd-param-changed". > - Update doc especially for multi-word commands. > - Rename some functions from "optoin" to "param". OK for the documentation parts. Thanks. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] attach to command_param_changed observer. 2012-08-03 11:22 ` [PATCH 2/3] attach to command_param_changed observer Yao Qi 2012-08-03 11:30 ` Eli Zaretskii @ 2012-08-03 17:36 ` Tom Tromey 1 sibling, 0 replies; 15+ messages in thread From: Tom Tromey @ 2012-08-03 17:36 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> 2012-08-03 Yao Qi <yao@codesourcery.com> Yao> * NEWS: Mention new MI notification. Yao> * mi/mi-interp.c: Declare mi_command_param_changed. Yao> (mi_interpreter_init): Attach mi_command_param_changed to Yao> observer command_param_changed. Yao> (mi_command_param_changed): New. Yao> Remove mi_suppress_breakpoint_notifications. Yao> Define global variable mi_suppress_notification. Yao> (mi_breakpoint_created): Update. Yao> (mi_breakpoint_deleted): Likewise. Yao> (mi_breakpoint_modified): Likewise. Yao> * mi/mi-main.c (mi_cmd_execute): Likewise. Check command Yao> 'gdb-set' and set mi_suppress_notification. Yao> * mi/mi-main.h: (mi_suppress_notification): New struct. Code bits are ok once patch #1 is resolved. Tom ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 3/3] test case 2012-08-03 11:22 [RCF 0/3 V3] MI notification of command parameter change Yao Qi 2012-08-03 11:22 ` [PATCH 1/3] new observer command_param_changed Yao Qi 2012-08-03 11:22 ` [PATCH 2/3] attach to command_param_changed observer Yao Qi @ 2012-08-03 11:22 ` Yao Qi 2012-08-03 17:37 ` Tom Tromey 2012-08-10 0:57 ` [committed]: [RCF 0/3 V3] MI notification of command parameter change Yao Qi 3 siblings, 1 reply; 15+ messages in thread From: Yao Qi @ 2012-08-03 11:22 UTC (permalink / raw) To: gdb-patches gdb/testsuite: 2012-08-03 Yao Qi <yao@codesourcery.com> * gdb.mi/mi-cmd-param-changed.exp: New. * gdb.mi/mi-cli.exp: Update for MI notification "=cmd-param-changed". * gdb.mi/mi-var-rtti.exp, gdb.mi/mi2-cli.exp: Likewise. * gdb.mi/mi2-prompt.exp: Likewise. --- gdb/testsuite/gdb.mi/mi-cli.exp | 4 +- gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp | 97 +++++++++++++++++++++++++ gdb/testsuite/gdb.mi/mi-var-rtti.exp | 2 +- gdb/testsuite/gdb.mi/mi2-cli.exp | 4 +- gdb/testsuite/gdb.mi/mi2-prompt.exp | 5 +- 5 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp diff --git a/gdb/testsuite/gdb.mi/mi-cli.exp b/gdb/testsuite/gdb.mi/mi-cli.exp index b7abbc7..f487cbd 100644 --- a/gdb/testsuite/gdb.mi/mi-cli.exp +++ b/gdb/testsuite/gdb.mi/mi-cli.exp @@ -70,7 +70,7 @@ set line_callee4_body [expr $line_callee4_head + 2] set line_callee4_next [expr $line_callee4_body + 1] mi_gdb_test "-interpreter-exec console \"set args foobar\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"args\",value=\"foobar\".*\\^done" \ "-interpreter-exec console \"set args foobar\"" mi_gdb_test "-interpreter-exec console \"show args\"" \ @@ -90,7 +90,7 @@ mi_gdb_test "-interpreter-exec console \"info break\"" \ "-interpreter-exec console \"info break\"" mi_gdb_test "-interpreter-exec console \"set listsize 1\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"listsize\",value=\"1\".*\\^done" \ "-interpreter-exec console \"set listsize 1\"" # {.*\~"32[ \t(\\t)]*callee1.*\\n".*\^done } diff --git a/gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp b/gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp new file mode 100644 index 0000000..362194b --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp @@ -0,0 +1,97 @@ +# Copyright 2012 Free Software Foundation, Inc. + +# 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/>. + +load_lib mi-support.exp +set MIFLAGS "-i=mi" + +standard_testfile basics.c + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested mi-cmd-param-changed.exp + return -1 +} + +proc test_command_param_changed { } { with_test_prefix "cmd param" { + if [mi_gdb_start] { + return + } + mi_run_to_main + + foreach opt { "on" "off" "step" } { + mi_gdb_test "set scheduler-locking ${opt}" \ + ".*=cmd-param-changed,param=\"scheduler-locking\",value=\"${opt}\".*\\^done" \ + "\"set scheduler-locking ${opt}\"" + } + foreach opt { "on" "off" "step" } { + mi_gdb_test "interpreter-exec console \"set scheduler-locking ${opt}\"" \ + ".*=cmd-param-changed,param=\"scheduler-locking\",value=\"${opt}\".*\\^done" \ + "interpreter-exec \"set scheduler-locking ${opt}\"" + } + # Don't emit MI notification for request from MI. + mi_gdb_test "-gdb-set scheduler-locking on" \ + {\^done} \ + "\"set scheduler-locking on\" no event (requested by MI)" + + mi_gdb_test "interpreter-exec mi \"-gdb-set scheduler-locking step\"" \ + "\\&\"interpreter-exec mi .*\"-gdb-set scheduler-locking step.*\"\\\\n\"\r\n\\^done\r\n\\^done" \ + "\"set scheduler-locking step\" no event (requested by MI interp)" + mi_gdb_test "set scheduler-locking step" \ + "\\&\"set scheduler-locking step\\\\n\"\r\n\\^done" \ + "\"set scheduler-locking stepr\" no event" + + + foreach command { "circular-trace-buffer" "check type" } { + + # The default value of each command option may be different, so we first + # set it to 'off', and this may or may not trigger MI notification. + mi_gdb_test "set ${command} off" ".*\\^done" "\"set ${command}\" warmup" + + foreach boolean_opt { "on" "off" } { + mi_gdb_test "set ${command} ${boolean_opt}" \ + ".*=cmd-param-changed,param=\"${command}\",value=\"${boolean_opt}\".*\\^done" \ + "\"set ${command} ${boolean_opt}\"" + } + mi_gdb_test "set ${command} off" \ + "\\&\"set ${command} off\\\\n\"\r\n\\^done" \ + "\"set ${command}\" no event" + } + + + foreach command { "trace-notes" } { + foreach str_opt { "foo" "bar" } { + mi_gdb_test "set ${command} ${str_opt}" \ + ".*=cmd-param-changed,param=\"${command}\",value=\"${str_opt}\".*\\^done" \ + "\"set ${command} ${str_opt}\"" + } + mi_gdb_test "set ${command} bar" \ + "\\&\"set ${command} bar\\\\n\"\r\n(\\&\"warning.*)\\^done" \ + "\"set ${command} bar\" no event" + } + + # No notification is emitted for 'maint set' commands. + foreach command { "profile" "show-debug-regs" } { + foreach boolean_opt { "on" "off" } { + mi_gdb_test "maint set ${command} ${boolean_opt}" \ + "\\&\"maint set ${command} ${boolean_opt}\\\\n\"\r\n\\^done" \ + "\"maint set ${command} ${boolean_opt}\"" + } + } + + mi_gdb_exit +}} + +test_command_param_changed + +return 0 diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.exp b/gdb/testsuite/gdb.mi/mi-var-rtti.exp index a718ffb..f283ca0 100644 --- a/gdb/testsuite/gdb.mi/mi-var-rtti.exp +++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp @@ -37,7 +37,7 @@ mi_prepare_inline_tests $srcfile # Enable using RTTI to determine real types of the objects proc set_print_object {state testname} { mi_gdb_test "-interpreter-exec console \"set print object ${state}\"" \ - {\^done} \ + "(.*=cmd-param-changed,param=\"object\",value=\"${state}\".*|)\\^done" \ "-interpreter-exec console \"set print object ${state}\" in $testname" } diff --git a/gdb/testsuite/gdb.mi/mi2-cli.exp b/gdb/testsuite/gdb.mi/mi2-cli.exp index e84b191..9ab7518 100644 --- a/gdb/testsuite/gdb.mi/mi2-cli.exp +++ b/gdb/testsuite/gdb.mi/mi2-cli.exp @@ -69,7 +69,7 @@ set line_callee4_head [gdb_get_line_number "callee4 ("] set line_callee4_body [expr $line_callee4_head + 2] mi_gdb_test "-interpreter-exec console \"set args foobar\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"args\",value=\"foobar\".*\\^done" \ "-interpreter-exec console \"set args foobar\"" mi_gdb_test "-interpreter-exec console \"show args\"" \ @@ -89,7 +89,7 @@ mi_gdb_test "-interpreter-exec console \"info break\"" \ "-interpreter-exec console \"info break\"" mi_gdb_test "-interpreter-exec console \"set listsize 1\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"listsize\",value=\"1\".*\\^done" \ "-interpreter-exec console \"set listsize 1\"" # {.*\~"32[ \t(\\t)]*callee1.*\\n".*\^done } diff --git a/gdb/testsuite/gdb.mi/mi2-prompt.exp b/gdb/testsuite/gdb.mi/mi2-prompt.exp index 6145c38..eb9edec 100644 --- a/gdb/testsuite/gdb.mi/mi2-prompt.exp +++ b/gdb/testsuite/gdb.mi/mi2-prompt.exp @@ -23,8 +23,9 @@ if [mi_gdb_start] { # Check console 'set prompt' does not affect the MI output. -mi_gdb_test {-interpreter-exec console "set prompt (banana) "} {\^done} \ - "console set prompt" +mi_gdb_test {-interpreter-exec console "set prompt (banana) "} \ + ".*=cmd-param-changed,param=\"prompt\",value=\"\\(banana\\) \".*\\^done" \ + "console set prompt" mi_gdb_test "-break-list" ".*}" "-break-list" gdb_exit -- 1.7.7.6 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] test case 2012-08-03 11:22 ` [PATCH 3/3] test case Yao Qi @ 2012-08-03 17:37 ` Tom Tromey 2012-08-06 15:48 ` Yao Qi 0 siblings, 1 reply; 15+ messages in thread From: Tom Tromey @ 2012-08-03 17:37 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> * gdb.mi/mi-cmd-param-changed.exp: New. Yao> * gdb.mi/mi-cli.exp: Update for MI notification "=cmd-param-changed". Yao> * gdb.mi/mi-var-rtti.exp, gdb.mi/mi2-cli.exp: Likewise. Yao> * gdb.mi/mi2-prompt.exp: Likewise. This looks good but I did not see a test for abbreviated multi-word commands, and I think that would be a useful addition. Tom ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] test case 2012-08-03 17:37 ` Tom Tromey @ 2012-08-06 15:48 ` Yao Qi 2012-08-06 20:21 ` Tom Tromey 0 siblings, 1 reply; 15+ messages in thread From: Yao Qi @ 2012-08-06 15:48 UTC (permalink / raw) To: gdb-patches; +Cc: Tom Tromey On Friday, August 03, 2012 11:37:39 AM Tom Tromey wrote: > This looks good but I did not see a test for abbreviated multi-word > commands, and I think that would be a useful addition. Right, a test for a abbreviated multi-word is added. + # Full command parameters are included in the notification when a + # abbreviated one is typed. + mi_gdb_test "set ch type on" \ + ".*=cmd-param-changed,param=\"check type\",value=\"on\".*\\^done" \ + "\"set ch type on\"" Except this, there is no other changes. -- Yao (齐尧) gdb/testsuite: 2012-08-06 Yao Qi <yao@codesourcery.com> * gdb.mi/mi-cmd-param-changed.exp: New. * gdb.mi/mi-cli.exp: Update for MI notification "=cmd-param-changed". * gdb.mi/mi-var-rtti.exp, gdb.mi/mi2-cli.exp: Likewise. * gdb.mi/mi2-prompt.exp: Likewise. --- gdb/testsuite/gdb.mi/mi-cli.exp | 4 +- gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp | 103 +++++++++++++++++++++++++ gdb/testsuite/gdb.mi/mi-var-rtti.exp | 2 +- gdb/testsuite/gdb.mi/mi2-cli.exp | 4 +- gdb/testsuite/gdb.mi/mi2-prompt.exp | 5 +- 5 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp diff --git a/gdb/testsuite/gdb.mi/mi-cli.exp b/gdb/testsuite/gdb.mi/mi-cli.exp index b7abbc7..f487cbd 100644 --- a/gdb/testsuite/gdb.mi/mi-cli.exp +++ b/gdb/testsuite/gdb.mi/mi-cli.exp @@ -70,7 +70,7 @@ set line_callee4_body [expr $line_callee4_head + 2] set line_callee4_next [expr $line_callee4_body + 1] mi_gdb_test "-interpreter-exec console \"set args foobar\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"args\",value=\"foobar\".*\\^done" \ "-interpreter-exec console \"set args foobar\"" mi_gdb_test "-interpreter-exec console \"show args\"" \ @@ -90,7 +90,7 @@ mi_gdb_test "-interpreter-exec console \"info break\"" \ "-interpreter-exec console \"info break\"" mi_gdb_test "-interpreter-exec console \"set listsize 1\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"listsize\",value=\"1\".*\\^done" \ "-interpreter-exec console \"set listsize 1\"" # {.*\~"32[ \t(\\t)]*callee1.*\\n".*\^done } diff --git a/gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp b/gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp new file mode 100644 index 0000000..8c2195c --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp @@ -0,0 +1,103 @@ +# Copyright 2012 Free Software Foundation, Inc. + +# 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/>. + +load_lib mi-support.exp +set MIFLAGS "-i=mi" + +standard_testfile basics.c + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested mi-cmd-param-changed.exp + return -1 +} + +proc test_command_param_changed { } { with_test_prefix "cmd param" { + if [mi_gdb_start] { + return + } + mi_run_to_main + + foreach opt { "on" "off" "step" } { + mi_gdb_test "set scheduler-locking ${opt}" \ + ".*=cmd-param-changed,param=\"scheduler-locking\",value=\"${opt}\".*\\^done" \ + "\"set scheduler-locking ${opt}\"" + } + foreach opt { "on" "off" "step" } { + mi_gdb_test "interpreter-exec console \"set scheduler-locking ${opt}\"" \ + ".*=cmd-param-changed,param=\"scheduler-locking\",value=\"${opt}\".*\\^done" \ + "interpreter-exec \"set scheduler-locking ${opt}\"" + } + # Don't emit MI notification for request from MI. + mi_gdb_test "-gdb-set scheduler-locking on" \ + {\^done} \ + "\"set scheduler-locking on\" no event (requested by MI)" + + mi_gdb_test "interpreter-exec mi \"-gdb-set scheduler-locking step\"" \ + "\\&\"interpreter-exec mi .*\"-gdb-set scheduler-locking step.*\"\\\\n\"\r\n\\^done\r\n\\^done" \ + "\"set scheduler-locking step\" no event (requested by MI interp)" + mi_gdb_test "set scheduler-locking step" \ + "\\&\"set scheduler-locking step\\\\n\"\r\n\\^done" \ + "\"set scheduler-locking stepr\" no event" + + + foreach command { "circular-trace-buffer" "check type" } { + + # The default value of each command option may be different, so we first + # set it to 'off', and this may or may not trigger MI notification. + mi_gdb_test "set ${command} off" ".*\\^done" "\"set ${command}\" warmup" + + foreach boolean_opt { "on" "off" } { + mi_gdb_test "set ${command} ${boolean_opt}" \ + ".*=cmd-param-changed,param=\"${command}\",value=\"${boolean_opt}\".*\\^done" \ + "\"set ${command} ${boolean_opt}\"" + } + mi_gdb_test "set ${command} off" \ + "\\&\"set ${command} off\\\\n\"\r\n\\^done" \ + "\"set ${command}\" no event" + } + + + foreach command { "trace-notes" "remote exec-file" } { + foreach str_opt { "foo" "bar" } { + mi_gdb_test "set ${command} ${str_opt}" \ + ".*=cmd-param-changed,param=\"${command}\",value=\"${str_opt}\".*\\^done" \ + "\"set ${command} ${str_opt}\"" + } + mi_gdb_test "set ${command} bar" \ + "\\&\"set ${command} bar\\\\n\"\r\n(\\&\"warning.*|)\\^done" \ + "\"set ${command} bar\" no event" + } + + # No notification is emitted for 'maint set' commands. + foreach command { "profile" "show-debug-regs" } { + foreach boolean_opt { "on" "off" } { + mi_gdb_test "maint set ${command} ${boolean_opt}" \ + "\\&\"maint set ${command} ${boolean_opt}\\\\n\"\r\n\\^done" \ + "\"maint set ${command} ${boolean_opt}\"" + } + } + + # Full command parameters are included in the notification when a + # abbreviated one is typed. + mi_gdb_test "set ch type on" \ + ".*=cmd-param-changed,param=\"check type\",value=\"on\".*\\^done" \ + "\"set ch type on\"" + + mi_gdb_exit +}} + +test_command_param_changed + +return 0 diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.exp b/gdb/testsuite/gdb.mi/mi-var-rtti.exp index a718ffb..dc2f922 100644 --- a/gdb/testsuite/gdb.mi/mi-var-rtti.exp +++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp @@ -37,7 +37,7 @@ mi_prepare_inline_tests $srcfile # Enable using RTTI to determine real types of the objects proc set_print_object {state testname} { mi_gdb_test "-interpreter-exec console \"set print object ${state}\"" \ - {\^done} \ + "(.*=cmd-param-changed,param=\"print object\",value=\"${state}\".*|)\\^done" \ "-interpreter-exec console \"set print object ${state}\" in $testname" } diff --git a/gdb/testsuite/gdb.mi/mi2-cli.exp b/gdb/testsuite/gdb.mi/mi2-cli.exp index e84b191..9ab7518 100644 --- a/gdb/testsuite/gdb.mi/mi2-cli.exp +++ b/gdb/testsuite/gdb.mi/mi2-cli.exp @@ -69,7 +69,7 @@ set line_callee4_head [gdb_get_line_number "callee4 ("] set line_callee4_body [expr $line_callee4_head + 2] mi_gdb_test "-interpreter-exec console \"set args foobar\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"args\",value=\"foobar\".*\\^done" \ "-interpreter-exec console \"set args foobar\"" mi_gdb_test "-interpreter-exec console \"show args\"" \ @@ -89,7 +89,7 @@ mi_gdb_test "-interpreter-exec console \"info break\"" \ "-interpreter-exec console \"info break\"" mi_gdb_test "-interpreter-exec console \"set listsize 1\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"listsize\",value=\"1\".*\\^done" \ "-interpreter-exec console \"set listsize 1\"" # {.*\~"32[ \t(\\t)]*callee1.*\\n".*\^done } diff --git a/gdb/testsuite/gdb.mi/mi2-prompt.exp b/gdb/testsuite/gdb.mi/mi2-prompt.exp index 6145c38..eb9edec 100644 --- a/gdb/testsuite/gdb.mi/mi2-prompt.exp +++ b/gdb/testsuite/gdb.mi/mi2-prompt.exp @@ -23,8 +23,9 @@ if [mi_gdb_start] { # Check console 'set prompt' does not affect the MI output. -mi_gdb_test {-interpreter-exec console "set prompt (banana) "} {\^done} \ - "console set prompt" +mi_gdb_test {-interpreter-exec console "set prompt (banana) "} \ + ".*=cmd-param-changed,param=\"prompt\",value=\"\\(banana\\) \".*\\^done" \ + "console set prompt" mi_gdb_test "-break-list" ".*}" "-break-list" gdb_exit -- 1.7.7.6 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] test case 2012-08-06 15:48 ` Yao Qi @ 2012-08-06 20:21 ` Tom Tromey 0 siblings, 0 replies; 15+ messages in thread From: Tom Tromey @ 2012-08-06 20:21 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> Right, a test for a abbreviated multi-word is added. Yao> 2012-08-06 Yao Qi <yao@codesourcery.com> Yao> * gdb.mi/mi-cmd-param-changed.exp: New. Yao> * gdb.mi/mi-cli.exp: Update for MI notification "=cmd-param-changed". Yao> * gdb.mi/mi-var-rtti.exp, gdb.mi/mi2-cli.exp: Likewise. Yao> * gdb.mi/mi2-prompt.exp: Likewise. This version is ok. Thanks. Tom ^ permalink raw reply [flat|nested] 15+ messages in thread
* [committed]: [RCF 0/3 V3] MI notification of command parameter change 2012-08-03 11:22 [RCF 0/3 V3] MI notification of command parameter change Yao Qi ` (2 preceding siblings ...) 2012-08-03 11:22 ` [PATCH 3/3] test case Yao Qi @ 2012-08-10 0:57 ` Yao Qi 3 siblings, 0 replies; 15+ messages in thread From: Yao Qi @ 2012-08-10 0:57 UTC (permalink / raw) To: gdb-patches On Friday, August 03, 2012 07:21:41 PM Yao Qi wrote: > Hi, > This is the V3, and V2 can be found here, > > [RCF 0/6 V2] MI notification of command option change > http://sourceware.org/ml/gdb-patches/2012-07/msg00689.html > > In this version, GDB will emit MI notification for all 'set' > commands (except 'maint set' commands). The difference of V3 > is described in each patch. Code indentatoin patch is not > posted, as I think it is obvious if this series is approved. > > Regression tested on x86_64-linux. This is what I committed, with the indentation fix. -- Yao (齐尧) gdb: 2012-08-09 Yao Qi <yao@codesourcery.com> * cli/cli-decode.c (set_cmd_prefix): New. (lookup_cmd_for_prefixlist): New. (add_prefix_cmd): Call set_cmd_prefix and update field 'prefix' of each cmd_list_element in *prefixlist. (add_setshow_cmd_full): set_cmd_prefix. (add_alias_cmd): Likewise. * cli/cli-decode.h (struct cmd_list_element) <prefix>: New field. Declare 'auto_boolean_enums'. * cli/cli-setshow.c: Include "observer.h". (notify_command_param_changed_p): New. (add_setshow_auto_boolean_cmd): Move auto_boolean_enums out. Remove 'static'. (do_setshow_command): Split it to ... (do_set_command, do_show_command): ... them. New. (do_set_command): Call observer_notify_command_param_changed if notify_command_param_changed_p returns true. (cmd_show_list): Caller update. * auto-load.c (set_auto_load_cmd): Likewise. * remote.c (show_remote_cmd): Likewise. * cli/cli-setshow.h: Update declarations. * top.c (execute_command): Call do_set_command and do_show_command. * NEWS: Mention new MI notification. * mi/mi-interp.c: Declare mi_command_param_changed. (mi_interpreter_init): Attach mi_command_param_changed to observer command_param_changed. (mi_command_param_changed): New. Remove mi_suppress_breakpoint_notifications. Define global variable mi_suppress_notification. (mi_breakpoint_created): Update. (mi_breakpoint_deleted): Likewise. (mi_breakpoint_modified): Likewise. * mi/mi-main.c (mi_cmd_execute): Likewise. Check command 'gdb-set' and set mi_suppress_notification. * mi/mi-main.h: (mi_suppress_notification): New struct. gdb/doc: 2012-08-09 Yao Qi <yao@codesourcery.com> * observer.texi: New observer command_param_changed. * gdb.texinfo (GDB/MI Async Records): Doc for '=cmd-param-changed'. gdb/testsuite: 2012-08-09 Yao Qi <yao@codesourcery.com> * gdb.mi/mi-cmd-param-changed.exp: New. * gdb.mi/mi-cli.exp: Update for MI notification "=cmd-param-changed". * gdb.mi/mi-var-rtti.exp, gdb.mi/mi2-cli.exp: Likewise. * gdb.mi/mi2-prompt.exp: Likewise. --- gdb/NEWS | 5 + gdb/auto-load.c | 2 +- gdb/cli/cli-decode.c | 67 +++- gdb/cli/cli-decode.h | 4 + gdb/cli/cli-setshow.c | 615 ++++++++++++++++--------- gdb/cli/cli-setshow.h | 10 +- gdb/doc/gdb.texinfo | 6 + gdb/doc/observer.texi | 8 + gdb/mi/mi-interp.c | 44 ++- gdb/mi/mi-main.c | 11 +- gdb/mi/mi-main.h | 10 +- gdb/remote.c | 2 +- gdb/testsuite/gdb.mi/mi-cli.exp | 4 +- gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp | 103 ++++ gdb/testsuite/gdb.mi/mi-var-rtti.exp | 2 +- gdb/testsuite/gdb.mi/mi2-cli.exp | 4 +- gdb/testsuite/gdb.mi/mi2-prompt.exp | 5 +- gdb/top.c | 6 +- 18 files changed, 671 insertions(+), 237 deletions(-) create mode 100644 gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp diff --git a/gdb/NEWS b/gdb/NEWS index 06df79e..d693e64 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -20,6 +20,11 @@ maint info bfds List the BFDs known to GDB. +* MI changes + + ** Command parameter changes are now notified using new async record + "=cmd-param-changed". + *** Changes in GDB 7.5 * GDB now supports x32 ABI. Visit <http://sites.google.com/site/x32abi/> diff --git a/gdb/auto-load.c b/gdb/auto-load.c index 2cc52c6..03a7539 100644 --- a/gdb/auto-load.c +++ b/gdb/auto-load.c @@ -1022,7 +1022,7 @@ set_auto_load_cmd (char *args, int from_tty) if (list->var_type == var_boolean) { gdb_assert (list->type == set_cmd); - do_setshow_command (args, from_tty, list); + do_set_command (args, from_tty, list); } } diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index c337b43..3c2e152 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -52,6 +52,53 @@ static struct cmd_list_element *find_cmd (char *command, static void help_all (struct ui_file *stream); +/* Look up a command whose 'prefixlist' is KEY. Return the command if found, + otherwise return NULL. */ + +static struct cmd_list_element * +lookup_cmd_for_prefixlist (struct cmd_list_element **key, + struct cmd_list_element *list) +{ + struct cmd_list_element *p = NULL; + + for (p = list; p != NULL; p = p->next) + { + struct cmd_list_element *q; + + if (p->prefixlist == NULL) + continue; + else if (p->prefixlist == key) + return p; + + q = lookup_cmd_for_prefixlist (key, *(p->prefixlist)); + if (q != NULL) + return q; + } + + return NULL; +} + +static void +set_cmd_prefix (struct cmd_list_element *c, struct cmd_list_element **list) +{ + struct cmd_list_element *p; + + /* Check to see if *LIST contains any element other than C. */ + for (p = *list; p != NULL; p = p->next) + if (p != c) + break; + + if (p == NULL) + { + /* *SET_LIST only contains SET. */ + p = lookup_cmd_for_prefixlist (list, setlist); + + c->prefix = p ? (p->cmd_pointer ? p->cmd_pointer : p) : p; + } + else + c->prefix = p->prefix; +} + static void print_help_for_command (struct cmd_list_element *c, char *prefix, int recurse, struct ui_file *stream); @@ -193,6 +240,7 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int), c->prefixlist = NULL; c->prefixname = NULL; c->allow_unknown = 0; + c->prefix = NULL; c->abbrev_flag = 0; set_cmd_completer (c, make_symbol_completion_list_fn); c->destroyer = NULL; @@ -268,6 +316,8 @@ add_alias_cmd (char *name, char *oldname, enum command_class class, c->cmd_pointer = old; c->alias_chain = old->aliases; old->aliases = c; + + set_cmd_prefix (c, list); return c; } @@ -284,10 +334,21 @@ add_prefix_cmd (char *name, enum command_class class, struct cmd_list_element **list) { struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + struct cmd_list_element *p; c->prefixlist = prefixlist; c->prefixname = prefixname; c->allow_unknown = allow_unknown; + + if (list == &cmdlist) + c->prefix = NULL; + else + set_cmd_prefix (c, list); + + /* Update the field 'prefix' of each cmd_list_element in *PREFIXLIST. */ + for (p = *prefixlist; p != NULL; p = p->next) + p->prefix = c; + return c; } @@ -392,6 +453,9 @@ add_setshow_cmd_full (char *name, full_set_doc, set_list); if (set_func != NULL) set_cmd_sfunc (set, set_func); + + set_cmd_prefix (set, set_list); + show = add_set_or_show_cmd (name, show_cmd, class, var_type, var, full_show_doc, show_list); show->show_value_func = show_func; @@ -430,6 +494,8 @@ add_setshow_enum_cmd (char *name, c->enums = enumlist; } +const char * const auto_boolean_enums[] = { "on", "off", "auto", NULL }; + /* Add an auto-boolean command named NAME to both the set and show command list lists. CLASS is as in add_cmd. VAR is address of the variable which will contain the value. DOC is the documentation @@ -445,7 +511,6 @@ add_setshow_auto_boolean_cmd (char *name, struct cmd_list_element **set_list, struct cmd_list_element **show_list) { - static const char *auto_boolean_enums[] = { "on", "off", "auto", NULL }; struct cmd_list_element *c; add_setshow_cmd_full (name, class, var_auto_boolean, var, diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h index b5e0790..edae6e8 100644 --- a/gdb/cli/cli-decode.h +++ b/gdb/cli/cli-decode.h @@ -149,6 +149,9 @@ struct cmd_list_element recognized; call the prefix's own function in that case. */ char allow_unknown; + /* The prefix command of this command. */ + struct cmd_list_element *prefix; + /* Nonzero says this is an abbreviation, and should not be mentioned in lists of commands. This allows "br<tab>" to complete to "break", which it @@ -232,5 +235,6 @@ extern void not_just_help_class_command (char *arg, int from_tty); extern void print_doc_line (struct ui_file *, char *); +extern const char * const auto_boolean_enums[]; #endif /* !defined (CLI_DECODE_H) */ diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c index 7ffb89e..89e095a 100644 --- a/gdb/cli/cli-setshow.c +++ b/gdb/cli/cli-setshow.c @@ -21,6 +21,7 @@ #include <ctype.h> #include "gdb_string.h" #include "arch-utils.h" +#include "observer.h" #include "ui-out.h" @@ -32,6 +33,21 @@ static int parse_binary_operation (char *); +/* Return true if the change of command parameter should be notified. */ + +static int +notify_command_param_changed_p (int param_changed, struct cmd_list_element *c) +{ + if (param_changed == 0) + return 0; + + if (c->class == class_maintenance || c->class == class_deprecated + || c->class == class_obscure) + return 0; + + return 1; +} + \f static enum auto_boolean parse_auto_binary_operation (const char *arg) @@ -116,283 +132,462 @@ deprecated_show_value_hack (struct ui_file *ignore_file, } } -/* Do a "set" or "show" command. ARG is NULL if no argument, or the +/* Do a "set" command. ARG is NULL if no argument, or the text of the argument, and FROM_TTY is nonzero if this command is being entered directly by the user (i.e. these are just like any other command). C is the command list element for the command. */ void -do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) +do_set_command (char *arg, int from_tty, struct cmd_list_element *c) { - struct ui_out *uiout = current_uiout; + /* A flag to indicate the option is changed or not. */ + int option_changed = 0; + + gdb_assert (c->type == set_cmd); - if (c->type == set_cmd) + switch (c->var_type) { - switch (c->var_type) - { - case var_string: + case var_string: + { + char *new; + char *p; + char *q; + int ch; + + if (arg == NULL) + arg = ""; + new = (char *) xmalloc (strlen (arg) + 2); + p = arg; + q = new; + while ((ch = *p++) != '\000') { - char *new; - char *p; - char *q; - int ch; - - if (arg == NULL) - arg = ""; - new = (char *) xmalloc (strlen (arg) + 2); - p = arg; - q = new; - while ((ch = *p++) != '\000') + if (ch == '\\') { - if (ch == '\\') - { - /* \ at end of argument is used after spaces - so they won't be lost. */ - /* This is obsolete now that we no longer strip - trailing whitespace and actually, the backslash - didn't get here in my test, readline or - something did something funky with a backslash - right before a newline. */ - if (*p == 0) - break; - ch = parse_escape (get_current_arch (), &p); - if (ch == 0) - break; /* C loses */ - else if (ch > 0) - *q++ = ch; - } - else + /* \ at end of argument is used after spaces + so they won't be lost. */ + /* This is obsolete now that we no longer strip + trailing whitespace and actually, the backslash + didn't get here in my test, readline or + something did something funky with a backslash + right before a newline. */ + if (*p == 0) + break; + ch = parse_escape (get_current_arch (), &p); + if (ch == 0) + break; /* C loses */ + else if (ch > 0) *q++ = ch; } + else + *q++ = ch; + } #if 0 - if (*(p - 1) != '\\') - *q++ = ' '; + if (*(p - 1) != '\\') + *q++ = ' '; #endif - *q++ = '\0'; - new = (char *) xrealloc (new, q - new); + *q++ = '\0'; + new = (char *) xrealloc (new, q - new); + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, new) != 0) + { xfree (*(char **) c->var); *(char **) c->var = new; + + option_changed = 1; } - break; - case var_string_noescape: - if (arg == NULL) - arg = ""; + else + xfree (new); + } + break; + case var_string_noescape: + if (arg == NULL) + arg = ""; + + if (*(char **) c->var == NULL || strcmp (*(char **) c->var, arg) != 0) + { xfree (*(char **) c->var); *(char **) c->var = xstrdup (arg); - break; - case var_filename: - if (arg == NULL) - error_no_arg (_("filename to set it to.")); - /* FALLTHROUGH */ - case var_optional_filename: - xfree (*(char **) c->var); - if (arg != NULL) - { - /* Clear trailing whitespace of filename. */ - char *ptr = arg + strlen (arg) - 1; + option_changed = 1; + } + break; + case var_filename: + if (arg == NULL) + error_no_arg (_("filename to set it to.")); + /* FALLTHROUGH */ + case var_optional_filename: + { + char *val = NULL; - while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) - ptr--; - *(ptr + 1) = '\0'; + if (arg != NULL) + { + /* Clear trailing whitespace of filename. */ + char *ptr = arg + strlen (arg) - 1; - *(char **) c->var = tilde_expand (arg); - } - else - *(char **) c->var = xstrdup (""); - break; - case var_boolean: - *(int *) c->var = parse_binary_operation (arg); - break; - case var_auto_boolean: - *(enum auto_boolean *) c->var = parse_auto_binary_operation (arg); - break; - case var_uinteger: - case var_zuinteger: - if (arg == NULL) - error_no_arg (_("integer to set it to.")); - *(unsigned int *) c->var = parse_and_eval_long (arg); - if (c->var_type == var_uinteger && *(unsigned int *) c->var == 0) - *(unsigned int *) c->var = UINT_MAX; - break; - case var_integer: - case var_zinteger: + while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) + ptr--; + *(ptr + 1) = '\0'; + + val = tilde_expand (arg); + } + else + val = xstrdup (""); + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, val) != 0) { - unsigned int val; - - if (arg == NULL) - error_no_arg (_("integer to set it to.")); - val = parse_and_eval_long (arg); - if (val == 0 && c->var_type == var_integer) - *(int *) c->var = INT_MAX; - else if (val >= INT_MAX) - error (_("integer %u out of range"), val); - else - *(int *) c->var = val; - break; + xfree (*(char **) c->var); + *(char **) c->var = val; + + option_changed = 1; } - case var_enum: + else + xfree (val); + } + break; + case var_boolean: + { + int val = parse_binary_operation (arg); + + if (val != *(int *) c->var) + { + *(int *) c->var = val; + + option_changed = 1; + } + } + break; + case var_auto_boolean: + { + enum auto_boolean val = parse_auto_binary_operation (arg); + + if (*(enum auto_boolean *) c->var != val) + { + *(enum auto_boolean *) c->var = val; + + option_changed = 1; + } + } + break; + case var_uinteger: + case var_zuinteger: + if (arg == NULL) + error_no_arg (_("integer to set it to.")); + { + unsigned int val = parse_and_eval_long (arg); + + if (c->var_type == var_uinteger && val == 0) + val = UINT_MAX; + + if (*(unsigned int *) c->var != val) + { + *(unsigned int *) c->var = val; + + option_changed = 1; + } + } + break; + case var_integer: + case var_zinteger: + { + unsigned int val; + + if (arg == NULL) + error_no_arg (_("integer to set it to.")); + val = parse_and_eval_long (arg); + if (val == 0 && c->var_type == var_integer) + val = INT_MAX; + else if (val >= INT_MAX) + error (_("integer %u out of range"), val); + + if (*(int *) c->var != val) { - int i; - int len; - int nmatches; - const char *match = NULL; - char *p; - - /* If no argument was supplied, print an informative error - message. */ - if (arg == NULL) + *(int *) c->var = val; + + option_changed = 1; + } + break; + } + case var_enum: + { + int i; + int len; + int nmatches; + const char *match = NULL; + char *p; + + /* If no argument was supplied, print an informative error + message. */ + if (arg == NULL) + { + char *msg; + int msg_len = 0; + + for (i = 0; c->enums[i]; i++) + msg_len += strlen (c->enums[i]) + 2; + + msg = xmalloc (msg_len); + *msg = '\0'; + make_cleanup (xfree, msg); + + for (i = 0; c->enums[i]; i++) { - char *msg; - int msg_len = 0; - - for (i = 0; c->enums[i]; i++) - msg_len += strlen (c->enums[i]) + 2; - - msg = xmalloc (msg_len); - *msg = '\0'; - make_cleanup (xfree, msg); - - for (i = 0; c->enums[i]; i++) - { - if (i != 0) - strcat (msg, ", "); - strcat (msg, c->enums[i]); - } - error (_("Requires an argument. Valid arguments are %s."), - msg); + if (i != 0) + strcat (msg, ", "); + strcat (msg, c->enums[i]); } + error (_("Requires an argument. Valid arguments are %s."), + msg); + } - p = strchr (arg, ' '); + p = strchr (arg, ' '); - if (p) - len = p - arg; - else - len = strlen (arg); + if (p) + len = p - arg; + else + len = strlen (arg); - nmatches = 0; - for (i = 0; c->enums[i]; i++) - if (strncmp (arg, c->enums[i], len) == 0) + nmatches = 0; + for (i = 0; c->enums[i]; i++) + if (strncmp (arg, c->enums[i], len) == 0) + { + if (c->enums[i][len] == '\0') + { + match = c->enums[i]; + nmatches = 1; + break; /* Exact match. */ + } + else { - if (c->enums[i][len] == '\0') - { - match = c->enums[i]; - nmatches = 1; - break; /* Exact match. */ - } - else - { - match = c->enums[i]; - nmatches++; - } + match = c->enums[i]; + nmatches++; } + } - if (nmatches <= 0) - error (_("Undefined item: \"%s\"."), arg); + if (nmatches <= 0) + error (_("Undefined item: \"%s\"."), arg); - if (nmatches > 1) - error (_("Ambiguous item \"%s\"."), arg); + if (nmatches > 1) + error (_("Ambiguous item \"%s\"."), arg); + if (*(const char **) c->var != match) + { *(const char **) c->var = match; + + option_changed = 1; } - break; - default: - error (_("gdb internal error: bad var_type in do_setshow_command")); - } + } + break; + default: + error (_("gdb internal error: bad var_type in do_setshow_command")); } - else if (c->type == show_cmd) + c->func (c, NULL, from_tty); + if (deprecated_set_hook) + deprecated_set_hook (c); + + if (notify_command_param_changed_p (option_changed, c)) { - struct cleanup *old_chain; - struct ui_file *stb; + char *name, *cp; + struct cmd_list_element **cmds; + struct cmd_list_element *p; + int i; + int length = 0; + + /* Compute the whole multi-word command options. If user types command + 'set foo bar baz on', c->name is 'baz', and GDB can't pass "bar" to + command option change notification, because it is confusing. We can + trace back through field 'prefix' to compute the whole options, + and pass "foo bar baz" to notification. */ + + for (i = 0, p = c; p != NULL; i++) + { + length += strlen (p->name); + length++; + + p = p->prefix; + } + cp = name = xmalloc (length); + cmds = xmalloc (sizeof (struct cmd_list_element *) * i); + + /* Track back through filed 'prefix' and cache them in CMDS. */ + for (i = 0, p = c; p != NULL; i++) + { + cmds[i] = p; + p = p->prefix; + } + + /* Don't trigger any observer notification if prefixlist is not + setlist. */ + i--; + if (cmds[i]->prefixlist != &setlist) + { + xfree (cmds); + xfree (name); + + return; + } + /* Traverse them in the reversed order, and copy their names into + NAME. */ + for (i--; i >= 0; i--) + { + memcpy (cp, cmds[i]->name, strlen (cmds[i]->name)); + cp += strlen (cmds[i]->name); - stb = mem_fileopen (); - old_chain = make_cleanup_ui_file_delete (stb); + if (i != 0) + { + cp[0] = ' '; + cp++; + } + } + cp[0] = 0; - /* Possibly call the pre hook. */ - if (c->pre_show_hook) - (c->pre_show_hook) (c); + xfree (cmds); switch (c->var_type) { case var_string: - if (*(char **) c->var) - fputstr_filtered (*(char **) c->var, '"', stb); - break; case var_string_noescape: - case var_optional_filename: case var_filename: + case var_optional_filename: case var_enum: - if (*(char **) c->var) - fputs_filtered (*(char **) c->var, stb); + observer_notify_command_param_changed (name, *(char **) c->var); break; case var_boolean: - fputs_filtered (*(int *) c->var ? "on" : "off", stb); + { + char *opt = *(int *) c->var ? "on" : "off"; + + observer_notify_command_param_changed (name, opt); + } break; case var_auto_boolean: - switch (*(enum auto_boolean*) c->var) - { - case AUTO_BOOLEAN_TRUE: - fputs_filtered ("on", stb); - break; - case AUTO_BOOLEAN_FALSE: - fputs_filtered ("off", stb); - break; - case AUTO_BOOLEAN_AUTO: - fputs_filtered ("auto", stb); - break; - default: - internal_error (__FILE__, __LINE__, - _("do_setshow_command: " - "invalid var_auto_boolean")); - break; - } + { + const char *s = auto_boolean_enums[*(enum auto_boolean *) c->var]; + + observer_notify_command_param_changed (name, s); + } break; case var_uinteger: case var_zuinteger: - if (c->var_type == var_uinteger - && *(unsigned int *) c->var == UINT_MAX) - fputs_filtered ("unlimited", stb); - else - fprintf_filtered (stb, "%u", *(unsigned int *) c->var); + { + char s[64]; + + xsnprintf (s, sizeof s, "%u", *(unsigned int *) c->var); + observer_notify_command_param_changed (name, s); + } break; case var_integer: case var_zinteger: - if (c->var_type == var_integer - && *(int *) c->var == INT_MAX) - fputs_filtered ("unlimited", stb); - else - fprintf_filtered (stb, "%d", *(int *) c->var); - break; + { + char s[64]; - default: - error (_("gdb internal error: bad var_type in do_setshow_command")); + xsnprintf (s, sizeof s, "%d", *(int *) c->var); + observer_notify_command_param_changed (name, s); + } + break; } + xfree (name); + } +} +/* Do a "show" command. ARG is NULL if no argument, or the + text of the argument, and FROM_TTY is nonzero if this command is + being entered directly by the user (i.e. these are just like any + other command). C is the command list element for the command. */ - /* FIXME: cagney/2005-02-10: Need to split this in half: code to - convert the value into a string (esentially the above); and - code to print the value out. For the latter there should be - MI and CLI specific versions. */ +void +do_show_command (char *arg, int from_tty, struct cmd_list_element *c) +{ + struct ui_out *uiout = current_uiout; + struct cleanup *old_chain; + struct ui_file *stb; - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_stream (uiout, "value", stb); - else - { - char *value = ui_file_xstrdup (stb, NULL); + gdb_assert (c->type == show_cmd); + + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); - make_cleanup (xfree, value); - if (c->show_value_func != NULL) - c->show_value_func (gdb_stdout, from_tty, c, value); - else - deprecated_show_value_hack (gdb_stdout, from_tty, c, value); + /* Possibly call the pre hook. */ + if (c->pre_show_hook) + (c->pre_show_hook) (c); + + switch (c->var_type) + { + case var_string: + if (*(char **) c->var) + fputstr_filtered (*(char **) c->var, '"', stb); + break; + case var_string_noescape: + case var_optional_filename: + case var_filename: + case var_enum: + if (*(char **) c->var) + fputs_filtered (*(char **) c->var, stb); + break; + case var_boolean: + fputs_filtered (*(int *) c->var ? "on" : "off", stb); + break; + case var_auto_boolean: + switch (*(enum auto_boolean*) c->var) + { + case AUTO_BOOLEAN_TRUE: + fputs_filtered ("on", stb); + break; + case AUTO_BOOLEAN_FALSE: + fputs_filtered ("off", stb); + break; + case AUTO_BOOLEAN_AUTO: + fputs_filtered ("auto", stb); + break; + default: + internal_error (__FILE__, __LINE__, + _("do_show_command: " + "invalid var_auto_boolean")); + break; } - do_cleanups (old_chain); + break; + case var_uinteger: + case var_zuinteger: + if (c->var_type == var_uinteger + && *(unsigned int *) c->var == UINT_MAX) + fputs_filtered ("unlimited", stb); + else + fprintf_filtered (stb, "%u", *(unsigned int *) c->var); + break; + case var_integer: + case var_zinteger: + if (c->var_type == var_integer + && *(int *) c->var == INT_MAX) + fputs_filtered ("unlimited", stb); + else + fprintf_filtered (stb, "%d", *(int *) c->var); + break; + + default: + error (_("gdb internal error: bad var_type in do_show_command")); } + + + /* FIXME: cagney/2005-02-10: Need to split this in half: code to + convert the value into a string (esentially the above); and + code to print the value out. For the latter there should be + MI and CLI specific versions. */ + + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_stream (uiout, "value", stb); else - error (_("gdb internal error: bad cmd_type in do_setshow_command")); + { + char *value = ui_file_xstrdup (stb, NULL); + + make_cleanup (xfree, value); + if (c->show_value_func != NULL) + c->show_value_func (gdb_stdout, from_tty, c, value); + else + deprecated_show_value_hack (gdb_stdout, from_tty, c, value); + } + do_cleanups (old_chain); + c->func (c, NULL, from_tty); - if (c->type == set_cmd && deprecated_set_hook) - deprecated_set_hook (c); } /* Show all the settings in a list of show commands. */ @@ -431,7 +626,7 @@ cmd_show_list (struct cmd_list_element *list, int from_tty, char *prefix) ui_out_field_string (uiout, "name", list->name); ui_out_text (uiout, ": "); if (list->type == show_cmd) - do_setshow_command ((char *) NULL, from_tty, list); + do_show_command ((char *) NULL, from_tty, list); else cmd_func (list, NULL, from_tty); /* Close the tuple. */ diff --git a/gdb/cli/cli-setshow.h b/gdb/cli/cli-setshow.h index cb8d2c5..ffe9abd 100644 --- a/gdb/cli/cli-setshow.h +++ b/gdb/cli/cli-setshow.h @@ -21,12 +21,10 @@ struct cmd_list_element; /* Exported to cli/cli-cmds.c and gdb/top.c */ -/* Do a "set" or "show" command. ARG is NULL if no argument, or the - text of the argument, and FROM_TTY is nonzero if this command is - being entered directly by the user (i.e. these are just like any - other command). C is the command list element for the command. */ -extern void do_setshow_command (char *arg, int from_tty, - struct cmd_list_element *c); +extern void do_set_command (char *arg, int from_tty, + struct cmd_list_element *c); +extern void do_show_command (char *arg, int from_tty, + struct cmd_list_element *c); /* Exported to cli/cli-cmds.c and gdb/top.c, language.c and valprint.c */ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 4e0342a..a03532e 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -27620,6 +27620,12 @@ breakpoint commands; @xref{GDB/MI Breakpoint Commands}. The Note that if a breakpoint is emitted in the result record of a command, then it will not also be emitted in an async record. +@item =cmd-param-changed,param=@var{param},value=@var{value} +Reports that a parameter of the command @code{set @var{param}} is +changed to @var{value}. In the multi-word @code{set} command, +the @var{param} is the whole parameter list to @code{set} command. +For example, In command @code{set check type on}, @var{param} +is @code{check type} and @var{value} is @code{on}. @end table @node GDB/MI Frame Information diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi index 14d4ac3..bf84820 100644 --- a/gdb/doc/observer.texi +++ b/gdb/doc/observer.texi @@ -234,6 +234,14 @@ the current top-level prompt. Variable gdb_datadir has been set. The value may not necessarily change. @end deftypefun +@deftypefun void command_param_changed (const char *@var{param}, const char *@var{value}) +The parameter of some @code{set} commands in console are changed. This +method is called after a command @code{set @var{param} @var{value}}. +@var{param} is the parameter of @code{set} command, and @var{value} +is the value of changed parameter. + +@end deftypefun + @deftypefun void test_notification (int @var{somearg}) This observer is used for internal testing. Do not use. See testsuite/gdb.gdb/observer.exp. diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index b487136..94df818 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -71,6 +71,7 @@ static void mi_about_to_proceed (void); static void mi_breakpoint_created (struct breakpoint *b); static void mi_breakpoint_deleted (struct breakpoint *b); static void mi_breakpoint_modified (struct breakpoint *b); +static void mi_command_param_changed (const char *param, const char *value); static int report_initial_inferior (struct inferior *inf, void *closure); @@ -128,6 +129,7 @@ mi_interpreter_init (struct interp *interp, int top_level) observer_attach_breakpoint_created (mi_breakpoint_created); observer_attach_breakpoint_deleted (mi_breakpoint_deleted); observer_attach_breakpoint_modified (mi_breakpoint_modified); + observer_attach_command_param_changed (mi_command_param_changed); /* The initial inferior is created before this function is called, so we need to report it explicitly. Use iteration in @@ -501,10 +503,14 @@ mi_about_to_proceed (void) mi_proceeded = 1; } -/* When non-zero, no MI notifications will be emitted in - response to breakpoint change observers. */ +/* When the element is non-zero, no MI notifications will be emitted in + response to the corresponding observers. */ -int mi_suppress_breakpoint_notifications = 0; +struct mi_suppress_notification mi_suppress_notification = + { + 0, + 0, + }; /* Emit notification about a created breakpoint. */ @@ -515,7 +521,7 @@ mi_breakpoint_created (struct breakpoint *b) struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); volatile struct gdb_exception e; - if (mi_suppress_breakpoint_notifications) + if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) @@ -546,7 +552,7 @@ mi_breakpoint_deleted (struct breakpoint *b) { struct mi_interp *mi = top_level_interpreter_data (); - if (mi_suppress_breakpoint_notifications) + if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) @@ -569,7 +575,7 @@ mi_breakpoint_modified (struct breakpoint *b) struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); volatile struct gdb_exception e; - if (mi_suppress_breakpoint_notifications) + if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) @@ -730,6 +736,32 @@ mi_solib_unloaded (struct so_list *solib) gdb_flush (mi->event_channel); } +/* Emit notification about the command parameter change. */ + +static void +mi_command_param_changed (const char *param, const char *value) +{ + struct mi_interp *mi = top_level_interpreter_data (); + struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); + + if (mi_suppress_notification.cmd_param_changed) + return; + + target_terminal_ours (); + + fprintf_unfiltered (mi->event_channel, + "cmd-param-changed"); + + ui_out_redirect (mi_uiout, mi->event_channel); + + ui_out_field_string (mi_uiout, "param", param); + ui_out_field_string (mi_uiout, "value", value); + + ui_out_redirect (mi_uiout, NULL); + + gdb_flush (mi->event_channel); +} + static int report_initial_inferior (struct inferior *inf, void *closure) { diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index dfb4892..4db3652 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -2099,8 +2099,15 @@ mi_cmd_execute (struct mi_parse *parse) if (strncmp (parse->command, "break-", sizeof ("break-") - 1 ) == 0) { - make_cleanup_restore_integer (&mi_suppress_breakpoint_notifications); - mi_suppress_breakpoint_notifications = 1; + make_cleanup_restore_integer (&mi_suppress_notification.breakpoint); + mi_suppress_notification.breakpoint = 1; + } + else if (strncmp (parse->command, "gdb-set", sizeof ("gdb-set") - 1) == 0) + { + int *p = &mi_suppress_notification.cmd_param_changed; + + make_cleanup_restore_integer (p); + mi_suppress_notification.cmd_param_changed = 1; } if (parse->cmd->argv_func != NULL) diff --git a/gdb/mi/mi-main.h b/gdb/mi/mi-main.h index beac2cd..f4268c2 100644 --- a/gdb/mi/mi-main.h +++ b/gdb/mi/mi-main.h @@ -32,7 +32,15 @@ extern char *current_token; extern int running_result_record_printed; extern int mi_proceeded; -extern int mi_suppress_breakpoint_notifications; + +struct mi_suppress_notification +{ + /* Breakpoint notification suppressed? */ + int breakpoint; + /* Command param changed notification suppressed? */ + int cmd_param_changed; +}; +extern struct mi_suppress_notification mi_suppress_notification; #endif diff --git a/gdb/remote.c b/gdb/remote.c index fa514dc..87b8921 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -11270,7 +11270,7 @@ show_remote_cmd (char *args, int from_tty) ui_out_field_string (uiout, "name", list->name); ui_out_text (uiout, ": "); if (list->type == show_cmd) - do_setshow_command ((char *) NULL, from_tty, list); + do_show_command ((char *) NULL, from_tty, list); else cmd_func (list, NULL, from_tty); /* Close the tuple. */ diff --git a/gdb/testsuite/gdb.mi/mi-cli.exp b/gdb/testsuite/gdb.mi/mi-cli.exp index b7abbc7..f487cbd 100644 --- a/gdb/testsuite/gdb.mi/mi-cli.exp +++ b/gdb/testsuite/gdb.mi/mi-cli.exp @@ -70,7 +70,7 @@ set line_callee4_body [expr $line_callee4_head + 2] set line_callee4_next [expr $line_callee4_body + 1] mi_gdb_test "-interpreter-exec console \"set args foobar\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"args\",value=\"foobar\".*\\^done" \ "-interpreter-exec console \"set args foobar\"" mi_gdb_test "-interpreter-exec console \"show args\"" \ @@ -90,7 +90,7 @@ mi_gdb_test "-interpreter-exec console \"info break\"" \ "-interpreter-exec console \"info break\"" mi_gdb_test "-interpreter-exec console \"set listsize 1\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"listsize\",value=\"1\".*\\^done" \ "-interpreter-exec console \"set listsize 1\"" # {.*\~"32[ \t(\\t)]*callee1.*\\n".*\^done } diff --git a/gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp b/gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp new file mode 100644 index 0000000..8c2195c --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-cmd-param-changed.exp @@ -0,0 +1,103 @@ +# Copyright 2012 Free Software Foundation, Inc. + +# 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/>. + +load_lib mi-support.exp +set MIFLAGS "-i=mi" + +standard_testfile basics.c + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested mi-cmd-param-changed.exp + return -1 +} + +proc test_command_param_changed { } { with_test_prefix "cmd param" { + if [mi_gdb_start] { + return + } + mi_run_to_main + + foreach opt { "on" "off" "step" } { + mi_gdb_test "set scheduler-locking ${opt}" \ + ".*=cmd-param-changed,param=\"scheduler-locking\",value=\"${opt}\".*\\^done" \ + "\"set scheduler-locking ${opt}\"" + } + foreach opt { "on" "off" "step" } { + mi_gdb_test "interpreter-exec console \"set scheduler-locking ${opt}\"" \ + ".*=cmd-param-changed,param=\"scheduler-locking\",value=\"${opt}\".*\\^done" \ + "interpreter-exec \"set scheduler-locking ${opt}\"" + } + # Don't emit MI notification for request from MI. + mi_gdb_test "-gdb-set scheduler-locking on" \ + {\^done} \ + "\"set scheduler-locking on\" no event (requested by MI)" + + mi_gdb_test "interpreter-exec mi \"-gdb-set scheduler-locking step\"" \ + "\\&\"interpreter-exec mi .*\"-gdb-set scheduler-locking step.*\"\\\\n\"\r\n\\^done\r\n\\^done" \ + "\"set scheduler-locking step\" no event (requested by MI interp)" + mi_gdb_test "set scheduler-locking step" \ + "\\&\"set scheduler-locking step\\\\n\"\r\n\\^done" \ + "\"set scheduler-locking stepr\" no event" + + + foreach command { "circular-trace-buffer" "check type" } { + + # The default value of each command option may be different, so we first + # set it to 'off', and this may or may not trigger MI notification. + mi_gdb_test "set ${command} off" ".*\\^done" "\"set ${command}\" warmup" + + foreach boolean_opt { "on" "off" } { + mi_gdb_test "set ${command} ${boolean_opt}" \ + ".*=cmd-param-changed,param=\"${command}\",value=\"${boolean_opt}\".*\\^done" \ + "\"set ${command} ${boolean_opt}\"" + } + mi_gdb_test "set ${command} off" \ + "\\&\"set ${command} off\\\\n\"\r\n\\^done" \ + "\"set ${command}\" no event" + } + + + foreach command { "trace-notes" "remote exec-file" } { + foreach str_opt { "foo" "bar" } { + mi_gdb_test "set ${command} ${str_opt}" \ + ".*=cmd-param-changed,param=\"${command}\",value=\"${str_opt}\".*\\^done" \ + "\"set ${command} ${str_opt}\"" + } + mi_gdb_test "set ${command} bar" \ + "\\&\"set ${command} bar\\\\n\"\r\n(\\&\"warning.*|)\\^done" \ + "\"set ${command} bar\" no event" + } + + # No notification is emitted for 'maint set' commands. + foreach command { "profile" "show-debug-regs" } { + foreach boolean_opt { "on" "off" } { + mi_gdb_test "maint set ${command} ${boolean_opt}" \ + "\\&\"maint set ${command} ${boolean_opt}\\\\n\"\r\n\\^done" \ + "\"maint set ${command} ${boolean_opt}\"" + } + } + + # Full command parameters are included in the notification when a + # abbreviated one is typed. + mi_gdb_test "set ch type on" \ + ".*=cmd-param-changed,param=\"check type\",value=\"on\".*\\^done" \ + "\"set ch type on\"" + + mi_gdb_exit +}} + +test_command_param_changed + +return 0 diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.exp b/gdb/testsuite/gdb.mi/mi-var-rtti.exp index a718ffb..dc2f922 100644 --- a/gdb/testsuite/gdb.mi/mi-var-rtti.exp +++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp @@ -37,7 +37,7 @@ mi_prepare_inline_tests $srcfile # Enable using RTTI to determine real types of the objects proc set_print_object {state testname} { mi_gdb_test "-interpreter-exec console \"set print object ${state}\"" \ - {\^done} \ + "(.*=cmd-param-changed,param=\"print object\",value=\"${state}\".*|)\\^done" \ "-interpreter-exec console \"set print object ${state}\" in $testname" } diff --git a/gdb/testsuite/gdb.mi/mi2-cli.exp b/gdb/testsuite/gdb.mi/mi2-cli.exp index e84b191..9ab7518 100644 --- a/gdb/testsuite/gdb.mi/mi2-cli.exp +++ b/gdb/testsuite/gdb.mi/mi2-cli.exp @@ -69,7 +69,7 @@ set line_callee4_head [gdb_get_line_number "callee4 ("] set line_callee4_body [expr $line_callee4_head + 2] mi_gdb_test "-interpreter-exec console \"set args foobar\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"args\",value=\"foobar\".*\\^done" \ "-interpreter-exec console \"set args foobar\"" mi_gdb_test "-interpreter-exec console \"show args\"" \ @@ -89,7 +89,7 @@ mi_gdb_test "-interpreter-exec console \"info break\"" \ "-interpreter-exec console \"info break\"" mi_gdb_test "-interpreter-exec console \"set listsize 1\"" \ - {\^done} \ + ".*=cmd-param-changed,param=\"listsize\",value=\"1\".*\\^done" \ "-interpreter-exec console \"set listsize 1\"" # {.*\~"32[ \t(\\t)]*callee1.*\\n".*\^done } diff --git a/gdb/testsuite/gdb.mi/mi2-prompt.exp b/gdb/testsuite/gdb.mi/mi2-prompt.exp index 6145c38..eb9edec 100644 --- a/gdb/testsuite/gdb.mi/mi2-prompt.exp +++ b/gdb/testsuite/gdb.mi/mi2-prompt.exp @@ -23,8 +23,9 @@ if [mi_gdb_start] { # Check console 'set prompt' does not affect the MI output. -mi_gdb_test {-interpreter-exec console "set prompt (banana) "} {\^done} \ - "console set prompt" +mi_gdb_test {-interpreter-exec console "set prompt (banana) "} \ + ".*=cmd-param-changed,param=\"prompt\",value=\"\\(banana\\) \".*\\^done" \ + "console set prompt" mi_gdb_test "-break-list" ".*}" "-break-list" gdb_exit diff --git a/gdb/top.c b/gdb/top.c index 213c68c..8251d1b 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -474,8 +474,10 @@ execute_command (char *p, int from_tty) /* c->user_commands would be NULL in the case of a python command. */ if (c->class == class_user && c->user_commands) execute_user_command (c, arg); - else if (c->type == set_cmd || c->type == show_cmd) - do_setshow_command (arg, from_tty, c); + else if (c->type == set_cmd) + do_set_command (arg, from_tty, c); + else if (c->type == show_cmd) + do_show_command (arg, from_tty, c); else if (!cmd_func_p (c)) error (_("That is not a command, just a help topic.")); else if (deprecated_call_command_hook) -- 1.7.7.6 ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2012-08-10 0:57 UTC | newest] Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-08-03 11:22 [RCF 0/3 V3] MI notification of command parameter change Yao Qi 2012-08-03 11:22 ` [PATCH 1/3] new observer command_param_changed Yao Qi 2012-08-03 17:35 ` Tom Tromey 2012-08-06 15:44 ` Yao Qi 2012-08-06 20:21 ` Tom Tromey 2012-08-07 2:58 ` Yao Qi 2012-08-08 18:11 ` Tom Tromey 2012-08-03 11:22 ` [PATCH 2/3] attach to command_param_changed observer Yao Qi 2012-08-03 11:30 ` Eli Zaretskii 2012-08-03 17:36 ` Tom Tromey 2012-08-03 11:22 ` [PATCH 3/3] test case Yao Qi 2012-08-03 17:37 ` Tom Tromey 2012-08-06 15:48 ` Yao Qi 2012-08-06 20:21 ` Tom Tromey 2012-08-10 0:57 ` [committed]: [RCF 0/3 V3] MI notification of command parameter change Yao Qi
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox