[PATCH v2] Change how "print/x" displays floating-point value

Tom Tromey tromey@adacore.com
Thu Mar 10 19:20:08 GMT 2022


Currently, "print/x" will display a floating-point value by first
casting it to an integer type.  This yields weird results like:

    (gdb) print/x 1.5
    $1 = 0x1

This has confused users multiple times -- see PR gdb/16242, where
there are several dups.  I've also seen some confusion from this
internally at AdaCore.

The manual says:

    'x'
	 Regard the bits of the value as an integer, and print the integer
	 in hexadecimal.

... which seems more useful.  So, perhaps what happened is that this
was incorrectly implemented (or maybe correctly implemented and then
regressed, as there don't seem to be any tests).

This patch fixes the bug.

There was a previous discussion where we agreed to preserve the old
behavior:

    https://sourceware.org/legacy-ml/gdb-patches/2017-06/msg00314.html

However, I think it makes more sense to follow the manual.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=16242
---
 gdb/NEWS                                  |  6 +++++
 gdb/doc/gdb.texinfo                       | 28 ++++++++++++-----------
 gdb/printcmd.c                            |  9 ++------
 gdb/testsuite/gdb.base/printcmds.c        |  2 ++
 gdb/testsuite/gdb.base/printcmds.exp      | 23 +++++++++++++++++--
 gdb/testsuite/gdb.base/return-nodebug.exp |  7 +++++-
 6 files changed, 52 insertions(+), 23 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 4d282cb37dd..c9b6f42616b 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -125,6 +125,12 @@ show ada source-charset
 
 * Changed commands
 
+print
+  Printing of floating-point values with base-modifying formats like
+  /x has been changed to display the underlying bytes of the value in
+  the desired base.  This was GDB's documented behavior, but was never
+  implemented correctly.
+
 maint packet
   This command can now print a reply, if the reply includes
   non-printable characters.  Any non-printable characters are printed
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e61cef36a2d..d216fa1d529 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10756,23 +10756,24 @@ letters supported are:
 
 @table @code
 @item x
-Regard the bits of the value as an integer, and print the integer in
-hexadecimal.
+Print the binary representation of the value in hexadecimal.
 
 @item d
-Print as integer in signed decimal.
+Print the binary representation of the value in decimal.
 
 @item u
-Print as integer in unsigned decimal.
+Print the binary representation of the value as an decimal, as if it
+were unsigned.
 
 @item o
-Print as integer in octal.
+Print the binary representation of the value in octal.
 
 @item t
-Print as integer in binary.  The letter @samp{t} stands for ``two''.
-@footnote{@samp{b} cannot be used because these format letters are also
-used with the @code{x} command, where @samp{b} stands for ``byte'';
-see @ref{Memory,,Examining Memory}.}
+Print the binary representation of the value in binary.  The letter
+@samp{t} stands for ``two''.  @footnote{@samp{b} cannot be used
+because these format letters are also used with the @code{x} command,
+where @samp{b} stands for ``byte''; see @ref{Memory,,Examining
+Memory}.}
 
 @item a
 @cindex unknown address, locating
@@ -10791,10 +10792,11 @@ The command @code{info symbol 0x54320} yields similar results.
 @xref{Symbols, info symbol}.
 
 @item c
-Regard as an integer and print it as a character constant.  This
-prints both the numerical value and its character representation.  The
-character representation is replaced with the octal escape @samp{\nnn}
-for characters outside the 7-bit @sc{ascii} range.
+Cast the value to an integer (unlike other formats, this does not just
+reinterpret the underlying bits) and print it as a character constant.
+This prints both the numerical value and its character representation.
+The character representation is replaced with the octal escape
+@samp{\nnn} for characters outside the 7-bit @sc{ascii} range.
 
 Without this format, @value{GDBN} displays @code{char},
 @w{@code{unsigned char}}, and @w{@code{signed char}} data as character
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 6f9be820b0c..30de1927d39 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -426,19 +426,14 @@ print_scalar_formatted (const gdb_byte *valaddr, struct type *type,
       len = newlen;
     }
 
-  /* Historically gdb has printed floats by first casting them to a
-     long, and then printing the long.  PR cli/16242 suggests changing
-     this to using C-style hex float format.
-
-     Biased range types and sub-word scalar types must also be handled
+  /* Biased range types and sub-word scalar types must be handled
      here; the value is correctly computed by unpack_long.  */
   gdb::byte_vector converted_bytes;
   /* Some cases below will unpack the value again.  In the biased
      range case, we want to avoid this, so we store the unpacked value
      here for possible use later.  */
   gdb::optional<LONGEST> val_long;
-  if (((type->code () == TYPE_CODE_FLT
-	|| is_fixed_point_type (type))
+  if ((is_fixed_point_type (type)
        && (options->format == 'o'
 	   || options->format == 'x'
 	   || options->format == 't'
diff --git a/gdb/testsuite/gdb.base/printcmds.c b/gdb/testsuite/gdb.base/printcmds.c
index 9af6bf3aacb..78291a2803c 100644
--- a/gdb/testsuite/gdb.base/printcmds.c
+++ b/gdb/testsuite/gdb.base/printcmds.c
@@ -246,6 +246,8 @@ char invalid_RRR[] = "aaaaaaaaaaaaaaaaaaaa"
 
 /* -- */
 
+float f_var = 65.0f;
+
 int main ()
 {
   void *p = malloc (1);
diff --git a/gdb/testsuite/gdb.base/printcmds.exp b/gdb/testsuite/gdb.base/printcmds.exp
index 37632985a07..3260c8a3c09 100644
--- a/gdb/testsuite/gdb.base/printcmds.exp
+++ b/gdb/testsuite/gdb.base/printcmds.exp
@@ -158,8 +158,27 @@ proc test_float_rejected {} {
 # Regression test for PR gdb/21675
 proc test_radices {} {
     gdb_test "print/o 16777211" " = 077777773"
-    gdb_test "print/d 1.5" " = 1"
-    gdb_test "print/u 1.5" " = 1"
+
+    # This is written in a somewhat funny way to avoid assuming a
+    # particular float format.
+    set s_int [get_sizeof int -1]
+    set s_float [get_sizeof float -1]
+    if {$s_int == $s_float && $s_int != -1} {
+	foreach fmt {d u x t o} {
+	    set ival [get_valueof "/$fmt" "*(int *) &f_var" "FAIL" \
+			  "get_valueof int/$fmt"]
+	    set fval [get_valueof "/$fmt" f_var "FAIL" \
+			  "get_valueof float/$fmt"]
+	    # See PR gdb/16242 for this.
+	    if {[string compare $ival $fval] == 0 && $ival != "FAIL"} {
+		pass "print/$fmt f_var"
+	    } else {
+		fail "print/$fmt f_var"
+	    }
+	}
+    }
+
+    gdb_test "print/c f_var" " = 65 'A'"
 
     gdb_test "print/u (char) -1" " = 255"
     gdb_test "print/d (unsigned char) -1" " = -1"
diff --git a/gdb/testsuite/gdb.base/return-nodebug.exp b/gdb/testsuite/gdb.base/return-nodebug.exp
index 6fd41bee884..1cce09d2fc4 100644
--- a/gdb/testsuite/gdb.base/return-nodebug.exp
+++ b/gdb/testsuite/gdb.base/return-nodebug.exp
@@ -38,7 +38,12 @@ proc do_test {type} {
 		"advance to marker"
 
 	    # And if it returned the full width of the result.
-	    gdb_test "print /d t" " = -1" "full width of the returned result"
+	    if {$type == "float" || $type == "double"} {
+		set flag ""
+	    } else {
+		set flag "/d"
+	    }
+	    gdb_test "print $flag t" " = -1" "full width of the returned result"
 	}
     }
 }
-- 
2.34.1



More information about the Gdb-patches mailing list