[PING][PATCH v7] gdb: Add new 'print nibbles' feature
Enze Li
lienze2010@hotmail.com
Tue Jan 11 14:06:41 GMT 2022
Hi all,
Kindly PING for this patch. :)
Also, I'm not sure if the patch of this size needs to be split into
smaller patches for easier review, please let me know if so.
Cheers!
Enze
On Wed, 2021-12-29 at 21:45 +0800, Enze Li via Gdb-patches wrote:
> New in v7:
> - Address Tom Tromey's comments. Use specific digit
> separators when debugging C++ and Rust programs.
>
> New in v6:
> - Address Eli's comments. Use a new complementary method
> with the number 0.
>
> New in v5:
> - Address Bruno's comments. Fix regressions caused by code
> conflicts.
>
> Make an introduction of a new print setting that can be set
> by 'set print nibbles [on|off]'. The default value is OFF,
> which can be changed by users manually.
>
> Of course, 'show print nibbles' is also included in the patch.
>
> This new feature displays binary values by group, with four
> bits per group.
>
> The motivation behind this work is to enhance the readability
> of binary values.
>
> Here's a GDB session before this patch is applied.
> (gdb) print var_a
> $1 = 1230
> (gdb) print/t var_a
> $2 = 10011001110
>
> With this patch applied, we have a new print setting to use.
> (gdb) print var_a
> $1 = 1230
> (gdb) print/t var_a
> $2 = 10011001110
> (gdb) set print nibbles on
> (gdb) print/t var_a
> $3 = 0100 1100 1110
>
> Tested on x86_64-linux(little-endian) and mips-linux(big-endian).
> ---
> gdb/NEWS | 5 ++
> gdb/doc/gdb.texinfo | 35 ++++++++++--
> gdb/printcmd.c | 2 +-
> gdb/testsuite/gdb.base/options.exp | 1 +
> gdb/testsuite/gdb.base/printcmds.exp | 14 +++++
> gdb/testsuite/gdb.cp/printnibbles.cc | 24 +++++++++
> gdb/testsuite/gdb.cp/printnibbles.exp | 55 +++++++++++++++++++
> gdb/testsuite/gdb.rust/printnibbles.exp | 46 ++++++++++++++++
> gdb/testsuite/gdb.rust/printnibbles.rs | 23 ++++++++
> gdb/valprint.c | 71
> ++++++++++++++++++++++++-
> gdb/valprint.h | 6 ++-
> 11 files changed, 275 insertions(+), 7 deletions(-)
> create mode 100644 gdb/testsuite/gdb.cp/printnibbles.cc
> create mode 100644 gdb/testsuite/gdb.cp/printnibbles.exp
> create mode 100644 gdb/testsuite/gdb.rust/printnibbles.exp
> create mode 100644 gdb/testsuite/gdb.rust/printnibbles.rs
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index c26e15b530a..c23560d1ced 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -257,6 +257,11 @@ set debug event-loop
> show debug event-loop
> Control the display of debug output about GDB's event loop.
>
> +set print nibbles [on|off]
> +show print nibbles
> + This controls whether the 'print/t' command will display binary
> values
> + in groups of four bits, known as "nibbles". The default is 'off'.
> +
> set print memory-tag-violations
> show print memory-tag-violations
> Control whether to display additional information about memory tag
> violations
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 77cd184c47b..2afcd16eadf 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -2142,10 +2142,10 @@ on @code{-} after the command name. For
> example:
>
> @smallexample
> (@value{GDBP}) print -@key{TAB}@key{TAB}
> --address -max-depth -pretty -symbol
> --array -memory-tag-violations -raw-values -union
> --array-indexes -null-stop -repeats -vtbl
> --elements -object -static-members
> +-address -max-depth -object -static-
> members
> +-array -memory-tag-violations -pretty -symbol
> +-array-indexes -nibbles -raw-values -union
> +-elements -null-stop -repeats -vtbl
> @end smallexample
>
> Completion will in some cases guide you with a suggestion of what
> kind
> @@ -10019,6 +10019,10 @@ Set limit on string chars or array elements
> to print. The value
> Set the threshold after which nested structures are replaced with
> ellipsis. Related setting: @ref{set print max-depth}.
>
> +@item -nibbles [@code{on}|@code{off}]
> +Set whether to print binary values in groups of four bits, known
> +as ``nibbles''. @xref{set print nibbles}.
> +
> @item -memory-tag-violations [@code{on}|@code{off}]
> Set printing of additional information about memory tag violations.
> @xref{set print memory-tag-violations}.
> @@ -11381,6 +11385,29 @@ Stop printing element indexes when
> displaying arrays.
> Show whether the index of each element is printed when displaying
> arrays.
>
> +@anchor{set print nibbles}
> +@item set print nibbles
> +@itemx set print nibbles on
> +@cindex print binary values in groups of four bits
> +Print binary values in groups of four bits, known as @dfn{nibbles},
> +when using the print command of @value{GDBN} with the option
> @samp{/t}.
> +For example, this is what it looks like with @code{set print nibbles
> on}:
> +
> +@smallexample
> +@group
> +(@value{GDBP}) print val_flags
> +$1 = 1230
> +(@value{GDBP}) print/t val_flags
> +$2 = 0100 1100 1110
> +@end group
> +@end smallexample
> +
> +@item set print nibbles off
> +Don't printing binary values in groups. This is the default.
> +
> +@item show print nibbles
> +Show whether to print binary values in groups of four bits.
> +
> @anchor{set print elements}
> @item set print elements @var{number-of-elements}
> @itemx set print elements unlimited
> diff --git a/gdb/printcmd.c b/gdb/printcmd.c
> index e408b19db63..ef1a80ecae3 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -490,7 +490,7 @@ print_scalar_formatted (const gdb_byte *valaddr,
> struct type *type,
> break;
>
> case 't':
> - print_binary_chars (stream, valaddr, len, byte_order, size >
> 0);
> + print_binary_chars (stream, valaddr, len, byte_order, size >
> 0, options);
> break;
> case 'x':
> print_hex_chars (stream, valaddr, len, byte_order, size > 0);
> diff --git a/gdb/testsuite/gdb.base/options.exp
> b/gdb/testsuite/gdb.base/options.exp
> index 94372aa9fc7..1a680a3baf4 100644
> --- a/gdb/testsuite/gdb.base/options.exp
> +++ b/gdb/testsuite/gdb.base/options.exp
> @@ -168,6 +168,7 @@ proc_with_prefix test-print {{prefix ""}} {
> "-elements"
> "-max-depth"
> "-memory-tag-violations"
> + "-nibbles"
> "-null-stop"
> "-object"
> "-pretty"
> diff --git a/gdb/testsuite/gdb.base/printcmds.exp
> b/gdb/testsuite/gdb.base/printcmds.exp
> index b2f90aaff10..0b015b27e28 100644
> --- a/gdb/testsuite/gdb.base/printcmds.exp
> +++ b/gdb/testsuite/gdb.base/printcmds.exp
> @@ -690,6 +690,19 @@ proc test_print_char_arrays {} {
> gdb_test_no_output "set print address off" "address off char
> arrays"
> }
>
> +proc test_print_nibbles {} {
> + gdb_test_no_output "set print nibbles on"
> + gdb_test "p/t 0" " = 0"
> + gdb_test "p/t 0x0" " = 0"
> + gdb_test "p/t 0x30" " = 0011 0000"
> + gdb_test "p/t 0xff" " = 1111 1111"
> + gdb_test "p/t 0x0f" " = 1111"
> + gdb_test "p/t 0x01" " = 0001"
> + gdb_test "p/t 0xf0f" " = 1111 0000 1111"
> + gdb_test "p/t 0x70f" " = 0111 0000 1111"
> + gdb_test_no_output "set print nibbles off"
> +}
> +
> proc test_print_string_constants {} {
> global gdb_prompt
>
> @@ -1067,6 +1080,7 @@ test_print_int_arrays
> test_print_typedef_arrays
> test_artificial_arrays
> test_print_char_arrays
> +test_print_nibbles
> # We used to do the runto main here.
> test_print_string_constants
> test_print_array_constants
> diff --git a/gdb/testsuite/gdb.cp/printnibbles.cc
> b/gdb/testsuite/gdb.cp/printnibbles.cc
> new file mode 100644
> index 00000000000..c82c344c6d4
> --- /dev/null
> +++ b/gdb/testsuite/gdb.cp/printnibbles.cc
> @@ -0,0 +1,24 @@
> +/* This test script is part of GDB, the GNU debugger.
> +
> + Copyright 2021 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or
> modify
> + it under the terms of the GNU General Public License as published
> by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see
> <http://www.gnu.org/licenses/>. */
> +
> +int main()
> +{
> + /* Create an array to test the output of 'print nibbles' */
> + unsigned int print_arr[] = {0, 0x0, 0x30, 0xff, 0x0f, 0x01, 0xf0f,
> 0x70f};
> +
> + return 0; // breakpoint: constructs-
> done
> +}
> diff --git a/gdb/testsuite/gdb.cp/printnibbles.exp
> b/gdb/testsuite/gdb.cp/printnibbles.exp
> new file mode 100644
> index 00000000000..575cadccc1c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.cp/printnibbles.exp
> @@ -0,0 +1,55 @@
> +# Copyright 2021 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or
> modify
> +# it under the terms of the GNU General Public License as published
> by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see
> <http://www.gnu.org/licenses/>.
> +
> +# Regression test for 'print nibbles' commands.
> +
> +if { [skip_cplus_tests] } { continue }
> +
> +#
> +# test running programs
> +#
> +
> +standard_testfile .cc
> +
> +if [get_compiler_info "c++"] {
> + return -1
> +}
> +
> +if {[prepare_for_testing "failed to prepare" $testfile $srcfile
> {debug c++}]} {
> + return -1
> +}
> +
> +if ![runto_main] then {
> + perror "couldn't run to breakpoint"
> + continue
> +}
> +
> +gdb_breakpoint [gdb_get_line_number "constructs-done"]
> +gdb_continue_to_breakpoint "end of constructors"
> +
> +# test the output of 'print nibbles'
> +gdb_test_no_output "set print nibbles on"
> +gdb_test "p/t print_arr\[0\]" " = 0"
> +gdb_test "p/t print_arr\[1\]" " = 0"
> +gdb_test "p/t print_arr\[2\]" " = 0011'0000"
> +gdb_test "p/t print_arr\[3\]" " = 1111'1111"
> +gdb_test "p/t print_arr\[4\]" " = 1111"
> +gdb_test "p/t print_arr\[5\]" " = 0001"
> +gdb_test "p/t print_arr\[6\]" " = 1111'0000'1111"
> +gdb_test "p/t print_arr\[7\]" " = 0111'0000'1111"
> +gdb_test_no_output "set print nibbles off"
> +
> +gdb_exit
> +return 0
> diff --git a/gdb/testsuite/gdb.rust/printnibbles.exp
> b/gdb/testsuite/gdb.rust/printnibbles.exp
> new file mode 100644
> index 00000000000..5d324164028
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/printnibbles.exp
> @@ -0,0 +1,46 @@
> +# Copyright 2021 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or
> modify
> +# it under the terms of the GNU General Public License as published
> by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see
> <http://www.gnu.org/licenses/>.
> +
> +# Regression test for 'print nibbles' commands.
> +
> +load_lib rust-support.exp
> +if {[skip_rust_tests]} {
> + continue
> +}
> +
> +standard_testfile .rs
> +if {[prepare_for_testing "failed to prepare" $testfile $srcfile \
> + {debug rust}]} {
> + return -1
> +}
> +
> +set line [gdb_get_line_number "breakpoint"]
> +if {![runto ${srcfile}:$line]} {
> + untested "could not run to breakpoint"
> + return -1
> +}
> +
> +# test the output of 'print nibbles'
> +gdb_test_no_output "set print nibbles on"
> +gdb_test "p/t print_arr\[0\]" " = 0"
> +gdb_test "p/t print_arr\[1\]" " = 0"
> +gdb_test "p/t print_arr\[2\]" " = 0011_0000"
> +gdb_test "p/t print_arr\[3\]" " = 1111_1111"
> +gdb_test "p/t print_arr\[4\]" " = 1111"
> +gdb_test "p/t print_arr\[5\]" " = 0001"
> +gdb_test "p/t print_arr\[6\]" " = 1111_0000_1111"
> +gdb_test "p/t print_arr\[7\]" " = 0111_0000_1111"
> +gdb_test_no_output "set print nibbles off"
> +
> diff --git a/gdb/testsuite/gdb.rust/printnibbles.rs
> b/gdb/testsuite/gdb.rust/printnibbles.rs
> new file mode 100644
> index 00000000000..d3fe9e04306
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/printnibbles.rs
> @@ -0,0 +1,23 @@
> +// Copyright (C) 2021 Free Software Foundation, Inc.
> +
> +// This program is free software; you can redistribute it and/or
> modify
> +// it under the terms of the GNU General Public License as published
> by
> +// the Free Software Foundation; either version 3 of the License, or
> +// (at your option) any later version.
> +//
> +// This program is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +// GNU General Public License for more details.
> +//
> +// You should have received a copy of the GNU General Public License
> +// along with this program. If not, see
> <http://www.gnu.org/licenses/>.
> +
> +#![allow(unused_variables)]
> +
> +fn main() {
> + // Create an array to test the output of 'print nibbles'
> + let print_arr:[u32;8] = [0, 0x0, 0x30, 0xff, 0x0f, 0x01, 0xf0f,
> 0x70f];
> +
> + println!(""); // breakpoint
> +}
> diff --git a/gdb/valprint.c b/gdb/valprint.c
> index 4230dcec228..9931d311a56 100644
> --- a/gdb/valprint.c
> +++ b/gdb/valprint.c
> @@ -97,6 +97,8 @@ static void val_print_type_code_flags (struct type
> *type,
> int embedded_offset,
> struct ui_file *stream);
>
> +static char get_digit_separator ();
> +
> #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. */
>
> @@ -108,6 +110,7 @@ struct value_print_options user_print_options =
> 0, /* vtblprint */
> 1, /* unionprint */
> 1, /* addressprint */
> + false, /* nibblesprint */
> 0, /* objectprint */
> PRINT_MAX_DEFAULT, /* print_max */
> 10, /* repeat_count_threshold */
> @@ -260,6 +263,17 @@ show_unionprint (struct ui_file *file, int
> from_tty,
> value);
> }
>
> +/* Controls the format of printing binary values. */
> +
> +static void
> +show_nibbles (struct ui_file *file, int from_tty,
> + struct cmd_list_element *c, const char *value)
> +{
> + fprintf_filtered (file,
> + _("Printing binary values in groups is %s.\n"),
> + value);
> +}
> +
> /* If nonzero, causes machine addresses to be printed in certain
> contexts. */
>
> static void
> @@ -1365,20 +1379,46 @@ print_floating (const gdb_byte *valaddr,
> struct type *type,
> fputs_filtered (str.c_str (), stream);
> }
>
> +/* Return the digit separator for the current debugging language. */
> +
> +static char
> +get_digit_separator ()
> +{
> + if (current_language != nullptr)
> + {
> + switch (current_language->la_language)
> + {
> + case language_cplus:
> + return '\'';
> + case language_rust:
> + return '_';
> + default:
> + return ' ';
> + }
> + }
> + else
> + return ' ';
> +}
> +
> void
> print_binary_chars (struct ui_file *stream, const gdb_byte *valaddr,
> - unsigned len, enum bfd_endian byte_order, bool
> zero_pad)
> + unsigned len, enum bfd_endian byte_order, bool
> zero_pad,
> + const struct value_print_options *options)
> {
> const gdb_byte *p;
> unsigned int i;
> int b;
> bool seen_a_one = false;
> + char digit_separator = ' ';
>
> /* Declared "int" so it will be signed.
> This ensures that right shift will shift in zeros. */
>
> const int mask = 0x080;
>
> + if (options->nibblesprint)
> + digit_separator = get_digit_separator();
> +
> if (byte_order == BFD_ENDIAN_BIG)
> {
> for (p = valaddr;
> @@ -1390,6 +1430,9 @@ print_binary_chars (struct ui_file *stream,
> const gdb_byte *valaddr,
>
> for (i = 0; i < (HOST_CHAR_BIT * sizeof (*p)); i++)
> {
> + if (options->nibblesprint && seen_a_one && i % 4 == 0)
> + fputc_filtered (digit_separator, stream);
> +
> if (*p & (mask >> i))
> b = '1';
> else
> @@ -1397,6 +1440,13 @@ print_binary_chars (struct ui_file *stream,
> const gdb_byte *valaddr,
>
> if (zero_pad || seen_a_one || b == '1')
> fputc_filtered (b, stream);
> + else if (options->nibblesprint)
> + {
> + if ((0xf0 & (mask >> i) && (*p & 0xf0)) ||
> + (0x0f & (mask >> i) && (*p & 0x0f)))
> + fputc_filtered (b, stream);
> + }
> +
> if (b == '1')
> seen_a_one = true;
> }
> @@ -1410,6 +1460,9 @@ print_binary_chars (struct ui_file *stream,
> const gdb_byte *valaddr,
> {
> for (i = 0; i < (HOST_CHAR_BIT * sizeof (*p)); i++)
> {
> + if (options->nibblesprint && seen_a_one && i % 4 == 0)
> + fputc_filtered (digit_separator, stream);
> +
> if (*p & (mask >> i))
> b = '1';
> else
> @@ -1417,6 +1470,13 @@ print_binary_chars (struct ui_file *stream,
> const gdb_byte *valaddr,
>
> if (zero_pad || seen_a_one || b == '1')
> fputc_filtered (b, stream);
> + else if (options->nibblesprint)
> + {
> + if ((0xf0 & (mask >> i) && (*p & 0xf0)) ||
> + (0x0f & (mask >> i) && (*p & 0x0f)))
> + fputc_filtered (b, stream);
> + }
> +
> if (b == '1')
> seen_a_one = true;
> }
> @@ -3016,6 +3076,15 @@ static const gdb::option::option_def
> value_print_option_defs[] = {
> NULL, /* help_doc */
> },
>
> + boolean_option_def {
> + "nibbles",
> + [] (value_print_options *opt) { return &opt->nibblesprint; },
> + show_nibbles, /* show_cmd_cb */
> + N_("Set whether to print binary values in groups of four
> bits."),
> + N_("Show whether to print binary values in groups of four
> bits."),
> + NULL, /* help_doc */
> + },
> +
> uinteger_option_def {
> "elements",
> [] (value_print_options *opt) { return &opt->print_max; },
> diff --git a/gdb/valprint.h b/gdb/valprint.h
> index e1dae2cc8fc..bb19c41ab68 100644
> --- a/gdb/valprint.h
> +++ b/gdb/valprint.h
> @@ -44,6 +44,9 @@ struct value_print_options
> /* Controls printing of addresses. */
> bool addressprint;
>
> + /* Controls printing of nibbles. */
> + bool nibblesprint;
> +
> /* Controls looking up an object's derived type using what we find
> in its vtables. */
> bool objectprint;
> @@ -149,7 +152,8 @@ extern void value_print_scalar_formatted
> int size, struct ui_file *stream);
>
> extern void print_binary_chars (struct ui_file *, const gdb_byte *,
> - unsigned int, enum bfd_endian, bool);
> + unsigned int, enum bfd_endian, bool,
> + const struct value_print_options
> *options);
>
> extern void print_octal_chars (struct ui_file *, const gdb_byte *,
> unsigned int, enum bfd_endian);
More information about the Gdb-patches
mailing list