xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===-- GDBRemoteCommunication.cpp ----------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "GDBRemoteCommunication.h"
100b57cec5SDimitry Andric 
11fe6060f1SDimitry Andric #include <climits>
12fe6060f1SDimitry Andric #include <cstring>
130b57cec5SDimitry Andric #include <future>
140b57cec5SDimitry Andric #include <sys/stat.h>
150b57cec5SDimitry Andric 
169dba64beSDimitry Andric #include "lldb/Host/Config.h"
170b57cec5SDimitry Andric #include "lldb/Host/ConnectionFileDescriptor.h"
180b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
190b57cec5SDimitry Andric #include "lldb/Host/Host.h"
200b57cec5SDimitry Andric #include "lldb/Host/HostInfo.h"
210b57cec5SDimitry Andric #include "lldb/Host/Pipe.h"
220b57cec5SDimitry Andric #include "lldb/Host/ProcessLaunchInfo.h"
230b57cec5SDimitry Andric #include "lldb/Host/Socket.h"
240b57cec5SDimitry Andric #include "lldb/Host/ThreadLauncher.h"
250b57cec5SDimitry Andric #include "lldb/Host/common/TCPSocket.h"
260b57cec5SDimitry Andric #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
270b57cec5SDimitry Andric #include "lldb/Target/Platform.h"
280b57cec5SDimitry Andric #include "lldb/Utility/Event.h"
290b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.h"
300b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
310b57cec5SDimitry Andric #include "lldb/Utility/RegularExpression.h"
320b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
330b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
340b57cec5SDimitry Andric #include "llvm/Support/ScopedPrinter.h"
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric #include "ProcessGDBRemoteLog.h"
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric #if defined(__APPLE__)
390b57cec5SDimitry Andric #define DEBUGSERVER_BASENAME "debugserver"
409dba64beSDimitry Andric #elif defined(_WIN32)
419dba64beSDimitry Andric #define DEBUGSERVER_BASENAME "lldb-server.exe"
420b57cec5SDimitry Andric #else
430b57cec5SDimitry Andric #define DEBUGSERVER_BASENAME "lldb-server"
440b57cec5SDimitry Andric #endif
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric #if defined(HAVE_LIBCOMPRESSION)
470b57cec5SDimitry Andric #include <compression.h>
480b57cec5SDimitry Andric #endif
490b57cec5SDimitry Andric 
50e8d8bef9SDimitry Andric #if LLVM_ENABLE_ZLIB
510b57cec5SDimitry Andric #include <zlib.h>
520b57cec5SDimitry Andric #endif
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric using namespace lldb;
550b57cec5SDimitry Andric using namespace lldb_private;
560b57cec5SDimitry Andric using namespace lldb_private::process_gdb_remote;
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric // GDBRemoteCommunication constructor
59bdd1243dSDimitry Andric GDBRemoteCommunication::GDBRemoteCommunication()
60bdd1243dSDimitry Andric     : Communication(),
610b57cec5SDimitry Andric #ifdef LLDB_CONFIGURATION_DEBUG
620b57cec5SDimitry Andric       m_packet_timeout(1000),
630b57cec5SDimitry Andric #else
640b57cec5SDimitry Andric       m_packet_timeout(1),
650b57cec5SDimitry Andric #endif
660b57cec5SDimitry Andric       m_echo_number(0), m_supports_qEcho(eLazyBoolCalculate), m_history(512),
67fcaf7f86SDimitry Andric       m_send_acks(true), m_is_platform(false),
68fcaf7f86SDimitry Andric       m_compression_type(CompressionType::None), m_listen_url() {
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric // Destructor
720b57cec5SDimitry Andric GDBRemoteCommunication::~GDBRemoteCommunication() {
730b57cec5SDimitry Andric   if (IsConnected()) {
740b57cec5SDimitry Andric     Disconnect();
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric #if defined(HAVE_LIBCOMPRESSION)
780b57cec5SDimitry Andric   if (m_decompression_scratch)
790b57cec5SDimitry Andric     free (m_decompression_scratch);
800b57cec5SDimitry Andric #endif
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric char GDBRemoteCommunication::CalculcateChecksum(llvm::StringRef payload) {
840b57cec5SDimitry Andric   int checksum = 0;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   for (char c : payload)
870b57cec5SDimitry Andric     checksum += c;
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   return checksum & 255;
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric size_t GDBRemoteCommunication::SendAck() {
931fd87a68SDimitry Andric   Log *log = GetLog(GDBRLog::Packets);
940b57cec5SDimitry Andric   ConnectionStatus status = eConnectionStatusSuccess;
950b57cec5SDimitry Andric   char ch = '+';
96349cc55cSDimitry Andric   const size_t bytes_written = WriteAll(&ch, 1, status, nullptr);
979dba64beSDimitry Andric   LLDB_LOGF(log, "<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch);
989dba64beSDimitry Andric   m_history.AddPacket(ch, GDBRemotePacket::ePacketTypeSend, bytes_written);
990b57cec5SDimitry Andric   return bytes_written;
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric size_t GDBRemoteCommunication::SendNack() {
1031fd87a68SDimitry Andric   Log *log = GetLog(GDBRLog::Packets);
1040b57cec5SDimitry Andric   ConnectionStatus status = eConnectionStatusSuccess;
1050b57cec5SDimitry Andric   char ch = '-';
106349cc55cSDimitry Andric   const size_t bytes_written = WriteAll(&ch, 1, status, nullptr);
1079dba64beSDimitry Andric   LLDB_LOGF(log, "<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch);
1089dba64beSDimitry Andric   m_history.AddPacket(ch, GDBRemotePacket::ePacketTypeSend, bytes_written);
1090b57cec5SDimitry Andric   return bytes_written;
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
1130b57cec5SDimitry Andric GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) {
1140b57cec5SDimitry Andric   StreamString packet(0, 4, eByteOrderBig);
1150b57cec5SDimitry Andric   packet.PutChar('$');
1160b57cec5SDimitry Andric   packet.Write(payload.data(), payload.size());
1170b57cec5SDimitry Andric   packet.PutChar('#');
1180b57cec5SDimitry Andric   packet.PutHex8(CalculcateChecksum(payload));
1195ffd83dbSDimitry Andric   std::string packet_str = std::string(packet.GetString());
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   return SendRawPacketNoLock(packet_str);
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
12581ad6265SDimitry Andric GDBRemoteCommunication::SendNotificationPacketNoLock(
12681ad6265SDimitry Andric     llvm::StringRef notify_type, std::deque<std::string> &queue,
12781ad6265SDimitry Andric     llvm::StringRef payload) {
12881ad6265SDimitry Andric   PacketResult ret = PacketResult::Success;
12981ad6265SDimitry Andric 
13081ad6265SDimitry Andric   // If there are no notification in the queue, send the notification
13181ad6265SDimitry Andric   // packet.
13281ad6265SDimitry Andric   if (queue.empty()) {
13381ad6265SDimitry Andric     StreamString packet(0, 4, eByteOrderBig);
13481ad6265SDimitry Andric     packet.PutChar('%');
13581ad6265SDimitry Andric     packet.Write(notify_type.data(), notify_type.size());
13681ad6265SDimitry Andric     packet.PutChar(':');
13781ad6265SDimitry Andric     packet.Write(payload.data(), payload.size());
13881ad6265SDimitry Andric     packet.PutChar('#');
13981ad6265SDimitry Andric     packet.PutHex8(CalculcateChecksum(payload));
14081ad6265SDimitry Andric     ret = SendRawPacketNoLock(packet.GetString(), true);
14181ad6265SDimitry Andric   }
14281ad6265SDimitry Andric 
14381ad6265SDimitry Andric   queue.push_back(payload.str());
14481ad6265SDimitry Andric   return ret;
14581ad6265SDimitry Andric }
14681ad6265SDimitry Andric 
14781ad6265SDimitry Andric GDBRemoteCommunication::PacketResult
1480b57cec5SDimitry Andric GDBRemoteCommunication::SendRawPacketNoLock(llvm::StringRef packet,
1490b57cec5SDimitry Andric                                             bool skip_ack) {
1500b57cec5SDimitry Andric   if (IsConnected()) {
1511fd87a68SDimitry Andric     Log *log = GetLog(GDBRLog::Packets);
1520b57cec5SDimitry Andric     ConnectionStatus status = eConnectionStatusSuccess;
1530b57cec5SDimitry Andric     const char *packet_data = packet.data();
1540b57cec5SDimitry Andric     const size_t packet_length = packet.size();
155349cc55cSDimitry Andric     size_t bytes_written = WriteAll(packet_data, packet_length, status, nullptr);
1560b57cec5SDimitry Andric     if (log) {
1570b57cec5SDimitry Andric       size_t binary_start_offset = 0;
1580b57cec5SDimitry Andric       if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) ==
1590b57cec5SDimitry Andric           0) {
1600b57cec5SDimitry Andric         const char *first_comma = strchr(packet_data, ',');
1610b57cec5SDimitry Andric         if (first_comma) {
1620b57cec5SDimitry Andric           const char *second_comma = strchr(first_comma + 1, ',');
1630b57cec5SDimitry Andric           if (second_comma)
1640b57cec5SDimitry Andric             binary_start_offset = second_comma - packet_data + 1;
1650b57cec5SDimitry Andric         }
1660b57cec5SDimitry Andric       }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric       // If logging was just enabled and we have history, then dump out what we
1690b57cec5SDimitry Andric       // have to the log so we get the historical context. The Dump() call that
1700b57cec5SDimitry Andric       // logs all of the packet will set a boolean so that we don't dump this
1710b57cec5SDimitry Andric       // more than once
1720b57cec5SDimitry Andric       if (!m_history.DidDumpToLog())
1730b57cec5SDimitry Andric         m_history.Dump(log);
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric       if (binary_start_offset) {
1760b57cec5SDimitry Andric         StreamString strm;
1770b57cec5SDimitry Andric         // Print non binary data header
1780b57cec5SDimitry Andric         strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written,
1790b57cec5SDimitry Andric                     (int)binary_start_offset, packet_data);
1800b57cec5SDimitry Andric         const uint8_t *p;
1810b57cec5SDimitry Andric         // Print binary data exactly as sent
1820b57cec5SDimitry Andric         for (p = (const uint8_t *)packet_data + binary_start_offset; *p != '#';
1830b57cec5SDimitry Andric              ++p)
1840b57cec5SDimitry Andric           strm.Printf("\\x%2.2x", *p);
1850b57cec5SDimitry Andric         // Print the checksum
1860b57cec5SDimitry Andric         strm.Printf("%*s", (int)3, p);
1870b57cec5SDimitry Andric         log->PutString(strm.GetString());
1880b57cec5SDimitry Andric       } else
1899dba64beSDimitry Andric         LLDB_LOGF(log, "<%4" PRIu64 "> send packet: %.*s",
1909dba64beSDimitry Andric                   (uint64_t)bytes_written, (int)packet_length, packet_data);
1910b57cec5SDimitry Andric     }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric     m_history.AddPacket(packet.str(), packet_length,
1949dba64beSDimitry Andric                         GDBRemotePacket::ePacketTypeSend, bytes_written);
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric     if (bytes_written == packet_length) {
1970b57cec5SDimitry Andric       if (!skip_ack && GetSendAcks())
1980b57cec5SDimitry Andric         return GetAck();
1990b57cec5SDimitry Andric       else
2000b57cec5SDimitry Andric         return PacketResult::Success;
2010b57cec5SDimitry Andric     } else {
2029dba64beSDimitry Andric       LLDB_LOGF(log, "error: failed to send packet: %.*s", (int)packet_length,
2030b57cec5SDimitry Andric                 packet_data);
2040b57cec5SDimitry Andric     }
2050b57cec5SDimitry Andric   }
2060b57cec5SDimitry Andric   return PacketResult::ErrorSendFailed;
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult GDBRemoteCommunication::GetAck() {
2100b57cec5SDimitry Andric   StringExtractorGDBRemote packet;
2114824e7fdSDimitry Andric   PacketResult result = WaitForPacketNoLock(packet, GetPacketTimeout(), false);
2120b57cec5SDimitry Andric   if (result == PacketResult::Success) {
2130b57cec5SDimitry Andric     if (packet.GetResponseType() ==
2140b57cec5SDimitry Andric         StringExtractorGDBRemote::ResponseType::eAck)
2150b57cec5SDimitry Andric       return PacketResult::Success;
2160b57cec5SDimitry Andric     else
2170b57cec5SDimitry Andric       return PacketResult::ErrorSendAck;
2180b57cec5SDimitry Andric   }
2190b57cec5SDimitry Andric   return result;
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
2230b57cec5SDimitry Andric GDBRemoteCommunication::ReadPacket(StringExtractorGDBRemote &response,
2240b57cec5SDimitry Andric                                    Timeout<std::micro> timeout,
2250b57cec5SDimitry Andric                                    bool sync_on_timeout) {
2264824e7fdSDimitry Andric   using ResponseType = StringExtractorGDBRemote::ResponseType;
2274824e7fdSDimitry Andric 
2281fd87a68SDimitry Andric   Log *log = GetLog(GDBRLog::Packets);
2294824e7fdSDimitry Andric   for (;;) {
2304824e7fdSDimitry Andric     PacketResult result =
2314824e7fdSDimitry Andric         WaitForPacketNoLock(response, timeout, sync_on_timeout);
2324824e7fdSDimitry Andric     if (result != PacketResult::Success ||
2334824e7fdSDimitry Andric         (response.GetResponseType() != ResponseType::eAck &&
2344824e7fdSDimitry Andric          response.GetResponseType() != ResponseType::eNack))
2354824e7fdSDimitry Andric       return result;
2364824e7fdSDimitry Andric     LLDB_LOG(log, "discarding spurious `{0}` packet", response.GetStringRef());
2370b57cec5SDimitry Andric   }
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
2410b57cec5SDimitry Andric GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet,
2420b57cec5SDimitry Andric                                             Timeout<std::micro> timeout,
2430b57cec5SDimitry Andric                                             bool sync_on_timeout) {
2440b57cec5SDimitry Andric   uint8_t buffer[8192];
2450b57cec5SDimitry Andric   Status error;
2460b57cec5SDimitry Andric 
2471fd87a68SDimitry Andric   Log *log = GetLog(GDBRLog::Packets);
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric   // Check for a packet from our cache first without trying any reading...
2500b57cec5SDimitry Andric   if (CheckForPacket(nullptr, 0, packet) != PacketType::Invalid)
2510b57cec5SDimitry Andric     return PacketResult::Success;
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric   bool timed_out = false;
2540b57cec5SDimitry Andric   bool disconnected = false;
2550b57cec5SDimitry Andric   while (IsConnected() && !timed_out) {
2560b57cec5SDimitry Andric     lldb::ConnectionStatus status = eConnectionStatusNoConnection;
2570b57cec5SDimitry Andric     size_t bytes_read = Read(buffer, sizeof(buffer), timeout, status, &error);
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric     LLDB_LOGV(log,
2600b57cec5SDimitry Andric               "Read(buffer, sizeof(buffer), timeout = {0}, "
2610b57cec5SDimitry Andric               "status = {1}, error = {2}) => bytes_read = {3}",
262e8d8bef9SDimitry Andric               timeout, Communication::ConnectionStatusAsString(status), error,
2630b57cec5SDimitry Andric               bytes_read);
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric     if (bytes_read > 0) {
2660b57cec5SDimitry Andric       if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid)
2670b57cec5SDimitry Andric         return PacketResult::Success;
2680b57cec5SDimitry Andric     } else {
2690b57cec5SDimitry Andric       switch (status) {
2700b57cec5SDimitry Andric       case eConnectionStatusTimedOut:
2710b57cec5SDimitry Andric       case eConnectionStatusInterrupted:
2720b57cec5SDimitry Andric         if (sync_on_timeout) {
2730b57cec5SDimitry Andric           /// Sync the remote GDB server and make sure we get a response that
2740b57cec5SDimitry Andric           /// corresponds to what we send.
2750b57cec5SDimitry Andric           ///
2760b57cec5SDimitry Andric           /// Sends a "qEcho" packet and makes sure it gets the exact packet
2770b57cec5SDimitry Andric           /// echoed back. If the qEcho packet isn't supported, we send a qC
2780b57cec5SDimitry Andric           /// packet and make sure we get a valid thread ID back. We use the
2790b57cec5SDimitry Andric           /// "qC" packet since its response if very unique: is responds with
2800b57cec5SDimitry Andric           /// "QC%x" where %x is the thread ID of the current thread. This
2810b57cec5SDimitry Andric           /// makes the response unique enough from other packet responses to
2820b57cec5SDimitry Andric           /// ensure we are back on track.
2830b57cec5SDimitry Andric           ///
2840b57cec5SDimitry Andric           /// This packet is needed after we time out sending a packet so we
2850b57cec5SDimitry Andric           /// can ensure that we are getting the response for the packet we
2860b57cec5SDimitry Andric           /// are sending. There are no sequence IDs in the GDB remote
2870b57cec5SDimitry Andric           /// protocol (there used to be, but they are not supported anymore)
2880b57cec5SDimitry Andric           /// so if you timeout sending packet "abc", you might then send
2890b57cec5SDimitry Andric           /// packet "cde" and get the response for the previous "abc" packet.
2900b57cec5SDimitry Andric           /// Many responses are "OK" or "" (unsupported) or "EXX" (error) so
2910b57cec5SDimitry Andric           /// many responses for packets can look like responses for other
2920b57cec5SDimitry Andric           /// packets. So if we timeout, we need to ensure that we can get
2930b57cec5SDimitry Andric           /// back on track. If we can't get back on track, we must
2940b57cec5SDimitry Andric           /// disconnect.
2950b57cec5SDimitry Andric           bool sync_success = false;
2960b57cec5SDimitry Andric           bool got_actual_response = false;
2970b57cec5SDimitry Andric           // We timed out, we need to sync back up with the
2980b57cec5SDimitry Andric           char echo_packet[32];
2990b57cec5SDimitry Andric           int echo_packet_len = 0;
3000b57cec5SDimitry Andric           RegularExpression response_regex;
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric           if (m_supports_qEcho == eLazyBoolYes) {
3030b57cec5SDimitry Andric             echo_packet_len = ::snprintf(echo_packet, sizeof(echo_packet),
3040b57cec5SDimitry Andric                                          "qEcho:%u", ++m_echo_number);
3050b57cec5SDimitry Andric             std::string regex_str = "^";
3060b57cec5SDimitry Andric             regex_str += echo_packet;
3070b57cec5SDimitry Andric             regex_str += "$";
3089dba64beSDimitry Andric             response_regex = RegularExpression(regex_str);
3090b57cec5SDimitry Andric           } else {
3100b57cec5SDimitry Andric             echo_packet_len =
3110b57cec5SDimitry Andric                 ::snprintf(echo_packet, sizeof(echo_packet), "qC");
3129dba64beSDimitry Andric             response_regex =
3139dba64beSDimitry Andric                 RegularExpression(llvm::StringRef("^QC[0-9A-Fa-f]+$"));
3140b57cec5SDimitry Andric           }
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric           PacketResult echo_packet_result =
3170b57cec5SDimitry Andric               SendPacketNoLock(llvm::StringRef(echo_packet, echo_packet_len));
3180b57cec5SDimitry Andric           if (echo_packet_result == PacketResult::Success) {
3190b57cec5SDimitry Andric             const uint32_t max_retries = 3;
3200b57cec5SDimitry Andric             uint32_t successful_responses = 0;
3210b57cec5SDimitry Andric             for (uint32_t i = 0; i < max_retries; ++i) {
3220b57cec5SDimitry Andric               StringExtractorGDBRemote echo_response;
3230b57cec5SDimitry Andric               echo_packet_result =
3240b57cec5SDimitry Andric                   WaitForPacketNoLock(echo_response, timeout, false);
3250b57cec5SDimitry Andric               if (echo_packet_result == PacketResult::Success) {
3260b57cec5SDimitry Andric                 ++successful_responses;
3270b57cec5SDimitry Andric                 if (response_regex.Execute(echo_response.GetStringRef())) {
3280b57cec5SDimitry Andric                   sync_success = true;
3290b57cec5SDimitry Andric                   break;
3300b57cec5SDimitry Andric                 } else if (successful_responses == 1) {
3310b57cec5SDimitry Andric                   // We got something else back as the first successful
3320b57cec5SDimitry Andric                   // response, it probably is the  response to the packet we
3330b57cec5SDimitry Andric                   // actually wanted, so copy it over if this is the first
3340b57cec5SDimitry Andric                   // success and continue to try to get the qEcho response
3350b57cec5SDimitry Andric                   packet = echo_response;
3360b57cec5SDimitry Andric                   got_actual_response = true;
3370b57cec5SDimitry Andric                 }
3380b57cec5SDimitry Andric               } else if (echo_packet_result == PacketResult::ErrorReplyTimeout)
3390b57cec5SDimitry Andric                 continue; // Packet timed out, continue waiting for a response
3400b57cec5SDimitry Andric               else
3410b57cec5SDimitry Andric                 break; // Something else went wrong getting the packet back, we
3420b57cec5SDimitry Andric                        // failed and are done trying
3430b57cec5SDimitry Andric             }
3440b57cec5SDimitry Andric           }
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric           // We weren't able to sync back up with the server, we must abort
3470b57cec5SDimitry Andric           // otherwise all responses might not be from the right packets...
3480b57cec5SDimitry Andric           if (sync_success) {
3490b57cec5SDimitry Andric             // We timed out, but were able to recover
3500b57cec5SDimitry Andric             if (got_actual_response) {
3510b57cec5SDimitry Andric               // We initially timed out, but we did get a response that came in
3520b57cec5SDimitry Andric               // before the successful reply to our qEcho packet, so lets say
3530b57cec5SDimitry Andric               // everything is fine...
3540b57cec5SDimitry Andric               return PacketResult::Success;
3550b57cec5SDimitry Andric             }
3560b57cec5SDimitry Andric           } else {
3570b57cec5SDimitry Andric             disconnected = true;
3580b57cec5SDimitry Andric             Disconnect();
3590b57cec5SDimitry Andric           }
3600b57cec5SDimitry Andric         }
3610b57cec5SDimitry Andric         timed_out = true;
3620b57cec5SDimitry Andric         break;
3630b57cec5SDimitry Andric       case eConnectionStatusSuccess:
3640b57cec5SDimitry Andric         // printf ("status = success but error = %s\n",
3650b57cec5SDimitry Andric         // error.AsCString("<invalid>"));
3660b57cec5SDimitry Andric         break;
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric       case eConnectionStatusEndOfFile:
3690b57cec5SDimitry Andric       case eConnectionStatusNoConnection:
3700b57cec5SDimitry Andric       case eConnectionStatusLostConnection:
3710b57cec5SDimitry Andric       case eConnectionStatusError:
3720b57cec5SDimitry Andric         disconnected = true;
3730b57cec5SDimitry Andric         Disconnect();
3740b57cec5SDimitry Andric         break;
3750b57cec5SDimitry Andric       }
3760b57cec5SDimitry Andric     }
3770b57cec5SDimitry Andric   }
3780b57cec5SDimitry Andric   packet.Clear();
3790b57cec5SDimitry Andric   if (disconnected)
3800b57cec5SDimitry Andric     return PacketResult::ErrorDisconnected;
3810b57cec5SDimitry Andric   if (timed_out)
3820b57cec5SDimitry Andric     return PacketResult::ErrorReplyTimeout;
3830b57cec5SDimitry Andric   else
3840b57cec5SDimitry Andric     return PacketResult::ErrorReplyFailed;
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric bool GDBRemoteCommunication::DecompressPacket() {
3881fd87a68SDimitry Andric   Log *log = GetLog(GDBRLog::Packets);
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric   if (!CompressionIsEnabled())
3910b57cec5SDimitry Andric     return true;
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric   size_t pkt_size = m_bytes.size();
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric   // Smallest possible compressed packet is $N#00 - an uncompressed empty
3960b57cec5SDimitry Andric   // reply, most commonly indicating an unsupported packet.  Anything less than
3970b57cec5SDimitry Andric   // 5 characters, it's definitely not a compressed packet.
3980b57cec5SDimitry Andric   if (pkt_size < 5)
3990b57cec5SDimitry Andric     return true;
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric   if (m_bytes[0] != '$' && m_bytes[0] != '%')
4020b57cec5SDimitry Andric     return true;
4030b57cec5SDimitry Andric   if (m_bytes[1] != 'C' && m_bytes[1] != 'N')
4040b57cec5SDimitry Andric     return true;
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   size_t hash_mark_idx = m_bytes.find('#');
4070b57cec5SDimitry Andric   if (hash_mark_idx == std::string::npos)
4080b57cec5SDimitry Andric     return true;
4090b57cec5SDimitry Andric   if (hash_mark_idx + 2 >= m_bytes.size())
4100b57cec5SDimitry Andric     return true;
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric   if (!::isxdigit(m_bytes[hash_mark_idx + 1]) ||
4130b57cec5SDimitry Andric       !::isxdigit(m_bytes[hash_mark_idx + 2]))
4140b57cec5SDimitry Andric     return true;
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   size_t content_length =
4170b57cec5SDimitry Andric       pkt_size -
4180b57cec5SDimitry Andric       5; // not counting '$', 'C' | 'N', '#', & the two hex checksum chars
4190b57cec5SDimitry Andric   size_t content_start = 2; // The first character of the
4200b57cec5SDimitry Andric                             // compressed/not-compressed text of the packet
4210b57cec5SDimitry Andric   size_t checksum_idx =
4220b57cec5SDimitry Andric       hash_mark_idx +
4230b57cec5SDimitry Andric       1; // The first character of the two hex checksum characters
4240b57cec5SDimitry Andric 
4250b57cec5SDimitry Andric   // Normally size_of_first_packet == m_bytes.size() but m_bytes may contain
4260b57cec5SDimitry Andric   // multiple packets. size_of_first_packet is the size of the initial packet
4270b57cec5SDimitry Andric   // which we'll replace with the decompressed version of, leaving the rest of
4280b57cec5SDimitry Andric   // m_bytes unmodified.
4290b57cec5SDimitry Andric   size_t size_of_first_packet = hash_mark_idx + 3;
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric   // Compressed packets ("$C") start with a base10 number which is the size of
4320b57cec5SDimitry Andric   // the uncompressed payload, then a : and then the compressed data.  e.g.
4330b57cec5SDimitry Andric   // $C1024:<binary>#00 Update content_start and content_length to only include
4340b57cec5SDimitry Andric   // the <binary> part of the packet.
4350b57cec5SDimitry Andric 
4360b57cec5SDimitry Andric   uint64_t decompressed_bufsize = ULONG_MAX;
4370b57cec5SDimitry Andric   if (m_bytes[1] == 'C') {
4380b57cec5SDimitry Andric     size_t i = content_start;
4390b57cec5SDimitry Andric     while (i < hash_mark_idx && isdigit(m_bytes[i]))
4400b57cec5SDimitry Andric       i++;
4410b57cec5SDimitry Andric     if (i < hash_mark_idx && m_bytes[i] == ':') {
4420b57cec5SDimitry Andric       i++;
4430b57cec5SDimitry Andric       content_start = i;
4440b57cec5SDimitry Andric       content_length = hash_mark_idx - content_start;
4450b57cec5SDimitry Andric       std::string bufsize_str(m_bytes.data() + 2, i - 2 - 1);
4460b57cec5SDimitry Andric       errno = 0;
4470b57cec5SDimitry Andric       decompressed_bufsize = ::strtoul(bufsize_str.c_str(), nullptr, 10);
4480b57cec5SDimitry Andric       if (errno != 0 || decompressed_bufsize == ULONG_MAX) {
4490b57cec5SDimitry Andric         m_bytes.erase(0, size_of_first_packet);
4500b57cec5SDimitry Andric         return false;
4510b57cec5SDimitry Andric       }
4520b57cec5SDimitry Andric     }
4530b57cec5SDimitry Andric   }
4540b57cec5SDimitry Andric 
4550b57cec5SDimitry Andric   if (GetSendAcks()) {
4560b57cec5SDimitry Andric     char packet_checksum_cstr[3];
4570b57cec5SDimitry Andric     packet_checksum_cstr[0] = m_bytes[checksum_idx];
4580b57cec5SDimitry Andric     packet_checksum_cstr[1] = m_bytes[checksum_idx + 1];
4590b57cec5SDimitry Andric     packet_checksum_cstr[2] = '\0';
4600b57cec5SDimitry Andric     long packet_checksum = strtol(packet_checksum_cstr, nullptr, 16);
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric     long actual_checksum = CalculcateChecksum(
4630b57cec5SDimitry Andric         llvm::StringRef(m_bytes).substr(1, hash_mark_idx - 1));
4640b57cec5SDimitry Andric     bool success = packet_checksum == actual_checksum;
4650b57cec5SDimitry Andric     if (!success) {
4669dba64beSDimitry Andric       LLDB_LOGF(log,
4670b57cec5SDimitry Andric                 "error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x",
4680b57cec5SDimitry Andric                 (int)(pkt_size), m_bytes.c_str(), (uint8_t)packet_checksum,
4690b57cec5SDimitry Andric                 (uint8_t)actual_checksum);
4700b57cec5SDimitry Andric     }
4710b57cec5SDimitry Andric     // Send the ack or nack if needed
4720b57cec5SDimitry Andric     if (!success) {
4730b57cec5SDimitry Andric       SendNack();
4740b57cec5SDimitry Andric       m_bytes.erase(0, size_of_first_packet);
4750b57cec5SDimitry Andric       return false;
4760b57cec5SDimitry Andric     } else {
4770b57cec5SDimitry Andric       SendAck();
4780b57cec5SDimitry Andric     }
4790b57cec5SDimitry Andric   }
4800b57cec5SDimitry Andric 
4810b57cec5SDimitry Andric   if (m_bytes[1] == 'N') {
4820b57cec5SDimitry Andric     // This packet was not compressed -- delete the 'N' character at the start
4830b57cec5SDimitry Andric     // and the packet may be processed as-is.
4840b57cec5SDimitry Andric     m_bytes.erase(1, 1);
4850b57cec5SDimitry Andric     return true;
4860b57cec5SDimitry Andric   }
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric   // Reverse the gdb-remote binary escaping that was done to the compressed
4890b57cec5SDimitry Andric   // text to guard characters like '$', '#', '}', etc.
4900b57cec5SDimitry Andric   std::vector<uint8_t> unescaped_content;
4910b57cec5SDimitry Andric   unescaped_content.reserve(content_length);
4920b57cec5SDimitry Andric   size_t i = content_start;
4930b57cec5SDimitry Andric   while (i < hash_mark_idx) {
4940b57cec5SDimitry Andric     if (m_bytes[i] == '}') {
4950b57cec5SDimitry Andric       i++;
4960b57cec5SDimitry Andric       unescaped_content.push_back(m_bytes[i] ^ 0x20);
4970b57cec5SDimitry Andric     } else {
4980b57cec5SDimitry Andric       unescaped_content.push_back(m_bytes[i]);
4990b57cec5SDimitry Andric     }
5000b57cec5SDimitry Andric     i++;
5010b57cec5SDimitry Andric   }
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric   uint8_t *decompressed_buffer = nullptr;
5040b57cec5SDimitry Andric   size_t decompressed_bytes = 0;
5050b57cec5SDimitry Andric 
5060b57cec5SDimitry Andric   if (decompressed_bufsize != ULONG_MAX) {
5070b57cec5SDimitry Andric     decompressed_buffer = (uint8_t *)malloc(decompressed_bufsize);
5080b57cec5SDimitry Andric     if (decompressed_buffer == nullptr) {
5090b57cec5SDimitry Andric       m_bytes.erase(0, size_of_first_packet);
5100b57cec5SDimitry Andric       return false;
5110b57cec5SDimitry Andric     }
5120b57cec5SDimitry Andric   }
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric #if defined(HAVE_LIBCOMPRESSION)
5150b57cec5SDimitry Andric   if (m_compression_type == CompressionType::ZlibDeflate ||
5160b57cec5SDimitry Andric       m_compression_type == CompressionType::LZFSE ||
5170b57cec5SDimitry Andric       m_compression_type == CompressionType::LZ4 ||
5180b57cec5SDimitry Andric       m_compression_type == CompressionType::LZMA) {
5190b57cec5SDimitry Andric     compression_algorithm compression_type;
5200b57cec5SDimitry Andric     if (m_compression_type == CompressionType::LZFSE)
5210b57cec5SDimitry Andric       compression_type = COMPRESSION_LZFSE;
5220b57cec5SDimitry Andric     else if (m_compression_type == CompressionType::ZlibDeflate)
5230b57cec5SDimitry Andric       compression_type = COMPRESSION_ZLIB;
5240b57cec5SDimitry Andric     else if (m_compression_type == CompressionType::LZ4)
5250b57cec5SDimitry Andric       compression_type = COMPRESSION_LZ4_RAW;
5260b57cec5SDimitry Andric     else if (m_compression_type == CompressionType::LZMA)
5270b57cec5SDimitry Andric       compression_type = COMPRESSION_LZMA;
5280b57cec5SDimitry Andric 
5290b57cec5SDimitry Andric     if (m_decompression_scratch_type != m_compression_type) {
5300b57cec5SDimitry Andric       if (m_decompression_scratch) {
5310b57cec5SDimitry Andric         free (m_decompression_scratch);
5320b57cec5SDimitry Andric         m_decompression_scratch = nullptr;
5330b57cec5SDimitry Andric       }
5340b57cec5SDimitry Andric       size_t scratchbuf_size = 0;
5350b57cec5SDimitry Andric       if (m_compression_type == CompressionType::LZFSE)
5360b57cec5SDimitry Andric         scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZFSE);
5370b57cec5SDimitry Andric       else if (m_compression_type == CompressionType::LZ4)
5380b57cec5SDimitry Andric         scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZ4_RAW);
5390b57cec5SDimitry Andric       else if (m_compression_type == CompressionType::ZlibDeflate)
5400b57cec5SDimitry Andric         scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_ZLIB);
5410b57cec5SDimitry Andric       else if (m_compression_type == CompressionType::LZMA)
542*0fca6ea1SDimitry Andric         scratchbuf_size =
543*0fca6ea1SDimitry Andric             compression_decode_scratch_buffer_size(COMPRESSION_LZMA);
5440b57cec5SDimitry Andric       if (scratchbuf_size > 0) {
5450b57cec5SDimitry Andric         m_decompression_scratch = (void*) malloc (scratchbuf_size);
5460b57cec5SDimitry Andric         m_decompression_scratch_type = m_compression_type;
5470b57cec5SDimitry Andric       }
5480b57cec5SDimitry Andric     }
5490b57cec5SDimitry Andric 
5500b57cec5SDimitry Andric     if (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr) {
5510b57cec5SDimitry Andric       decompressed_bytes = compression_decode_buffer(
5520b57cec5SDimitry Andric           decompressed_buffer, decompressed_bufsize,
5530b57cec5SDimitry Andric           (uint8_t *)unescaped_content.data(), unescaped_content.size(),
5540b57cec5SDimitry Andric           m_decompression_scratch, compression_type);
5550b57cec5SDimitry Andric     }
5560b57cec5SDimitry Andric   }
5570b57cec5SDimitry Andric #endif
5580b57cec5SDimitry Andric 
559e8d8bef9SDimitry Andric #if LLVM_ENABLE_ZLIB
5600b57cec5SDimitry Andric   if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX &&
5610b57cec5SDimitry Andric       decompressed_buffer != nullptr &&
5620b57cec5SDimitry Andric       m_compression_type == CompressionType::ZlibDeflate) {
5630b57cec5SDimitry Andric     z_stream stream;
5640b57cec5SDimitry Andric     memset(&stream, 0, sizeof(z_stream));
5650b57cec5SDimitry Andric     stream.next_in = (Bytef *)unescaped_content.data();
5660b57cec5SDimitry Andric     stream.avail_in = (uInt)unescaped_content.size();
5670b57cec5SDimitry Andric     stream.total_in = 0;
5680b57cec5SDimitry Andric     stream.next_out = (Bytef *)decompressed_buffer;
5690b57cec5SDimitry Andric     stream.avail_out = decompressed_bufsize;
5700b57cec5SDimitry Andric     stream.total_out = 0;
5710b57cec5SDimitry Andric     stream.zalloc = Z_NULL;
5720b57cec5SDimitry Andric     stream.zfree = Z_NULL;
5730b57cec5SDimitry Andric     stream.opaque = Z_NULL;
5740b57cec5SDimitry Andric 
5750b57cec5SDimitry Andric     if (inflateInit2(&stream, -15) == Z_OK) {
5760b57cec5SDimitry Andric       int status = inflate(&stream, Z_NO_FLUSH);
5770b57cec5SDimitry Andric       inflateEnd(&stream);
5780b57cec5SDimitry Andric       if (status == Z_STREAM_END) {
5790b57cec5SDimitry Andric         decompressed_bytes = stream.total_out;
5800b57cec5SDimitry Andric       }
5810b57cec5SDimitry Andric     }
5820b57cec5SDimitry Andric   }
5830b57cec5SDimitry Andric #endif
5840b57cec5SDimitry Andric 
5850b57cec5SDimitry Andric   if (decompressed_bytes == 0 || decompressed_buffer == nullptr) {
5860b57cec5SDimitry Andric     if (decompressed_buffer)
5870b57cec5SDimitry Andric       free(decompressed_buffer);
5880b57cec5SDimitry Andric     m_bytes.erase(0, size_of_first_packet);
5890b57cec5SDimitry Andric     return false;
5900b57cec5SDimitry Andric   }
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric   std::string new_packet;
5930b57cec5SDimitry Andric   new_packet.reserve(decompressed_bytes + 6);
5940b57cec5SDimitry Andric   new_packet.push_back(m_bytes[0]);
5950b57cec5SDimitry Andric   new_packet.append((const char *)decompressed_buffer, decompressed_bytes);
5960b57cec5SDimitry Andric   new_packet.push_back('#');
5970b57cec5SDimitry Andric   if (GetSendAcks()) {
5980b57cec5SDimitry Andric     uint8_t decompressed_checksum = CalculcateChecksum(
5990b57cec5SDimitry Andric         llvm::StringRef((const char *)decompressed_buffer, decompressed_bytes));
6000b57cec5SDimitry Andric     char decompressed_checksum_str[3];
6010b57cec5SDimitry Andric     snprintf(decompressed_checksum_str, 3, "%02x", decompressed_checksum);
6020b57cec5SDimitry Andric     new_packet.append(decompressed_checksum_str);
6030b57cec5SDimitry Andric   } else {
6040b57cec5SDimitry Andric     new_packet.push_back('0');
6050b57cec5SDimitry Andric     new_packet.push_back('0');
6060b57cec5SDimitry Andric   }
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric   m_bytes.replace(0, size_of_first_packet, new_packet.data(),
6090b57cec5SDimitry Andric                   new_packet.size());
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric   free(decompressed_buffer);
6120b57cec5SDimitry Andric   return true;
6130b57cec5SDimitry Andric }
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric GDBRemoteCommunication::PacketType
6160b57cec5SDimitry Andric GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len,
6170b57cec5SDimitry Andric                                        StringExtractorGDBRemote &packet) {
6180b57cec5SDimitry Andric   // Put the packet data into the buffer in a thread safe fashion
6190b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex);
6200b57cec5SDimitry Andric 
6211fd87a68SDimitry Andric   Log *log = GetLog(GDBRLog::Packets);
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric   if (src && src_len > 0) {
6240b57cec5SDimitry Andric     if (log && log->GetVerbose()) {
6250b57cec5SDimitry Andric       StreamString s;
6269dba64beSDimitry Andric       LLDB_LOGF(log, "GDBRemoteCommunication::%s adding %u bytes: %.*s",
6270b57cec5SDimitry Andric                 __FUNCTION__, (uint32_t)src_len, (uint32_t)src_len, src);
6280b57cec5SDimitry Andric     }
6290b57cec5SDimitry Andric     m_bytes.append((const char *)src, src_len);
6300b57cec5SDimitry Andric   }
6310b57cec5SDimitry Andric 
6320b57cec5SDimitry Andric   bool isNotifyPacket = false;
6330b57cec5SDimitry Andric 
6340b57cec5SDimitry Andric   // Parse up the packets into gdb remote packets
6350b57cec5SDimitry Andric   if (!m_bytes.empty()) {
6360b57cec5SDimitry Andric     // end_idx must be one past the last valid packet byte. Start it off with
6370b57cec5SDimitry Andric     // an invalid value that is the same as the current index.
6380b57cec5SDimitry Andric     size_t content_start = 0;
6390b57cec5SDimitry Andric     size_t content_length = 0;
6400b57cec5SDimitry Andric     size_t total_length = 0;
6410b57cec5SDimitry Andric     size_t checksum_idx = std::string::npos;
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric     // Size of packet before it is decompressed, for logging purposes
6440b57cec5SDimitry Andric     size_t original_packet_size = m_bytes.size();
6450b57cec5SDimitry Andric     if (CompressionIsEnabled()) {
6460b57cec5SDimitry Andric       if (!DecompressPacket()) {
6470b57cec5SDimitry Andric         packet.Clear();
6480b57cec5SDimitry Andric         return GDBRemoteCommunication::PacketType::Standard;
6490b57cec5SDimitry Andric       }
6500b57cec5SDimitry Andric     }
6510b57cec5SDimitry Andric 
6520b57cec5SDimitry Andric     switch (m_bytes[0]) {
6530b57cec5SDimitry Andric     case '+':                            // Look for ack
6540b57cec5SDimitry Andric     case '-':                            // Look for cancel
6550b57cec5SDimitry Andric     case '\x03':                         // ^C to halt target
6560b57cec5SDimitry Andric       content_length = total_length = 1; // The command is one byte long...
6570b57cec5SDimitry Andric       break;
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric     case '%': // Async notify packet
6600b57cec5SDimitry Andric       isNotifyPacket = true;
661bdd1243dSDimitry Andric       [[fallthrough]];
6620b57cec5SDimitry Andric 
6630b57cec5SDimitry Andric     case '$':
6640b57cec5SDimitry Andric       // Look for a standard gdb packet?
6650b57cec5SDimitry Andric       {
6660b57cec5SDimitry Andric         size_t hash_pos = m_bytes.find('#');
6670b57cec5SDimitry Andric         if (hash_pos != std::string::npos) {
6680b57cec5SDimitry Andric           if (hash_pos + 2 < m_bytes.size()) {
6690b57cec5SDimitry Andric             checksum_idx = hash_pos + 1;
6700b57cec5SDimitry Andric             // Skip the dollar sign
6710b57cec5SDimitry Andric             content_start = 1;
6720b57cec5SDimitry Andric             // Don't include the # in the content or the $ in the content
6730b57cec5SDimitry Andric             // length
6740b57cec5SDimitry Andric             content_length = hash_pos - 1;
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric             total_length =
6770b57cec5SDimitry Andric                 hash_pos + 3; // Skip the # and the two hex checksum bytes
6780b57cec5SDimitry Andric           } else {
6790b57cec5SDimitry Andric             // Checksum bytes aren't all here yet
6800b57cec5SDimitry Andric             content_length = std::string::npos;
6810b57cec5SDimitry Andric           }
6820b57cec5SDimitry Andric         }
6830b57cec5SDimitry Andric       }
6840b57cec5SDimitry Andric       break;
6850b57cec5SDimitry Andric 
6860b57cec5SDimitry Andric     default: {
6870b57cec5SDimitry Andric       // We have an unexpected byte and we need to flush all bad data that is
6880b57cec5SDimitry Andric       // in m_bytes, so we need to find the first byte that is a '+' (ACK), '-'
6890b57cec5SDimitry Andric       // (NACK), \x03 (CTRL+C interrupt), or '$' character (start of packet
6900b57cec5SDimitry Andric       // header) or of course, the end of the data in m_bytes...
6910b57cec5SDimitry Andric       const size_t bytes_len = m_bytes.size();
6920b57cec5SDimitry Andric       bool done = false;
6930b57cec5SDimitry Andric       uint32_t idx;
6940b57cec5SDimitry Andric       for (idx = 1; !done && idx < bytes_len; ++idx) {
6950b57cec5SDimitry Andric         switch (m_bytes[idx]) {
6960b57cec5SDimitry Andric         case '+':
6970b57cec5SDimitry Andric         case '-':
6980b57cec5SDimitry Andric         case '\x03':
6990b57cec5SDimitry Andric         case '%':
7000b57cec5SDimitry Andric         case '$':
7010b57cec5SDimitry Andric           done = true;
7020b57cec5SDimitry Andric           break;
7030b57cec5SDimitry Andric 
7040b57cec5SDimitry Andric         default:
7050b57cec5SDimitry Andric           break;
7060b57cec5SDimitry Andric         }
7070b57cec5SDimitry Andric       }
7089dba64beSDimitry Andric       LLDB_LOGF(log, "GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'",
7090b57cec5SDimitry Andric                 __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str());
7100b57cec5SDimitry Andric       m_bytes.erase(0, idx - 1);
7110b57cec5SDimitry Andric     } break;
7120b57cec5SDimitry Andric     }
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric     if (content_length == std::string::npos) {
7150b57cec5SDimitry Andric       packet.Clear();
7160b57cec5SDimitry Andric       return GDBRemoteCommunication::PacketType::Invalid;
7170b57cec5SDimitry Andric     } else if (total_length > 0) {
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric       // We have a valid packet...
7200b57cec5SDimitry Andric       assert(content_length <= m_bytes.size());
7210b57cec5SDimitry Andric       assert(total_length <= m_bytes.size());
7220b57cec5SDimitry Andric       assert(content_length <= total_length);
7230b57cec5SDimitry Andric       size_t content_end = content_start + content_length;
7240b57cec5SDimitry Andric 
7250b57cec5SDimitry Andric       bool success = true;
7260b57cec5SDimitry Andric       if (log) {
7270b57cec5SDimitry Andric         // If logging was just enabled and we have history, then dump out what
7280b57cec5SDimitry Andric         // we have to the log so we get the historical context. The Dump() call
7290b57cec5SDimitry Andric         // that logs all of the packet will set a boolean so that we don't dump
7300b57cec5SDimitry Andric         // this more than once
7310b57cec5SDimitry Andric         if (!m_history.DidDumpToLog())
7320b57cec5SDimitry Andric           m_history.Dump(log);
7330b57cec5SDimitry Andric 
7340b57cec5SDimitry Andric         bool binary = false;
7350b57cec5SDimitry Andric         // Only detect binary for packets that start with a '$' and have a
7360b57cec5SDimitry Andric         // '#CC' checksum
7370b57cec5SDimitry Andric         if (m_bytes[0] == '$' && total_length > 4) {
7380b57cec5SDimitry Andric           for (size_t i = 0; !binary && i < total_length; ++i) {
7390b57cec5SDimitry Andric             unsigned char c = m_bytes[i];
7405ffd83dbSDimitry Andric             if (!llvm::isPrint(c) && !llvm::isSpace(c)) {
7410b57cec5SDimitry Andric               binary = true;
7420b57cec5SDimitry Andric             }
7430b57cec5SDimitry Andric           }
7440b57cec5SDimitry Andric         }
7450b57cec5SDimitry Andric         if (binary) {
7460b57cec5SDimitry Andric           StreamString strm;
7470b57cec5SDimitry Andric           // Packet header...
7480b57cec5SDimitry Andric           if (CompressionIsEnabled())
7490b57cec5SDimitry Andric             strm.Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %c",
7500b57cec5SDimitry Andric                         (uint64_t)original_packet_size, (uint64_t)total_length,
7510b57cec5SDimitry Andric                         m_bytes[0]);
7520b57cec5SDimitry Andric           else
7530b57cec5SDimitry Andric             strm.Printf("<%4" PRIu64 "> read packet: %c",
7540b57cec5SDimitry Andric                         (uint64_t)total_length, m_bytes[0]);
7550b57cec5SDimitry Andric           for (size_t i = content_start; i < content_end; ++i) {
7560b57cec5SDimitry Andric             // Remove binary escaped bytes when displaying the packet...
7570b57cec5SDimitry Andric             const char ch = m_bytes[i];
7580b57cec5SDimitry Andric             if (ch == 0x7d) {
7590b57cec5SDimitry Andric               // 0x7d is the escape character.  The next character is to be
7600b57cec5SDimitry Andric               // XOR'd with 0x20.
7610b57cec5SDimitry Andric               const char escapee = m_bytes[++i] ^ 0x20;
7620b57cec5SDimitry Andric               strm.Printf("%2.2x", escapee);
7630b57cec5SDimitry Andric             } else {
7640b57cec5SDimitry Andric               strm.Printf("%2.2x", (uint8_t)ch);
7650b57cec5SDimitry Andric             }
7660b57cec5SDimitry Andric           }
7670b57cec5SDimitry Andric           // Packet footer...
7680b57cec5SDimitry Andric           strm.Printf("%c%c%c", m_bytes[total_length - 3],
7690b57cec5SDimitry Andric                       m_bytes[total_length - 2], m_bytes[total_length - 1]);
7700b57cec5SDimitry Andric           log->PutString(strm.GetString());
7710b57cec5SDimitry Andric         } else {
7720b57cec5SDimitry Andric           if (CompressionIsEnabled())
7739dba64beSDimitry Andric             LLDB_LOGF(log, "<%4" PRIu64 ":%" PRIu64 "> read packet: %.*s",
7740b57cec5SDimitry Andric                       (uint64_t)original_packet_size, (uint64_t)total_length,
7750b57cec5SDimitry Andric                       (int)(total_length), m_bytes.c_str());
7760b57cec5SDimitry Andric           else
7779dba64beSDimitry Andric             LLDB_LOGF(log, "<%4" PRIu64 "> read packet: %.*s",
7780b57cec5SDimitry Andric                       (uint64_t)total_length, (int)(total_length),
7790b57cec5SDimitry Andric                       m_bytes.c_str());
7800b57cec5SDimitry Andric         }
7810b57cec5SDimitry Andric       }
7820b57cec5SDimitry Andric 
7830b57cec5SDimitry Andric       m_history.AddPacket(m_bytes, total_length,
7849dba64beSDimitry Andric                           GDBRemotePacket::ePacketTypeRecv, total_length);
7850b57cec5SDimitry Andric 
7860b57cec5SDimitry Andric       // Copy the packet from m_bytes to packet_str expanding the run-length
7875ffd83dbSDimitry Andric       // encoding in the process.
7885ffd83dbSDimitry Andric       std ::string packet_str =
7895ffd83dbSDimitry Andric           ExpandRLE(m_bytes.substr(content_start, content_end - content_start));
7909dba64beSDimitry Andric       packet = StringExtractorGDBRemote(packet_str);
7910b57cec5SDimitry Andric 
7920b57cec5SDimitry Andric       if (m_bytes[0] == '$' || m_bytes[0] == '%') {
7930b57cec5SDimitry Andric         assert(checksum_idx < m_bytes.size());
7940b57cec5SDimitry Andric         if (::isxdigit(m_bytes[checksum_idx + 0]) ||
7950b57cec5SDimitry Andric             ::isxdigit(m_bytes[checksum_idx + 1])) {
7960b57cec5SDimitry Andric           if (GetSendAcks()) {
7970b57cec5SDimitry Andric             const char *packet_checksum_cstr = &m_bytes[checksum_idx];
7980b57cec5SDimitry Andric             char packet_checksum = strtol(packet_checksum_cstr, nullptr, 16);
7990b57cec5SDimitry Andric             char actual_checksum = CalculcateChecksum(
8000b57cec5SDimitry Andric                 llvm::StringRef(m_bytes).slice(content_start, content_end));
8010b57cec5SDimitry Andric             success = packet_checksum == actual_checksum;
8020b57cec5SDimitry Andric             if (!success) {
8039dba64beSDimitry Andric               LLDB_LOGF(log,
8049dba64beSDimitry Andric                         "error: checksum mismatch: %.*s expected 0x%2.2x, "
8050b57cec5SDimitry Andric                         "got 0x%2.2x",
8060b57cec5SDimitry Andric                         (int)(total_length), m_bytes.c_str(),
8070b57cec5SDimitry Andric                         (uint8_t)packet_checksum, (uint8_t)actual_checksum);
8080b57cec5SDimitry Andric             }
8090b57cec5SDimitry Andric             // Send the ack or nack if needed
8100b57cec5SDimitry Andric             if (!success)
8110b57cec5SDimitry Andric               SendNack();
8120b57cec5SDimitry Andric             else
8130b57cec5SDimitry Andric               SendAck();
8140b57cec5SDimitry Andric           }
8150b57cec5SDimitry Andric         } else {
8160b57cec5SDimitry Andric           success = false;
8179dba64beSDimitry Andric           LLDB_LOGF(log, "error: invalid checksum in packet: '%s'\n",
8180b57cec5SDimitry Andric                     m_bytes.c_str());
8190b57cec5SDimitry Andric         }
8200b57cec5SDimitry Andric       }
8210b57cec5SDimitry Andric 
8220b57cec5SDimitry Andric       m_bytes.erase(0, total_length);
8230b57cec5SDimitry Andric       packet.SetFilePos(0);
8240b57cec5SDimitry Andric 
8250b57cec5SDimitry Andric       if (isNotifyPacket)
8260b57cec5SDimitry Andric         return GDBRemoteCommunication::PacketType::Notify;
8270b57cec5SDimitry Andric       else
8280b57cec5SDimitry Andric         return GDBRemoteCommunication::PacketType::Standard;
8290b57cec5SDimitry Andric     }
8300b57cec5SDimitry Andric   }
8310b57cec5SDimitry Andric   packet.Clear();
8320b57cec5SDimitry Andric   return GDBRemoteCommunication::PacketType::Invalid;
8330b57cec5SDimitry Andric }
8340b57cec5SDimitry Andric 
8350b57cec5SDimitry Andric Status GDBRemoteCommunication::StartListenThread(const char *hostname,
8360b57cec5SDimitry Andric                                                  uint16_t port) {
8370b57cec5SDimitry Andric   if (m_listen_thread.IsJoinable())
8380b57cec5SDimitry Andric     return Status("listen thread already running");
8390b57cec5SDimitry Andric 
8400b57cec5SDimitry Andric   char listen_url[512];
8410b57cec5SDimitry Andric   if (hostname && hostname[0])
8420b57cec5SDimitry Andric     snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port);
8430b57cec5SDimitry Andric   else
8440b57cec5SDimitry Andric     snprintf(listen_url, sizeof(listen_url), "listen://%i", port);
8450b57cec5SDimitry Andric   m_listen_url = listen_url;
8465ffd83dbSDimitry Andric   SetConnection(std::make_unique<ConnectionFileDescriptor>());
8470b57cec5SDimitry Andric   llvm::Expected<HostThread> listen_thread = ThreadLauncher::LaunchThread(
84881ad6265SDimitry Andric       listen_url, [this] { return GDBRemoteCommunication::ListenThread(); });
8490b57cec5SDimitry Andric   if (!listen_thread)
8500b57cec5SDimitry Andric     return Status(listen_thread.takeError());
8510b57cec5SDimitry Andric   m_listen_thread = *listen_thread;
8520b57cec5SDimitry Andric 
8530b57cec5SDimitry Andric   return Status();
8540b57cec5SDimitry Andric }
8550b57cec5SDimitry Andric 
8560b57cec5SDimitry Andric bool GDBRemoteCommunication::JoinListenThread() {
8570b57cec5SDimitry Andric   if (m_listen_thread.IsJoinable())
8580b57cec5SDimitry Andric     m_listen_thread.Join(nullptr);
8590b57cec5SDimitry Andric   return true;
8600b57cec5SDimitry Andric }
8610b57cec5SDimitry Andric 
86281ad6265SDimitry Andric lldb::thread_result_t GDBRemoteCommunication::ListenThread() {
8630b57cec5SDimitry Andric   Status error;
8640b57cec5SDimitry Andric   ConnectionFileDescriptor *connection =
86581ad6265SDimitry Andric       (ConnectionFileDescriptor *)GetConnection();
8660b57cec5SDimitry Andric 
8670b57cec5SDimitry Andric   if (connection) {
8680b57cec5SDimitry Andric     // Do the listen on another thread so we can continue on...
869349cc55cSDimitry Andric     if (connection->Connect(
87081ad6265SDimitry Andric             m_listen_url.c_str(),
87181ad6265SDimitry Andric             [this](llvm::StringRef port_str) {
872349cc55cSDimitry Andric               uint16_t port = 0;
873349cc55cSDimitry Andric               llvm::to_integer(port_str, port, 10);
87481ad6265SDimitry Andric               m_port_promise.set_value(port);
875349cc55cSDimitry Andric             },
876349cc55cSDimitry Andric             &error) != eConnectionStatusSuccess)
87781ad6265SDimitry Andric       SetConnection(nullptr);
8780b57cec5SDimitry Andric   }
8790b57cec5SDimitry Andric   return {};
8800b57cec5SDimitry Andric }
8810b57cec5SDimitry Andric 
8820b57cec5SDimitry Andric Status GDBRemoteCommunication::StartDebugserverProcess(
8830b57cec5SDimitry Andric     const char *url, Platform *platform, ProcessLaunchInfo &launch_info,
8840b57cec5SDimitry Andric     uint16_t *port, const Args *inferior_args, int pass_comm_fd) {
8851fd87a68SDimitry Andric   Log *log = GetLog(GDBRLog::Process);
8869dba64beSDimitry Andric   LLDB_LOGF(log, "GDBRemoteCommunication::%s(url=%s, port=%" PRIu16 ")",
8879dba64beSDimitry Andric             __FUNCTION__, url ? url : "<empty>", port ? *port : uint16_t(0));
8880b57cec5SDimitry Andric 
8890b57cec5SDimitry Andric   Status error;
8900b57cec5SDimitry Andric   // If we locate debugserver, keep that located version around
8910b57cec5SDimitry Andric   static FileSpec g_debugserver_file_spec;
8920b57cec5SDimitry Andric 
8930b57cec5SDimitry Andric   char debugserver_path[PATH_MAX];
8940b57cec5SDimitry Andric   FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
8950b57cec5SDimitry Andric 
8960b57cec5SDimitry Andric   Environment host_env = Host::GetEnvironment();
8970b57cec5SDimitry Andric 
8980b57cec5SDimitry Andric   // Always check to see if we have an environment override for the path to the
8990b57cec5SDimitry Andric   // debugserver to use and use it if we do.
9000b57cec5SDimitry Andric   std::string env_debugserver_path = host_env.lookup("LLDB_DEBUGSERVER_PATH");
9010b57cec5SDimitry Andric   if (!env_debugserver_path.empty()) {
9020b57cec5SDimitry Andric     debugserver_file_spec.SetFile(env_debugserver_path,
9030b57cec5SDimitry Andric                                   FileSpec::Style::native);
9049dba64beSDimitry Andric     LLDB_LOGF(log,
9059dba64beSDimitry Andric               "GDBRemoteCommunication::%s() gdb-remote stub exe path set "
9060b57cec5SDimitry Andric               "from environment variable: %s",
9070b57cec5SDimitry Andric               __FUNCTION__, env_debugserver_path.c_str());
9080b57cec5SDimitry Andric   } else
9090b57cec5SDimitry Andric     debugserver_file_spec = g_debugserver_file_spec;
9100b57cec5SDimitry Andric   bool debugserver_exists =
9110b57cec5SDimitry Andric       FileSystem::Instance().Exists(debugserver_file_spec);
9120b57cec5SDimitry Andric   if (!debugserver_exists) {
9130b57cec5SDimitry Andric     // The debugserver binary is in the LLDB.framework/Resources directory.
9140b57cec5SDimitry Andric     debugserver_file_spec = HostInfo::GetSupportExeDir();
9150b57cec5SDimitry Andric     if (debugserver_file_spec) {
9160b57cec5SDimitry Andric       debugserver_file_spec.AppendPathComponent(DEBUGSERVER_BASENAME);
9170b57cec5SDimitry Andric       debugserver_exists = FileSystem::Instance().Exists(debugserver_file_spec);
9180b57cec5SDimitry Andric       if (debugserver_exists) {
9199dba64beSDimitry Andric         LLDB_LOGF(log,
9200b57cec5SDimitry Andric                   "GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'",
9210b57cec5SDimitry Andric                   __FUNCTION__, debugserver_file_spec.GetPath().c_str());
9220b57cec5SDimitry Andric 
9230b57cec5SDimitry Andric         g_debugserver_file_spec = debugserver_file_spec;
9240b57cec5SDimitry Andric       } else {
9250b57cec5SDimitry Andric         if (platform)
9260b57cec5SDimitry Andric           debugserver_file_spec =
9270b57cec5SDimitry Andric               platform->LocateExecutable(DEBUGSERVER_BASENAME);
9280b57cec5SDimitry Andric         else
9290b57cec5SDimitry Andric           debugserver_file_spec.Clear();
9300b57cec5SDimitry Andric         if (debugserver_file_spec) {
9310b57cec5SDimitry Andric           // Platform::LocateExecutable() wouldn't return a path if it doesn't
9320b57cec5SDimitry Andric           // exist
9330b57cec5SDimitry Andric           debugserver_exists = true;
9340b57cec5SDimitry Andric         } else {
9359dba64beSDimitry Andric           LLDB_LOGF(log,
9369dba64beSDimitry Andric                     "GDBRemoteCommunication::%s() could not find "
9370b57cec5SDimitry Andric                     "gdb-remote stub exe '%s'",
9380b57cec5SDimitry Andric                     __FUNCTION__, debugserver_file_spec.GetPath().c_str());
9390b57cec5SDimitry Andric         }
9400b57cec5SDimitry Andric         // Don't cache the platform specific GDB server binary as it could
9410b57cec5SDimitry Andric         // change from platform to platform
9420b57cec5SDimitry Andric         g_debugserver_file_spec.Clear();
9430b57cec5SDimitry Andric       }
9440b57cec5SDimitry Andric     }
9450b57cec5SDimitry Andric   }
9460b57cec5SDimitry Andric 
9470b57cec5SDimitry Andric   if (debugserver_exists) {
9480b57cec5SDimitry Andric     debugserver_file_spec.GetPath(debugserver_path, sizeof(debugserver_path));
9490b57cec5SDimitry Andric 
9500b57cec5SDimitry Andric     Args &debugserver_args = launch_info.GetArguments();
9510b57cec5SDimitry Andric     debugserver_args.Clear();
9520b57cec5SDimitry Andric 
9530b57cec5SDimitry Andric     // Start args with "debugserver /file/path -r --"
9540b57cec5SDimitry Andric     debugserver_args.AppendArgument(llvm::StringRef(debugserver_path));
9550b57cec5SDimitry Andric 
9560b57cec5SDimitry Andric #if !defined(__APPLE__)
9570b57cec5SDimitry Andric     // First argument to lldb-server must be mode in which to run.
9580b57cec5SDimitry Andric     debugserver_args.AppendArgument(llvm::StringRef("gdbserver"));
9590b57cec5SDimitry Andric #endif
9600b57cec5SDimitry Andric 
9610b57cec5SDimitry Andric     // If a url is supplied then use it
9620b57cec5SDimitry Andric     if (url)
9630b57cec5SDimitry Andric       debugserver_args.AppendArgument(llvm::StringRef(url));
9640b57cec5SDimitry Andric 
9650b57cec5SDimitry Andric     if (pass_comm_fd >= 0) {
9660b57cec5SDimitry Andric       StreamString fd_arg;
9670b57cec5SDimitry Andric       fd_arg.Printf("--fd=%i", pass_comm_fd);
9680b57cec5SDimitry Andric       debugserver_args.AppendArgument(fd_arg.GetString());
9690b57cec5SDimitry Andric       // Send "pass_comm_fd" down to the inferior so it can use it to
9700b57cec5SDimitry Andric       // communicate back with this process
9710b57cec5SDimitry Andric       launch_info.AppendDuplicateFileAction(pass_comm_fd, pass_comm_fd);
9720b57cec5SDimitry Andric     }
9730b57cec5SDimitry Andric 
9740b57cec5SDimitry Andric     // use native registers, not the GDB registers
9750b57cec5SDimitry Andric     debugserver_args.AppendArgument(llvm::StringRef("--native-regs"));
9760b57cec5SDimitry Andric 
9770b57cec5SDimitry Andric     if (launch_info.GetLaunchInSeparateProcessGroup()) {
9780b57cec5SDimitry Andric       debugserver_args.AppendArgument(llvm::StringRef("--setsid"));
9790b57cec5SDimitry Andric     }
9800b57cec5SDimitry Andric 
9810b57cec5SDimitry Andric     llvm::SmallString<128> named_pipe_path;
9820b57cec5SDimitry Andric     // socket_pipe is used by debug server to communicate back either
9830b57cec5SDimitry Andric     // TCP port or domain socket name which it listens on.
9840b57cec5SDimitry Andric     // The second purpose of the pipe to serve as a synchronization point -
9850b57cec5SDimitry Andric     // once data is written to the pipe, debug server is up and running.
9860b57cec5SDimitry Andric     Pipe socket_pipe;
9870b57cec5SDimitry Andric 
9880b57cec5SDimitry Andric     // port is null when debug server should listen on domain socket - we're
9890b57cec5SDimitry Andric     // not interested in port value but rather waiting for debug server to
9900b57cec5SDimitry Andric     // become available.
9910b57cec5SDimitry Andric     if (pass_comm_fd == -1) {
9920b57cec5SDimitry Andric       if (url) {
9930b57cec5SDimitry Andric // Create a temporary file to get the stdout/stderr and redirect the output of
9940b57cec5SDimitry Andric // the command into this file. We will later read this file if all goes well
9950b57cec5SDimitry Andric // and fill the data into "command_output_ptr"
9960b57cec5SDimitry Andric #if defined(__APPLE__)
9970b57cec5SDimitry Andric         // Binding to port zero, we need to figure out what port it ends up
9980b57cec5SDimitry Andric         // using using a named pipe...
9990b57cec5SDimitry Andric         error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe",
10000b57cec5SDimitry Andric                                                  false, named_pipe_path);
10010b57cec5SDimitry Andric         if (error.Fail()) {
10029dba64beSDimitry Andric           LLDB_LOGF(log,
10039dba64beSDimitry Andric                     "GDBRemoteCommunication::%s() "
10040b57cec5SDimitry Andric                     "named pipe creation failed: %s",
10050b57cec5SDimitry Andric                     __FUNCTION__, error.AsCString());
10060b57cec5SDimitry Andric           return error;
10070b57cec5SDimitry Andric         }
10080b57cec5SDimitry Andric         debugserver_args.AppendArgument(llvm::StringRef("--named-pipe"));
10090b57cec5SDimitry Andric         debugserver_args.AppendArgument(named_pipe_path);
10100b57cec5SDimitry Andric #else
10110b57cec5SDimitry Andric         // Binding to port zero, we need to figure out what port it ends up
10120b57cec5SDimitry Andric         // using using an unnamed pipe...
10130b57cec5SDimitry Andric         error = socket_pipe.CreateNew(true);
10140b57cec5SDimitry Andric         if (error.Fail()) {
10159dba64beSDimitry Andric           LLDB_LOGF(log,
10169dba64beSDimitry Andric                     "GDBRemoteCommunication::%s() "
10170b57cec5SDimitry Andric                     "unnamed pipe creation failed: %s",
10180b57cec5SDimitry Andric                     __FUNCTION__, error.AsCString());
10190b57cec5SDimitry Andric           return error;
10200b57cec5SDimitry Andric         }
10210b57cec5SDimitry Andric         pipe_t write = socket_pipe.GetWritePipe();
10220b57cec5SDimitry Andric         debugserver_args.AppendArgument(llvm::StringRef("--pipe"));
10230b57cec5SDimitry Andric         debugserver_args.AppendArgument(llvm::to_string(write));
10240b57cec5SDimitry Andric         launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor());
10250b57cec5SDimitry Andric #endif
10260b57cec5SDimitry Andric       } else {
10270b57cec5SDimitry Andric         // No host and port given, so lets listen on our end and make the
10280b57cec5SDimitry Andric         // debugserver connect to us..
10290b57cec5SDimitry Andric         error = StartListenThread("127.0.0.1", 0);
10300b57cec5SDimitry Andric         if (error.Fail()) {
10319dba64beSDimitry Andric           LLDB_LOGF(log,
10329dba64beSDimitry Andric                     "GDBRemoteCommunication::%s() unable to start listen "
10330b57cec5SDimitry Andric                     "thread: %s",
10340b57cec5SDimitry Andric                     __FUNCTION__, error.AsCString());
10350b57cec5SDimitry Andric           return error;
10360b57cec5SDimitry Andric         }
10370b57cec5SDimitry Andric 
10380b57cec5SDimitry Andric         // Wait for 10 seconds to resolve the bound port
1039349cc55cSDimitry Andric         std::future<uint16_t> port_future = m_port_promise.get_future();
1040349cc55cSDimitry Andric         uint16_t port_ = port_future.wait_for(std::chrono::seconds(10)) ==
1041349cc55cSDimitry Andric                                  std::future_status::ready
1042349cc55cSDimitry Andric                              ? port_future.get()
1043349cc55cSDimitry Andric                              : 0;
10440b57cec5SDimitry Andric         if (port_ > 0) {
10450b57cec5SDimitry Andric           char port_cstr[32];
10460b57cec5SDimitry Andric           snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", port_);
10470b57cec5SDimitry Andric           // Send the host and port down that debugserver and specify an option
10480b57cec5SDimitry Andric           // so that it connects back to the port we are listening to in this
10490b57cec5SDimitry Andric           // process
10500b57cec5SDimitry Andric           debugserver_args.AppendArgument(llvm::StringRef("--reverse-connect"));
10510b57cec5SDimitry Andric           debugserver_args.AppendArgument(llvm::StringRef(port_cstr));
10520b57cec5SDimitry Andric           if (port)
10530b57cec5SDimitry Andric             *port = port_;
10540b57cec5SDimitry Andric         } else {
10550b57cec5SDimitry Andric           error.SetErrorString("failed to bind to port 0 on 127.0.0.1");
10569dba64beSDimitry Andric           LLDB_LOGF(log, "GDBRemoteCommunication::%s() failed: %s",
10579dba64beSDimitry Andric                     __FUNCTION__, error.AsCString());
10580b57cec5SDimitry Andric           return error;
10590b57cec5SDimitry Andric         }
10600b57cec5SDimitry Andric       }
10610b57cec5SDimitry Andric     }
10620b57cec5SDimitry Andric     std::string env_debugserver_log_file =
10630b57cec5SDimitry Andric         host_env.lookup("LLDB_DEBUGSERVER_LOG_FILE");
10640b57cec5SDimitry Andric     if (!env_debugserver_log_file.empty()) {
10650b57cec5SDimitry Andric       debugserver_args.AppendArgument(
10660b57cec5SDimitry Andric           llvm::formatv("--log-file={0}", env_debugserver_log_file).str());
10670b57cec5SDimitry Andric     }
10680b57cec5SDimitry Andric 
10690b57cec5SDimitry Andric #if defined(__APPLE__)
10700b57cec5SDimitry Andric     const char *env_debugserver_log_flags =
10710b57cec5SDimitry Andric         getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
10720b57cec5SDimitry Andric     if (env_debugserver_log_flags) {
10730b57cec5SDimitry Andric       debugserver_args.AppendArgument(
10740b57cec5SDimitry Andric           llvm::formatv("--log-flags={0}", env_debugserver_log_flags).str());
10750b57cec5SDimitry Andric     }
10760b57cec5SDimitry Andric #else
10770b57cec5SDimitry Andric     std::string env_debugserver_log_channels =
10780b57cec5SDimitry Andric         host_env.lookup("LLDB_SERVER_LOG_CHANNELS");
10790b57cec5SDimitry Andric     if (!env_debugserver_log_channels.empty()) {
10800b57cec5SDimitry Andric       debugserver_args.AppendArgument(
10810b57cec5SDimitry Andric           llvm::formatv("--log-channels={0}", env_debugserver_log_channels)
10820b57cec5SDimitry Andric               .str());
10830b57cec5SDimitry Andric     }
10840b57cec5SDimitry Andric #endif
10850b57cec5SDimitry Andric 
10860b57cec5SDimitry Andric     // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an
10870b57cec5SDimitry Andric     // env var doesn't come back.
10880b57cec5SDimitry Andric     uint32_t env_var_index = 1;
10890b57cec5SDimitry Andric     bool has_env_var;
10900b57cec5SDimitry Andric     do {
10910b57cec5SDimitry Andric       char env_var_name[64];
10920b57cec5SDimitry Andric       snprintf(env_var_name, sizeof(env_var_name),
10930b57cec5SDimitry Andric                "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++);
10940b57cec5SDimitry Andric       std::string extra_arg = host_env.lookup(env_var_name);
10950b57cec5SDimitry Andric       has_env_var = !extra_arg.empty();
10960b57cec5SDimitry Andric 
10970b57cec5SDimitry Andric       if (has_env_var) {
10980b57cec5SDimitry Andric         debugserver_args.AppendArgument(llvm::StringRef(extra_arg));
10999dba64beSDimitry Andric         LLDB_LOGF(log,
11009dba64beSDimitry Andric                   "GDBRemoteCommunication::%s adding env var %s contents "
11010b57cec5SDimitry Andric                   "to stub command line (%s)",
11020b57cec5SDimitry Andric                   __FUNCTION__, env_var_name, extra_arg.c_str());
11030b57cec5SDimitry Andric       }
11040b57cec5SDimitry Andric     } while (has_env_var);
11050b57cec5SDimitry Andric 
11060b57cec5SDimitry Andric     if (inferior_args && inferior_args->GetArgumentCount() > 0) {
11070b57cec5SDimitry Andric       debugserver_args.AppendArgument(llvm::StringRef("--"));
11080b57cec5SDimitry Andric       debugserver_args.AppendArguments(*inferior_args);
11090b57cec5SDimitry Andric     }
11100b57cec5SDimitry Andric 
11110b57cec5SDimitry Andric     // Copy the current environment to the gdbserver/debugserver instance
11120b57cec5SDimitry Andric     launch_info.GetEnvironment() = host_env;
11130b57cec5SDimitry Andric 
11140b57cec5SDimitry Andric     // Close STDIN, STDOUT and STDERR.
11150b57cec5SDimitry Andric     launch_info.AppendCloseFileAction(STDIN_FILENO);
11160b57cec5SDimitry Andric     launch_info.AppendCloseFileAction(STDOUT_FILENO);
11170b57cec5SDimitry Andric     launch_info.AppendCloseFileAction(STDERR_FILENO);
11180b57cec5SDimitry Andric 
11190b57cec5SDimitry Andric     // Redirect STDIN, STDOUT and STDERR to "/dev/null".
11200b57cec5SDimitry Andric     launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false);
11210b57cec5SDimitry Andric     launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true);
11220b57cec5SDimitry Andric     launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true);
11230b57cec5SDimitry Andric 
11240b57cec5SDimitry Andric     if (log) {
11250b57cec5SDimitry Andric       StreamString string_stream;
11260b57cec5SDimitry Andric       Platform *const platform = nullptr;
11270b57cec5SDimitry Andric       launch_info.Dump(string_stream, platform);
11289dba64beSDimitry Andric       LLDB_LOGF(log, "launch info for gdb-remote stub:\n%s",
11290b57cec5SDimitry Andric                 string_stream.GetData());
11300b57cec5SDimitry Andric     }
11310b57cec5SDimitry Andric     error = Host::LaunchProcess(launch_info);
11320b57cec5SDimitry Andric 
11330b57cec5SDimitry Andric     if (error.Success() &&
11340b57cec5SDimitry Andric         (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) &&
11350b57cec5SDimitry Andric         pass_comm_fd == -1) {
11360b57cec5SDimitry Andric       if (named_pipe_path.size() > 0) {
11370b57cec5SDimitry Andric         error = socket_pipe.OpenAsReader(named_pipe_path, false);
11380b57cec5SDimitry Andric         if (error.Fail())
11399dba64beSDimitry Andric           LLDB_LOGF(log,
11409dba64beSDimitry Andric                     "GDBRemoteCommunication::%s() "
11410b57cec5SDimitry Andric                     "failed to open named pipe %s for reading: %s",
11429dba64beSDimitry Andric                     __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
11430b57cec5SDimitry Andric       }
11440b57cec5SDimitry Andric 
11450b57cec5SDimitry Andric       if (socket_pipe.CanWrite())
11460b57cec5SDimitry Andric         socket_pipe.CloseWriteFileDescriptor();
11470b57cec5SDimitry Andric       if (socket_pipe.CanRead()) {
11480b57cec5SDimitry Andric         char port_cstr[PATH_MAX] = {0};
11490b57cec5SDimitry Andric         port_cstr[0] = '\0';
11500b57cec5SDimitry Andric         size_t num_bytes = sizeof(port_cstr);
11510b57cec5SDimitry Andric         // Read port from pipe with 10 second timeout.
11520b57cec5SDimitry Andric         error = socket_pipe.ReadWithTimeout(
11530b57cec5SDimitry Andric             port_cstr, num_bytes, std::chrono::seconds{10}, num_bytes);
11540b57cec5SDimitry Andric         if (error.Success() && (port != nullptr)) {
11550b57cec5SDimitry Andric           assert(num_bytes > 0 && port_cstr[num_bytes - 1] == '\0');
1156349cc55cSDimitry Andric           uint16_t child_port = 0;
1157349cc55cSDimitry Andric           // FIXME: improve error handling
1158349cc55cSDimitry Andric           llvm::to_integer(port_cstr, child_port);
11590b57cec5SDimitry Andric           if (*port == 0 || *port == child_port) {
11600b57cec5SDimitry Andric             *port = child_port;
11619dba64beSDimitry Andric             LLDB_LOGF(log,
11629dba64beSDimitry Andric                       "GDBRemoteCommunication::%s() "
11630b57cec5SDimitry Andric                       "debugserver listens %u port",
11640b57cec5SDimitry Andric                       __FUNCTION__, *port);
11650b57cec5SDimitry Andric           } else {
11669dba64beSDimitry Andric             LLDB_LOGF(log,
11679dba64beSDimitry Andric                       "GDBRemoteCommunication::%s() "
11680b57cec5SDimitry Andric                       "debugserver listening on port "
11690b57cec5SDimitry Andric                       "%d but requested port was %d",
11709dba64beSDimitry Andric                       __FUNCTION__, (uint32_t)child_port, (uint32_t)(*port));
11710b57cec5SDimitry Andric           }
11720b57cec5SDimitry Andric         } else {
11739dba64beSDimitry Andric           LLDB_LOGF(log,
11749dba64beSDimitry Andric                     "GDBRemoteCommunication::%s() "
11750b57cec5SDimitry Andric                     "failed to read a port value from pipe %s: %s",
11769dba64beSDimitry Andric                     __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
11770b57cec5SDimitry Andric         }
11780b57cec5SDimitry Andric         socket_pipe.Close();
11790b57cec5SDimitry Andric       }
11800b57cec5SDimitry Andric 
11810b57cec5SDimitry Andric       if (named_pipe_path.size() > 0) {
11820b57cec5SDimitry Andric         const auto err = socket_pipe.Delete(named_pipe_path);
11830b57cec5SDimitry Andric         if (err.Fail()) {
11849dba64beSDimitry Andric           LLDB_LOGF(log,
11850b57cec5SDimitry Andric                     "GDBRemoteCommunication::%s failed to delete pipe %s: %s",
11860b57cec5SDimitry Andric                     __FUNCTION__, named_pipe_path.c_str(), err.AsCString());
11870b57cec5SDimitry Andric         }
11880b57cec5SDimitry Andric       }
11890b57cec5SDimitry Andric 
11900b57cec5SDimitry Andric       // Make sure we actually connect with the debugserver...
11910b57cec5SDimitry Andric       JoinListenThread();
11920b57cec5SDimitry Andric     }
11930b57cec5SDimitry Andric   } else {
11940b57cec5SDimitry Andric     error.SetErrorStringWithFormat("unable to locate " DEBUGSERVER_BASENAME);
11950b57cec5SDimitry Andric   }
11960b57cec5SDimitry Andric 
11970b57cec5SDimitry Andric   if (error.Fail()) {
11989dba64beSDimitry Andric     LLDB_LOGF(log, "GDBRemoteCommunication::%s() failed: %s", __FUNCTION__,
11990b57cec5SDimitry Andric               error.AsCString());
12000b57cec5SDimitry Andric   }
12010b57cec5SDimitry Andric 
12020b57cec5SDimitry Andric   return error;
12030b57cec5SDimitry Andric }
12040b57cec5SDimitry Andric 
12050b57cec5SDimitry Andric void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); }
12060b57cec5SDimitry Andric 
12070b57cec5SDimitry Andric llvm::Error
12080b57cec5SDimitry Andric GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
12090b57cec5SDimitry Andric                                        GDBRemoteCommunication &server) {
12100b57cec5SDimitry Andric   const bool child_processes_inherit = false;
12110b57cec5SDimitry Andric   const int backlog = 5;
12120b57cec5SDimitry Andric   TCPSocket listen_socket(true, child_processes_inherit);
12130b57cec5SDimitry Andric   if (llvm::Error error =
1214e8d8bef9SDimitry Andric           listen_socket.Listen("localhost:0", backlog).ToError())
12150b57cec5SDimitry Andric     return error;
12160b57cec5SDimitry Andric 
1217bdd1243dSDimitry Andric   Socket *accept_socket = nullptr;
12180b57cec5SDimitry Andric   std::future<Status> accept_status = std::async(
12190b57cec5SDimitry Andric       std::launch::async, [&] { return listen_socket.Accept(accept_socket); });
12200b57cec5SDimitry Andric 
12210b57cec5SDimitry Andric   llvm::SmallString<32> remote_addr;
12220b57cec5SDimitry Andric   llvm::raw_svector_ostream(remote_addr)
1223e8d8bef9SDimitry Andric       << "connect://localhost:" << listen_socket.GetLocalPortNumber();
12240b57cec5SDimitry Andric 
12250b57cec5SDimitry Andric   std::unique_ptr<ConnectionFileDescriptor> conn_up(
12260b57cec5SDimitry Andric       new ConnectionFileDescriptor());
12270b57cec5SDimitry Andric   Status status;
12280b57cec5SDimitry Andric   if (conn_up->Connect(remote_addr, &status) != lldb::eConnectionStatusSuccess)
12290b57cec5SDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
12300b57cec5SDimitry Andric                                    "Unable to connect: %s", status.AsCString());
12310b57cec5SDimitry Andric 
12325ffd83dbSDimitry Andric   client.SetConnection(std::move(conn_up));
12330b57cec5SDimitry Andric   if (llvm::Error error = accept_status.get().ToError())
12340b57cec5SDimitry Andric     return error;
12350b57cec5SDimitry Andric 
12365ffd83dbSDimitry Andric   server.SetConnection(
12375ffd83dbSDimitry Andric       std::make_unique<ConnectionFileDescriptor>(accept_socket));
12380b57cec5SDimitry Andric   return llvm::Error::success();
12390b57cec5SDimitry Andric }
12400b57cec5SDimitry Andric 
12410b57cec5SDimitry Andric GDBRemoteCommunication::ScopedTimeout::ScopedTimeout(
12420b57cec5SDimitry Andric     GDBRemoteCommunication &gdb_comm, std::chrono::seconds timeout)
1243fcaf7f86SDimitry Andric     : m_gdb_comm(gdb_comm), m_saved_timeout(0), m_timeout_modified(false) {
12440b57cec5SDimitry Andric   auto curr_timeout = gdb_comm.GetPacketTimeout();
12450b57cec5SDimitry Andric   // Only update the timeout if the timeout is greater than the current
12460b57cec5SDimitry Andric   // timeout. If the current timeout is larger, then just use that.
12470b57cec5SDimitry Andric   if (curr_timeout < timeout) {
12480b57cec5SDimitry Andric     m_timeout_modified = true;
12490b57cec5SDimitry Andric     m_saved_timeout = m_gdb_comm.SetPacketTimeout(timeout);
12500b57cec5SDimitry Andric   }
12510b57cec5SDimitry Andric }
12520b57cec5SDimitry Andric 
12530b57cec5SDimitry Andric GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout() {
12540b57cec5SDimitry Andric   // Only restore the timeout if we set it in the constructor.
12550b57cec5SDimitry Andric   if (m_timeout_modified)
12560b57cec5SDimitry Andric     m_gdb_comm.SetPacketTimeout(m_saved_timeout);
12570b57cec5SDimitry Andric }
12580b57cec5SDimitry Andric 
12590b57cec5SDimitry Andric void llvm::format_provider<GDBRemoteCommunication::PacketResult>::format(
12600b57cec5SDimitry Andric     const GDBRemoteCommunication::PacketResult &result, raw_ostream &Stream,
12610b57cec5SDimitry Andric     StringRef Style) {
12620b57cec5SDimitry Andric   using PacketResult = GDBRemoteCommunication::PacketResult;
12630b57cec5SDimitry Andric 
12640b57cec5SDimitry Andric   switch (result) {
12650b57cec5SDimitry Andric   case PacketResult::Success:
12660b57cec5SDimitry Andric     Stream << "Success";
12670b57cec5SDimitry Andric     break;
12680b57cec5SDimitry Andric   case PacketResult::ErrorSendFailed:
12690b57cec5SDimitry Andric     Stream << "ErrorSendFailed";
12700b57cec5SDimitry Andric     break;
12710b57cec5SDimitry Andric   case PacketResult::ErrorSendAck:
12720b57cec5SDimitry Andric     Stream << "ErrorSendAck";
12730b57cec5SDimitry Andric     break;
12740b57cec5SDimitry Andric   case PacketResult::ErrorReplyFailed:
12750b57cec5SDimitry Andric     Stream << "ErrorReplyFailed";
12760b57cec5SDimitry Andric     break;
12770b57cec5SDimitry Andric   case PacketResult::ErrorReplyTimeout:
12780b57cec5SDimitry Andric     Stream << "ErrorReplyTimeout";
12790b57cec5SDimitry Andric     break;
12800b57cec5SDimitry Andric   case PacketResult::ErrorReplyInvalid:
12810b57cec5SDimitry Andric     Stream << "ErrorReplyInvalid";
12820b57cec5SDimitry Andric     break;
12830b57cec5SDimitry Andric   case PacketResult::ErrorReplyAck:
12840b57cec5SDimitry Andric     Stream << "ErrorReplyAck";
12850b57cec5SDimitry Andric     break;
12860b57cec5SDimitry Andric   case PacketResult::ErrorDisconnected:
12870b57cec5SDimitry Andric     Stream << "ErrorDisconnected";
12880b57cec5SDimitry Andric     break;
12890b57cec5SDimitry Andric   case PacketResult::ErrorNoSequenceLock:
12900b57cec5SDimitry Andric     Stream << "ErrorNoSequenceLock";
12910b57cec5SDimitry Andric     break;
12920b57cec5SDimitry Andric   }
12930b57cec5SDimitry Andric }
12945ffd83dbSDimitry Andric 
12955ffd83dbSDimitry Andric std::string GDBRemoteCommunication::ExpandRLE(std::string packet) {
12965ffd83dbSDimitry Andric   // Reserve enough byte for the most common case (no RLE used).
12975ffd83dbSDimitry Andric   std::string decoded;
12985ffd83dbSDimitry Andric   decoded.reserve(packet.size());
12995ffd83dbSDimitry Andric   for (std::string::const_iterator c = packet.begin(); c != packet.end(); ++c) {
13005ffd83dbSDimitry Andric     if (*c == '*') {
13015ffd83dbSDimitry Andric       // '*' indicates RLE. Next character will give us the repeat count and
13025ffd83dbSDimitry Andric       // previous character is what is to be repeated.
13035ffd83dbSDimitry Andric       char char_to_repeat = decoded.back();
13045ffd83dbSDimitry Andric       // Number of time the previous character is repeated.
13055ffd83dbSDimitry Andric       int repeat_count = *++c + 3 - ' ';
13065ffd83dbSDimitry Andric       // We have the char_to_repeat and repeat_count. Now push it in the
13075ffd83dbSDimitry Andric       // packet.
13085ffd83dbSDimitry Andric       for (int i = 0; i < repeat_count; ++i)
13095ffd83dbSDimitry Andric         decoded.push_back(char_to_repeat);
13105ffd83dbSDimitry Andric     } else if (*c == 0x7d) {
13115ffd83dbSDimitry Andric       // 0x7d is the escape character.  The next character is to be XOR'd with
13125ffd83dbSDimitry Andric       // 0x20.
13135ffd83dbSDimitry Andric       char escapee = *++c ^ 0x20;
13145ffd83dbSDimitry Andric       decoded.push_back(escapee);
13155ffd83dbSDimitry Andric     } else {
13165ffd83dbSDimitry Andric       decoded.push_back(*c);
13175ffd83dbSDimitry Andric     }
13185ffd83dbSDimitry Andric   }
13195ffd83dbSDimitry Andric   return decoded;
13205ffd83dbSDimitry Andric }
1321