From patchwork Sat Apr 13 19:00:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philippe Waroquiers X-Patchwork-Id: 32281 Received: (qmail 26471 invoked by alias); 13 Apr 2019 19:00:50 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 26411 invoked by uid 89); 13 Apr 2019 19:00:50 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-21.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.1 spammy=Temporarily, interior, strcat, letters X-HELO: mailsec106.isp.belgacom.be Received: from mailsec106.isp.belgacom.be (HELO mailsec106.isp.belgacom.be) (195.238.20.102) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 13 Apr 2019 19:00:43 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=skynet.be; i=@skynet.be; q=dns/txt; s=securemail; t=1555182043; x=1586718043; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=0M1zg4kgrTonFtMctbx4RfUw/V3SV0/V31/V6mvoGL8=; b=zvuFRxkSs5vjtIDSAgPFlvif1bCyblrflPqVlYk3Ca+/ihHaadNemzV7 0PcbMaFszxL6Ci7RPmhWK9x/rX7fxg==; Received: from 212.135-131-109.adsl-dyn.isp.belgacom.be (HELO md.home) ([109.131.135.212]) by relay.skynet.be with ESMTP/TLS/DHE-RSA-AES128-GCM-SHA256; 13 Apr 2019 21:00:34 +0200 From: Philippe Waroquiers To: gdb-patches@sourceware.org Cc: Philippe Waroquiers Subject: [RFA 1/3] / command : fast way to change setting(s), run a command, reset settings(s). Date: Sat, 13 Apr 2019 21:00:14 +0200 Message-Id: <20190413190016.11970-2-philippe.waroquiers@skynet.be> In-Reply-To: <20190413190016.11970-1-philippe.waroquiers@skynet.be> References: <20190413190016.11970-1-philippe.waroquiers@skynet.be> MIME-Version: 1.0 X-IsSubscribed: yes GDB has a lot of settings related to how commands behaves and/or print things. There is however currently no easy way to temporarily change a setting for a command. This patch implements a new command called /, that allows to temporarily change the settings in order to execute another command. The objective for this / command is to be fast to type, so it uses 1 or 2 letters codes to identify which settings(s) to temporarily set. Examples with printing an array: ******************************** gdb -ex 'b 24' -ex 'run' ./gdb/testsuite/outputs/gdb.ada/tick_length_array_enum_idx/foo_n207_004 Default setting: arrays are not pretty printed. p full $1 = (false, true, false, true, false) To 'one time' pretty print an array, we currently need to do: set print array on p full $2 = (false, true, false, true, false) set print array off With the / command: /a p full To set it off, prefix with !. E.g.: /!a p some_array is the same as: set print array off p full set print array on Note: the / command in fact restores the setting in force before / changes them. I.e., if 'set print array' was on before '/!a p some_array' then after the execution of / command, it is still on. Other example: to print the array indexes: /i p full is the equivalent of: set print array-index on p full set print array-index off These can be combined, i.e. /ai p full is the equivalent of: set print array on set print array-index on p full set print array-index off set print array off Numeric settings can also be overriden. For example, the nr of elements to print for an array (default is 200): set print elements 2 p full set print elements 200 is the equivalent of: /2e p full If e is not prefixed by a digit, then this is the same as no limit: set print elements unlimited p full set print elements 200 is the equivalent of; /e p full One can also do: /ai2e p full to print full array with temporarily setting of pretty printing 2 elements, with array indexes. There is not enough letter to support all the print settings etc. So, the upper case letters are used to introduce prefixes, typically used for the less used settings. For example: stepi bt #0 0x0000555555555a3f in foo_n207_004 () at ... set print address off bt #0 foo_n207_004 () at ... set print address on The last 3 commands are the equivalent of: /Pa bt It is also possible to override enum settings. E.g. set print frame-arguments all bt set print frame-arguments scalars is equivalent to: /fa bt Similarly, one can now easily set the language for just one command: set language c print something set language auto is equivalent to: /lc print something In terms of implementation: A argument slash_seq (with default value nullptr) has been added to: add_setshow_boolean_cmd add_setshow_uinteger_cmd add_setshow_enum_cmd. The above behaviour is obtained by passing the relevant string value for this new slash_seq argument. E.g. to have a shortcut /a for pretty printing array, the "a" has been added as last argument in the below call: add_setshow_boolean_cmd ("array", class_support, &user_print_options.prettyformat_arrays, _("\ Set pretty formatting of arrays."), _("\ Show pretty formatting of arrays."), NULL, NULL, show_prettyformat_arrays, &setprintlist, &showprintlist, "a"); The set print frame-arguments shortcuts are obtained by adding "f[asn]" as last argument, where 'a' means 'all', 's' means 'scalars', 'n' means 'none'. The full list of settings that can be used is given by 'help /' (see below). Of course, we might add some more settings to the below list. For example, the (probably soon to land) 'set print max-depth' should added to the list (the letter d is still available for this one :). (gdb) help / Usage: /SETTING... COMMAND Temporarily changes settings according to SETTING, run COMMAND, and then restore the settings to their previous values. Each temporarily changeable setting is identified by a unique sequence of one or more letters. A boolean setting is temporarily activated (set to "on") by giving its sequence of letters. If the boolean sequence of letters is prefixed by !, the boolean setting is deactivated (set to "off"). An integer setting is temporarily changed by using its sequence of letters optionally prefixed by the temporary value desired. If no prefix value is given before the integer setting letters, the integer setting is temporarily changed to an unlimited value. An enum setting is temporarily changed by giving its sequence of letters followed by a letter designating the chosen enum value. Example: /100e!ai print some_array is equivalent to: # save current values of the settings set print elements/array/array-index. set print elements 100 set print array off set print array-index on print some_array # restore the saved values of the changed settings. The temporarily changeable settings are: /Be set backtrace past-entry Boolean on|off /Bl set backtrace limit Unsigned integer (0 means unlimited) /Bm set backtrace past-main Boolean on|off /Co set print object Boolean on|off /Cs set print static-members Boolean on|off /Cv set print vtbl Boolean on|off /Pa set print address Boolean on|off /Ps set print symbol Boolean on|off /Rf set print raw frame-arguments Boolean on|off /a set print array Boolean on|off /e set print elements Unsigned integer (0 means unlimited) /f[asn] set print frame-arguments Enum, a = all, s = scalars, n = none /i set print array-indexes Boolean on|off /l[aluAscCdfgmMOo] set language Enum, a = auto, l = local, u = unknown, A = ada, s = asm, c = c, C = c++, d = d, f = fortran, g = go, m = minimal, M = modula-2, O = objective-c, o = opencl /n set print null-stop Boolean on|off /p set print pretty Boolean on|off /r set print repeats Unsigned integer (0 means unlimited) /u set print union Boolean on|off /v set varsize-limit Unsigned integer (0 means unlimited) (gdb) gdb/ChangeLog 2019-04-13 Philippe Waroquiers * cli/cli-decode.c (slash_settings): New variable. (slash_settings_var_type_name): New typedef. (slash_settings_var_type_names): New variable. (get_slash_settings_var_type_name, slash_ncmp, check_mismatch, scoped_set_restore_slash_settings::scoped_set_restore_slash_settings, scoped_set_restore_slash_settings::command, prefixname, scoped_set_restore_slash_settings::~scoped_set_restore_slash_settings, scoped_set_restore_slash_settings::swap_values): New functions. (add_set_or_show_cmd, add_setshow_cmd_full, add_setshow_enum_cmd, add_setshow_boolean_cmd, add_setshow_uinteger_cmd): New arg slash_seq. (apropos_cmd): Also match on the command slash_seq. (help_cmd): Output the list of slash_settings when help is requested for /. If there is a slash_seq setting for a command, output it in the help command output. (print_help_cor_command): Likewise. (find_command_name_length): Recognise / as a command. * cli/cli-decode.h (struct cmd_list_element): New component slash_seq. (slash_setting_value): New struct. (scoped_set_restore_slash_settings): New class. command.h (add_setshow_enum_cmd, add_setshow_boolean_cmd, add_setshow_uinteger_cmd): New slash_sea arg. * top.c (slash_command): New function. (init_main): Add the new slash_command. * ada-lang.c, cp-valprint.c, gdb/frame.c, language.c, stack.c, valprint.c (_initialize_*): Add some slash_seq args. --- gdb/ada-lang.c | 3 +- gdb/cli/cli-decode.c | 394 +++++++++++++++++++++++++++++++++++++++++-- gdb/cli/cli-decode.h | 43 +++++ gdb/command.h | 9 +- gdb/cp-valprint.c | 9 +- gdb/frame.c | 9 +- gdb/language.c | 3 +- gdb/stack.c | 6 +- gdb/top.c | 39 +++++ gdb/valprint.c | 27 ++- 10 files changed, 502 insertions(+), 40 deletions(-) diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index ccf8ed8039..b106649913 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -14541,7 +14541,8 @@ Set the maximum number of bytes allowed in a variable-size object."), _("\ Show the maximum number of bytes allowed in a variable-size object."), _("\ Attempts to access an object whose size is not a compile-time constant\n\ and exceeds this limit will cause an error."), - NULL, NULL, &setlist, &showlist); + NULL, NULL, &setlist, &showlist, + "v"); add_info ("exceptions", info_exceptions_command, _("\ diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index 50430953c7..ac5008ee2a 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -429,13 +429,275 @@ empty_sfunc (const char *args, int from_tty, struct cmd_list_element *c) { } +/* List of cmd_list_elements whose var can be temporarily set by the + / command. */ + +static std::vector slash_settings; + +/* A printable representation of the var_types the / command accepts. */ +typedef struct +{ + const char *var_type_name; + enum var_types var_type; +} slash_settings_var_type_name; + +static const slash_settings_var_type_name slash_settings_var_type_names[] = +{ + { "Boolean on|off", var_boolean }, + { "Unsigned integer (0 means unlimited)", var_uinteger }, + { "Enum", var_enum }, + { NULL, var_boolean } +}; + +static const char * +get_slash_settings_var_type_name (var_types var_type) +{ + for (const slash_settings_var_type_name *v = slash_settings_var_type_names; + v->var_type_name; + v++) + if (v->var_type == var_type) + return v->var_type_name; + + gdb_assert (0); +} + +/* Like strncmp, but stops the comparison at n char or when a [ character + or null character is encountered. */ +static int +slash_ncmp (const char *left, const char *right, size_t n) +{ + size_t l; + size_t r; + + for (l = 0; l <= n && left[l] != 0 && left[l] != '['; l++) + ; + for (r = 0; r <= n && right[r] != 0 && right[r] != '['; r++) + ; + + return strncmp (left, right, l > r ? r : l); +} + +/* If CMD has a prefix, returns its prefix name, otherwise returns "". */ +static const char * +prefixname (const cmd_list_element *cmd) +{ + return cmd->prefix == nullptr ? "" : cmd->prefix->prefixname; +} + +/* Verifies that EXPECTED matches the type of FOUND. + If a mismatch is found, throws an error using EXPECTED_ORIGIN + to indicate the source of the mismatch. */ + +static void +check_mismatch (var_types expected, cmd_list_element *found, + const char *expected_origin, const char *beg_found) +{ + if (expected != found->var_type) + error (_("Value type for / setting \"%s\" (%s%s) is '%s'.\n" + "Found unexpected '%s' qualifier at \"%s\""), + found->slash_seq, prefixname (found), found->name, + get_slash_settings_var_type_name (found->var_type), + get_slash_settings_var_type_name (expected), + expected_origin); +} + +/* See cli-decode.h */ + +scoped_set_restore_slash_settings::scoped_set_restore_slash_settings +(const char *args) +{ + const char *p = args; + + if (p == nullptr) + error (_("/ must be followed by one or more SETTING letters.")); + + /* First accumulate all the cmd_list_elements in saved vector, + with the new desired value. We will then swap the values + once we have succesfully parse all the settings. */ + while (*p && *p != ' ') + { + slash_setting_value v; + const char *beg; + bool check_expected = false; + /* The following variables are set when (and only used if) + check_expected is true. We default initialize them to silence + gcc warning. */ + const char *expected_origin = NULL; + var_types expected = var_optional_filename; + unsigned int uinteger_val = 1234567890; + + if (*(p) == '!') + { + check_expected = true; + expected_origin = p; + expected = var_boolean; + p++; + } + else if (isdigit (*p)) + { + check_expected = true; + expected_origin = p; + expected = var_uinteger; + uinteger_val = atoi (p); + while (isdigit (*p)) + p++; + } + + beg = p; + while (isupper (*p)) + p++; + for (auto it = slash_settings.begin (); it != slash_settings.end (); it++) + { + cmd_list_element *o = *it; + + if (slash_ncmp (o->slash_seq, beg, p + 1 - beg) == 0) + { + v.cmd = o; + p++; + if (check_expected) + check_mismatch (expected, o, expected_origin, beg); + switch (o->var_type) + { + case var_boolean: + if (check_expected) + v.value.boolean_var = 0; + else + v.value.boolean_var = 1; + break; + + case var_uinteger: + if (check_expected) + { + v.value.uinteger_val = uinteger_val; + if (v.value.uinteger_val == 0) + v.value.uinteger_val = UINT_MAX; + } + else + v.value.uinteger_val = UINT_MAX; + break; + + case var_enum: + { + const char *l = o->slash_seq; + const char *f; + + while (*l && *l != '[') + l++; + gdb_assert (*l == '['); + l++; + f = l; + while (*f && *f != *p) + f++; + if (!*f) + error (_("Value for slash setting '%c'" + " not recognised at \"%s\""), + *beg, beg + 1); + p++; + v.value.enum_val = o->enums[f - l]; + break; + } + + default: + gdb_assert (0); + } + + saved.emplace_back (v); + break; + } + } + if (beg == p) + { + if (*beg == ' ') + { + if (check_expected) + { + if (expected == var_uinteger) + error (_("Unsigned integer setting expected following" + " integer value at \"%s\""), expected_origin); + else if (expected == var_boolean) + error (_("Boolean setting expected following" + " ! at \"%s\""), expected_origin); + else + gdb_assert (0); + } + else + error (_("No slash setting found at \"%s\""), beg); + } + else + error (_("Slash setting not recognised at \"%s\""), beg); + } + } + + while (*p == ' ') + p++; + this->cmd = p; + + if (*p == 0) + error (_("/SETTING... must be followed by a COMMAND.")); + + swap_values (); +} + +/* See cli-decode.h */ + +const char *scoped_set_restore_slash_settings::command () +{ + return this->cmd; +} + +/* See cli-decode.h */ + +scoped_set_restore_slash_settings::~scoped_set_restore_slash_settings () +{ + swap_values (); +} + +/* See cli-decode.h */ + +void scoped_set_restore_slash_settings::swap_values () +{ +#define SWAPVAL_SAVED_I(TYPE, COMP) do { \ + TYPE tmp = saved[i].value.COMP; \ + saved[i].value.COMP = *(TYPE*)saved[i].cmd->var; \ + *(TYPE*)saved[i].cmd->var = tmp; } while (0) + + for (int i = 0; i < saved.size (); i++) + { + switch (saved[i].cmd->var_type) + { + case var_boolean: + SWAPVAL_SAVED_I (int, boolean_var); + break; + + case var_uinteger: + SWAPVAL_SAVED_I (unsigned int, uinteger_val); + break; + + case var_enum: + SWAPVAL_SAVED_I (const char *, enum_val); + break; + + default: + gdb_assert (0); + } + /* If some function must be run after changing the value, call it. + Note: we harcode NULL for the ARGS parameter. + We might instead "print" the *_val values in a string and pass + this printed value instead. A NULL seems to be ok for now. */ + if (cmd_func_p (saved[i].cmd)) + cmd_func (saved[i].cmd, NULL, 0); + } +} + /* Add element named NAME to command list LIST (the list for set/show or some sublist thereof). TYPE is set_cmd or show_cmd. CLASS is as in add_cmd. VAR_TYPE is the kind of thing we are setting. VAR is address of the variable being controlled by this command. - DOC is the documentation string. */ + DOC is the documentation string. + if SLASH_SEQ is not null, the setting controlled by this command + will be temporarily changeable by the / command. */ static struct cmd_list_element * add_set_or_show_cmd (const char *name, @@ -444,17 +706,49 @@ add_set_or_show_cmd (const char *name, var_types var_type, void *var, const char *doc, - struct cmd_list_element **list) + struct cmd_list_element **list, + const char *slash_seq) { struct cmd_list_element *c = add_cmd (name, theclass, doc, list); gdb_assert (type == set_cmd || type == show_cmd); + gdb_assert (type == set_cmd || slash_seq == nullptr); + c->type = type; c->var_type = var_type; c->var = var; /* This needs to be something besides NULL so that this isn't treated as a help class. */ set_cmd_sfunc (c, empty_sfunc); + + /* Handle the optional slash_seq. */ + if (slash_seq != nullptr) + { + int cmp = 1; + + for (auto it = slash_settings.begin (); it != slash_settings.end (); it++) + { + cmd_list_element *o = *it; + + cmp = slash_ncmp (slash_seq, o->slash_seq, UINT_MAX); + if (cmp == 0) + { + printf_unfiltered ("slash_seq /%s for cmd %s%s\n", + slash_seq, prefixname (c), c->name); + printf_unfiltered ("conflicts with slash_seq /%s for cmd %s%s\n", + o->slash_seq, prefixname (o), o->name); + gdb_assert (0); + } + else if (cmp < 0) + { + slash_settings.insert (it, c); + break; + } + } + if (cmp > 0) + slash_settings.emplace_back (c); + c->slash_seq = slash_seq; + } return c; } @@ -465,7 +759,9 @@ add_set_or_show_cmd (const char *name, non-NULL). SET_DOC, SHOW_DOC and HELP_DOC are the documentation strings. PRINT the format string to print the value. SET_RESULT and SHOW_RESULT, if not NULL, are set to the resulting command - structures. */ + structures. If not nullptr, SLASH_SEQ gives the sequence of letters + that can be used in the / command to temporarily set + the value of this setting. */ static void add_setshow_cmd_full (const char *name, @@ -478,7 +774,8 @@ add_setshow_cmd_full (const char *name, struct cmd_list_element **set_list, struct cmd_list_element **show_list, struct cmd_list_element **set_result, - struct cmd_list_element **show_result) + struct cmd_list_element **show_result, + const char *slash_seq = nullptr) { struct cmd_list_element *set; struct cmd_list_element *show; @@ -496,7 +793,7 @@ add_setshow_cmd_full (const char *name, full_show_doc = xstrdup (show_doc); } set = add_set_or_show_cmd (name, set_cmd, theclass, var_type, var, - full_set_doc, set_list); + full_set_doc, set_list, slash_seq); set->doc_allocated = 1; if (set_func != NULL) @@ -505,7 +802,7 @@ add_setshow_cmd_full (const char *name, set_cmd_prefix (set, set_list); show = add_set_or_show_cmd (name, show_cmd, theclass, var_type, var, - full_show_doc, show_list); + full_show_doc, show_list, NULL); show->doc_allocated = 1; show->show_value_func = show_func; @@ -532,7 +829,8 @@ add_setshow_enum_cmd (const char *name, show_value_ftype *show_func, struct cmd_list_element **set_list, struct cmd_list_element **show_list, - void *context) + void *context, + const char *slash_seq) { struct cmd_list_element *c, *show; @@ -540,7 +838,8 @@ add_setshow_enum_cmd (const char *name, set_doc, show_doc, help_doc, set_func, show_func, set_list, show_list, - &c, &show); + &c, &show, + slash_seq); c->enums = enumlist; set_cmd_context (c, context); @@ -585,7 +884,8 @@ add_setshow_boolean_cmd (const char *name, enum command_class theclass, int *var cmd_const_sfunc_ftype *set_func, show_value_ftype *show_func, struct cmd_list_element **set_list, - struct cmd_list_element **show_list) + struct cmd_list_element **show_list, + const char *slash_seq) { static const char *boolean_enums[] = { "on", "off", NULL }; struct cmd_list_element *c; @@ -594,7 +894,7 @@ add_setshow_boolean_cmd (const char *name, enum command_class theclass, int *var set_doc, show_doc, help_doc, set_func, show_func, set_list, show_list, - &c, NULL); + &c, NULL, slash_seq); c->enums = boolean_enums; } @@ -740,7 +1040,8 @@ add_setshow_uinteger_cmd (const char *name, enum command_class theclass, cmd_const_sfunc_ftype *set_func, show_value_ftype *show_func, struct cmd_list_element **set_list, - struct cmd_list_element **show_list) + struct cmd_list_element **show_list, + const char *slash_seq) { struct cmd_list_element *set; @@ -748,7 +1049,7 @@ add_setshow_uinteger_cmd (const char *name, enum command_class theclass, set_doc, show_doc, help_doc, set_func, show_func, set_list, show_list, - &set, NULL); + &set, NULL, slash_seq); set_cmd_completer (set, integer_unlimited_completer); } @@ -965,6 +1266,22 @@ apropos_cmd (struct ui_file *stream, 0 /* don't recurse */, stream); } } + if (c->slash_seq != NULL) + { + size_t slash_seq_len = strlen (c->slash_seq) + 1; + char slash_seq [slash_seq_len + 1]; + + slash_seq[0] = '/'; + slash_seq[1] = 0; + strcat (slash_seq + 1, c->slash_seq); + returnvalue = regex.search (slash_seq, slash_seq_len, 0, + slash_seq_len, NULL); + if (returnvalue >= 0) + { + print_help_for_command (c, prefix, + 0 /* don't recurse */, stream); + } + } if (c->doc != NULL && returnvalue < 0) { size_t doc_len = strlen (c->doc); @@ -1034,7 +1351,47 @@ help_cmd (const char *command, struct ui_file *stream) listed. */ fputs_filtered (c->doc, stream); - fputs_filtered ("\n", stream); + if (strcmp (c->name, "/") == 0) + { + /* The / command help needs to be completed by the list of + settings that can be temporarily set. */ + for (const cmd_list_element *o : slash_settings) + { + std::string msg = string_printf ("/%-8s %s%s", o->slash_seq, + prefixname (o), o->name); + fprintf_filtered (stream, "%-40s %s", msg.c_str (), + get_slash_settings_var_type_name (o->var_type)); + if (o->var_type == var_enum) + { + const char *l = o->slash_seq; + const char *f; + + while (*l && *l != '[') + l++; + gdb_assert (*l == '['); + l++; + f = l; + while (*f && *f != ']') + { + fprintf_filtered (stream, ","); + wrap_here (" "); + fprintf_filtered (stream, " %c = %s", + *f, o->enums[f - l]); + f++; + } + gdb_assert (*f == ']'); + } + fputs_filtered ("\n", stream); + } + } + else + fputs_filtered ("\n", stream); + + if (c->slash_seq != nullptr) + fprintf_filtered + (stream, + _("Use /%s COMMAND to temporarily change this setting to run COMMAND.\n"), + c->slash_seq); if (c->prefixlist == 0 && c->func != NULL) return; @@ -1212,10 +1569,11 @@ static void print_help_for_command (struct cmd_list_element *c, const char *prefix, int recurse, struct ui_file *stream) { - fprintf_filtered (stream, "%s%s -- ", prefix, c->name); + fprintf_filtered (stream, "%s%s%s%s -- ", prefix, c->name, + c->slash_seq == nullptr ? "" : ", /", + c->slash_seq == nullptr ? "" : c->slash_seq); print_doc_line (stream, c->doc); fputs_filtered ("\n", stream); - if (recurse && c->prefixlist != 0 && c->abbrev_flag == 0) @@ -1311,9 +1669,9 @@ find_command_name_length (const char *text) Note that this is larger than the character set allowed when creating user-defined commands. */ - /* Recognize '!' as a single character command so that, e.g., "!ls" - works as expected. */ - if (*p == '!') + /* Recognize '!' and '/' as a single character command so that, e.g., "!ls" + and "/ai print some array" works as expected. */ + if (*p == '!' || *p == '/') return 1; while (isalnum (*p) || *p == '-' || *p == '_' diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h index c53683d95c..49581da0a9 100644 --- a/gdb/cli/cli-decode.h +++ b/gdb/cli/cli-decode.h @@ -209,6 +209,10 @@ struct cmd_list_element matter if type is not_set. */ void *var = nullptr; + /* Sequence of characters that can be used by the / command + to temporarily set the variable affected by "set". */ + const char *slash_seq = nullptr; + /* Pointer to NULL terminated list of enumerated values (like argv). */ const char *const *enums = nullptr; @@ -270,4 +274,43 @@ extern int cli_user_command_p (struct cmd_list_element *); extern int find_command_name_length (const char *); +/* A structure that maintains a value for a variable changeable using CMD. */ + +typedef struct +{ + cmd_list_element *cmd; + union { + int boolean_var; + unsigned int uinteger_val; + const char *enum_val; + } value; +} slash_setting_value; + +/* Processes the given ARGS to change the settings according to the + slash sequences found in ARGS. + Restore the previous settings values upon destruction. */ + +class scoped_set_restore_slash_settings +{ +public: + + explicit scoped_set_restore_slash_settings (const char *args); + + /* Returns the command to execute after having processed the / settings + found in ARGS. */ + const char *command (); + + ~scoped_set_restore_slash_settings (); + + DISABLE_COPY_AND_ASSIGN (scoped_set_restore_slash_settings); + +private: + /* The command to execute with the temporarily changed settings. */ + const char *cmd; + std::vector saved; + + /* Swap the values in SAVED with the real settings values. */ + void swap_values (); +}; + #endif /* CLI_CLI_DECODE_H */ diff --git a/gdb/command.h b/gdb/command.h index 4a239a7196..c8f4d19792 100644 --- a/gdb/command.h +++ b/gdb/command.h @@ -315,7 +315,8 @@ extern void add_setshow_enum_cmd (const char *name, show_value_ftype *show_func, struct cmd_list_element **set_list, struct cmd_list_element **show_list, - void *context = nullptr); + void *context = nullptr, + const char *slash_seq = nullptr); extern void add_setshow_auto_boolean_cmd (const char *name, enum command_class theclass, @@ -336,7 +337,8 @@ extern void add_setshow_boolean_cmd (const char *name, cmd_const_sfunc_ftype *set_func, show_value_ftype *show_func, struct cmd_list_element **set_list, - struct cmd_list_element **show_list); + struct cmd_list_element **show_list, + const char *slash_seq = nullptr); extern void add_setshow_filename_cmd (const char *name, enum command_class theclass, @@ -403,7 +405,8 @@ extern void add_setshow_uinteger_cmd (const char *name, cmd_const_sfunc_ftype *set_func, show_value_ftype *show_func, struct cmd_list_element **set_list, - struct cmd_list_element **show_list); + struct cmd_list_element **show_list, + const char *slash_seq = nullptr); extern void add_setshow_zinteger_cmd (const char *name, enum command_class theclass, diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c index e883179dfa..14b553f206 100644 --- a/gdb/cp-valprint.c +++ b/gdb/cp-valprint.c @@ -811,7 +811,8 @@ Set printing of C++ static members."), _("\ Show printing of C++ static members."), NULL, NULL, show_static_field_print, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "Cs"); add_setshow_boolean_cmd ("vtbl", class_support, &user_print_options.vtblprint, _("\ @@ -819,7 +820,8 @@ Set printing of C++ virtual function tables."), _("\ Show printing of C++ virtual function tables."), NULL, NULL, show_vtblprint, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "Cv"); add_setshow_boolean_cmd ("object", class_support, &user_print_options.objectprint, _("\ @@ -827,7 +829,8 @@ Set printing of object's derived type based on vtable info."), _("\ Show printing of object's derived type based on vtable info."), NULL, NULL, show_objectprint, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "Co"); obstack_begin (&dont_print_stat_array_obstack, 32 * sizeof (struct type *)); diff --git a/gdb/frame.c b/gdb/frame.c index f4303d13cc..0170ae0f4d 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -2926,7 +2926,8 @@ of the stack trace."), NULL, show_backtrace_past_main, &set_backtrace_cmdlist, - &show_backtrace_cmdlist); + &show_backtrace_cmdlist, + "Bm"); add_setshow_boolean_cmd ("past-entry", class_obscure, &backtrace_past_entry, _("\ @@ -2940,7 +2941,8 @@ the rest of the stack trace."), NULL, show_backtrace_past_entry, &set_backtrace_cmdlist, - &show_backtrace_cmdlist); + &show_backtrace_cmdlist, + "Be"); add_setshow_uinteger_cmd ("limit", class_obscure, &backtrace_limit, _("\ @@ -2951,7 +2953,8 @@ Literal \"unlimited\" or zero means no limit."), NULL, show_backtrace_limit, &set_backtrace_cmdlist, - &show_backtrace_cmdlist); + &show_backtrace_cmdlist, + "Bl"); /* Debug this files internals. */ add_setshow_zuinteger_cmd ("frame", class_maintenance, &frame_debug, _("\ diff --git a/gdb/language.c b/gdb/language.c index 954e4c200f..b804e34efa 100644 --- a/gdb/language.c +++ b/gdb/language.c @@ -584,7 +584,8 @@ add_set_language_command () _("Show the current source language."), NULL, set_language_command, show_language_command, - &setlist, &showlist); + &setlist, &showlist, NULL, + "l[aluAscCdfgmMOo]"); } /* Iterate through all registered languages looking for and calling diff --git a/gdb/stack.c b/gdb/stack.c index f7fd9433b5..5a2491e45a 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -3103,7 +3103,8 @@ Usage: func NAME")); print_frame_arguments_choices, &print_frame_arguments, _("Set printing of non-scalar frame arguments"), _("Show printing of non-scalar frame arguments"), - NULL, NULL, NULL, &setprintlist, &showprintlist); + NULL, NULL, NULL, &setprintlist, &showprintlist, + NULL, "f[asn]"); add_setshow_boolean_cmd ("frame-arguments", no_class, &print_raw_frame_arguments, _("\ @@ -3112,7 +3113,8 @@ Show whether to print frame arguments in raw form."), _("\ If set, frame arguments are printed in raw form, bypassing any\n\ pretty-printers for that value."), NULL, NULL, - &setprintrawlist, &showprintrawlist); + &setprintrawlist, &showprintrawlist, + "Rf"); add_setshow_auto_boolean_cmd ("disassemble-next-line", class_stack, &disassemble_next_line, _("\ diff --git a/gdb/top.c b/gdb/top.c index 60ca74da25..76838d9d33 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -2016,6 +2016,16 @@ init_gdb_version_vars (void) set_internalvar_integer (minor_version_var, vminor + (vrevision > 0)); } +/* Implementation of the "/" slash command. */ + +static void +slash_command (const char *args, int from_tty) +{ + scoped_set_restore_slash_settings settings (args); + + execute_command (settings.command (), from_tty); +} + static void init_main (void) { @@ -2164,6 +2174,35 @@ Create a new UI. It takes two arguments:\n\ The first argument is the name of the interpreter to run.\n\ The second argument is the terminal the UI runs on.\n"), &cmdlist); set_cmd_completer (c, interpreter_completer); + + add_com ("/", class_support, slash_command, _("\ +Usage: /SETTING... COMMAND\n\ +Temporarily changes settings according to SETTING, run COMMAND,\n\ +and then restore the settings to their previous values.\n\ +Each temporarily changeable setting is identified by a unique sequence\n\ +of one or more letters.\n\ +A boolean setting is temporarily activated (set to \"on\") by giving\n\ +its sequence of letters. If the boolean sequence of letters is prefixed\n\ +by !, the boolean setting is deactivated (set to \"off\").\n\ +An integer setting is temporarily changed by using its sequence of letters\n\ +optionally prefixed by the temporary value desired.\n\ +If no prefix value is given before the integer setting letters,\n\ +the integer setting is temporarily changed to an unlimited value.\n\ +An enum setting is temporarily changed by giving its sequence of letters\n\ +followed by a letter designating the chosen enum value.\n\ +Example:\n\ + /100e!ai print some_array\n\ +is equivalent to:\n\ + # save current values of the settings set print elements/array/array-index.\n\ + set print elements 100\n\ + set print array off\n\ + set print array-index on\n\ + print some_array\n\ + # restore the saved values of the changed settings.\n\ +The temporarily changeable settings are:\n")); + /* Note that the slash_command on-line help terminates with ':', as + the help_cmd function will output the list of / settings that + can be used. */ } void diff --git a/gdb/valprint.c b/gdb/valprint.c index b02ebf6c27..1a736bb8a7 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -3055,7 +3055,8 @@ Show limit on string chars or array elements to print."), _("\ \"set print elements unlimited\" causes there to be no limit."), NULL, show_print_max, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "e"); add_setshow_boolean_cmd ("null-stop", no_class, &user_print_options.stop_print_at_null, _("\ @@ -3063,7 +3064,8 @@ Set printing of char arrays to stop at first null char."), _("\ Show printing of char arrays to stop at first null char."), NULL, NULL, show_stop_print_at_null, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "n"); add_setshow_uinteger_cmd ("repeats", no_class, &user_print_options.repeat_count_threshold, _("\ @@ -3072,7 +3074,8 @@ Show threshold for repeated print elements."), _("\ \"set print repeats unlimited\" causes all elements to be individually printed."), NULL, show_repeat_count_threshold, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "r"); add_setshow_boolean_cmd ("pretty", class_support, &user_print_options.prettyformat_structs, _("\ @@ -3080,7 +3083,8 @@ Set pretty formatting of structures."), _("\ Show pretty formatting of structures."), NULL, NULL, show_prettyformat_structs, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "p"); add_setshow_boolean_cmd ("union", class_support, &user_print_options.unionprint, _("\ @@ -3088,7 +3092,8 @@ Set printing of unions interior to structures."), _("\ Show printing of unions interior to structures."), NULL, NULL, show_unionprint, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "u"); add_setshow_boolean_cmd ("array", class_support, &user_print_options.prettyformat_arrays, _("\ @@ -3096,7 +3101,8 @@ Set pretty formatting of arrays."), _("\ Show pretty formatting of arrays."), NULL, NULL, show_prettyformat_arrays, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "a"); add_setshow_boolean_cmd ("address", class_support, &user_print_options.addressprint, _("\ @@ -3104,7 +3110,8 @@ Set printing of addresses."), _("\ Show printing of addresses."), NULL, NULL, show_addressprint, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "Pa"); add_setshow_boolean_cmd ("symbol", class_support, &user_print_options.symbol_print, _("\ @@ -3112,7 +3119,8 @@ Set printing of symbol names when printing pointers."), _("\ Show printing of symbol names when printing pointers."), NULL, NULL, show_symbol_print, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "Ps"); add_setshow_zuinteger_cmd ("input-radix", class_support, &input_radix_1, _("\ @@ -3151,5 +3159,6 @@ Use 'show input-radix' or 'show output-radix' to independently show each."), &user_print_options.print_array_indexes, _("\ Set printing of array indexes."), _("\ Show printing of array indexes"), NULL, NULL, show_print_array_indexes, - &setprintlist, &showprintlist); + &setprintlist, &showprintlist, + "i"); }