From: Tom Tromey Date: Thu, 14 Nov 2019 22:00:19 +0000 (-0700) Subject: Handle %I64d in format_pieces X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=6ba185213659517b4299a3e4c92813839f19f045;p=deliverable%2Fbinutils-gdb.git 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 * gdbsupport/format.c (format_pieces): Parse %I64d. * unittests/format_pieces-selftests.c (test_windows_formats): New function. (run_tests): Call it. Change-Id: If335c7c2fc8d01e629cd55182394a483334d79c7 --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0249048583..0c81de4a6b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2019-11-21 Tom Tromey + + * 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 Byte reverse display of variables with DW_END_big, DW_END_little diff --git a/gdb/gdbsupport/format.c b/gdb/gdbsupport/format.c index 2e2d90a924..67daa6d6df 100644 --- a/gdb/gdbsupport/format.c +++ b/gdb/gdbsupport/format.c @@ -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. */ diff --git a/gdb/unittests/format_pieces-selftests.c b/gdb/unittests/format_pieces-selftests.c index 3971201478..d7e97d4069 100644 --- a/gdb/unittests/format_pieces-selftests.c +++ b/gdb/unittests/format_pieces-selftests.c @@ -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 */