diff options
author | Tom Tromey <tom@tromey.com> | 2024-03-27 10:43:57 -0600 |
---|---|---|
committer | Tom Tromey <tom@tromey.com> | 2024-06-20 10:45:05 -0600 |
commit | 6eb63917ce17236f0189e8d7ff4b60e24741770b (patch) | |
tree | 206081da38a1dac3e5166d55942ffa90061e2d15 /gdb | |
parent | 4429b54cc831e436d27ba6f0e3c417543c22f486 (diff) | |
download | fsf-binutils-gdb-6eb63917ce17236f0189e8d7ff4b60e24741770b.zip fsf-binutils-gdb-6eb63917ce17236f0189e8d7ff4b60e24741770b.tar.gz fsf-binutils-gdb-6eb63917ce17236f0189e8d7ff4b60e24741770b.tar.bz2 |
Handle "info symbol" in Rust language mode
When I changed the Rust parser to handle 128-bit ints, this
inadvertently broke some other gdb commands. For example, "info
symbol 0xffffffffffffffff" now fails, because the resulting value is
128 bits, but this is rejected by extract_integer.
This patch fixes the problem by changing extract_integer to allow
over-long integers as long as the high bytes are either 0, or (for
signed types) 0xff.
Regression tested on x86-64 Fedora 38.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31565
Approved-By: Andrew Burgess <aburgess@redhat.com>
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/extract-store-integer.c | 99 | ||||
-rw-r--r-- | gdb/extract-store-integer.h | 4 | ||||
-rw-r--r-- | gdb/testsuite/gdb.rust/simple.exp | 3 |
3 files changed, 102 insertions, 4 deletions
diff --git a/gdb/extract-store-integer.c b/gdb/extract-store-integer.c index b2892e4..644273c 100644 --- a/gdb/extract-store-integer.c +++ b/gdb/extract-store-integer.c @@ -26,9 +26,61 @@ extract_integer (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order { typename std::make_unsigned<T>::type retval = 0; + /* It is ok if BUF is wider than T, but only if the value is + representable. */ + bool bad_repr = false; if (buf.size () > (int) sizeof (T)) - error (_("\ -That operation is not available on integers of more than %d bytes."), + { + const size_t end = buf.size () - sizeof (T); + if (byte_order == BFD_ENDIAN_BIG) + { + for (size_t i = 0; i < end; ++i) + { + /* High bytes == 0 are always ok, and high bytes == 0xff + are ok when the type is signed. */ + if ((buf[i] == 0 + || (std::is_signed<T>::value && buf[i] == 0xff)) + /* All the high bytes must be the same, no + alternating 0 and 0xff. */ + && (i == 0 || buf[i - 1] == buf[i])) + { + /* Ok. */ + } + else + { + bad_repr = true; + break; + } + } + buf = buf.slice (end); + } + else + { + size_t bufsz = buf.size () - 1; + for (size_t i = bufsz; i >= end; --i) + { + /* High bytes == 0 are always ok, and high bytes == 0xff + are ok when the type is signed. */ + if ((buf[i] == 0 + || (std::is_signed<T>::value && buf[i] == 0xff)) + /* All the high bytes must be the same, no + alternating 0 and 0xff. */ + && (i == bufsz || buf[i] == buf[i + 1])) + { + /* Ok. */ + } + else + { + bad_repr = true; + break; + } + } + buf = buf.slice (0, end); + } + } + + if (bad_repr) + error (_("Value cannot be represented as integer of %d bytes."), (int) sizeof (T)); /* Start at the most significant end of the integer, and work towards @@ -240,6 +292,47 @@ copy_integer_to_size_test () do_cint_test (0xff2112345678, 0xffffff2112345678, 8, 0xffffff2112345678, 6); } +template<typename T> +void +do_extract_test (gdb_byte byte1, gdb_byte byte2, enum bfd_endian endian, + std::optional<T> expected) +{ + std::optional<T> result; + + try + { + const gdb_byte val[2] = { byte1, byte2 }; + result = extract_integer<T> (gdb::make_array_view (val, 2), endian); + } + catch (const gdb_exception_error &) + { + } + + SELF_CHECK (result == expected); +} + +template<typename T> +void +do_extract_tests (gdb_byte low, gdb_byte high, std::optional<T> expected) +{ + do_extract_test (low, high, BFD_ENDIAN_LITTLE, expected); + do_extract_test (high, low, BFD_ENDIAN_BIG, expected); +} + +static void +extract_integer_test () +{ + do_extract_tests<uint8_t> (0x00, 0xff, {}); + do_extract_tests<uint8_t> (0x7f, 0x23, {}); + do_extract_tests<uint8_t> (0x80, 0xff, {}); + do_extract_tests<uint8_t> (0x00, 0x00, 0x00); + + do_extract_tests<int8_t> (0xff, 0x00, 0xff); + do_extract_tests<int8_t> (0x7f, 0x23, {}); + do_extract_tests<int8_t> (0x80, 0xff, 0x80); + do_extract_tests<int8_t> (0x00, 0x00, 0x00); +} + } // namespace selftests #endif @@ -251,5 +344,7 @@ _initialize_extract_store_integer () #if GDB_SELF_TEST selftests::register_test ("copy_integer_to_size", selftests::copy_integer_to_size_test); + selftests::register_test ("extract_integer", + selftests::extract_integer_test); #endif } diff --git a/gdb/extract-store-integer.h b/gdb/extract-store-integer.h index b2c0f35..a51ef3d 100644 --- a/gdb/extract-store-integer.h +++ b/gdb/extract-store-integer.h @@ -18,9 +18,9 @@ #ifndef GDB_EXTRACT_STORE_INTEGER_H #define GDB_EXTRACT_STORE_INTEGER_H -#include "gdbsupport/traits.h" +#include <type_traits> -template<typename T, typename = RequireLongest<T>> +template<typename T, typename = std::is_integral<T>> T extract_integer (gdb::array_view<const gdb_byte>, enum bfd_endian byte_order); static inline LONGEST diff --git a/gdb/testsuite/gdb.rust/simple.exp b/gdb/testsuite/gdb.rust/simple.exp index 1e6fc94..37a2e07 100644 --- a/gdb/testsuite/gdb.rust/simple.exp +++ b/gdb/testsuite/gdb.rust/simple.exp @@ -421,3 +421,6 @@ gdb_test "print 4 - 3 - 1" " = 0" # Another operator precedence bug. gdb_test "print \$one = \$two = 75" " = \\\(\\\)" + +gdb_test "info symbol 0xffffffffffffffff" \ + "No symbol matches 0xffffffffffffffff." |