* [PATCH v4 6/8] GDB: Allow arbitrary keywords in integer set commands
2022-03-09 19:17 [PATCH v4 0/8] gdb: split array and string limiting options Maciej W. Rozycki
` (4 preceding siblings ...)
2022-03-09 19:18 ` [PATCH v4 5/8] GDB/testsuite: Add coverage for `print -elements' command Maciej W. Rozycki
@ 2022-03-09 19:18 ` Maciej W. Rozycki
2022-03-09 19:18 ` [PATCH v4 7/8] GDB: Add a character string limiting option Maciej W. Rozycki
` (2 subsequent siblings)
8 siblings, 0 replies; 22+ messages in thread
From: Maciej W. Rozycki @ 2022-03-09 19:18 UTC (permalink / raw)
To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch
Rather than just `unlimited' allow the integer set commands (or command
options) to define arbitrary keywords for the user to use, removing
hardcoded arrangements for the `unlimited' keyword.
Make obsolete the confusingly named `var_zinteger', `var_zuinteger' and
`var_zuinteger_unlimited' `set'/`show' command variable types redefining
them in terms of `var_uinteger', `var_integer' and `var_pinteger', which
have the range of [0;UINT_MAX], [INT_MIN;INT_MAX], and [0;INT_MAX] each.
Following existing practice `var_pinteger' allows extra negative values
to be used, however unlike `var_zuinteger_unlimited' any number of such
values can be defined rather than just `-1'.
The "p" in `var_pinteger' stands for "positive", for the lack of a more
appropriate unambiguous letter, even though 0 obviously is not positive;
"n" would be confusing as to whether it stands for "non-negative" or
"negative".
Add a new structure, `literal_def', the entries of which define extra
keywords allowed for a command and numerical values they correspond to.
Those values are not verified against the basic range supported by the
underlying variable type, allowing extra values to be allowed outside
that range, which may or may not be individually made visible to the
user. An optional value translation is possible with the structure to
follow the existing practice for some commands where user-entered 0 is
internally translated to UINT_MAX or INT_MAX. Such translation can now
be arbitrary. Literals defined by this structure are automatically used
for completion as necessary.
So for example:
const literal_def integer_unlimited_literals[] =
{
{ "unlimited", 0, INT_MAX, true },
{ nullptr }
};
defines an extra `unlimited' keyword and a user-visible 0 value, both of
which get translated to INT_MAX for the setting to be used with.
Similarly:
const literal_def zuinteger_unlimited_literals[] =
{
{ "unlimited", -1, -1, true },
{ nullptr }
};
defines the same keyword and a corresponding user-visible -1 value that is
used for the requested setting. If the last member was set to `false'
here, then only the keyword would be allowed for the user to enter and
while -1 would still be used internally trying to enter it as a part of a
command would result in an "integer -1 out of range" error.
The obsolete command variable types still remain for Guile and Python
use. Eventually they need to be removed, however that would require a
further rework of our Guile and Python support code. Given that these
variable types have been exported as keywords for those languages, those
definitions have to stay, however it would be better to redefine them in
terms of the modern variable types and overall export a better interface
that reflects the flexibility of our core code now.
There is no user-visible change from this rework, so no documentation or
testsuite updates.
---
Hi,
NB I have observed that the value of INT_MIN is not correctly handled:
internally -2147483648 is interpreted as 2147483648 and consequently such
a value is rejected, e.g:
(gdb) show heuristic-fence-post
The distance searched for the start of a function is 0.
(gdb) set heuristic-fence-post -2147483647
(gdb) show heuristic-fence-post
The distance searched for the start of a function is -2147483647.
(gdb) set heuristic-fence-post -2147483648
integer 2147483648 out of range
(gdb)
umm... (not that it makes sense to set negative values for the heuristic
fence post, but that's irrelevant here). I haven't tried to track the
root cause for this.
Maciej
New change in v4.
---
gdb/cli/cli-cmds.c | 56 ++++----
gdb/cli/cli-decode.c | 302 ++++++++++++++++++++++++++++++++++++++---------
gdb/cli/cli-option.c | 116 +++++++++++-------
gdb/cli/cli-option.h | 34 +++--
gdb/cli/cli-setshow.c | 249 ++++++++++++++++++--------------------
gdb/cli/cli-setshow.h | 20 +--
gdb/command.h | 108 ++++++++++++++--
gdb/guile/scm-param.c | 102 +++++++++------
gdb/maint-test-options.c | 4
gdb/python/py-param.c | 39 ++++--
gdb/python/python.c | 49 +++----
gdb/valprint.c | 9 -
12 files changed, 716 insertions(+), 372 deletions(-)
gdb-setshow-cmd-extra-literals.diff
Index: src/gdb/cli/cli-cmds.c
===================================================================
--- src.orig/gdb/cli/cli-cmds.c
+++ src/gdb/cli/cli-cmds.c
@@ -2200,22 +2200,37 @@ value_from_setting (const setting &var,
{
switch (var.type ())
{
+ case var_uinteger:
case var_integer:
- if (var.get<int> () == INT_MAX)
- return value_from_longest (builtin_type (gdbarch)->builtin_int,
- 0);
- else
- return value_from_longest (builtin_type (gdbarch)->builtin_int,
- var.get<int> ());
- case var_zinteger:
- return value_from_longest (builtin_type (gdbarch)->builtin_int,
- var.get<int> ());
+ case var_pinteger:
+ {
+ LONGEST value
+ = (var.type () == var_uinteger
+ ? static_cast<LONGEST> (var.get<unsigned int> ())
+ : static_cast<LONGEST> (var.get<int> ()));
+
+ if (var.extra_literals () != nullptr)
+ for (const literal_def *l = var.extra_literals ();
+ l->literal != nullptr;
+ l++)
+ if (value == l->use)
+ {
+ value = l->val;
+ break;
+ }
+
+ if (var.type () == var_uinteger)
+ return
+ value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
+ static_cast<const unsigned int> (value));
+ else
+ return
+ value_from_longest (builtin_type (gdbarch)->builtin_int,
+ static_cast<const int> (value));
+ }
case var_boolean:
return value_from_longest (builtin_type (gdbarch)->builtin_int,
var.get<bool> () ? 1 : 0);
- case var_zuinteger_unlimited:
- return value_from_longest (builtin_type (gdbarch)->builtin_int,
- var.get<int> ());
case var_auto_boolean:
{
int val;
@@ -2237,17 +2252,6 @@ value_from_setting (const setting &var,
return value_from_longest (builtin_type (gdbarch)->builtin_int,
val);
}
- case var_uinteger:
- if (var.get<unsigned int> () == UINT_MAX)
- return value_from_ulongest
- (builtin_type (gdbarch)->builtin_unsigned_int, 0);
- else
- return value_from_ulongest
- (builtin_type (gdbarch)->builtin_unsigned_int,
- var.get<unsigned int> ());
- case var_zuinteger:
- return value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
- var.get<unsigned int> ());
case var_string:
case var_string_noescape:
case var_optional_filename:
@@ -2317,13 +2321,11 @@ str_value_from_setting (const setting &v
{
switch (var.type ())
{
+ case var_uinteger:
case var_integer:
- case var_zinteger:
+ case var_pinteger:
case var_boolean:
- case var_zuinteger_unlimited:
case var_auto_boolean:
- case var_uinteger:
- case var_zuinteger:
{
std::string cmd_val = get_setshow_command_value_string (var);
Index: src/gdb/cli/cli-decode.c
===================================================================
--- src.orig/gdb/cli/cli-decode.c
+++ src/gdb/cli/cli-decode.c
@@ -580,11 +580,51 @@ add_setshow_cmd_full_erased (const char
return {set, show};
}
+/* Completes on integer commands that support extra literals. */
+
+static void
+integer_literals_completer (struct cmd_list_element *c,
+ completion_tracker &tracker,
+ const char *text, const char *word)
+{
+ const literal_def *extra_literals = c->var->extra_literals ();
+
+ if (*text == '\0')
+ {
+ tracker.add_completion (make_unique_xstrdup ("NUMBER"));
+ for (const literal_def *l = extra_literals;
+ l->literal != nullptr;
+ l++)
+ tracker.add_completion (make_unique_xstrdup (l->literal));
+ }
+ else
+ for (const literal_def *l = extra_literals;
+ l->literal != nullptr;
+ l++)
+ if (startswith (l->literal, text))
+ tracker.add_completion (make_unique_xstrdup (l->literal));
+}
+
+/* Add element named NAME to both the command SET_LIST and SHOW_LIST.
+ THECLASS 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. EXTRA_LITERALS if non-NULL define extra literals to be
+ accepted in lieu of a number for integer variables. If nullptr is
+ given as VAR, then both SET_SETTING_FUNC and GET_SETTING_FUNC must
+ be provided. SET_SETTING_FUNC and GET_SETTING_FUNC are callbacks
+ used to access and modify the underlying property, whatever its
+ storage is. SET_FUNC and SHOW_FUNC are the callback functions
+ (if non-NULL). SET_DOC, SHOW_DOC and HELP_DOC are the
+ documentation strings.
+
+ Return the newly created set and show commands. */
+
template<typename T>
static set_show_commands
add_setshow_cmd_full (const char *name,
enum command_class theclass,
var_types var_type, T *var,
+ const literal_def *extra_literals,
const char *set_doc, const char *show_doc,
const char *help_doc,
typename setting_func_types<T>::set set_setting_func,
@@ -595,18 +635,44 @@ add_setshow_cmd_full (const char *name,
struct cmd_list_element **show_list)
{
auto erased_args
- = setting::erase_args (var_type, var,
+ = setting::erase_args (var_type, var, extra_literals,
set_setting_func, get_setting_func);
+ auto cmds = add_setshow_cmd_full_erased (name,
+ theclass,
+ var_type, erased_args,
+ set_doc, show_doc,
+ help_doc,
+ set_func,
+ show_func,
+ set_list,
+ show_list);
- return add_setshow_cmd_full_erased (name,
- theclass,
- var_type, erased_args,
- set_doc, show_doc,
- help_doc,
- set_func,
- show_func,
- set_list,
- show_list);
+ if (extra_literals != nullptr)
+ set_cmd_completer (cmds.set, integer_literals_completer);
+
+ return cmds;
+}
+
+/* Same as above but omitting EXTRA_LITERALS. */
+
+template<typename T>
+static set_show_commands
+add_setshow_cmd_full (const char *name,
+ enum command_class theclass,
+ var_types var_type, T *var,
+ const char *set_doc, const char *show_doc,
+ const char *help_doc,
+ typename setting_func_types<T>::set set_setting_func,
+ typename setting_func_types<T>::get get_setting_func,
+ cmd_func_ftype *set_func,
+ show_value_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list)
+{
+ return add_setshow_cmd_full (name, theclass, var_type, var, nullptr,
+ set_doc, show_doc, help_doc,
+ set_setting_func, get_setting_func,
+ set_func, show_func, set_list, show_list);
}
/* Add element named NAME to command list LIST (the list for set or
@@ -975,25 +1041,6 @@ add_setshow_optional_filename_cmd (const
return cmds;
}
-/* Completes on literal "unlimited". Used by integer commands that
- support a special "unlimited" value. */
-
-static void
-integer_unlimited_completer (struct cmd_list_element *ignore,
- completion_tracker &tracker,
- const char *text, const char *word)
-{
- static const char * const keywords[] =
- {
- "unlimited",
- NULL,
- };
-
- if (*text == '\0')
- tracker.add_completion (make_unique_xstrdup ("NUMBER"));
- complete_on_enum (tracker, keywords, text, word);
-}
-
/* Add element named NAME to both the set and show command LISTs (the
list for set/show or some sublist thereof). CLASS is as in
add_cmd. VAR is address of the variable which will contain the
@@ -1002,6 +1049,55 @@ integer_unlimited_completer (struct cmd_
set_show_commands
add_setshow_integer_cmd (const char *name, enum command_class theclass,
+ int *var, const literal_def *extra_literals,
+ const char *set_doc, const char *show_doc,
+ const char *help_doc,
+ cmd_func_ftype *set_func,
+ show_value_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list)
+{
+ set_show_commands commands
+ = add_setshow_cmd_full<int> (name, theclass, var_integer, var,
+ extra_literals, set_doc, show_doc,
+ help_doc, nullptr, nullptr, set_func,
+ show_func, set_list, show_list);
+ return commands;
+}
+
+/* Same as above but using a getter and a setter function instead of a pointer
+ to a global storage buffer. */
+
+set_show_commands
+add_setshow_integer_cmd (const char *name, command_class theclass,
+ const literal_def *extra_literals,
+ const char *set_doc, const char *show_doc,
+ const char *help_doc,
+ setting_func_types<int>::set set_func,
+ setting_func_types<int>::get get_func,
+ show_value_ftype *show_func,
+ cmd_list_element **set_list,
+ cmd_list_element **show_list)
+{
+ auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
+ extra_literals, set_doc, show_doc,
+ help_doc, set_func, get_func, nullptr,
+ show_func, set_list, show_list);
+ return cmds;
+}
+
+/* Accept `unlimited' or 0, translated internally to INT_MAX. */
+const literal_def integer_unlimited_literals[] =
+ {
+ { "unlimited", 0, INT_MAX, true },
+ { nullptr }
+ };
+
+/* Same as above but using `integer_unlimited_literals', with a pointer
+ to a global storage buffer. */
+
+set_show_commands
+add_setshow_integer_cmd (const char *name, enum command_class theclass,
int *var,
const char *set_doc, const char *show_doc,
const char *help_doc,
@@ -1012,12 +1108,10 @@ add_setshow_integer_cmd (const char *nam
{
set_show_commands commands
= add_setshow_cmd_full<int> (name, theclass, var_integer, var,
+ integer_unlimited_literals,
set_doc, show_doc, help_doc,
nullptr, nullptr, set_func,
show_func, set_list, show_list);
-
- set_cmd_completer (commands.set, integer_unlimited_completer);
-
return commands;
}
@@ -1035,12 +1129,54 @@ add_setshow_integer_cmd (const char *nam
cmd_list_element **show_list)
{
auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
+ integer_unlimited_literals,
set_doc, show_doc, help_doc, set_func,
get_func, nullptr, show_func, set_list,
show_list);
+ return cmds;
+}
- set_cmd_completer (cmds.set, integer_unlimited_completer);
+/* Add element named NAME to both the set and show command LISTs (the
+ list for set/show or some sublist thereof). CLASS is as in
+ add_cmd. VAR is address of the variable which will contain the
+ value. SET_DOC and SHOW_DOC are the documentation strings. */
+
+set_show_commands
+add_setshow_pinteger_cmd (const char *name, enum command_class theclass,
+ int *var, const literal_def *extra_literals,
+ const char *set_doc, const char *show_doc,
+ const char *help_doc,
+ cmd_func_ftype *set_func,
+ show_value_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list)
+{
+ set_show_commands commands
+ = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var,
+ extra_literals, set_doc, show_doc,
+ help_doc, nullptr, nullptr, set_func,
+ show_func, set_list, show_list);
+ return commands;
+}
+/* Same as above but using a getter and a setter function instead of a pointer
+ to a global storage buffer. */
+
+set_show_commands
+add_setshow_pinteger_cmd (const char *name, command_class theclass,
+ const literal_def *extra_literals,
+ const char *set_doc, const char *show_doc,
+ const char *help_doc,
+ setting_func_types<int>::set set_func,
+ setting_func_types<int>::get get_func,
+ show_value_ftype *show_func,
+ cmd_list_element **set_list,
+ cmd_list_element **show_list)
+{
+ auto cmds = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr,
+ extra_literals, set_doc, show_doc,
+ help_doc, set_func, get_func, nullptr,
+ show_func, set_list, show_list);
return cmds;
}
@@ -1051,7 +1187,7 @@ add_setshow_integer_cmd (const char *nam
set_show_commands
add_setshow_uinteger_cmd (const char *name, enum command_class theclass,
- unsigned int *var,
+ unsigned int *var, const literal_def *extra_literals,
const char *set_doc, const char *show_doc,
const char *help_doc,
cmd_func_ftype *set_func,
@@ -1061,12 +1197,9 @@ add_setshow_uinteger_cmd (const char *na
{
set_show_commands commands
= add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var,
- set_doc, show_doc, help_doc,
- nullptr, nullptr, set_func,
+ extra_literals, set_doc, show_doc,
+ help_doc, nullptr, nullptr, set_func,
show_func, set_list, show_list);
-
- set_cmd_completer (commands.set, integer_unlimited_completer);
-
return commands;
}
@@ -1075,6 +1208,7 @@ add_setshow_uinteger_cmd (const char *na
set_show_commands
add_setshow_uinteger_cmd (const char *name, command_class theclass,
+ const literal_def *extra_literals,
const char *set_doc, const char *show_doc,
const char *help_doc,
setting_func_types<unsigned int>::set set_func,
@@ -1084,13 +1218,63 @@ add_setshow_uinteger_cmd (const char *na
cmd_list_element **show_list)
{
auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
- nullptr, set_doc, show_doc,
- help_doc, set_func, get_func,
- nullptr, show_func, set_list,
+ nullptr, extra_literals,
+ set_doc, show_doc, help_doc,
+ set_func, get_func, nullptr,
+ show_func, set_list,
show_list);
+ return cmds;
+}
- set_cmd_completer (cmds.set, integer_unlimited_completer);
+/* Accept `unlimited' or 0, translated internally to UINT_MAX. */
+const literal_def uinteger_unlimited_literals[] =
+ {
+ { "unlimited", 0, UINT_MAX, true },
+ { nullptr }
+ };
+
+/* Same as above but using `uinteger_unlimited_literals', with a pointer
+ to a global storage buffer. */
+
+set_show_commands
+add_setshow_uinteger_cmd (const char *name, enum command_class theclass,
+ unsigned int *var,
+ const char *set_doc, const char *show_doc,
+ const char *help_doc,
+ cmd_func_ftype *set_func,
+ show_value_ftype *show_func,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list)
+{
+ set_show_commands commands
+ = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var,
+ uinteger_unlimited_literals,
+ set_doc, show_doc, help_doc, nullptr,
+ nullptr, set_func, show_func,
+ set_list, show_list);
+ return commands;
+}
+
+/* Same as above but using a getter and a setter function instead of a pointer
+ to a global storage buffer. */
+set_show_commands
+add_setshow_uinteger_cmd (const char *name, command_class theclass,
+ const char *set_doc, const char *show_doc,
+ const char *help_doc,
+ setting_func_types<unsigned int>::set set_func,
+ setting_func_types<unsigned int>::get get_func,
+ show_value_ftype *show_func,
+ cmd_list_element **set_list,
+ cmd_list_element **show_list)
+{
+ auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
+ nullptr,
+ uinteger_unlimited_literals,
+ set_doc, show_doc, help_doc,
+ set_func, get_func, nullptr,
+ show_func, set_list,
+ show_list);
return cmds;
}
@@ -1109,7 +1293,7 @@ add_setshow_zinteger_cmd (const char *na
struct cmd_list_element **set_list,
struct cmd_list_element **show_list)
{
- return add_setshow_cmd_full<int> (name, theclass, var_zinteger, var,
+ return add_setshow_cmd_full<int> (name, theclass, var_integer, var,
set_doc, show_doc, help_doc,
nullptr, nullptr, set_func,
show_func, set_list, show_list);
@@ -1128,12 +1312,22 @@ add_setshow_zinteger_cmd (const char *na
cmd_list_element **set_list,
cmd_list_element **show_list)
{
- return add_setshow_cmd_full<int> (name, theclass, var_zinteger, nullptr,
+ return add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
set_doc, show_doc, help_doc, set_func,
get_func, nullptr, show_func, set_list,
show_list);
}
+/* Accept `unlimited' or -1, using -1 internally. */
+const literal_def zuinteger_unlimited_literals[] =
+ {
+ { "unlimited", -1, -1, true },
+ { nullptr }
+ };
+
+/* Same as above but using `zuinteger_unlimited_literals', with a pointer
+ to a global storage buffer. */
+
set_show_commands
add_setshow_zuinteger_unlimited_cmd (const char *name,
enum command_class theclass,
@@ -1147,13 +1341,11 @@ add_setshow_zuinteger_unlimited_cmd (con
struct cmd_list_element **show_list)
{
set_show_commands commands
- = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited, var,
+ = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var,
+ zuinteger_unlimited_literals,
set_doc, show_doc, help_doc, nullptr,
nullptr, set_func, show_func, set_list,
show_list);
-
- set_cmd_completer (commands.set, integer_unlimited_completer);
-
return commands;
}
@@ -1171,13 +1363,11 @@ add_setshow_zuinteger_unlimited_cmd (con
cmd_list_element **show_list)
{
auto cmds
- = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited,
- nullptr, set_doc, show_doc, help_doc, set_func,
+ = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr,
+ zuinteger_unlimited_literals,
+ set_doc, show_doc, help_doc, set_func,
get_func, nullptr, show_func, set_list,
show_list);
-
- set_cmd_completer (cmds.set, integer_unlimited_completer);
-
return cmds;
}
@@ -1196,7 +1386,7 @@ add_setshow_zuinteger_cmd (const char *n
struct cmd_list_element **set_list,
struct cmd_list_element **show_list)
{
- return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger,
+ return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
var, set_doc, show_doc, help_doc,
nullptr, nullptr, set_func,
show_func, set_list, show_list);
@@ -1215,7 +1405,7 @@ add_setshow_zuinteger_cmd (const char *n
cmd_list_element **set_list,
cmd_list_element **show_list)
{
- return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger,
+ return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
nullptr, set_doc, show_doc,
help_doc, set_func, get_func,
nullptr, show_func, set_list,
Index: src/gdb/cli/cli-option.c
===================================================================
--- src.orig/gdb/cli/cli-option.c
+++ src/gdb/cli/cli-option.c
@@ -38,7 +38,7 @@ union option_value
/* For var_uinteger options. */
unsigned int uinteger;
- /* For var_zuinteger_unlimited options. */
+ /* For var_integer and var_pinteger options. */
int integer;
/* For var_enum options. */
@@ -356,42 +356,55 @@ parse_option (gdb::array_view<const opti
return option_def_and_value {*match, match_ctx, val};
}
case var_uinteger:
- case var_zuinteger_unlimited:
+ case var_integer:
+ case var_pinteger:
{
if (completion != nullptr)
{
- if (**args == '\0')
- {
- /* Convenience to let the user know what the option
- can accept. Note there's no common prefix between
- the strings on purpose, so that readline doesn't do
- a partial match. */
- completion->tracker.add_completion
- (make_unique_xstrdup ("NUMBER"));
- completion->tracker.add_completion
- (make_unique_xstrdup ("unlimited"));
- return {};
- }
- else if (startswith ("unlimited", *args))
+ if (match->extra_literals != nullptr)
{
- completion->tracker.add_completion
- (make_unique_xstrdup ("unlimited"));
- return {};
+ /* Convenience to let the user know what the option can
+ accept. Make sure there's no common prefix between
+ "NUMBER" and all the strings when adding new ones,
+ so that readline doesn't do a partial match. */
+ if (**args == '\0')
+ {
+ completion->tracker.add_completion
+ (make_unique_xstrdup ("NUMBER"));
+ for (const literal_def *l = match->extra_literals;
+ l->literal != nullptr;
+ l++)
+ completion->tracker.add_completion
+ (make_unique_xstrdup (l->literal));
+ return {};
+ }
+ else
+ {
+ bool completions = false;
+ for (const literal_def *l = match->extra_literals;
+ l->literal != nullptr;
+ l++)
+ if (startswith (l->literal, *args))
+ {
+ completion->tracker.add_completion
+ (make_unique_xstrdup (l->literal));
+ completions = true;
+ }
+ if (completions)
+ return {};
+ }
}
}
- if (match->type == var_zuinteger_unlimited)
- {
- option_value val;
- val.integer = parse_cli_var_zuinteger_unlimited (args, false);
- return option_def_and_value {*match, match_ctx, val};
- }
+ LONGEST v = parse_cli_var_integer (match->type,
+ match->extra_literals,
+ args, false);
+ option_value val;
+ if (match->type == var_uinteger)
+ val.uinteger = v;
else
- {
- option_value val;
- val.uinteger = parse_cli_var_uinteger (match->type, args, false);
- return option_def_and_value {*match, match_ctx, val};
- }
+ val.integer = v;
+ return option_def_and_value {*match, match_ctx, val};
}
case var_enum:
{
@@ -593,7 +606,7 @@ save_option_value_in_ctx (gdb::optional<
*ov->option.var_address.uinteger (ov->option, ov->ctx)
= ov->value->uinteger;
break;
- case var_zuinteger_unlimited:
+ case var_integer:
*ov->option.var_address.integer (ov->option, ov->ctx)
= ov->value->integer;
break;
@@ -664,8 +677,20 @@ get_val_type_str (const option_def &opt,
case var_boolean:
return "[on|off]";
case var_uinteger:
- case var_zuinteger_unlimited:
- return "NUMBER|unlimited";
+ case var_integer:
+ case var_pinteger:
+ {
+ buffer = "NUMBER";
+ if (opt.extra_literals != nullptr)
+ for (const literal_def *l = opt.extra_literals;
+ l->literal != nullptr;
+ l++)
+ {
+ buffer += '|';
+ buffer += l->literal;
+ }
+ return buffer.c_str ();
+ }
case var_enum:
{
buffer = "";
@@ -789,20 +814,31 @@ add_setshow_cmds_for_options (command_cl
{
add_setshow_uinteger_cmd (option.name, cmd_class,
option.var_address.uinteger (option, data),
+ option.extra_literals,
option.set_doc, option.show_doc,
option.help_doc,
nullptr, option.show_cmd_cb,
set_list, show_list);
}
- else if (option.type == var_zuinteger_unlimited)
+ else if (option.type == var_integer)
{
- add_setshow_zuinteger_unlimited_cmd
- (option.name, cmd_class,
- option.var_address.integer (option, data),
- option.set_doc, option.show_doc,
- option.help_doc,
- nullptr, option.show_cmd_cb,
- set_list, show_list);
+ add_setshow_integer_cmd (option.name, cmd_class,
+ option.var_address.integer (option, data),
+ option.extra_literals,
+ option.set_doc, option.show_doc,
+ option.help_doc,
+ nullptr, option.show_cmd_cb,
+ set_list, show_list);
+ }
+ else if (option.type == var_pinteger)
+ {
+ add_setshow_pinteger_cmd (option.name, cmd_class,
+ option.var_address.integer (option, data),
+ option.extra_literals,
+ option.set_doc, option.show_doc,
+ option.help_doc,
+ nullptr, option.show_cmd_cb,
+ set_list, show_list);
}
else if (option.type == var_enum)
{
Index: src/gdb/cli/cli-option.h
===================================================================
--- src.orig/gdb/cli/cli-option.h
+++ src/gdb/cli/cli-option.h
@@ -49,12 +49,13 @@ struct option_def
used to create the option's "set/show" commands. */
constexpr option_def (const char *name_,
var_types var_type_,
+ const literal_def *extra_literals_,
erased_get_var_address_ftype *erased_get_var_address_,
show_value_ftype *show_cmd_cb_,
const char *set_doc_,
const char *show_doc_,
const char *help_doc_)
- : name (name_), type (var_type_),
+ : name (name_), type (var_type_), extra_literals (extra_literals_),
erased_get_var_address (erased_get_var_address_),
var_address {},
show_cmd_cb (show_cmd_cb_),
@@ -68,6 +69,9 @@ struct option_def
/* The option's type. */
var_types type;
+ /* Extra literals, such as `unlimited', accepted in lieu of a number. */
+ const literal_def *extra_literals;
+
/* A function that gets the controlling variable's address, type
erased. */
erased_get_var_address_ftype *erased_get_var_address;
@@ -160,7 +164,7 @@ struct boolean_option_def : option_def
const char *set_doc_,
const char *show_doc_ = nullptr,
const char *help_doc_ = nullptr)
- : option_def (long_option_, var_boolean,
+ : option_def (long_option_, var_boolean, nullptr,
(erased_get_var_address_ftype *) get_var_address_cb_,
show_cmd_cb_,
set_doc_, show_doc_, help_doc_)
@@ -207,11 +211,12 @@ struct uinteger_option_def : option_def
{
uinteger_option_def (const char *long_option_,
unsigned int *(*get_var_address_cb_) (Context *),
+ const literal_def *extra_literals_,
show_value_ftype *show_cmd_cb_,
const char *set_doc_,
const char *show_doc_ = nullptr,
const char *help_doc_ = nullptr)
- : option_def (long_option_, var_uinteger,
+ : option_def (long_option_, var_uinteger, extra_literals_,
(erased_get_var_address_ftype *) get_var_address_cb_,
show_cmd_cb_,
set_doc_, show_doc_, help_doc_)
@@ -220,18 +225,19 @@ struct uinteger_option_def : option_def
}
};
-/* A var_zuinteger_unlimited command line option. */
+/* A var_integer command line option. */
template<typename Context>
-struct zuinteger_unlimited_option_def : option_def
+struct integer_option_def : option_def
{
- zuinteger_unlimited_option_def (const char *long_option_,
- int *(*get_var_address_cb_) (Context *),
- show_value_ftype *show_cmd_cb_,
- const char *set_doc_,
- const char *show_doc_ = nullptr,
- const char *help_doc_ = nullptr)
- : option_def (long_option_, var_zuinteger_unlimited,
+ integer_option_def (const char *long_option_,
+ int *(*get_var_address_cb_) (Context *),
+ const literal_def *extra_literals_,
+ show_value_ftype *show_cmd_cb_,
+ const char *set_doc_,
+ const char *show_doc_ = nullptr,
+ const char *help_doc_ = nullptr)
+ : option_def (long_option_, var_integer, extra_literals_,
(erased_get_var_address_ftype *) get_var_address_cb_,
show_cmd_cb_,
set_doc_, show_doc_, help_doc_)
@@ -252,7 +258,7 @@ struct enum_option_def : option_def
const char *set_doc_,
const char *show_doc_ = nullptr,
const char *help_doc_ = nullptr)
- : option_def (long_option_, var_enum,
+ : option_def (long_option_, var_enum, nullptr,
(erased_get_var_address_ftype *) get_var_address_cb_,
show_cmd_cb_,
set_doc_, show_doc_, help_doc_)
@@ -273,7 +279,7 @@ struct string_option_def : option_def
const char *set_doc_,
const char *show_doc_ = nullptr,
const char *help_doc_ = nullptr)
- : option_def (long_option_, var_string,
+ : option_def (long_option_, var_string, nullptr,
(erased_get_var_address_ftype *) get_var_address_cb_,
show_cmd_cb_,
set_doc_, show_doc_, help_doc_)
Index: src/gdb/cli/cli-setshow.c
===================================================================
--- src.orig/gdb/cli/cli-setshow.c
+++ src/gdb/cli/cli-setshow.c
@@ -149,10 +149,11 @@ deprecated_show_value_hack (struct ui_fi
}
}
-/* Returns true if ARG is "unlimited". */
+/* Returns true and the value in VAL if ARG is an accepted literal. */
static bool
-is_unlimited_literal (const char **arg, bool expression)
+get_literal_val (LONGEST &val, const literal_def *extra_literals,
+ const char **arg, bool expression)
{
*arg = skip_spaces (*arg);
@@ -162,85 +163,108 @@ is_unlimited_literal (const char **arg,
size_t len = p - *arg;
- if (len > 0 && strncmp ("unlimited", *arg, len) == 0)
- {
- *arg += len;
-
- /* If parsing an expression (i.e., parsing for a "set" command),
- anything after "unlimited" is junk. For options, anything
- after "unlimited" might be a command argument or another
- option. */
- if (expression)
+ if (len > 0 && extra_literals != nullptr)
+ for (const literal_def *l = extra_literals;
+ l->literal != nullptr;
+ l++)
+ if (strncmp (l->literal, *arg, len) == 0)
{
- const char *after = skip_spaces (*arg);
- if (*after != '\0')
- error (_("Junk after \"%.*s\": %s"),
- (int) len, unl_start, after);
- }
+ *arg += len;
- return true;
- }
+ /* If parsing an expression (i.e., parsing for a "set" command),
+ anything after the literal is junk. For options, anything
+ after the literal might be a command argument or another
+ option. */
+ if (expression)
+ {
+ const char *after = skip_spaces (*arg);
+ if (*after != '\0')
+ error (_("Junk after \"%.*s\": %s"),
+ (int) len, unl_start, after);
+ }
+
+ val = l->use;
+ return true;
+ }
return false;
}
/* See cli-setshow.h. */
-unsigned int
-parse_cli_var_uinteger (var_types var_type, const char **arg,
- bool expression)
+LONGEST
+parse_cli_var_integer (var_types var_type, const literal_def *extra_literals,
+ const char **arg, bool expression)
{
LONGEST val;
if (*arg == nullptr || **arg == '\0')
{
- if (var_type == var_uinteger)
- error_no_arg (_("integer to set it to, or \"unlimited\""));
- else
+ if (extra_literals == nullptr)
error_no_arg (_("integer to set it to"));
- }
-
- if (var_type == var_uinteger && is_unlimited_literal (arg, expression))
- val = 0;
- else if (expression)
- val = parse_and_eval_long (*arg);
- else
- val = get_ulongest (arg);
-
- if (var_type == var_uinteger && val == 0)
- val = UINT_MAX;
- else if (val < 0
- /* For var_uinteger, don't let the user set the value
- to UINT_MAX directly, as that exposes an
- implementation detail to the user interface. */
- || (var_type == var_uinteger && val >= UINT_MAX)
- || (var_type == var_zuinteger && val > UINT_MAX))
- error (_("integer %s out of range"), plongest (val));
-
- return val;
-}
-
-/* See cli-setshow.h. */
+ else
+ {
+ std::string buffer = "";
+ size_t count = 0;
-int
-parse_cli_var_zuinteger_unlimited (const char **arg, bool expression)
-{
- LONGEST val;
+ for (const literal_def *l = extra_literals;
+ l->literal != nullptr;
+ l++, count++)
+ {
+ if (count != 0)
+ buffer += ", ";
+ buffer = buffer + '"' + l->literal + '"';
+ }
+ if (count > 1)
+ error_no_arg
+ (string_printf (_("integer to set it to, or one of: %s"),
+ buffer.c_str ()).c_str ());
+ else
+ error_no_arg
+ (string_printf (_("integer to set it to, or %s"),
+ buffer.c_str ()).c_str ());
+ }
+ }
- if (*arg == nullptr || **arg == '\0')
- error_no_arg (_("integer to set it to, or \"unlimited\""));
+ if (!get_literal_val (val, extra_literals, arg, expression))
+ {
+ if (expression)
+ val = parse_and_eval_long (*arg);
+ else
+ val = get_ulongest (arg);
- if (is_unlimited_literal (arg, expression))
- val = -1;
- else if (expression)
- val = parse_and_eval_long (*arg);
- else
- val = get_ulongest (arg);
+ enum tribool allowed = TRIBOOL_UNKNOWN;
+ if (extra_literals != nullptr)
+ {
+ for (const literal_def *l = extra_literals;
+ l->literal != nullptr;
+ l++)
+ if (val == l->val)
+ {
+ allowed = l->allow ? TRIBOOL_TRUE : TRIBOOL_FALSE;
+ val = l->use;
+ break;
+ }
+ else if (val == l->use)
+ {
+ allowed = TRIBOOL_FALSE;
+ break;
+ }
+ }
- if (val > INT_MAX)
- error (_("integer %s out of range"), plongest (val));
- else if (val < -1)
- error (_("only -1 is allowed to set as unlimited"));
+ if (allowed == TRIBOOL_UNKNOWN)
+ {
+ if (var_type == var_pinteger && val < 0)
+ error (_("only -1 is allowed to set as unlimited"));
+ else if (val > UINT_MAX || val < INT_MIN
+ || (var_type == var_uinteger && val < 0)
+ || (var_type == var_integer && val > INT_MAX)
+ || (var_type == var_pinteger && val > INT_MAX))
+ allowed = TRIBOOL_FALSE;
+ }
+ if (allowed == TRIBOOL_FALSE)
+ error (_("integer %s out of range"), plongest (val));
+ }
return val;
}
@@ -405,41 +429,18 @@ do_set_command (const char *arg, int fro
option_changed = c->var->set<enum auto_boolean> (parse_auto_binary_operation (arg));
break;
case var_uinteger:
- case var_zuinteger:
option_changed
- = c->var->set<unsigned int> (parse_cli_var_uinteger (c->var->type (),
- &arg, true));
+ = c->var->set<unsigned int> (parse_cli_var_integer (c->var->type (),
+ c->var->
+ extra_literals (),
+ &arg, true));
break;
case var_integer:
- case var_zinteger:
- {
- LONGEST val;
-
- if (*arg == '\0')
- {
- if (c->var->type () == var_integer)
- error_no_arg (_("integer to set it to, or \"unlimited\""));
- else
- error_no_arg (_("integer to set it to"));
- }
-
- if (c->var->type () == var_integer && is_unlimited_literal (&arg, true))
- val = 0;
- else
- val = parse_and_eval_long (arg);
-
- if (val == 0 && c->var->type () == var_integer)
- val = INT_MAX;
- else if (val < INT_MIN
- /* For var_integer, don't let the user set the value
- to INT_MAX directly, as that exposes an
- implementation detail to the user interface. */
- || (c->var->type () == var_integer && val >= INT_MAX)
- || (c->var->type () == var_zinteger && val > INT_MAX))
- error (_("integer %s out of range"), plongest (val));
-
- option_changed = c->var->set<int> (val);
- }
+ case var_pinteger:
+ option_changed
+ = c->var->set<int> (parse_cli_var_integer (c->var->type (),
+ c->var->extra_literals (),
+ &arg, true));
break;
case var_enum:
{
@@ -454,10 +455,6 @@ do_set_command (const char *arg, int fro
option_changed = c->var->set<const char *> (match);
}
break;
- case var_zuinteger_unlimited:
- option_changed = c->var->set<int>
- (parse_cli_var_zuinteger_unlimited (&arg, true));
- break;
default:
error (_("gdb internal error: bad var_type in do_setshow_command"));
}
@@ -551,7 +548,6 @@ do_set_command (const char *arg, int fro
}
break;
case var_uinteger:
- case var_zuinteger:
{
char s[64];
@@ -560,8 +556,7 @@ do_set_command (const char *arg, int fro
}
break;
case var_integer:
- case var_zinteger:
- case var_zuinteger_unlimited:
+ case var_pinteger:
{
char s[64];
@@ -623,36 +618,32 @@ get_setshow_command_value_string (const
}
break;
case var_uinteger:
- case var_zuinteger:
- {
- const unsigned int value = var.get<unsigned int> ();
-
- if (var.type () == var_uinteger
- && value == UINT_MAX)
- stb.puts ("unlimited");
- else
- stb.printf ("%u", value);
- }
- break;
case var_integer:
- case var_zinteger:
+ case var_pinteger:
{
- const int value = var.get<int> ();
+ bool printed = false;
+ const LONGEST value
+ = (var.type () == var_uinteger
+ ? static_cast<LONGEST> (var.get<unsigned int> ())
+ : static_cast<LONGEST> (var.get<int> ()));
- if (var.type () == var_integer
- && value == INT_MAX)
- stb.puts ("unlimited");
- else
- stb.printf ("%d", value);
- }
- break;
- case var_zuinteger_unlimited:
- {
- const int value = var.get<int> ();
- if (value == -1)
- stb.puts ("unlimited");
- else
- stb.printf ("%d", value);
+ if (var.extra_literals () != nullptr)
+ for (const literal_def *l = var.extra_literals ();
+ l->literal != nullptr;
+ l++)
+ if (value == l->use)
+ {
+ stb.puts (l->literal);
+ printed = true;
+ break;
+ }
+ if (!printed)
+ {
+ if (var.type () == var_uinteger)
+ stb.printf ("%u", static_cast<const unsigned int> (value));
+ else
+ stb.printf ("%d", static_cast<const int> (value));
+ }
}
break;
default:
Index: src/gdb/cli/cli-setshow.h
===================================================================
--- src.orig/gdb/cli/cli-setshow.h
+++ src/gdb/cli/cli-setshow.h
@@ -29,21 +29,19 @@ extern int parse_cli_boolean_value (cons
past a successfully parsed value. */
extern int parse_cli_boolean_value (const char **arg);
-/* Parse ARG, an option to a var_uinteger or var_zuinteger variable.
- Either returns the parsed value on success or throws an error. If
- EXPRESSION is true, *ARG is parsed as an expression; otherwise, it
- is parsed with get_ulongest. It's not possible to parse the
+/* Parse ARG, an option to a var_uinteger, var_integer or var_pinteger
+ variable. Return the parsed value on success or throw an error. If
+ EXTRA_LITERALS is non-null, then interpret those literals accordingly.
+ If EXPRESSION is true, *ARG is parsed as an expression; otherwise,
+ it is parsed with get_ulongest. It's not possible to parse the
integer as an expression when there may be valid input after the
integer, such as when parsing command options. E.g., "print
-elements NUMBER -obj --". In such case, parsing as an expression
would parse "-obj --" as part of the expression as well. */
-extern unsigned int parse_cli_var_uinteger (var_types var_type,
- const char **arg,
- bool expression);
-
-/* Like parse_cli_var_uinteger, for var_zuinteger_unlimited. */
-extern int parse_cli_var_zuinteger_unlimited (const char **arg,
- bool expression);
+extern LONGEST parse_cli_var_integer (var_types var_type,
+ const literal_def *extra_literals,
+ const char **arg,
+ bool expression);
/* Parse ARG, an option to a var_enum variable. ENUM is a
null-terminated array of possible values. Either returns the parsed
Index: src/gdb/command.h
===================================================================
--- src.orig/gdb/command.h
+++ src/gdb/command.h
@@ -84,16 +84,18 @@ typedef enum var_types
value. */
var_auto_boolean,
- /* Unsigned Integer. *VAR is an unsigned int. The user can type
- 0 to mean "unlimited", which is stored in *VAR as UINT_MAX. */
+ /* Unsigned Integer. *VAR is an unsigned int. In the Guile and Python
+ APIs 0 means unlimited, which is stored in *VAR as UINT_MAX. */
var_uinteger,
- /* Like var_uinteger but signed. *VAR is an int. The user can
- type 0 to mean "unlimited", which is stored in *VAR as
- INT_MAX. The only remaining use of it is the Python API.
- Don't use it elsewhere. */
+ /* Like var_uinteger but signed. *VAR is an int. In the Guile and
+ Python APIs 0 means unlimited, which is stored in *VAR as INT_MAX. */
var_integer,
+ /* Like var_integer but negative numbers are not allowed,
+ except for special values. *VAR is an int. */
+ var_pinteger,
+
/* String which the user enters with escapes (e.g. the user types
\n and it is a real newline in the stored string).
*VAR is a std::string, "" if the string is empty. */
@@ -106,15 +108,16 @@ typedef enum var_types
var_optional_filename,
/* String which stores a filename. (*VAR) is a std::string. */
var_filename,
- /* ZeroableInteger. *VAR is an int. Like var_integer except
- that zero really means zero. */
+ /* Like var_integer. *VAR is an int. The only remaining uses
+ of it are the Guile and Python APIs. Don't use it elsewhere. */
var_zinteger,
- /* ZeroableUnsignedInteger. *VAR is an unsigned int. Zero really
- means zero. */
+ /* Like var_uinteger. *VAR is an unsigned int. The only remaining
+ uses of it are the Guile and Python APIs. Don't use it elsewhere. */
var_zuinteger,
- /* ZeroableUnsignedInteger with unlimited value. *VAR is an int,
- but its range is [0, INT_MAX]. -1 stands for unlimited and
- other negative numbers are not allowed. */
+ /* Like var_pinteger. *VAR is an int, but its range is [-1, INT_MAX].
+ -1 stands for unlimited and other negative numbers are not allowed.
+ The only remaining uses of it are the Guile and Python APIs. Don't
+ use it elsewhere. */
var_zuinteger_unlimited,
/* Enumerated type. Can only have one of the specified values.
*VAR is a char pointer to the name of the element that we
@@ -123,6 +126,22 @@ typedef enum var_types
}
var_types;
+/* A structure describing an extra literal accepted and shown in place
+ of a number. */
+typedef struct literal_defs
+ {
+ /* The literal to define, e.g. "unlimited". */
+ const char *literal;
+ /* A number optionally accepted that stands for the literal. */
+ LONGEST val;
+ /* The number to substitute internally for LITERAL or VAL;
+ the use of this number is not allowed (unless the same as VAL). */
+ LONGEST use;
+ /* True if the use of VAL is allowed; otherwise only the literal is. */
+ bool allow;
+ }
+literal_def;
+
/* Return true if a setting of type VAR_TYPE is backed with type T.
This function is left without definition intentionally. This template is
@@ -153,15 +172,14 @@ inline bool var_type_uses<enum auto_bool
template<>
inline bool var_type_uses<unsigned int> (var_types t)
{
- return (t == var_uinteger || t == var_zinteger || t == var_zuinteger);
+ return t == var_uinteger;
}
/* Return true if a setting of type T is backed by an int variable. */
template<>
inline bool var_type_uses<int> (var_types t)
{
- return (t == var_integer || t == var_zinteger
- || t == var_zuinteger_unlimited);
+ return t == var_integer || t == var_pinteger;
}
/* Return true if a setting of type T is backed by a std::string variable. */
@@ -233,6 +251,7 @@ struct setting
struct erased_args
{
void *var;
+ const void *extra_literals;
erased_func setter;
erased_func getter;
};
@@ -240,6 +259,7 @@ struct setting
template<typename T>
static erased_args erase_args (var_types var_type,
T *var,
+ const literal_def *extra_literals,
typename setting_func_types<T>::set set_setting_func,
typename setting_func_types<T>::get get_setting_func)
{
@@ -254,6 +274,7 @@ struct setting
return {
var,
+ extra_literals,
reinterpret_cast<erased_func> (set_setting_func),
reinterpret_cast<erased_func> (get_setting_func)
};
@@ -265,6 +286,7 @@ struct setting
setting (var_types var_type, const erased_args &args)
: m_var_type (var_type),
m_var (args.var),
+ m_extra_literals (args.extra_literals),
m_getter (args.getter),
m_setter (args.setter)
{
@@ -295,6 +317,10 @@ struct setting
var_types type () const
{ return m_var_type; }
+ /* Access any extra literals accepted. */
+ const literal_def *extra_literals () const
+ { return static_cast<const literal_def *> (m_extra_literals); }
+
/* Return the current value.
The template parameter T is the type of the variable used to store the
@@ -357,6 +383,9 @@ struct setting
non-nullptr. */
void *m_var = nullptr;
+ /* Any extra literals accepted. */
+ const void *m_extra_literals = nullptr;
+
/* Pointer to a user provided getter. */
erased_func m_getter = nullptr;
@@ -652,6 +681,11 @@ typedef void (show_value_ftype) (struct
instead print the value out directly. */
extern show_value_ftype deprecated_show_value_hack;
+/* Various sets of extra literals accepted. */
+extern const literal_def integer_unlimited_literals[];
+extern const literal_def uinteger_unlimited_literals[];
+extern const literal_def zuinteger_unlimited_literals[];
+
extern set_show_commands add_setshow_enum_cmd
(const char *name, command_class theclass, const char *const *enumlist,
const char **var, const char *set_doc, const char *show_doc,
@@ -748,6 +782,20 @@ extern set_show_commands add_setshow_opt
cmd_list_element **show_list);
extern set_show_commands add_setshow_integer_cmd
+ (const char *name, command_class theclass, int *var,
+ const literal_def *extra_literals, const char *set_doc,
+ const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
+ show_value_ftype *show_func, cmd_list_element **set_list,
+ cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_integer_cmd
+ (const char *name, command_class theclass, const literal_def *extra_literals,
+ const char *set_doc, const char *show_doc, const char *help_doc,
+ setting_func_types<int>::set set_func,
+ setting_func_types<int>::get get_func, show_value_ftype *show_func,
+ cmd_list_element **set_list, cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_integer_cmd
(const char *name, command_class theclass, int *var, const char *set_doc,
const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
show_value_ftype *show_func, cmd_list_element **set_list,
@@ -760,6 +808,34 @@ extern set_show_commands add_setshow_int
setting_func_types<int>::get get_func, show_value_ftype *show_func,
cmd_list_element **set_list, cmd_list_element **show_list);
+extern set_show_commands add_setshow_pinteger_cmd
+ (const char *name, command_class theclass, int *var,
+ const literal_def *extra_literals, const char *set_doc,
+ const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
+ show_value_ftype *show_func, cmd_list_element **set_list,
+ cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_pinteger_cmd
+ (const char *name, command_class theclass, const literal_def *extra_literals,
+ const char *set_doc, const char *show_doc, const char *help_doc,
+ setting_func_types<int>::set set_func,
+ setting_func_types<int>::get get_func, show_value_ftype *show_func,
+ cmd_list_element **set_list, cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_uinteger_cmd
+ (const char *name, command_class theclass, unsigned int *var,
+ const literal_def *extra_literals,
+ const char *set_doc, const char *show_doc, const char *help_doc,
+ cmd_func_ftype *set_func, show_value_ftype *show_func,
+ cmd_list_element **set_list, cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_uinteger_cmd
+ (const char *name, command_class theclass, const literal_def *extra_literals,
+ const char *set_doc, const char *show_doc, const char *help_doc,
+ setting_func_types<unsigned int>::set set_func,
+ setting_func_types<unsigned int>::get get_func, show_value_ftype *show_func,
+ cmd_list_element **set_list, cmd_list_element **show_list);
+
extern set_show_commands add_setshow_uinteger_cmd
(const char *name, command_class theclass, unsigned int *var,
const char *set_doc, const char *show_doc, const char *help_doc,
Index: src/gdb/guile/scm-param.c
===================================================================
--- src.orig/gdb/guile/scm-param.c
+++ src/gdb/guile/scm-param.c
@@ -117,18 +117,33 @@ struct param_smob
static setting
make_setting (param_smob *s)
{
- if (var_type_uses<bool> (s->type))
- return setting (s->type, &s->value.boolval);
- else if (var_type_uses<int> (s->type))
- return setting (s->type, &s->value.intval);
- else if (var_type_uses<auto_boolean> (s->type))
- return setting (s->type, &s->value.autoboolval);
- else if (var_type_uses<unsigned int> (s->type))
- return setting (s->type, &s->value.uintval);
- else if (var_type_uses<std::string> (s->type))
- return setting (s->type, s->value.stringval);
- else if (var_type_uses<const char *> (s->type))
- return setting (s->type, &s->value.cstringval);
+ enum var_types type = s->type;
+
+ switch (type)
+ {
+ case var_zinteger:
+ type = var_integer;
+ break;
+ case var_zuinteger:
+ type = var_uinteger;
+ break;
+ case var_zuinteger_unlimited:
+ type = var_pinteger;
+ break;
+ }
+
+ if (var_type_uses<bool> (type))
+ return setting (type, &s->value.boolval);
+ else if (var_type_uses<int> (type))
+ return setting (type, &s->value.intval);
+ else if (var_type_uses<auto_boolean> (type))
+ return setting (type, &s->value.autoboolval);
+ else if (var_type_uses<unsigned int> (type))
+ return setting (type, &s->value.uintval);
+ else if (var_type_uses<std::string> (type))
+ return setting (type, s->value.stringval);
+ else if (var_type_uses<const char *> (type))
+ return setting (type, &s->value.cstringval);
else
gdb_assert_not_reached ("unhandled var type");
}
@@ -588,10 +603,6 @@ pascm_param_type_name (enum var_types pa
static SCM
pascm_param_value (const setting &var, int arg_pos, const char *func_name)
{
- /* Note: We *could* support var_integer here in case someone is trying to get
- the value of a Python-created parameter (which is the only place that
- still supports var_integer). To further discourage its use we do not. */
-
switch (var.type ())
{
case var_string:
@@ -631,20 +642,35 @@ pascm_param_value (const setting &var, i
return auto_keyword;
}
- case var_zuinteger_unlimited:
- if (var.get<int> () == -1)
- return unlimited_keyword;
- gdb_assert (var.get<int> () >= 0);
- /* Fall through. */
- case var_zinteger:
- return scm_from_int (var.get<int> ());
-
case var_uinteger:
- if (var.get<unsigned int> ()== UINT_MAX)
- return unlimited_keyword;
- /* Fall through. */
- case var_zuinteger:
- return scm_from_uint (var.get<unsigned int> ());
+ case var_integer:
+ case var_pinteger:
+ {
+ LONGEST value
+ = (var.type () == var_uinteger
+ ? static_cast<LONGEST> (var.get<unsigned int> ())
+ : static_cast<LONGEST> (var.get<int> ()));
+
+ bool literal = false;
+ if (var.extra_literals () != nullptr)
+ for (const literal_def *l = var.extra_literals ();
+ l->literal != nullptr;
+ l++)
+ if (value == l->use)
+ {
+ if (strcmp (l->literal, "unlimited") == 0)
+ return unlimited_keyword;
+ value = l->val;
+ literal = true;
+ }
+ if (var.type () == var_pinteger && !literal)
+ gdb_assert (value >= 0);
+
+ if (var.type () == var_uinteger)
+ return scm_from_uint (static_cast<const unsigned int> (value));
+ else
+ return scm_from_int (static_cast<const int> (value));
+ }
default:
break;
@@ -666,14 +692,14 @@ pascm_set_param_value_x (param_smob *p_s
{
setting var = make_setting (p_smob);
- switch (var.type ())
+ switch (p_smob->type)
{
case var_string:
case var_string_noescape:
case var_optional_filename:
case var_filename:
SCM_ASSERT_TYPE (scm_is_string (value)
- || (var.type () != var_filename
+ || (p_smob->type != var_filename
&& gdbscm_is_false (value)),
value, arg_pos, func_name,
_("string or #f for non-PARAM_FILENAME parameters"));
@@ -739,8 +765,8 @@ pascm_set_param_value_x (param_smob *p_s
case var_uinteger:
case var_zuinteger:
case var_zuinteger_unlimited:
- if (var.type () == var_uinteger
- || var.type () == var_zuinteger_unlimited)
+ if (p_smob->type == var_uinteger
+ || p_smob->type == var_zuinteger_unlimited)
{
SCM_ASSERT_TYPE (gdbscm_is_bool (value)
|| scm_is_eq (value, unlimited_keyword),
@@ -748,7 +774,7 @@ pascm_set_param_value_x (param_smob *p_s
_("integer or #:unlimited"));
if (scm_is_eq (value, unlimited_keyword))
{
- if (var.type () == var_uinteger)
+ if (p_smob->type == var_uinteger)
var.set<unsigned int> (UINT_MAX);
else
var.set<int> (-1);
@@ -761,12 +787,12 @@ pascm_set_param_value_x (param_smob *p_s
_("integer"));
}
- if (var.type () == var_uinteger
- || var.type () == var_zuinteger)
+ if (p_smob->type == var_uinteger
+ || p_smob->type == var_zuinteger)
{
unsigned int u = scm_to_uint (value);
- if (var.type () == var_uinteger && u == 0)
+ if (p_smob->type == var_uinteger && u == 0)
u = UINT_MAX;
var.set<unsigned int> (u);
}
@@ -774,7 +800,7 @@ pascm_set_param_value_x (param_smob *p_s
{
int i = scm_to_int (value);
- if (var.type () == var_zuinteger_unlimited && i < -1)
+ if (p_smob->type == var_zuinteger_unlimited && i < -1)
{
gdbscm_out_of_range_error (func_name, arg_pos, value,
_("must be >= -1"));
Index: src/gdb/maint-test-options.c
===================================================================
--- src.orig/gdb/maint-test-options.c
+++ src/gdb/maint-test-options.c
@@ -207,6 +207,7 @@ static const gdb::option::option_def tes
gdb::option::uinteger_option_def<test_options_opts> {
"uinteger",
[] (test_options_opts *opts) { return &opts->uint_opt; },
+ uinteger_unlimited_literals,
nullptr, /* show_cmd_cb */
N_("A uinteger option."),
nullptr, /* show_doc */
@@ -214,9 +215,10 @@ static const gdb::option::option_def tes
},
/* A zuinteger_unlimited option. */
- gdb::option::zuinteger_unlimited_option_def<test_options_opts> {
+ gdb::option::integer_option_def<test_options_opts> {
"zuinteger-unlimited",
[] (test_options_opts *opts) { return &opts->zuint_unl_opt; },
+ zuinteger_unlimited_literals,
nullptr, /* show_cmd_cb */
N_("A zuinteger-unlimited option."),
nullptr, /* show_doc */
Index: src/gdb/python/py-param.c
===================================================================
--- src.orig/gdb/python/py-param.c
+++ src/gdb/python/py-param.c
@@ -96,18 +96,33 @@ struct parmpy_object
static setting
make_setting (parmpy_object *s)
{
- if (var_type_uses<bool> (s->type))
- return setting (s->type, &s->value.boolval);
- else if (var_type_uses<int> (s->type))
- return setting (s->type, &s->value.intval);
- else if (var_type_uses<auto_boolean> (s->type))
- return setting (s->type, &s->value.autoboolval);
- else if (var_type_uses<unsigned int> (s->type))
- return setting (s->type, &s->value.uintval);
- else if (var_type_uses<std::string> (s->type))
- return setting (s->type, s->value.stringval);
- else if (var_type_uses<const char *> (s->type))
- return setting (s->type, &s->value.cstringval);
+ enum var_types type = s->type;
+
+ switch (type)
+ {
+ case var_zinteger:
+ type = var_integer;
+ break;
+ case var_zuinteger:
+ type = var_uinteger;
+ break;
+ case var_zuinteger_unlimited:
+ type = var_pinteger;
+ break;
+ }
+
+ if (var_type_uses<bool> (type))
+ return setting (type, &s->value.boolval);
+ else if (var_type_uses<int> (type))
+ return setting (type, &s->value.intval);
+ else if (var_type_uses<auto_boolean> (type))
+ return setting (type, &s->value.autoboolval);
+ else if (var_type_uses<unsigned int> (type))
+ return setting (type, &s->value.uintval);
+ else if (var_type_uses<std::string> (type))
+ return setting (type, s->value.stringval);
+ else if (var_type_uses<const char *> (type))
+ return setting (type, &s->value.cstringval);
else
gdb_assert_not_reached ("unhandled var type");
}
Index: src/gdb/python/python.c
===================================================================
--- src.orig/gdb/python/python.c
+++ src/gdb/python/python.c
@@ -507,35 +507,34 @@ gdbpy_parameter_value (const setting &va
Py_RETURN_NONE;
}
- case var_integer:
- if (var.get<int> () == INT_MAX)
- Py_RETURN_NONE;
- /* Fall through. */
- case var_zinteger:
- return gdb_py_object_from_longest (var.get<int> ()).release ();
-
- case var_zuinteger_unlimited:
- {
- int val = var.get<int> ();
-
- if (val == -1)
- Py_RETURN_NONE;
- return gdb_py_object_from_longest (val).release ();
- }
-
case var_uinteger:
+ case var_integer:
+ case var_pinteger:
{
- unsigned int val = var.get<unsigned int> ();
+ LONGEST value
+ = (var.type () == var_uinteger
+ ? static_cast<LONGEST> (var.get<unsigned int> ())
+ : static_cast<LONGEST> (var.get<int> ()));
- if (val == UINT_MAX)
- Py_RETURN_NONE;
- return gdb_py_object_from_ulongest (val).release ();
- }
+ if (var.extra_literals () != nullptr)
+ for (const literal_def *l = var.extra_literals ();
+ l->literal != nullptr;
+ l++)
+ if (value == l->use)
+ {
+ if (strcmp (l->literal, "unlimited") == 0)
+ Py_RETURN_NONE;
+ value = l->val;
+ }
- case var_zuinteger:
- {
- unsigned int val = var.get<unsigned int> ();
- return gdb_py_object_from_ulongest (val).release ();
+ if (var.type () == var_uinteger)
+ return
+ gdb_py_object_from_ulongest
+ (static_cast<const unsigned int> (value)).release ();
+ else
+ return
+ gdb_py_object_from_longest
+ (static_cast<const int> (value)).release ();
}
}
Index: src/gdb/valprint.c
===================================================================
--- src.orig/gdb/valprint.c
+++ src/gdb/valprint.c
@@ -2967,8 +2967,8 @@ using boolean_option_def
= gdb::option::boolean_option_def<value_print_options>;
using uinteger_option_def
= gdb::option::uinteger_option_def<value_print_options>;
-using zuinteger_unlimited_option_def
- = gdb::option::zuinteger_unlimited_option_def<value_print_options>;
+using integer_option_def
+ = gdb::option::integer_option_def<value_print_options>;
/* Definitions of options for the "print" and "compile print"
commands. */
@@ -3004,15 +3004,17 @@ static const gdb::option::option_def val
uinteger_option_def {
"elements",
[] (value_print_options *opt) { return &opt->print_max; },
+ uinteger_unlimited_literals,
show_print_max, /* show_cmd_cb */
N_("Set limit on string chars or array elements to print."),
N_("Show limit on string chars or array elements to print."),
N_("\"unlimited\" causes there to be no limit."),
},
- zuinteger_unlimited_option_def {
+ integer_option_def {
"max-depth",
[] (value_print_options *opt) { return &opt->max_depth; },
+ zuinteger_unlimited_literals,
show_print_max_depth, /* show_cmd_cb */
N_("Set maximum print depth for nested structures, unions and arrays."),
N_("Show maximum print depth for nested structures, unions, and arrays."),
@@ -3072,6 +3074,7 @@ pretty-printers for that value.")
uinteger_option_def {
"repeats",
[] (value_print_options *opt) { return &opt->repeat_count_threshold; },
+ uinteger_unlimited_literals,
show_repeat_count_threshold, /* show_cmd_cb */
N_("Set threshold for repeated print elements."),
N_("Show threshold for repeated print elements."),
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v4 7/8] GDB: Add a character string limiting option
2022-03-09 19:17 [PATCH v4 0/8] gdb: split array and string limiting options Maciej W. Rozycki
` (5 preceding siblings ...)
2022-03-09 19:18 ` [PATCH v4 6/8] GDB: Allow arbitrary keywords in integer set commands Maciej W. Rozycki
@ 2022-03-09 19:18 ` Maciej W. Rozycki
2022-03-09 19:51 ` Eli Zaretskii
2022-03-09 19:18 ` [PATCH v4 8/8] GDB/testsuite: Expand for character string limiting options Maciej W. Rozycki
2022-03-09 19:47 ` [PATCH v4 0/8] gdb: split array and " Simon Sobisch
8 siblings, 1 reply; 22+ messages in thread
From: Maciej W. Rozycki @ 2022-03-09 19:18 UTC (permalink / raw)
To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch
From: Andrew Burgess <andrew.burgess@embecosm.com>
This commit splits the `set/show print elements' option into two. We
retain `set/show print elements' for controlling how many elements of an
array we print, but a new `set/show print characters' setting is added
which is used for controlling how many characters of a string are
printed.
The motivation behind this change is to allow users a finer level of
control over how data is printed, reflecting that, although strings can
be thought of as arrays of characters, users often want to treat these
two things differently.
For compatibility reasons by default the `set/show print characters'
option is set to `elements', which makes the limit for character strings
follow the setting of the `set/show print elements' option, as it used
to. Using `set print characters' with any other value makes the limit
independent from the `set/show print elements' setting, however it can
be restored to the default with the `set print characters elements'
command at any time.
A corresponding `-characters' option for the `print' command is added,
with the same semantics, i.e. one can use `elements' to make a given
`print' invocation follow the limit of elements, be it set with the
`-elements' option also given with the same invocation or taken from the
`set/show print elements' setting, for characters as well regardless of
the current setting of the `set/show print characters' option.
The GDB changes are all pretty straightforward, just changing references
to the old 'print_max' to use a new `get_print_max_chars' helper which
figures out which of the two of `print_max' and `print_max_chars' values
to use.
Likewise, the documentation is just updated to reference the new setting
where appropriate.
To make people's life easier the message shown by `show print elements'
now indicates if the setting also applies to character strings:
(gdb) set print characters elements
(gdb) show print elements
Limit on string chars or array elements to print is 200.
(gdb) set print characters unlimited
(gdb) show print elements
Limit on array elements to print is 200.
(gdb)
which keeps it the same as it used to be, although in other contexts the
setting is described as applying to array elements only, e.g.:
(gdb) help set print elements
Set limit on array elements to print.
"unlimited" causes there to be no limit.
(gdb)
In the testsuite there are two minor updates, one to add `-characters'
to the list of completions now shown for the `print' command, and a bare
minimum pair of checks for the right handling of `set print characters'
and `show print characters', copied from the corresponding checks for
`set print elements' and `show print elements' respectively.
Co-Authored-By: Maciej W. Rozycki <macro@embecosm.com>
---
Changes from v3:
- rewrite in terms of flexible literal keyword handling added with 6/8,
- add a `set print characters elements' setting, which is also the
default, to make the string character limit follow that for array
elements in backwards-compatible manner,
- update documentation accordingly,
- remove testsuite updates delegated to 8/8, guaranteeing that the new
command does not influence any preexisting environment (except for
obvious cases where it is expected, such as command completion or help
messages),
- amend gdb.base/options.exp for the added completion for `print'
command's `-characters' option,
- expand gdb.base/default.exp with minimal test cases for `set/show print
characters'.
Changes from v2:
- place the new and the changed command at the right places each in NEWS.
Changes from v1:
- rename `print_smax' setting throughout to `print_max_chars', and
likewise `show_print_smax' function to `show_print_max_chars',
- document the Python part in the manual,
- update comments for `print_max' and `print_max_chars' in
`value_print_options',
- fix some typos.
---
gdb/NEWS | 11 ++++
gdb/ada-valprint.c | 6 +-
gdb/c-lang.c | 4 -
gdb/c-valprint.c | 5 +-
gdb/doc/gdb.texinfo | 39 ++++++++++++++---
gdb/doc/python.texi | 5 ++
gdb/language.h | 2
gdb/m2-lang.c | 3 -
gdb/m2-valprint.c | 4 +
gdb/p-lang.c | 3 -
gdb/p-valprint.c | 9 ++-
gdb/printcmd.c | 9 ++-
gdb/python/py-value.c | 4 +
gdb/testsuite/gdb.base/default.exp | 7 +++
gdb/testsuite/gdb.base/options.exp | 1
gdb/tracepoint.c | 4 -
gdb/valprint.c | 84 ++++++++++++++++++++++++++++---------
gdb/valprint.h | 20 +++++++-
18 files changed, 171 insertions(+), 49 deletions(-)
gdb-aburgess-print-elements-characters.diff
Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS
+++ src/gdb/NEWS
@@ -119,6 +119,17 @@ show ada source-charset
values for this follow the values that can be passed to the GNAT
compiler via the '-gnati' option. The default is ISO-8859-1.
+set print characters LIMIT
+show print characters
+print -characters LIMIT
+ This new setting is like 'set print elements', but controls how many
+ characters of a string are printed. This functionality used to be
+ covered by 'set print elements', but it can be controlled separately
+ now. LIMIT can be set to a numerical value to request that particular
+ character count, to 'unlimited' to print all characters of a string,
+ or to 'elements', which is also the default, to follow the setting of
+ 'set print elements' as it used to be.
+
* Changed commands
maint packet
Index: src/gdb/ada-valprint.c
===================================================================
--- src.orig/gdb/ada-valprint.c
+++ src/gdb/ada-valprint.c
@@ -470,7 +470,8 @@ printstr (struct ui_file *stream, struct
return;
}
- for (i = 0; i < length && things_printed < options->print_max; i += 1)
+ unsigned int print_max_chars = get_print_max_chars (options);
+ for (i = 0; i < length && things_printed < print_max_chars; i += 1)
{
/* Position of the character we are examining
to see whether it is repeated. */
@@ -706,12 +707,13 @@ ada_val_print_string (struct type *type,
elements up to it. */
if (options->stop_print_at_null)
{
+ unsigned int print_max_chars = get_print_max_chars (options);
int temp_len;
/* Look for a NULL char. */
for (temp_len = 0;
(temp_len < len
- && temp_len < options->print_max
+ && temp_len < print_max_chars
&& char_at (valaddr + offset_aligned,
temp_len, eltlen, byte_order) != 0);
temp_len += 1);
Index: src/gdb/c-lang.c
===================================================================
--- src.orig/gdb/c-lang.c
+++ src/gdb/c-lang.c
@@ -185,8 +185,8 @@ language_defn::printchar (int c, struct
/* Print the character string STRING, printing at most LENGTH
characters. LENGTH is -1 if the string is nul terminated. Each
character is WIDTH bytes long. Printing stops early if the number
- hits print_max; repeat counts are printed as appropriate. Print
- ellipses at the end if we had to stop before printing LENGTH
+ hits print_max_chars; repeat counts are printed as appropriate.
+ Print ellipses at the end if we had to stop before printing LENGTH
characters, or if FORCE_ELLIPSES. */
void
Index: src/gdb/c-valprint.c
===================================================================
--- src.orig/gdb/c-valprint.c
+++ src/gdb/c-valprint.c
@@ -267,11 +267,12 @@ c_value_print_array (struct value *val,
print elements up to it. */
if (options->stop_print_at_null)
{
+ unsigned int print_max_chars = get_print_max_chars (options);
unsigned int temp_len;
for (temp_len = 0;
(temp_len < len
- && temp_len < options->print_max
+ && temp_len < print_max_chars
&& extract_unsigned_integer (valaddr + temp_len * eltlen,
eltlen, byte_order) != 0);
++temp_len)
@@ -280,7 +281,7 @@ c_value_print_array (struct value *val,
/* Force printstr to print ellipses if
we've printed the maximum characters and
the next character is not \000. */
- if (temp_len == options->print_max && temp_len < len)
+ if (temp_len == print_max_chars && temp_len < len)
{
ULONGEST ival
= extract_unsigned_integer (valaddr + temp_len * eltlen,
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo
+++ src/gdb/doc/gdb.texinfo
@@ -10012,10 +10012,17 @@ Related setting: @ref{set print array}.
Set printing of array indexes.
Related setting: @ref{set print array-indexes}.
-@item -elements @var{number-of-elements}|@code{unlimited}
-Set limit on string chars or array elements to print. The value
+@item -characters @var{number-of-characters}|@code{elements}|@code{unlimited}
+Set limit on string characters to print. The value @code{elements}
+causes the limit on array elements to print to be used. The value
@code{unlimited} causes there to be no limit. Related setting:
-@ref{set print elements}.
+@ref{set print characters}.
+
+@item -elements @var{number-of-elements}|@code{unlimited}
+Set limit on array elements and optionally string characters to print.
+See @ref{set print characters} and the @code{-characters} option above
+for when this option applies to strings. The value @code{unlimited}
+causes there to be no limit. Related setting: @ref{set print elements}.
@item -max-depth @var{depth}|@code{unlimited}
Set the threshold after which nested structures are replaced with
@@ -11383,6 +11390,27 @@ Stop printing element indexes when displ
Show whether the index of each element is printed when displaying
arrays.
+@anchor{set print characters}
+@item set print characters @var{number-of-characters}
+@itemx set print characters elements
+@itemx set print characters unlimited
+@cindex number of string characters to print
+@cindex limit on number of printed string characters
+Set a limit on how many characters of a string @value{GDBN} will
+print. If @value{GDBN} is printing a large string, it stops printing
+after it has printed the number of characters set by the @code{set
+print characters} command.
+Setting @var{number-of-characters} to @code{elements} means
+that the limit on the number of characters to print follows
+one for array elements; see @ref{set print elements}.
+Setting @var{number-of-characters} to @code{unlimited} means
+that the number of characters to print is unlimited.
+When @value{GDBN} starts, this limit is set to @code{elements}.
+
+@item show print characters
+Display the number of characters of a large string that @value{GDBN}
+will print.
+
@anchor{set print elements}
@item set print elements @var{number-of-elements}
@itemx set print elements unlimited
@@ -11391,7 +11419,8 @@ arrays.
Set a limit on how many elements of an array @value{GDBN} will print.
If @value{GDBN} is printing a large array, it stops printing after it has
printed the number of elements set by the @code{set print elements} command.
-This limit also applies to the display of strings.
+By default this limit also applies to the display of strings; see
+@ref{set print characters}.
When @value{GDBN} starts, this limit is set to 200.
Setting @var{number-of-elements} to @code{unlimited} or zero means
that the number of elements to print is unlimited.
@@ -14894,7 +14923,7 @@ The optional @var{mods} changes the usua
@code{s} requests that pointers to chars be handled as strings, in
particular collecting the contents of the memory being pointed at, up
to the first zero. The upper bound is by default the value of the
-@code{print elements} variable; if @code{s} is followed by a decimal
+@code{print characters} variable; if @code{s} is followed by a decimal
number, that is the upper bound instead. So for instance
@samp{collect/s25 mystr} collects as many as 25 characters at
@samp{mystr}.
Index: src/gdb/doc/python.texi
===================================================================
--- src.orig/gdb/doc/python.texi
+++ src/gdb/doc/python.texi
@@ -1059,6 +1059,11 @@ the @emph{declared} type should be used.
representation of a C@t{++} object, @code{False} if they shouldn't (see
@code{set print static-members} in @ref{Print Settings}).
+@item max_characters
+Number of string characters to print, @code{0} to follow
+@code{max_elements}, or @code{UINT_MAX} to print an unlimited number
+of characters (see @code{set print characters} in @ref{Print Settings}).
+
@item max_elements
Number of array elements to print, or @code{0} to print an unlimited
number of elements (see @code{set print elements} in @ref{Print
Index: src/gdb/language.h
===================================================================
--- src.orig/gdb/language.h
+++ src/gdb/language.h
@@ -534,7 +534,7 @@ struct language_defn
struct ui_file * stream) const;
/* Print the character string STRING, printing at most LENGTH characters.
- Printing stops early if the number hits print_max; repeat counts
+ Printing stops early if the number hits print_max_chars; repeat counts
are printed as appropriate. Print ellipses at the end if we
had to stop before printing LENGTH characters, or if FORCE_ELLIPSES. */
Index: src/gdb/m2-lang.c
===================================================================
--- src.orig/gdb/m2-lang.c
+++ src/gdb/m2-lang.c
@@ -169,7 +169,8 @@ m2_language::printstr (struct ui_file *s
return;
}
- for (i = 0; i < length && things_printed < options->print_max; ++i)
+ unsigned int print_max_chars = get_print_max_chars (options);
+ for (i = 0; i < length && things_printed < print_max_chars; ++i)
{
/* Position of the character we are examining
to see whether it is repeated. */
Index: src/gdb/m2-valprint.c
===================================================================
--- src.orig/gdb/m2-valprint.c
+++ src/gdb/m2-valprint.c
@@ -327,12 +327,14 @@ m2_language::value_print_inner (struct v
elements up to it. */
if (options->stop_print_at_null)
{
+ unsigned int print_max_chars = get_print_max_chars (options);
unsigned int temp_len;
/* Look for a NULL char. */
for (temp_len = 0;
(valaddr[temp_len]
- && temp_len < len && temp_len < options->print_max);
+ && temp_len < len
+ && temp_len < print_max_chars);
temp_len++);
len = temp_len;
}
Index: src/gdb/p-lang.c
===================================================================
--- src.orig/gdb/p-lang.c
+++ src/gdb/p-lang.c
@@ -253,7 +253,8 @@ pascal_language::printstr (struct ui_fil
return;
}
- for (i = 0; i < length && things_printed < options->print_max; ++i)
+ unsigned int print_max_chars = get_print_max_chars (options);
+ for (i = 0; i < length && things_printed < print_max_chars; ++i)
{
/* Position of the character we are examining
to see whether it is repeated. */
Index: src/gdb/p-valprint.c
===================================================================
--- src.orig/gdb/p-valprint.c
+++ src/gdb/p-valprint.c
@@ -105,13 +105,16 @@ pascal_language::value_print_inner (stru
elements up to it. */
if (options->stop_print_at_null)
{
+ unsigned int print_max_chars
+ = get_print_max_chars (options);
unsigned int temp_len;
/* Look for a NULL char. */
for (temp_len = 0;
- extract_unsigned_integer (valaddr + temp_len * eltlen,
- eltlen, byte_order)
- && temp_len < len && temp_len < options->print_max;
+ (extract_unsigned_integer
+ (valaddr + temp_len * eltlen, eltlen, byte_order)
+ && temp_len < len
+ && temp_len < print_max_chars);
temp_len++);
len = temp_len;
}
Index: src/gdb/printcmd.c
===================================================================
--- src.orig/gdb/printcmd.c
+++ src/gdb/printcmd.c
@@ -962,17 +962,18 @@ find_string_backward (struct gdbarch *gd
chars_to_read * char_size);
chars_read /= char_size;
read_error = (chars_read == chars_to_read) ? 0 : 1;
+ unsigned int print_max_chars = get_print_max_chars (options);
/* Searching for '\0' from the end of buffer in backward direction. */
for (i = 0; i < chars_read && count > 0 ; ++i, ++chars_counted)
{
int offset = (chars_to_read - i - 1) * char_size;
if (integer_is_zero (&buffer[offset], char_size)
- || chars_counted == options->print_max)
+ || chars_counted == print_max_chars)
{
- /* Found '\0' or reached print_max. As OFFSET is the offset to
- '\0', we add CHAR_SIZE to return the start address of
- a string. */
+ /* Found '\0' or reached `print_max_chars'. As OFFSET
+ is the offset to '\0', we add CHAR_SIZE to return
+ the start address of a string. */
--count;
string_start_addr = addr + offset + char_size;
chars_counted = 0;
Index: src/gdb/python/py-value.c
===================================================================
--- src.orig/gdb/python/py-value.c
+++ src/gdb/python/py-value.c
@@ -645,6 +645,7 @@ valpy_format_string (PyObject *self, PyO
"actual_objects", /* See set print object on|off. */
"static_members", /* See set print static-members on|off. */
/* C non-bool options. */
+ "max_characters", /* See set print characters N. */
"max_elements", /* See set print elements N. */
"max_depth", /* See set print max-depth N. */
"repeat_threshold", /* See set print repeats. */
@@ -691,7 +692,7 @@ valpy_format_string (PyObject *self, PyO
char *format = NULL;
if (!gdb_PyArg_ParseTupleAndKeywords (args,
kw,
- "|O!O!O!O!O!O!O!O!O!O!O!IIIs",
+ "|O!O!O!O!O!O!O!O!O!O!O!IIIIs",
keywords,
&PyBool_Type, &raw_obj,
&PyBool_Type, &pretty_arrays_obj,
@@ -704,6 +705,7 @@ valpy_format_string (PyObject *self, PyO
&PyBool_Type, &deref_refs_obj,
&PyBool_Type, &actual_objects_obj,
&PyBool_Type, &static_members_obj,
+ &opts.print_max_chars,
&opts.print_max,
&opts.max_depth,
&opts.repeat_count_threshold,
Index: src/gdb/testsuite/gdb.base/default.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/default.exp
+++ src/gdb/testsuite/gdb.base/default.exp
@@ -522,6 +522,10 @@ gdb_test_no_output "set print address" "
gdb_test_no_output "set print array" "set print array"
#test set print asm-demangle
gdb_test_no_output "set print asm-demangle" "set print asm-demangle"
+#test set print characters
+gdb_test "set print characters" \
+ "Argument required \\(integer to set it to, or one of:\
+ \"elements\", \"unlimited\"\\)\\."
#test set print demangle
gdb_test_no_output "set print demangle" "set print demangle"
#test set print elements
@@ -665,6 +669,9 @@ gdb_test "show print address" "Printing
gdb_test "show print array" "Pretty formatting of arrays is on."
#test show print asm-demangle
gdb_test "show print asm-demangle" "Demangling of C\[+\]+/ObjC names in disassembly listings is on."
+#test show print characters
+gdb_test "show print characters" \
+ "Limit on string characters to print is elements\\."
#test show print demangle
gdb_test "show print demangle" "Demangling of encoded C\[+\]+/ObjC names when displaying symbols is on."
#test show print elements
Index: src/gdb/testsuite/gdb.base/options.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/options.exp
+++ src/gdb/testsuite/gdb.base/options.exp
@@ -165,6 +165,7 @@ proc_with_prefix test-print {{prefix ""}
"-address"
"-array"
"-array-indexes"
+ "-characters"
"-elements"
"-max-depth"
"-memory-tag-violations"
Index: src/gdb/tracepoint.c
===================================================================
--- src.orig/gdb/tracepoint.c
+++ src/gdb/tracepoint.c
@@ -546,9 +546,9 @@ decode_agent_options (const char *exp, i
if (target_supports_string_tracing ())
{
/* Allow an optional decimal number giving an explicit maximum
- string length, defaulting it to the "print elements" value;
+ string length, defaulting it to the "print characters" value;
so "collect/s80 mystr" gets at most 80 bytes of string. */
- *trace_string = opts.print_max;
+ *trace_string = get_print_max_chars (&opts);
exp++;
if (*exp >= '0' && *exp <= '9')
*trace_string = atoi (exp);
Index: src/gdb/valprint.c
===================================================================
--- src.orig/gdb/valprint.c
+++ src/gdb/valprint.c
@@ -97,8 +97,14 @@ static void val_print_type_code_flags (s
int embedded_offset,
struct ui_file *stream);
-#define PRINT_MAX_DEFAULT 200 /* Start print_max off at this value. */
-#define PRINT_MAX_DEPTH_DEFAULT 20 /* Start print_max_depth off at this value. */
+/* Start print_max at this value. */
+#define PRINT_MAX_DEFAULT 200
+
+/* Start print_max_chars at this value (meaning follow print_max). */
+#define PRINT_MAX_CHARS_DEFAULT 0
+
+/* Start print_max_depth at this value. */
+#define PRINT_MAX_DEPTH_DEFAULT 20
struct value_print_options user_print_options =
{
@@ -110,6 +116,7 @@ struct value_print_options user_print_op
1, /* addressprint */
0, /* objectprint */
PRINT_MAX_DEFAULT, /* print_max */
+ PRINT_MAX_CHARS_DEFAULT, /* print_max_chars */
10, /* repeat_count_threshold */
0, /* output_format */
0, /* format */
@@ -152,17 +159,31 @@ get_formatted_print_options (struct valu
opts->format = format;
}
+/* Implement 'show print elements'. */
+
static void
show_print_max (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
+ fprintf_filtered
+ (file,
+ (user_print_options.print_max_chars != 0
+ ? _("Limit on array elements to print is %s.\n")
+ : _("Limit on string chars or array elements to print is %s.\n")),
+ value);
+}
+
+/* Implement 'show print characters'. */
+
+static void
+show_print_max_chars (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
fprintf_filtered (file,
- _("Limit on string chars or array "
- "elements to print is %s.\n"),
+ _("Limit on string characters to print is %s.\n"),
value);
}
-
/* Default input and output radixes, and output format letter. */
unsigned input_radix = 10;
@@ -2587,9 +2608,9 @@ print_converted_chars_to_obstack (struct
/* Print the character string STRING, printing at most LENGTH
characters. LENGTH is -1 if the string is nul terminated. TYPE is
the type of each character. OPTIONS holds the printing options;
- printing stops early if the number hits print_max; repeat counts
- are printed as appropriate. Print ellipses at the end if we had to
- stop before printing LENGTH characters, or if FORCE_ELLIPSES.
+ printing stops early if the number hits print_max_chars; repeat
+ counts are printed as appropriate. Print ellipses at the end if we
+ had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.
QUOTE_CHAR is the character to print at each end of the string. If
C_STYLE_TERMINATOR is true, and the last character is 0, then it is
omitted. */
@@ -2643,7 +2664,8 @@ generic_printstr (struct ui_file *stream
/* Convert characters until the string is over or the maximum
number of printed characters has been reached. */
i = 0;
- while (i < options->print_max)
+ unsigned int print_max_chars = get_print_max_chars (options);
+ while (i < print_max_chars)
{
int r;
@@ -2695,7 +2717,7 @@ generic_printstr (struct ui_file *stream
/* Print a string from the inferior, starting at ADDR and printing up to LEN
characters, of WIDTH bytes a piece, to STREAM. If LEN is -1, printing
stops at the first null byte, otherwise printing proceeds (including null
- bytes) until either print_max or LEN characters have been printed,
+ bytes) until either print_max_chars or LEN characters have been printed,
whichever is smaller. ENCODING is the name of the string's
encoding. It can be NULL, in which case the target encoding is
assumed. */
@@ -2717,15 +2739,17 @@ val_print_string (struct type *elttype,
int width = TYPE_LENGTH (elttype);
/* First we need to figure out the limit on the number of characters we are
- going to attempt to fetch and print. This is actually pretty simple. If
- LEN >= zero, then the limit is the minimum of LEN and print_max. If
- LEN is -1, then the limit is print_max. This is true regardless of
- whether print_max is zero, UINT_MAX (unlimited), or something in between,
- because finding the null byte (or available memory) is what actually
- limits the fetch. */
+ going to attempt to fetch and print. This is actually pretty simple.
+ If LEN >= zero, then the limit is the minimum of LEN and print_max_chars.
+ If LEN is -1, then the limit is print_max_chars. This is true regardless
+ of whether print_max_chars is zero, UINT_MAX (unlimited), or something in
+ between, because finding the null byte (or available memory) is what
+ actually limits the fetch. */
- fetchlimit = (len == -1 ? options->print_max : std::min ((unsigned) len,
- options->print_max));
+ unsigned int print_max_chars = get_print_max_chars (options);
+ fetchlimit = (len == -1
+ ? print_max_chars
+ : std::min ((unsigned) len, print_max_chars));
err = read_string (addr, len, width, fetchlimit, byte_order,
&buffer, &bytes_read);
@@ -2970,6 +2994,15 @@ using uinteger_option_def
using integer_option_def
= gdb::option::integer_option_def<value_print_options>;
+/* Extra literals supported with the `set print characters' and
+ `print -characters' commands. */
+static const literal_def print_characters_literals[] =
+ {
+ { "elements", 0, 0, false },
+ { "unlimited", UINT_MAX, UINT_MAX, false },
+ { nullptr }
+ };
+
/* Definitions of options for the "print" and "compile print"
commands. */
static const gdb::option::option_def value_print_option_defs[] = {
@@ -3002,12 +3035,23 @@ static const gdb::option::option_def val
},
uinteger_option_def {
+ "characters",
+ [] (value_print_options *opt) { return &opt->print_max_chars; },
+ print_characters_literals,
+ show_print_max_chars, /* show_cmd_cb */
+ N_("Set limit on string chars to print."),
+ N_("Show limit on string chars to print."),
+ N_("\"elements\" causes the array element limit to be used.\n"
+ "\"unlimited\" causes there to be no limit."),
+ },
+
+ uinteger_option_def {
"elements",
[] (value_print_options *opt) { return &opt->print_max; },
uinteger_unlimited_literals,
show_print_max, /* show_cmd_cb */
- N_("Set limit on string chars or array elements to print."),
- N_("Show limit on string chars or array elements to print."),
+ N_("Set limit on array elements to print."),
+ N_("Show limit on array elements to print."),
N_("\"unlimited\" causes there to be no limit."),
},
Index: src/gdb/valprint.h
===================================================================
--- src.orig/gdb/valprint.h
+++ src/gdb/valprint.h
@@ -48,12 +48,15 @@ struct value_print_options
in its vtables. */
bool objectprint;
- /* Maximum number of chars to print for a string pointer value or vector
- contents, or UINT_MAX for no limit. Note that "set print elements 0"
- stores UINT_MAX in print_max, which displays in a show command as
- "unlimited". */
+ /* Maximum number of elements to print for vector contents, or UINT_MAX
+ for no limit. Note that "set print elements 0" stores UINT_MAX in
+ print_max, which displays in a show command as "unlimited". */
unsigned int print_max;
+ /* Maximum number of string chars to print for a string pointer value,
+ zero if to follow the value of print_max, or UINT_MAX for no limit. */
+ unsigned int print_max_chars;
+
/* Print repeat counts if there are more than this many repetitions
of an element in an array. */
unsigned int repeat_count_threshold;
@@ -105,6 +108,15 @@ struct value_print_options
bool finish_print;
};
+/* Return the character count limit for printing strings. */
+
+static inline unsigned int
+get_print_max_chars (const struct value_print_options *options)
+{
+ return (options->print_max_chars != 0
+ ? options->print_max_chars : options->print_max);
+}
+
/* Create an option_def_group for the value_print options, with OPTS
as context. */
extern gdb::option::option_def_group make_value_print_options_def_group
^ permalink raw reply [flat|nested] 22+ messages in thread