From 555cd03193c9c098d787bec93eadfe43b179db9c Mon Sep 17 00:00:00 2001 From: David Spickett Date: Fri, 25 Jun 2021 14:29:12 +0100 Subject: [lldb] Correct format of qMemTags type field The type field is a signed integer. (https://sourceware.org/gdb/current/onlinedocs/gdb/General-Query-Packets.html) However it's not packed in the packet in the way you might think. For example the type -1 should be: qMemTags:,:ffffffff Instead of: qMemTags:,:-1 This change makes lldb-server's parsing more strict and adds more tests to check that we handle negative types correctly in lldb and lldb-server. We only support one tag type value at this point, for AArch64 MTE, which is positive. So this doesn't change any of those interactions. It just brings us in line with GDB. Also check that the test target has MTE. Previously we just checked that we were AArch64 with a toolchain that supports MTE. Finally, update the tag type check for QMemTags to use the same conversion steps that qMemTags now does. Using static_cast can invoke UB and though we do do a limit check to avoid this, I think it's clearer with the new method. Reviewed By: omjavaid Differential Revision: https://reviews.llvm.org/D104914 --- .../GDBRemoteCommunicationServerLLGS.cpp | 28 ++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp') diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 5e69b57..8e1f6bc 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -3474,15 +3474,31 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemTags( if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':') return SendIllFormedResponse(packet, invalid_type_err); - int32_t type = - packet.GetS32(std::numeric_limits::max(), /*base=*/16); - if (type == std::numeric_limits::max() || + // Type is a signed integer but packed into the packet as its raw bytes. + // However, our GetU64 uses strtoull which allows +/-. We do not want this. + const char *first_type_char = packet.Peek(); + if (first_type_char && (*first_type_char == '+' || *first_type_char == '-')) + return SendIllFormedResponse(packet, invalid_type_err); + + // Extract type as unsigned then cast to signed. + // Using a uint64_t here so that we have some value outside of the 32 bit + // range to use as the invalid return value. + uint64_t raw_type = + packet.GetU64(std::numeric_limits::max(), /*base=*/16); + + if ( // Make sure the cast below would be valid + raw_type > std::numeric_limits::max() || // To catch inputs like "123aardvark" that will parse but clearly aren't // valid in this case. packet.GetBytesLeft()) { return SendIllFormedResponse(packet, invalid_type_err); } + // First narrow to 32 bits otherwise the copy into type would take + // the wrong 4 bytes on big endian. + uint32_t raw_type_32 = raw_type; + int32_t type = reinterpret_cast(raw_type_32); + StreamGDBRemote response; std::vector tags; Status error = m_current_process->ReadMemoryTags(type, addr, length, tags); @@ -3552,7 +3568,11 @@ GDBRemoteCommunicationServerLLGS::Handle_QMemTags( packet.GetU64(std::numeric_limits::max(), /*base=*/16); if (raw_type > std::numeric_limits::max()) return SendIllFormedResponse(packet, invalid_type_err); - int32_t type = static_cast(raw_type); + + // First narrow to 32 bits. Otherwise the copy below would get the wrong + // 4 bytes on big endian. + uint32_t raw_type_32 = raw_type; + int32_t type = reinterpret_cast(raw_type_32); // Tag data if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':') -- cgit v1.1