* [PATCH] gdb, gdbsupport, gdbserver: add support for printf 't' length modifier
@ 2026-01-12 18:24 simon.marchi
2026-01-15 19:24 ` Tom Tromey
2026-01-19 17:29 ` Guinevere Larsen
0 siblings, 2 replies; 7+ messages in thread
From: simon.marchi @ 2026-01-12 18:24 UTC (permalink / raw)
To: gdb-patches; +Cc: Simon Marchi
From: Simon Marchi <simon.marchi@polymtl.ca>
Tom de Vries reported [1] that a use of the `t` printf length modifier
(used for ptrdiff_t) breaks "set debug dwarf-die 1":
+break -qualified main
Reading Reading compcomp unit at offset unit at offset 0x00x39
Reading comp unit at offset 0x1a8
Reading comp unit at offset 0x1e9
Reading comp unit at offset 0x2c5
Reading comp unit at offset 0x2a2
Reading comp unit at offset 0x904
Unrecognized format specifier 't' in printf
This use is in dwarf2/read.c:
gdb_printf (gdb_stdlog, "Read die from %s@0x%tx of %s:\n",
m_die_section->get_name (),
(begin_info_ptr - m_die_section->buffer),
bfd_get_filename (m_abfd));
Add support for the `t` length modifier in format_pieces, which
gdb_printf ultimately uses (through ui_out::vmessage). Modify the three
users of format_pieces: gdb's printf command, gdb's ui_out::vmessage
function and gdbserver's ax_printf function.
The implementation is mostly copied from what we do for size_t.
Since format_pieces is also used to implement the printf command, this
patch brings user-visible changes. Before:
(gdb) printf "%td\n", -123
❌️ Unrecognized format specifier 't' in printf
After:
(gdb) printf "%td\n", -123
-123
[1] https://inbox.sourceware.org/gdb-patches/d4ccce34-aad5-4e3d-8fc9-efb2fc11275c@suse.de/
Change-Id: Ie9fce78f5f48082d8f8a9ca2847b5ae26acaa60d
---
gdb/printcmd.c | 10 ++++++++++
gdb/testsuite/gdb.base/printcmds.c | 6 ++++++
gdb/testsuite/gdb.base/printcmds.exp | 4 ++++
gdb/ui-out.c | 18 ++++++++++++++++++
gdb/unittests/format_pieces-selftests.c | 12 ++++++++----
gdbserver/ax.cc | 8 ++++++++
gdbsupport/format.cc | 11 ++++++++++-
gdbsupport/format.h | 2 +-
8 files changed, 65 insertions(+), 6 deletions(-)
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 783b83615d02..7c97fc719926 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -2815,6 +2815,16 @@ ui_printf (const char *arg, struct ui_file *stream)
{
size_t val = value_as_long (val_args[i]);
+ DIAGNOSTIC_PUSH
+ DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
+ gdb_printf (stream, current_substring, val);
+ DIAGNOSTIC_POP
+ break;
+ }
+ case ptrdiff_t_arg:
+ {
+ ptrdiff_t val = value_as_long (val_args[i]);
+
DIAGNOSTIC_PUSH
DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
gdb_printf (stream, current_substring, val);
diff --git a/gdb/testsuite/gdb.base/printcmds.c b/gdb/testsuite/gdb.base/printcmds.c
index 8445fcc1aa2a..82796932e1d3 100644
--- a/gdb/testsuite/gdb.base/printcmds.c
+++ b/gdb/testsuite/gdb.base/printcmds.c
@@ -2,6 +2,8 @@
It is explicitly unsigned to avoid differences due to native characters
being either signed or unsigned. */
#include <stdlib.h>
+#include <stddef.h>
+
unsigned char ctable1[256] = {
0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
@@ -77,6 +79,10 @@ charptr teststring2 = "more contents";
const char *teststring3 = "this is a longer test string that we can use";
+/* For testing printf with %z (size_t) and %t (ptrdiff_t) length modifiers. */
+size_t test_size = 1234;
+ptrdiff_t test_ptrdiff = -5678;
+
/* Test printing of a struct containing character arrays. */
struct some_arrays {
diff --git a/gdb/testsuite/gdb.base/printcmds.exp b/gdb/testsuite/gdb.base/printcmds.exp
index bc100f93df9a..32a952f01a55 100644
--- a/gdb/testsuite/gdb.base/printcmds.exp
+++ b/gdb/testsuite/gdb.base/printcmds.exp
@@ -908,6 +908,10 @@ proc test_printf {} {
# PR cli/14977.
gdb_test "printf \"%s\\n\", 0" "\\(null\\)"
+ # Test %z (size_t) and %t (ptrdiff_t) length modifiers.
+ gdb_test "printf \"%zu\\n\", test_size" "1234"
+ gdb_test "printf \"%td\\n\", test_ptrdiff" "-5678"
+
with_max_value_size 20 {
gdb_test {printf "%s", teststring3} \
"^printed string requires 45 bytes, which is more than max-value-size"
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 4f20e6b93477..87874e22530f 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -682,6 +682,24 @@ ui_out::vmessage (const ui_file_style &in_style, const char *format,
}
}
break;
+ case ptrdiff_t_arg:
+ {
+ ptrdiff_t val = va_arg (args, ptrdiff_t);
+ switch (piece.n_int_args)
+ {
+ case 0:
+ call_do_message (style, current_substring, val);
+ break;
+ case 1:
+ call_do_message (style, current_substring, intvals[0], val);
+ break;
+ case 2:
+ call_do_message (style, current_substring,
+ intvals[0], intvals[1], val);
+ break;
+ }
+ }
+ break;
case double_arg:
call_do_message (style, current_substring, va_arg (args, double));
break;
diff --git a/gdb/unittests/format_pieces-selftests.c b/gdb/unittests/format_pieces-selftests.c
index af574ccc900f..c5f3cf74f1dc 100644
--- a/gdb/unittests/format_pieces-selftests.c
+++ b/gdb/unittests/format_pieces-selftests.c
@@ -105,40 +105,44 @@ test_gdb_formats ()
static void
test_format_int_sizes ()
{
- check ("Hello\\t %hu%lu%llu%zu", /* ARI: %ll */
+ check ("Hello\\t %hu%lu%llu%zu%tu", /* ARI: %ll */
{
{"Hello\t ", literal_piece, 0},
{"%hu", int_arg, 0},
{"%lu", long_arg, 0},
{"%" LL "u", long_long_arg, 0},
{"%zu", size_t_arg, 0},
+ {"%tu", ptrdiff_t_arg, 0},
});
- check ("Hello\\t %hx%lx%llx%zx", /* ARI: %ll */
+ check ("Hello\\t %hx%lx%llx%zx%tx", /* ARI: %ll */
{
{"Hello\t ", literal_piece, 0},
{"%hx", int_arg, 0},
{"%lx", long_arg, 0},
{"%" LL "x", long_long_arg, 0},
{"%zx", size_t_arg, 0},
+ {"%tx", ptrdiff_t_arg, 0},
});
- check ("Hello\\t %ho%lo%llo%zo", /* ARI: %ll */
+ check ("Hello\\t %ho%lo%llo%zo%to", /* ARI: %ll */
{
{"Hello\t ", literal_piece, 0},
{"%ho", int_arg, 0},
{"%lo", long_arg, 0},
{"%" LL "o", long_long_arg, 0},
{"%zo", size_t_arg, 0},
+ {"%to", ptrdiff_t_arg, 0},
});
- check ("Hello\\t %hd%ld%lld%zd", /* ARI: %ll */
+ check ("Hello\\t %hd%ld%lld%zd%td", /* ARI: %ll */
{
{"Hello\t ", literal_piece, 0},
{"%hd", int_arg, 0},
{"%ld", long_arg, 0},
{"%" LL "d", long_long_arg, 0},
{"%zd", size_t_arg, 0},
+ {"%td", ptrdiff_t_arg, 0},
});
}
diff --git a/gdbserver/ax.cc b/gdbserver/ax.cc
index 44fcf3157291..4993bed2532c 100644
--- a/gdbserver/ax.cc
+++ b/gdbserver/ax.cc
@@ -908,6 +908,14 @@ ax_printf (CORE_ADDR fn, CORE_ADDR chan, const char *format,
break;
}
+ case ptrdiff_t_arg:
+ {
+ ptrdiff_t val = args[i];
+
+ printf (current_substring, val);
+ break;
+ }
+
case literal_piece:
/* Print a portion of the format string that has no
directives. Note that this will not include any
diff --git a/gdbsupport/format.cc b/gdbsupport/format.cc
index b515a95114e0..43995edf453e 100644
--- a/gdbsupport/format.cc
+++ b/gdbsupport/format.cc
@@ -111,6 +111,7 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions,
int seen_big_l = 0, seen_h = 0, seen_big_h = 0;
int seen_big_d = 0, seen_double_big_d = 0;
int seen_size_t = 0;
+ int seen_ptrdiff_t = 0;
int bad = 0;
int n_int_args = 0;
bool seen_i64 = false;
@@ -224,6 +225,11 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions,
seen_size_t = 1;
f++;
break;
+ case 't':
+ /* For ptrdiff_t. */
+ seen_ptrdiff_t = 1;
+ f++;
+ break;
case 'I':
/* Support the Windows '%I64' extension, because an
earlier call to format_pieces might have converted %lld
@@ -257,6 +263,8 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions,
case 'i':
if (seen_size_t)
this_argclass = size_t_arg;
+ else if (seen_ptrdiff_t)
+ this_argclass = ptrdiff_t_arg;
else if (lcount == 0)
this_argclass = int_arg;
else if (lcount == 1)
@@ -334,7 +342,8 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions,
if (lcount > 1 || seen_h || seen_big_h || seen_big_h
|| seen_big_d || seen_double_big_d || seen_size_t
- || seen_prec || seen_zero || seen_space || seen_plus)
+ || seen_ptrdiff_t || seen_prec || seen_zero || seen_space
+ || seen_plus)
bad = 1;
this_argclass = value_arg;
diff --git a/gdbsupport/format.h b/gdbsupport/format.h
index 91bcf1db55a6..ced10e46a716 100644
--- a/gdbsupport/format.h
+++ b/gdbsupport/format.h
@@ -36,7 +36,7 @@
enum argclass
{
literal_piece,
- int_arg, long_arg, long_long_arg, size_t_arg, ptr_arg,
+ int_arg, long_arg, long_long_arg, size_t_arg, ptrdiff_t_arg, ptr_arg,
string_arg, wide_string_arg, wide_char_arg,
double_arg, long_double_arg,
dec32float_arg, dec64float_arg, dec128float_arg,
base-commit: b9517052ce5c1d87bfd7030bcbf90a98f63fddf6
--
2.52.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] gdb, gdbsupport, gdbserver: add support for printf 't' length modifier
2026-01-12 18:24 [PATCH] gdb, gdbsupport, gdbserver: add support for printf 't' length modifier simon.marchi
@ 2026-01-15 19:24 ` Tom Tromey
2026-01-15 19:36 ` Simon Marchi
2026-01-19 17:29 ` Guinevere Larsen
1 sibling, 1 reply; 7+ messages in thread
From: Tom Tromey @ 2026-01-15 19:24 UTC (permalink / raw)
To: simon.marchi; +Cc: gdb-patches
>>>>> "Simon" == simon marchi <simon.marchi@polymtl.ca> writes:
Simon> Add support for the `t` length modifier in format_pieces, which
Simon> gdb_printf ultimately uses (through ui_out::vmessage). Modify the three
Simon> users of format_pieces: gdb's printf command, gdb's ui_out::vmessage
Simon> function and gdbserver's ax_printf function.
Thanks.
These modifiers are one of the clearest reasons that printf should be
replaced. I think we should generally avoid them. We've already got
plongest, etc; which seem safer. See commit a1537331 (the "other
direction") but there's also commit a5adb8f3 and probably more.
Anyway, it's ok.
Approved-By: Tom Tromey <tom@tromey.com>
Tom
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] gdb, gdbsupport, gdbserver: add support for printf 't' length modifier
2026-01-15 19:24 ` Tom Tromey
@ 2026-01-15 19:36 ` Simon Marchi
2026-01-15 19:42 ` Tom Tromey
0 siblings, 1 reply; 7+ messages in thread
From: Simon Marchi @ 2026-01-15 19:36 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 1/15/26 2:24 PM, Tom Tromey wrote:
>>>>>> "Simon" == simon marchi <simon.marchi@polymtl.ca> writes:
>
> Simon> Add support for the `t` length modifier in format_pieces, which
> Simon> gdb_printf ultimately uses (through ui_out::vmessage). Modify the three
> Simon> users of format_pieces: gdb's printf command, gdb's ui_out::vmessage
> Simon> function and gdbserver's ax_printf function.
>
> Thanks.
>
> These modifiers are one of the clearest reasons that printf should be
> replaced. I think we should generally avoid them. We've already got
> plongest, etc; which seem safer. See commit a1537331 (the "other
> direction") but there's also commit a5adb8f3 and probably more.
>
> Anyway, it's ok.
> Approved-By: Tom Tromey <tom@tromey.com>
>
> Tom
I think the reason for plongest is more that LONGEST can vary from build
to build. We could otherwise have PRILONGEST / PRIULONGEST / etc
macros, just like there is PRIu64 & co. But yeah if we do a move
nowadays, it would make more sense to move to std::format/{fmt}.
I pushed the patch, thanks.
Simon
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] gdb, gdbsupport, gdbserver: add support for printf 't' length modifier
2026-01-15 19:36 ` Simon Marchi
@ 2026-01-15 19:42 ` Tom Tromey
0 siblings, 0 replies; 7+ messages in thread
From: Tom Tromey @ 2026-01-15 19:42 UTC (permalink / raw)
To: Simon Marchi; +Cc: Tom Tromey, gdb-patches
>>>>> "Simon" == Simon Marchi <simon.marchi@polymtl.ca> writes:
Simon> I think the reason for plongest is more that LONGEST can vary from build
Simon> to build. We could otherwise have PRILONGEST / PRIULONGEST / etc
Simon> macros, just like there is PRIu64 & co.
We could have those but personally I think those PRI* things are
unreadably ugly.
As an aside, it's absurd for the gdb "printf" command to use these at
all. gdb already knows all the types, "%d" could easily handle any
integral type and "%td" is never truly necessary.
Tom
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] gdb, gdbsupport, gdbserver: add support for printf 't' length modifier
2026-01-12 18:24 [PATCH] gdb, gdbsupport, gdbserver: add support for printf 't' length modifier simon.marchi
2026-01-15 19:24 ` Tom Tromey
@ 2026-01-19 17:29 ` Guinevere Larsen
2026-01-19 18:09 ` Simon Marchi
1 sibling, 1 reply; 7+ messages in thread
From: Guinevere Larsen @ 2026-01-19 17:29 UTC (permalink / raw)
To: simon.marchi, gdb-patches
On 1/12/26 3:24 PM, simon.marchi@polymtl.ca wrote:
> From: Simon Marchi <simon.marchi@polymtl.ca>
>
> Tom de Vries reported [1] that a use of the `t` printf length modifier
> (used for ptrdiff_t) breaks "set debug dwarf-die 1":
>
> +break -qualified main
> Reading Reading compcomp unit at offset unit at offset 0x00x39
>
> Reading comp unit at offset 0x1a8
> Reading comp unit at offset 0x1e9
> Reading comp unit at offset 0x2c5
> Reading comp unit at offset 0x2a2
> Reading comp unit at offset 0x904
> Unrecognized format specifier 't' in printf
>
> This use is in dwarf2/read.c:
>
> gdb_printf (gdb_stdlog, "Read die from %s@0x%tx of %s:\n",
> m_die_section->get_name (),
> (begin_info_ptr - m_die_section->buffer),
> bfd_get_filename (m_abfd));
>
> Add support for the `t` length modifier in format_pieces, which
> gdb_printf ultimately uses (through ui_out::vmessage). Modify the three
> users of format_pieces: gdb's printf command, gdb's ui_out::vmessage
> function and gdbserver's ax_printf function.
>
> The implementation is mostly copied from what we do for size_t.
>
> Since format_pieces is also used to implement the printf command, this
> patch brings user-visible changes. Before:
>
> (gdb) printf "%td\n", -123
> ❌️ Unrecognized format specifier 't' in printf
>
> After:
>
> (gdb) printf "%td\n", -123
> -123
>
> [1] https://inbox.sourceware.org/gdb-patches/d4ccce34-aad5-4e3d-8fc9-efb2fc11275c@suse.de/
>
> Change-Id: Ie9fce78f5f48082d8f8a9ca2847b5ae26acaa60d
> ---
This commit seems to have caused a regression. After this, when starting
GDB without the quiet flag I get the following:
0x7ffc6b9bc520s
Copyright (C) 2026 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <0x7ffc6b9bc560s>
This is free software: you are free to change and redistribute it
There is NO WARRANTY, to the extent permitted by law.
Type "0x7ffc6b9bc5e0s" and "0x7ffc6b9bc5a0s" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "0x7ffc6b9bc620s" for configuration details.
For bug reporting instructions, please see:
0x7ffc6b9bc660s.
That is, anywhere where GDB would print a styled string, we seem to be
printing a pointer address instead.
> gdb/printcmd.c | 10 ++++++++++
> gdb/testsuite/gdb.base/printcmds.c | 6 ++++++
> gdb/testsuite/gdb.base/printcmds.exp | 4 ++++
> gdb/ui-out.c | 18 ++++++++++++++++++
> gdb/unittests/format_pieces-selftests.c | 12 ++++++++----
> gdbserver/ax.cc | 8 ++++++++
> gdbsupport/format.cc | 11 ++++++++++-
> gdbsupport/format.h | 2 +-
> 8 files changed, 65 insertions(+), 6 deletions(-)
>
> diff --git a/gdb/printcmd.c b/gdb/printcmd.c
> index 783b83615d02..7c97fc719926 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -2815,6 +2815,16 @@ ui_printf (const char *arg, struct ui_file *stream)
> {
> size_t val = value_as_long (val_args[i]);
>
> + DIAGNOSTIC_PUSH
> + DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
> + gdb_printf (stream, current_substring, val);
> + DIAGNOSTIC_POP
> + break;
> + }
> + case ptrdiff_t_arg:
> + {
> + ptrdiff_t val = value_as_long (val_args[i]);
> +
> DIAGNOSTIC_PUSH
> DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
> gdb_printf (stream, current_substring, val);
> diff --git a/gdb/testsuite/gdb.base/printcmds.c b/gdb/testsuite/gdb.base/printcmds.c
> index 8445fcc1aa2a..82796932e1d3 100644
> --- a/gdb/testsuite/gdb.base/printcmds.c
> +++ b/gdb/testsuite/gdb.base/printcmds.c
> @@ -2,6 +2,8 @@
> It is explicitly unsigned to avoid differences due to native characters
> being either signed or unsigned. */
> #include <stdlib.h>
> +#include <stddef.h>
> +
> unsigned char ctable1[256] = {
> 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
> 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
> @@ -77,6 +79,10 @@ charptr teststring2 = "more contents";
>
> const char *teststring3 = "this is a longer test string that we can use";
>
> +/* For testing printf with %z (size_t) and %t (ptrdiff_t) length modifiers. */
> +size_t test_size = 1234;
> +ptrdiff_t test_ptrdiff = -5678;
> +
> /* Test printing of a struct containing character arrays. */
>
> struct some_arrays {
> diff --git a/gdb/testsuite/gdb.base/printcmds.exp b/gdb/testsuite/gdb.base/printcmds.exp
> index bc100f93df9a..32a952f01a55 100644
> --- a/gdb/testsuite/gdb.base/printcmds.exp
> +++ b/gdb/testsuite/gdb.base/printcmds.exp
> @@ -908,6 +908,10 @@ proc test_printf {} {
> # PR cli/14977.
> gdb_test "printf \"%s\\n\", 0" "\\(null\\)"
>
> + # Test %z (size_t) and %t (ptrdiff_t) length modifiers.
> + gdb_test "printf \"%zu\\n\", test_size" "1234"
> + gdb_test "printf \"%td\\n\", test_ptrdiff" "-5678"
> +
> with_max_value_size 20 {
> gdb_test {printf "%s", teststring3} \
> "^printed string requires 45 bytes, which is more than max-value-size"
> diff --git a/gdb/ui-out.c b/gdb/ui-out.c
> index 4f20e6b93477..87874e22530f 100644
> --- a/gdb/ui-out.c
> +++ b/gdb/ui-out.c
> @@ -682,6 +682,24 @@ ui_out::vmessage (const ui_file_style &in_style, const char *format,
> }
> }
> break;
> + case ptrdiff_t_arg:
> + {
> + ptrdiff_t val = va_arg (args, ptrdiff_t);
> + switch (piece.n_int_args)
> + {
> + case 0:
> + call_do_message (style, current_substring, val);
> + break;
> + case 1:
> + call_do_message (style, current_substring, intvals[0], val);
> + break;
> + case 2:
> + call_do_message (style, current_substring,
> + intvals[0], intvals[1], val);
> + break;
> + }
> + }
> + break;
> case double_arg:
> call_do_message (style, current_substring, va_arg (args, double));
> break;
> diff --git a/gdb/unittests/format_pieces-selftests.c b/gdb/unittests/format_pieces-selftests.c
> index af574ccc900f..c5f3cf74f1dc 100644
> --- a/gdb/unittests/format_pieces-selftests.c
> +++ b/gdb/unittests/format_pieces-selftests.c
> @@ -105,40 +105,44 @@ test_gdb_formats ()
> static void
> test_format_int_sizes ()
> {
> - check ("Hello\\t %hu%lu%llu%zu", /* ARI: %ll */
> + check ("Hello\\t %hu%lu%llu%zu%tu", /* ARI: %ll */
> {
> {"Hello\t ", literal_piece, 0},
> {"%hu", int_arg, 0},
> {"%lu", long_arg, 0},
> {"%" LL "u", long_long_arg, 0},
> {"%zu", size_t_arg, 0},
> + {"%tu", ptrdiff_t_arg, 0},
> });
>
> - check ("Hello\\t %hx%lx%llx%zx", /* ARI: %ll */
> + check ("Hello\\t %hx%lx%llx%zx%tx", /* ARI: %ll */
> {
> {"Hello\t ", literal_piece, 0},
> {"%hx", int_arg, 0},
> {"%lx", long_arg, 0},
> {"%" LL "x", long_long_arg, 0},
> {"%zx", size_t_arg, 0},
> + {"%tx", ptrdiff_t_arg, 0},
> });
>
> - check ("Hello\\t %ho%lo%llo%zo", /* ARI: %ll */
> + check ("Hello\\t %ho%lo%llo%zo%to", /* ARI: %ll */
> {
> {"Hello\t ", literal_piece, 0},
> {"%ho", int_arg, 0},
> {"%lo", long_arg, 0},
> {"%" LL "o", long_long_arg, 0},
> {"%zo", size_t_arg, 0},
> + {"%to", ptrdiff_t_arg, 0},
> });
>
> - check ("Hello\\t %hd%ld%lld%zd", /* ARI: %ll */
> + check ("Hello\\t %hd%ld%lld%zd%td", /* ARI: %ll */
> {
> {"Hello\t ", literal_piece, 0},
> {"%hd", int_arg, 0},
> {"%ld", long_arg, 0},
> {"%" LL "d", long_long_arg, 0},
> {"%zd", size_t_arg, 0},
> + {"%td", ptrdiff_t_arg, 0},
> });
> }
>
> diff --git a/gdbserver/ax.cc b/gdbserver/ax.cc
> index 44fcf3157291..4993bed2532c 100644
> --- a/gdbserver/ax.cc
> +++ b/gdbserver/ax.cc
> @@ -908,6 +908,14 @@ ax_printf (CORE_ADDR fn, CORE_ADDR chan, const char *format,
> break;
> }
>
> + case ptrdiff_t_arg:
> + {
> + ptrdiff_t val = args[i];
> +
> + printf (current_substring, val);
> + break;
> + }
> +
> case literal_piece:
> /* Print a portion of the format string that has no
> directives. Note that this will not include any
> diff --git a/gdbsupport/format.cc b/gdbsupport/format.cc
> index b515a95114e0..43995edf453e 100644
> --- a/gdbsupport/format.cc
> +++ b/gdbsupport/format.cc
> @@ -111,6 +111,7 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions,
> int seen_big_l = 0, seen_h = 0, seen_big_h = 0;
> int seen_big_d = 0, seen_double_big_d = 0;
> int seen_size_t = 0;
> + int seen_ptrdiff_t = 0;
> int bad = 0;
> int n_int_args = 0;
> bool seen_i64 = false;
> @@ -224,6 +225,11 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions,
> seen_size_t = 1;
> f++;
> break;
> + case 't':
> + /* For ptrdiff_t. */
> + seen_ptrdiff_t = 1;
> + f++;
> + break;
> case 'I':
> /* Support the Windows '%I64' extension, because an
> earlier call to format_pieces might have converted %lld
> @@ -257,6 +263,8 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions,
> case 'i':
> if (seen_size_t)
> this_argclass = size_t_arg;
> + else if (seen_ptrdiff_t)
> + this_argclass = ptrdiff_t_arg;
> else if (lcount == 0)
> this_argclass = int_arg;
> else if (lcount == 1)
> @@ -334,7 +342,8 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions,
>
> if (lcount > 1 || seen_h || seen_big_h || seen_big_h
> || seen_big_d || seen_double_big_d || seen_size_t
> - || seen_prec || seen_zero || seen_space || seen_plus)
> + || seen_ptrdiff_t || seen_prec || seen_zero || seen_space
> + || seen_plus)
> bad = 1;
>
> this_argclass = value_arg;
> diff --git a/gdbsupport/format.h b/gdbsupport/format.h
> index 91bcf1db55a6..ced10e46a716 100644
> --- a/gdbsupport/format.h
> +++ b/gdbsupport/format.h
> @@ -36,7 +36,7 @@
> enum argclass
> {
> literal_piece,
> - int_arg, long_arg, long_long_arg, size_t_arg, ptr_arg,
> + int_arg, long_arg, long_long_arg, size_t_arg, ptrdiff_t_arg, ptr_arg,
> string_arg, wide_string_arg, wide_char_arg,
> double_arg, long_double_arg,
> dec32float_arg, dec64float_arg, dec128float_arg,
>
> base-commit: b9517052ce5c1d87bfd7030bcbf90a98f63fddf6
--
Cheers,
Guinevere Larsen
It/she
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] gdb, gdbsupport, gdbserver: add support for printf 't' length modifier
2026-01-19 17:29 ` Guinevere Larsen
@ 2026-01-19 18:09 ` Simon Marchi
2026-01-20 12:29 ` Guinevere Larsen
0 siblings, 1 reply; 7+ messages in thread
From: Simon Marchi @ 2026-01-19 18:09 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches
On 1/19/26 12:29 PM, Guinevere Larsen wrote:
> On 1/12/26 3:24 PM, simon.marchi@polymtl.ca wrote:
>> From: Simon Marchi <simon.marchi@polymtl.ca>
>>
>> Tom de Vries reported [1] that a use of the `t` printf length modifier
>> (used for ptrdiff_t) breaks "set debug dwarf-die 1":
>>
>> +break -qualified main
>> Reading Reading compcomp unit at offset unit at offset 0x00x39
>>
>> Reading comp unit at offset 0x1a8
>> Reading comp unit at offset 0x1e9
>> Reading comp unit at offset 0x2c5
>> Reading comp unit at offset 0x2a2
>> Reading comp unit at offset 0x904
>> Unrecognized format specifier 't' in printf
>>
>> This use is in dwarf2/read.c:
>>
>> gdb_printf (gdb_stdlog, "Read die from %s@0x%tx of %s:\n",
>> m_die_section->get_name (),
>> (begin_info_ptr - m_die_section->buffer),
>> bfd_get_filename (m_abfd));
>>
>> Add support for the `t` length modifier in format_pieces, which
>> gdb_printf ultimately uses (through ui_out::vmessage). Modify the three
>> users of format_pieces: gdb's printf command, gdb's ui_out::vmessage
>> function and gdbserver's ax_printf function.
>>
>> The implementation is mostly copied from what we do for size_t.
>>
>> Since format_pieces is also used to implement the printf command, this
>> patch brings user-visible changes. Before:
>>
>> (gdb) printf "%td\n", -123
>> ❌️ Unrecognized format specifier 't' in printf
>>
>> After:
>>
>> (gdb) printf "%td\n", -123
>> -123
>>
>> [1] https://inbox.sourceware.org/gdb-patches/d4ccce34-aad5-4e3d-8fc9-efb2fc11275c@suse.de/
>>
>> Change-Id: Ie9fce78f5f48082d8f8a9ca2847b5ae26acaa60d
>> ---
>
> This commit seems to have caused a regression. After this, when starting GDB without the quiet flag I get the following:
>
> 0x7ffc6b9bc520s
> Copyright (C) 2026 Free Software Foundation, Inc.
> License GPLv3+: GNU GPL version 3 or later <0x7ffc6b9bc560s>
> This is free software: you are free to change and redistribute it
> There is NO WARRANTY, to the extent permitted by law.
> Type "0x7ffc6b9bc5e0s" and "0x7ffc6b9bc5a0s" for details.
> This GDB was configured as "x86_64-pc-linux-gnu".
> Type "0x7ffc6b9bc620s" for configuration details.
> For bug reporting instructions, please see:
> 0x7ffc6b9bc660s.
>
> That is, anywhere where GDB would print a styled string, we seem to be printing a pointer address instead.
Hmm, I don't see this. I see a pink "GNU gdb (GDB)
18.0.50.20260119-git" where you see the "0x7ffc6b9bc660s".
We will need to figure out what is different between our setups.
Simon
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] gdb, gdbsupport, gdbserver: add support for printf 't' length modifier
2026-01-19 18:09 ` Simon Marchi
@ 2026-01-20 12:29 ` Guinevere Larsen
0 siblings, 0 replies; 7+ messages in thread
From: Guinevere Larsen @ 2026-01-20 12:29 UTC (permalink / raw)
To: Simon Marchi, gdb-patches
On 1/19/26 3:09 PM, Simon Marchi wrote:
> On 1/19/26 12:29 PM, Guinevere Larsen wrote:
>> On 1/12/26 3:24 PM, simon.marchi@polymtl.ca wrote:
>>> From: Simon Marchi <simon.marchi@polymtl.ca>
>>>
>>> Tom de Vries reported [1] that a use of the `t` printf length modifier
>>> (used for ptrdiff_t) breaks "set debug dwarf-die 1":
>>>
>>> +break -qualified main
>>> Reading Reading compcomp unit at offset unit at offset 0x00x39
>>>
>>> Reading comp unit at offset 0x1a8
>>> Reading comp unit at offset 0x1e9
>>> Reading comp unit at offset 0x2c5
>>> Reading comp unit at offset 0x2a2
>>> Reading comp unit at offset 0x904
>>> Unrecognized format specifier 't' in printf
>>>
>>> This use is in dwarf2/read.c:
>>>
>>> gdb_printf (gdb_stdlog, "Read die from %s@0x%tx of %s:\n",
>>> m_die_section->get_name (),
>>> (begin_info_ptr - m_die_section->buffer),
>>> bfd_get_filename (m_abfd));
>>>
>>> Add support for the `t` length modifier in format_pieces, which
>>> gdb_printf ultimately uses (through ui_out::vmessage). Modify the three
>>> users of format_pieces: gdb's printf command, gdb's ui_out::vmessage
>>> function and gdbserver's ax_printf function.
>>>
>>> The implementation is mostly copied from what we do for size_t.
>>>
>>> Since format_pieces is also used to implement the printf command, this
>>> patch brings user-visible changes. Before:
>>>
>>> (gdb) printf "%td\n", -123
>>> ❌️ Unrecognized format specifier 't' in printf
>>>
>>> After:
>>>
>>> (gdb) printf "%td\n", -123
>>> -123
>>>
>>> [1] https://inbox.sourceware.org/gdb-patches/d4ccce34-aad5-4e3d-8fc9-efb2fc11275c@suse.de/
>>>
>>> Change-Id: Ie9fce78f5f48082d8f8a9ca2847b5ae26acaa60d
>>> ---
>> This commit seems to have caused a regression. After this, when starting GDB without the quiet flag I get the following:
>>
>> 0x7ffc6b9bc520s
>> Copyright (C) 2026 Free Software Foundation, Inc.
>> License GPLv3+: GNU GPL version 3 or later <0x7ffc6b9bc560s>
>> This is free software: you are free to change and redistribute it
>> There is NO WARRANTY, to the extent permitted by law.
>> Type "0x7ffc6b9bc5e0s" and "0x7ffc6b9bc5a0s" for details.
>> This GDB was configured as "x86_64-pc-linux-gnu".
>> Type "0x7ffc6b9bc620s" for configuration details.
>> For bug reporting instructions, please see:
>> 0x7ffc6b9bc660s.
>>
>> That is, anywhere where GDB would print a styled string, we seem to be printing a pointer address instead.
>
> Hmm, I don't see this. I see a pink "GNU gdb (GDB)
> 18.0.50.20260119-git" where you see the "0x7ffc6b9bc660s".
> We will need to figure out what is different between our setups.
>
> Simon
>
Oh, oops, turns out it was my bad.
I was running make on the gdb subdirectory instead of the build
directory and never compiled gdbsupport
Once I did that things magically started working again!
Sorry about the noise
--
Cheers,
Guinevere Larsen
It/she
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-01-20 12:30 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-12 18:24 [PATCH] gdb, gdbsupport, gdbserver: add support for printf 't' length modifier simon.marchi
2026-01-15 19:24 ` Tom Tromey
2026-01-15 19:36 ` Simon Marchi
2026-01-15 19:42 ` Tom Tromey
2026-01-19 17:29 ` Guinevere Larsen
2026-01-19 18:09 ` Simon Marchi
2026-01-20 12:29 ` Guinevere Larsen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox