[Lldb-commits] [lldb] 88fbd8f - [lldb/Reproducers] Decode run-length encoding in GDB replay server.
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Mon Mar 16 08:47:45 PDT 2020
Author: Jonas Devlieghere
Date: 2020-03-16T08:47:39-07:00
New Revision: 88fbd8f9e79096da4d013f826fc8b4f0eea1ef66
URL: https://github.com/llvm/llvm-project/commit/88fbd8f9e79096da4d013f826fc8b4f0eea1ef66
DIFF: https://github.com/llvm/llvm-project/commit/88fbd8f9e79096da4d013f826fc8b4f0eea1ef66.diff
LOG: [lldb/Reproducers] Decode run-length encoding in GDB replay server.
The GDB replay server sanity-checks that every packet it receives
matches what it expects from the serialized packet log. This mechanism
tripped for TestReproducerAttach.py on Linux, because one of the packets
(jModulesInfo) uses run-length encoding. The replay server was comparing
the expanded incoming packet with the unexpanded packet in the log. As a
result, it claimed to have received an unexpected packet, which caused
the test to fail.
This patch addresses that issue by expanding the run-length encoding
before comparing the packets.
Differential revision: https://reviews.llvm.org/D76163
Added:
Modified:
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp
lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py
Removed:
################################################################################
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 1ed3e693d8d2..73bd9fb0bed8 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -810,31 +810,9 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len,
GDBRemotePacket::ePacketTypeRecv, total_length);
// Copy the packet from m_bytes to packet_str expanding the run-length
- // encoding in the process. Reserve enough byte for the most common case
- // (no RLE used)
- std ::string packet_str;
- packet_str.reserve(m_bytes.length());
- for (std::string::const_iterator c = m_bytes.begin() + content_start;
- c != m_bytes.begin() + content_end; ++c) {
- if (*c == '*') {
- // '*' indicates RLE. Next character will give us the repeat count
- // and previous character is what is to be repeated.
- char char_to_repeat = packet_str.back();
- // Number of time the previous character is repeated
- int repeat_count = *++c + 3 - ' ';
- // We have the char_to_repeat and repeat_count. Now push it in the
- // packet.
- for (int i = 0; i < repeat_count; ++i)
- packet_str.push_back(char_to_repeat);
- } else if (*c == 0x7d) {
- // 0x7d is the escape character. The next character is to be XOR'd
- // with 0x20.
- char escapee = *++c ^ 0x20;
- packet_str.push_back(escapee);
- } else {
- packet_str.push_back(*c);
- }
- }
+ // encoding in the process.
+ std ::string packet_str =
+ ExpandRLE(m_bytes.substr(content_start, content_end - content_start));
packet = StringExtractorGDBRemote(packet_str);
if (m_bytes[0] == '$' || m_bytes[0] == '%') {
@@ -1382,3 +1360,30 @@ void llvm::format_provider<GDBRemoteCommunication::PacketResult>::format(
break;
}
}
+
+std::string GDBRemoteCommunication::ExpandRLE(std::string packet) {
+ // Reserve enough byte for the most common case (no RLE used).
+ std::string decoded;
+ decoded.reserve(packet.size());
+ for (std::string::const_iterator c = packet.begin(); c != packet.end(); ++c) {
+ if (*c == '*') {
+ // '*' indicates RLE. Next character will give us the repeat count and
+ // previous character is what is to be repeated.
+ char char_to_repeat = decoded.back();
+ // Number of time the previous character is repeated.
+ int repeat_count = *++c + 3 - ' ';
+ // We have the char_to_repeat and repeat_count. Now push it in the
+ // packet.
+ for (int i = 0; i < repeat_count; ++i)
+ decoded.push_back(char_to_repeat);
+ } else if (*c == 0x7d) {
+ // 0x7d is the escape character. The next character is to be XOR'd with
+ // 0x20.
+ char escapee = *++c ^ 0x20;
+ decoded.push_back(escapee);
+ } else {
+ decoded.push_back(*c);
+ }
+ }
+ return decoded;
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
index 7c0ef197f89b..4cc466667c82 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -142,6 +142,9 @@ class GDBRemoteCommunication : public Communication {
static llvm::Error ConnectLocally(GDBRemoteCommunication &client,
GDBRemoteCommunication &server);
+ /// Expand GDB run-length encoding.
+ static std::string ExpandRLE(std::string);
+
protected:
std::chrono::seconds m_packet_timeout;
uint32_t m_echo_number;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp
index 8c6efe9ee9e2..910dcf2cf589 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp
@@ -131,22 +131,26 @@ GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse(
GDBRemotePacket entry = m_packet_history.back();
m_packet_history.pop_back();
+ // Decode run-length encoding.
+ const std::string expanded_data =
+ GDBRemoteCommunication::ExpandRLE(entry.packet.data);
+
// We've handled the handshake implicitly before. Skip the packet and move
// on.
if (entry.packet.data == "+")
continue;
if (entry.type == GDBRemotePacket::ePacketTypeSend) {
- if (unexpected(entry.packet.data, packet.GetStringRef())) {
+ if (unexpected(expanded_data, packet.GetStringRef())) {
LLDB_LOG(log,
"GDBRemoteCommunicationReplayServer expected packet: '{0}'",
- entry.packet.data);
+ expanded_data);
LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'",
packet.GetStringRef());
#ifndef NDEBUG
// This behaves like a regular assert, but prints the expected and
// received packet before aborting.
- printf("Reproducer expected packet: '%s'\n", entry.packet.data.c_str());
+ printf("Reproducer expected packet: '%s'\n", expanded_data.c_str());
printf("Reproducer received packet: '%s'\n",
packet.GetStringRef().data());
llvm::report_fatal_error("Encountered unexpected packet during replay");
@@ -155,7 +159,7 @@ GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse(
}
// Ignore QEnvironment packets as they're handled earlier.
- if (entry.packet.data.find("QEnvironment") == 1) {
+ if (expanded_data.find("QEnvironment") == 1) {
assert(m_packet_history.back().type ==
GDBRemotePacket::ePacketTypeRecv);
m_packet_history.pop_back();
diff --git a/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py
index e9a570b50976..968268d6838b 100644
--- a/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py
+++ b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py
@@ -15,7 +15,6 @@ class ReproducerAttachTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
NO_DEBUG_INFO_TESTCASE = True
- @skipIfLinux # Reproducer received unexpected packet.
@skipIfFreeBSD
@skipIfNetBSD
@skipIfWindows
More information about the lldb-commits
mailing list