Re: [pushed] gdb: Support printf 'z' size modifier

Andrew Burgess
2019-11-14T16:49:51Z

* Eli Zaretskii <eliz@gnu.org> [2019-11-14 14:54:50 +0200]:

> > Date: Tue, 12 Nov 2019 18:53:15 -0500
> > From: "Sourceware to Gerrit sync (Code Review)" <gerrit@gnutoolchain-gerrit.osci.io>
> > Cc: Kevin Buettner <kevinb@redhat.com>, Joel Brobecker <brobecker@adacore.com>, Pedro Alves <palves@redhat.com>, Simon Marchi <simon.marchi@polymtl.ca>, Tom Tromey <tromey@sourceware.org>
> >
> > gdb/ChangeLog:
> >
> > * gdbsupport/format.c (format_pieces::format_pieces): Support
> > printf 'z' size modifier.
> > * gdbsupport/format.h (enum argclass): Add size_t_arg.
> > * printcmd.c (ui_printf): Handle size_t_arg.
> > * ui-out.c (ui_out::vmessage): Likewise.
> > * unittests/format_pieces-selftests.c (test_format_int_sizes): New
> > function.
> > (run_tests): Call test_format_int_sizes.
>
> I believe this requires to use __USE_MINGW_ANSI_STDIO with the MinGW
> builds, since %z is not universally supported by the Windows runtime.

I only stumbled onto this issue as I hit a use of %z (which wasn't
guarded with __USE_MINGW_ANSI_STDIO) and wanted it to work now that
these strings pass through GDB's formatting code.

I guess we're no worse off now than we were before, but obviously
that's not saying much if we were possibly broken before.

I guess there are a couple of solutions:

1. Remove all uses of %z from GDB, and back out the %z support, or

2. Have GDB translate %z into some other suitable format specifier
for targets where %z is not supported.

Below is a patch that tries to take the second approach.

Feedback / thoughts welcome.

Thanks,
Andrew

----

commit fb431811b59597b63c5bb9bcf7bf8559991c52e1
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date: Thu Nov 14 16:40:57 2019 +0000

gdb: Support for %z format on MinGW

Eli pointed out that the %z size specifier is not supported on all
versions of MinGW. This commit attempts to work around this by
translating %z into some other suitable format specifier. So
something like %zd will become either %d, %ld, or %lld depending on
whether the sizeof (size_t) matches the sizeof (int), sizeof (long),
or sizeof (long long).

For the long long case we might also translate to %I64d if
USE_PRINTF_I64 is true.

I don't have access to MinGW so this code is mostly untested - I did
remove the '#if defined __MINGW32__ ....' check and try using %z in
some formatted prints, this all seemed to work fine - on my machine
sizeof (size_t) == sizeof (long).

gdb/ChangeLog:

* gdbsupport/format.c (format_pieces::format_pieces): Translate %z
into some other suitable format size specifier if it is not
supported.

Change-Id: I20f5e4cb1a7ab88f00f5e42d3fd8ca4aef00993d

diff --git a/gdb/gdbsupport/format.c b/gdb/gdbsupport/format.c
index 2e2d90a9246..e316e840e22 100644
--- a/gdb/gdbsupport/format.c
+++ b/gdb/gdbsupport/format.c
@@ -375,6 +375,40 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions)
strcpy (current_substring + length_before_ls, "s");
current_substring += length_before_ls + 2;
}
+#if defined __MINGW32__ && !defined __USE_MINGW_ANSI_STDIO
+ else if (this_argclass == size_t_arg)
+ {
+ /* Some versions of MinGW don't support the %z size format, so
+ lets change to use some appropriate alternative. */
+ *current_substring++ = '%';
+ if (sizeof (size_t) == sizeof (int))
+ {
+ *current_substring++ = *(percent_loc + 2);
+ this_argclass = int_arg;
+ }
+ else if (sizeof (size_t) == sizeof (long))
+ {
+ *current_substring++ = 'l';
+ *current_substring++ = *(percent_loc + 2);
+ this_argclass = long_arg;
+ }
+ else if (sizeof (size_t) == sizeof (long long))
+ {
+ if (USE_PRINTF_I64)
+ {
+ strcpy (current_substring, "I64");
+ current_substring += 3;
+ }
+ else
+ {
+ strcpy (current_substring, "ll");
+ current_substring += 2;
+ }
+ *current_substring++ = *(percent_loc + 2);
+ this_argclass = long_long_arg;
+ }
+ }
+#endif /* defined __MINGW32__ && !defined __USE_MINGW_ANSI_STDIO */
else
{
strncpy (current_substring, percent_loc, f - percent_loc);