[binutils-gdb] Rewrite Rust character printer
Tom Tromey
tromey@sourceware.org
Sat Jan 31 19:27:23 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=d26406ed1bf129482a92f05e0f6c405f502225e0
commit d26406ed1bf129482a92f05e0f6c405f502225e0
Author: Tom Tromey <tom@tromey.com>
Date: Mon Dec 22 13:20:40 2025 -0700
Rewrite Rust character printer
This adds a Rust-specific subclass of wchar_printer and arranges to
use it.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=20164
Diff:
---
gdb/rust-lang.c | 94 ++++++++++++++++++++++++++++----------
gdb/testsuite/gdb.rust/expr.exp | 4 +-
gdb/testsuite/gdb.rust/unicode.exp | 3 +-
3 files changed, 73 insertions(+), 28 deletions(-)
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 83786ff6e85..1695fd73344 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -38,6 +38,8 @@
#include "cli/cli-style.h"
#include "parser-defs.h"
#include "rust-exp.h"
+#include "char-print.h"
+#include "extract-store-integer.h"
/* See rust-lang.h. */
@@ -390,6 +392,69 @@ rust_array_like_element_type (struct type *type)
+/* A wchar_printer specialized for Rust syntax. */
+class rust_wchar_printer : public wchar_printer
+{
+ using wchar_printer::wchar_printer;
+
+ bool printable (gdb_wchar_t w) const override;
+ void print_char (gdb_wchar_t w) override;
+ void print_escape (const gdb_byte *orig, int orig_len) override;
+};
+
+bool
+rust_wchar_printer::printable (gdb_wchar_t w) const
+{
+ return (gdb_iswprint (w)
+ || w == LCST ('\n') || w == LCST ('\r')
+ || w == LCST ('\t') || w == LCST ('\0'));
+}
+
+void
+rust_wchar_printer::print_char (gdb_wchar_t w)
+{
+ if (w == LCST ('\\'))
+ m_file.write (LCST ("\\\\"));
+ else if (w == gdb_btowc (m_quoter))
+ {
+ m_file.write (LCST ('\\'));
+ m_file.write (w);
+ }
+ else if (w == LCST ('\n'))
+ m_file.write (LCST ("\\n"));
+ else if (w == LCST ('\r'))
+ m_file.write (LCST ("\\r"));
+ else if (w == LCST ('\t'))
+ m_file.write (LCST ("\\t"));
+ else if (w == LCST ('\0'))
+ m_file.write (LCST ("\\0"));
+ else
+ m_file.write (w);
+}
+
+void
+rust_wchar_printer::print_escape (const gdb_byte *orig, int orig_len)
+{
+ int i;
+
+ for (i = 0; i + m_width <= orig_len; i += m_width)
+ {
+ ULONGEST value = extract_unsigned_integer (&orig[i], m_width,
+ m_byte_order);
+ if (value <= 255)
+ gdb_printf (&m_file, "\\x%02x", (int) value);
+ else
+ gdb_printf (&m_file, "\\u{%06lx}", (unsigned long) value);
+ }
+
+ /* If we somehow have extra bytes, print them now. */
+ while (i < orig_len)
+ {
+ gdb_printf (&m_file, "\\x%02x", orig[i] & 0xff);
+ ++i;
+ }
+}
+
/* See language.h. */
void
@@ -417,9 +482,8 @@ rust_language::printstr (struct ui_file *stream, struct type *type,
}
}
- /* This is not ideal as it doesn't use our character printer. */
- generic_printstr (stream, type, string, length, encoding, force_ellipses,
- '"', 0, options);
+ rust_wchar_printer printer (type, '"', encoding);
+ printer.print (stream, string, length, force_ellipses, 0, options);
}
@@ -1776,29 +1840,11 @@ rust_language::printchar (int ch, struct type *chtype,
struct ui_file *stream) const
{
if (!rust_chartype_p (chtype))
+ generic_emit_char (ch, chtype, stream, target_charset (chtype->arch ()));
+ else
{
- generic_emit_char (ch, chtype, stream,
- target_charset (chtype->arch ()));
- return;
+ rust_wchar_printer (chtype, '\'').print (ch, stream);
}
- gdb_puts ("'", stream);
- if (ch == '\\')
- gdb_printf (stream, "\\%c", ch);
- else if (ch == '\n')
- gdb_puts ("\\n", stream);
- else if (ch == '\r')
- gdb_puts ("\\r", stream);
- else if (ch == '\t')
- gdb_puts ("\\t", stream);
- else if (ch == '\0')
- gdb_puts ("\\0", stream);
- else if (ch >= 32 && ch <= 127 && c_isprint (ch))
- gdb_putc (ch, stream);
- else if (ch <= 255)
- gdb_printf (stream, "\\x%02x", ch);
- else
- gdb_printf (stream, "\\u{%06x}", ch);
- gdb_puts ("'", stream);
}
/* See language.h. */
diff --git a/gdb/testsuite/gdb.rust/expr.exp b/gdb/testsuite/gdb.rust/expr.exp
index e3306c0f478..3eb72cf01b3 100644
--- a/gdb/testsuite/gdb.rust/expr.exp
+++ b/gdb/testsuite/gdb.rust/expr.exp
@@ -122,8 +122,8 @@ gdb_test "print \[0;1\]" " = \\\[0\\\]"
gdb_test "print b\"hi rust\"" " = b\"hi rust\""
# This isn't rusty syntax yet, but that's another bug -- this is just
# testing that byte escapes work properly.
-gdb_test "print b\"\\xddhi bob\"" " = b\"\\\\335hi bob\""
-gdb_test "print b\"has\\0nul\"" " = b\"has\\\\000nul\""
+gdb_test "print b\"\\xddhi bob\"" " = b\"\\\\xddhi bob\""
+gdb_test "print b\"has\\0nul\"" " = b\"has\\\\0nul\""
gdb_test "print br##\"hi\"##" " = b\"hi\""
gdb_test "print br##\"hi" "Unexpected EOF in string"
diff --git a/gdb/testsuite/gdb.rust/unicode.exp b/gdb/testsuite/gdb.rust/unicode.exp
index 401fb1f3502..b9951013738 100644
--- a/gdb/testsuite/gdb.rust/unicode.exp
+++ b/gdb/testsuite/gdb.rust/unicode.exp
@@ -39,8 +39,7 @@ if {![runto ${srcfile}:$line]} {
gdb_test "print 𝕯" " = 98" "print D"
gdb_test "print \"𝕯\"" " = \"𝕯\"" "print D in string"
-# This output is maybe not ideal, but it also isn't incorrect.
-gdb_test "print '𝕯'" " = 120175 '\\\\u\\\{01d56f\\\}'" \
+gdb_test "print '𝕯'" " = 120175 '𝕯'" \
"print D as char"
gdb_test "print cç" " = 97" "print cc"
More information about the Gdb-cvs
mailing list