public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v7] gdb: Add new 'print nibbles' feature
@ 2021-12-29 13:45 Enze Li
  2022-01-11 14:06 ` [PING][PATCH " Enze Li
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Enze Li @ 2021-12-29 13:45 UTC (permalink / raw)
  To: gdb-patches

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);
-- 
2.34.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PING][PATCH v7] gdb: Add new 'print nibbles' feature
  2021-12-29 13:45 [PATCH v7] gdb: Add new 'print nibbles' feature Enze Li
@ 2022-01-11 14:06 ` Enze Li
  2022-01-14 20:32 ` [PATCH " Tom Tromey
  2022-03-31 13:41 ` Pedro Alves
  2 siblings, 0 replies; 4+ messages in thread
From: Enze Li @ 2022-01-11 14:06 UTC (permalink / raw)
  To: gdb-patches

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);


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v7] gdb: Add new 'print nibbles' feature
  2021-12-29 13:45 [PATCH v7] gdb: Add new 'print nibbles' feature Enze Li
  2022-01-11 14:06 ` [PING][PATCH " Enze Li
@ 2022-01-14 20:32 ` Tom Tromey
  2022-03-31 13:41 ` Pedro Alves
  2 siblings, 0 replies; 4+ messages in thread
From: Tom Tromey @ 2022-01-14 20:32 UTC (permalink / raw)
  To: Enze Li via Gdb-patches

>>>>> ">" == Enze Li via Gdb-patches <gdb-patches@sourceware.org> writes:

>> 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.

Thank you for the patch.

>> +@item -nibbles [@code{on}|@code{off}]
>> +Set whether to print binary values in groups of four bits, known
>> +as ``nibbles''.  @xref{set print nibbles}.

I think if new print flags are added, we generally also add them to the
Python layer, see valpy_format_string.

>> +/* 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 ' ';

It's better to add this kind of thing to the language object itself, or
to generic_val_print_decorations.  I'd say probably the latter,
depending on whether that's difficult.

>> +		  if ((0xf0 & (mask >> i) && (*p & 0xf0)) ||
>> +		      (0x0f & (mask >> i) && (*p & 0x0f)))

In gdb operators are put at the start of the continuing line.
Also this reads very weirdly to me.  It could probably benefit from some
explict "!= 0" somewhere.

thanks,
Tom

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v7] gdb: Add new 'print nibbles' feature
  2021-12-29 13:45 [PATCH v7] gdb: Add new 'print nibbles' feature Enze Li
  2022-01-11 14:06 ` [PING][PATCH " Enze Li
  2022-01-14 20:32 ` [PATCH " Tom Tromey
@ 2022-03-31 13:41 ` Pedro Alves
  2 siblings, 0 replies; 4+ messages in thread
From: Pedro Alves @ 2022-03-31 13:41 UTC (permalink / raw)
  To: Enze Li, gdb-patches

Hi!


> +++ b/gdb/testsuite/gdb.cp/printnibbles.cc

...

> diff --git a/gdb/testsuite/gdb.cp/printnibbles.exp b/gdb/testsuite/gdb.cp/printnibbles.exp

...

> diff --git a/gdb/testsuite/gdb.rust/printnibbles.exp b/gdb/testsuite/gdb.rust/printnibbles.exp

...

> diff --git a/gdb/testsuite/gdb.rust/printnibbles.rs b/gdb/testsuite/gdb.rust/printnibbles.rs

...


I don't see why the testcases need to involve actual compiled programs?

It could just do "print/t 1230" (etc) instead of "print/t var" ?

With that, it would be possible to make the testcase iterate over all languages,
doing "set language $lang", and printing nibbles for each language.  gdb.base/nodebug.exp does
something like that, for example.

Pedro Alves

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-03-31 13:41 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-29 13:45 [PATCH v7] gdb: Add new 'print nibbles' feature Enze Li
2022-01-11 14:06 ` [PING][PATCH " Enze Li
2022-01-14 20:32 ` [PATCH " Tom Tromey
2022-03-31 13:41 ` Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).