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