Handle %I64d in format_pieces

We found a bug internally where gdb would crash while disassembling a
certain instruction.  This was tracked down to the handling of %I64d
in format_pieces.

format_pieces will convert %ll to %I64d on mingw -- so format_pieces
should also handle parsing this format.  In this patch, I've made the
parsing unconditional, since I think it is harmless to accept extra
formats.  I've also taken the opportunity to convert the length
modifier test to a "switch".

Tested internally using our failing test case.

gdb/ChangeLog
2019-11-21  Tom Tromey  <tromey@adacore.com>

	* gdbsupport/format.c (format_pieces): Parse %I64d.
	* unittests/format_pieces-selftests.c (test_windows_formats): New
	function.
	(run_tests): Call it.

Change-Id: If335c7c2fc8d01e629cd55182394a483334d79c7
This commit is contained in:
Tom Tromey 2019-11-14 15:00:19 -07:00
parent 34877895ca
commit 6ba1852136
3 changed files with 48 additions and 21 deletions

View File

@ -1,3 +1,10 @@
2019-11-21 Tom Tromey <tromey@adacore.com>
* gdbsupport/format.c (format_pieces): Parse %I64d.
* unittests/format_pieces-selftests.c (test_windows_formats): New
function.
(run_tests): Call it.
2019-11-21 Peeter Joot <peeter.joot@lzlabs.com>
Byte reverse display of variables with DW_END_big, DW_END_little

View File

@ -126,6 +126,7 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions)
int seen_size_t = 0;
int bad = 0;
int n_int_args = 0;
bool seen_i64 = false;
/* Skip over "%%", it will become part of a literal piece. */
if (*f == '%')
@ -195,13 +196,13 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions)
}
/* The next part of a format specifier is a length modifier. */
if (*f == 'h')
switch (*f)
{
case 'h':
seen_h = 1;
f++;
}
else if (*f == 'l')
{
break;
case 'l':
f++;
lcount++;
if (*f == 'l')
@ -209,21 +210,18 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions)
f++;
lcount++;
}
}
else if (*f == 'L')
{
break;
case 'L':
seen_big_l = 1;
f++;
}
/* Decimal32 modifier. */
else if (*f == 'H')
{
break;
case 'H':
/* Decimal32 modifier. */
seen_big_h = 1;
f++;
}
/* Decimal64 and Decimal128 modifiers. */
else if (*f == 'D')
{
break;
case 'D':
/* Decimal64 and Decimal128 modifiers. */
f++;
/* Check for a Decimal128. */
@ -234,13 +232,24 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions)
}
else
seen_big_d = 1;
}
/* For size_t or ssize_t. */
else if (*f == 'z')
{
break;
case 'z':
/* For size_t or ssize_t. */
seen_size_t = 1;
f++;
}
break;
case 'I':
/* Support the Windows '%I64' extension, because an
earlier call to format_pieces might have converted %lld
to %I64d. */
if (f[1] == '6' && f[2] == '4')
{
f += 3;
lcount = 2;
seen_i64 = true;
}
break;
}
switch (*f)
{
@ -353,7 +362,7 @@ format_pieces::format_pieces (const char **arg, bool gdb_extensions)
sub_start = current_substring;
if (lcount > 1 && USE_PRINTF_I64)
if (lcount > 1 && !seen_i64 && USE_PRINTF_I64)
{
/* Windows' printf does support long long, but not the usual way.
Convert %lld to %I64d. */

View File

@ -119,6 +119,16 @@ test_format_int_sizes ()
});
}
static void
test_windows_formats ()
{
check ("rc%I64d",
{
format_piece ("rc", literal_piece, 0),
format_piece ("%I64d", long_long_arg, 0),
});
}
static void
run_tests ()
{
@ -126,6 +136,7 @@ run_tests ()
test_format_specifier ();
test_gdb_formats ();
test_format_int_sizes ();
test_windows_formats ();
}
} /* namespace format_pieces */