12#include "lldb/Host/Config.h"
26#include "llvm/ADT/SmallString.h"
27#include "llvm/ADT/StringRef.h"
28#include "llvm/Config/llvm-config.h"
29#include "llvm/Support/Error.h"
30#include "llvm/Support/ScopedPrinter.h"
37#if HAVE_LIBCOMPRESSION
38#include <compression.h>
52#ifdef LLDB_CONFIGURATION_DEBUG
68#if HAVE_LIBCOMPRESSION
69 if (m_decompression_scratch)
70 free (m_decompression_scratch);
77 for (
char c : payload)
80 return checksum & 255;
87 const size_t bytes_written =
WriteAll(&ch, 1, status,
nullptr);
89 (uint64_t)bytes_written, ch);
98 const size_t bytes_written =
WriteAll(&ch, 1, status,
nullptr);
100 (uint64_t)bytes_written, ch);
102 return bytes_written;
109 packet.
Write(payload.data(), payload.size());
112 std::string packet_str = std::string(packet.
GetString());
119 llvm::StringRef notify_type, std::deque<std::string> &queue,
120 llvm::StringRef payload) {
128 packet.
Write(notify_type.data(), notify_type.size());
130 packet.
Write(payload.data(), payload.size());
136 queue.push_back(payload.str());
144 if (delay.count() > 0)
145 std::this_thread::sleep_for(delay);
150 const char *packet_data = packet.data();
151 const size_t packet_length = packet.size();
152 size_t bytes_written =
WriteAll(packet_data, packet_length, status,
nullptr);
154 size_t binary_start_offset = 0;
155 if (strncmp(packet_data,
"$vFile:pwrite:", strlen(
"$vFile:pwrite:")) ==
157 const char *first_comma = strchr(packet_data,
',');
159 const char *second_comma = strchr(first_comma + 1,
',');
161 binary_start_offset = second_comma - packet_data + 1;
172 if (binary_start_offset) {
175 strm.
Printf(
"%s <%4" PRIu64
"> send packet: %.*s",
m_name.c_str(),
176 (uint64_t)bytes_written, (
int)binary_start_offset,
180 for (p = (
const uint8_t *)packet_data + binary_start_offset; *p !=
'#';
182 strm.
Printf(
"\\x%2.2x", *p);
184 strm.
Printf(
"%*s", (
int)3, p);
188 (uint64_t)bytes_written, (
int)packet_length, packet_data);
191 m_history.AddPacket(packet.str(), packet_length,
194 if (bytes_written == packet_length) {
200 LLDB_LOGF(log,
"error: failed to send packet: %.*s", (
int)packet_length,
223 bool sync_on_timeout) {
241 bool sync_on_timeout) {
242 uint8_t buffer[8192];
255 llvm_unreachable(
"unreachable");
258 bool timed_out =
false;
259 bool disconnected =
false;
262 size_t bytes_read =
Read(buffer,
sizeof(buffer), timeout, status, &
error);
265 "Read(buffer, sizeof(buffer), timeout = {0}, "
266 "status = {1}, error = {2}) => bytes_read = {3}",
270 if (bytes_read > 0) {
278 llvm_unreachable(
"unreachable");
284 if (sync_on_timeout) {
307 bool sync_success =
false;
308 bool got_actual_response =
false;
310 char echo_packet[32];
311 int echo_packet_len = 0;
315 echo_packet_len = ::snprintf(echo_packet,
sizeof(echo_packet),
317 std::string regex_str =
"^";
318 regex_str += echo_packet;
323 ::snprintf(echo_packet,
sizeof(echo_packet),
"qC");
331 const uint32_t max_retries = 3;
332 uint32_t successful_responses = 0;
333 for (uint32_t i = 0; i < max_retries; ++i) {
338 ++successful_responses;
342 }
else if (successful_responses == 1) {
347 packet = echo_response;
348 got_actual_response =
true;
362 if (got_actual_response) {
406 size_t pkt_size =
m_bytes.size();
419 size_t hash_mark_idx =
m_bytes.find(
'#');
420 if (hash_mark_idx == std::string::npos)
422 if (hash_mark_idx + 2 >=
m_bytes.size())
425 if (!::isxdigit(
m_bytes[hash_mark_idx + 1]) ||
426 !::isxdigit(
m_bytes[hash_mark_idx + 2]))
429 size_t content_length =
432 size_t content_start = 2;
434 size_t checksum_idx =
442 size_t size_of_first_packet = hash_mark_idx + 3;
449 uint64_t decompressed_bufsize = ULONG_MAX;
451 size_t i = content_start;
452 while (i < hash_mark_idx && isdigit(
m_bytes[i]))
454 if (i < hash_mark_idx &&
m_bytes[i] ==
':') {
457 content_length = hash_mark_idx - content_start;
458 std::string bufsize_str(
m_bytes.data() + 2, i - 2 - 1);
460 decompressed_bufsize = ::strtoul(bufsize_str.c_str(),
nullptr, 10);
461 if (errno != 0 || decompressed_bufsize == ULONG_MAX) {
462 m_bytes.erase(0, size_of_first_packet);
469 char packet_checksum_cstr[3];
470 packet_checksum_cstr[0] =
m_bytes[checksum_idx];
471 packet_checksum_cstr[1] =
m_bytes[checksum_idx + 1];
472 packet_checksum_cstr[2] =
'\0';
473 long packet_checksum = strtol(packet_checksum_cstr,
nullptr, 16);
476 llvm::StringRef(
m_bytes).substr(1, hash_mark_idx - 1));
477 bool success = packet_checksum == actual_checksum;
480 "error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x",
481 (
int)(pkt_size),
m_bytes.c_str(), (uint8_t)packet_checksum,
482 (uint8_t)actual_checksum);
487 m_bytes.erase(0, size_of_first_packet);
503 std::vector<uint8_t> unescaped_content;
504 unescaped_content.reserve(content_length);
505 size_t i = content_start;
506 while (i < hash_mark_idx) {
509 unescaped_content.push_back(
m_bytes[i] ^ 0x20);
511 unescaped_content.push_back(
m_bytes[i]);
516 uint8_t *decompressed_buffer =
nullptr;
517 size_t decompressed_bytes = 0;
519 if (decompressed_bufsize != ULONG_MAX) {
520 decompressed_buffer = (uint8_t *)malloc(decompressed_bufsize);
521 if (decompressed_buffer ==
nullptr) {
522 m_bytes.erase(0, size_of_first_packet);
527#if HAVE_LIBCOMPRESSION
532 compression_algorithm compression_type;
534 compression_type = COMPRESSION_LZFSE;
536 compression_type = COMPRESSION_ZLIB;
538 compression_type = COMPRESSION_LZ4_RAW;
540 compression_type = COMPRESSION_LZMA;
543 if (m_decompression_scratch) {
544 free (m_decompression_scratch);
545 m_decompression_scratch =
nullptr;
547 size_t scratchbuf_size = 0;
549 scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZFSE);
551 scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZ4_RAW);
553 scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_ZLIB);
556 compression_decode_scratch_buffer_size(COMPRESSION_LZMA);
557 if (scratchbuf_size > 0) {
558 m_decompression_scratch = (
void*) malloc (scratchbuf_size);
563 if (decompressed_bufsize != ULONG_MAX && decompressed_buffer !=
nullptr) {
564 decompressed_bytes = compression_decode_buffer(
565 decompressed_buffer, decompressed_bufsize,
566 (uint8_t *)unescaped_content.data(), unescaped_content.size(),
567 m_decompression_scratch, compression_type);
573 if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX &&
574 decompressed_buffer !=
nullptr &&
577 memset(&stream, 0,
sizeof(z_stream));
578 stream.next_in = (Bytef *)unescaped_content.data();
579 stream.avail_in = (uInt)unescaped_content.size();
581 stream.next_out = (Bytef *)decompressed_buffer;
582 stream.avail_out = decompressed_bufsize;
583 stream.total_out = 0;
584 stream.zalloc = Z_NULL;
585 stream.zfree = Z_NULL;
586 stream.opaque = Z_NULL;
588 if (inflateInit2(&stream, -15) == Z_OK) {
589 int status = inflate(&stream, Z_NO_FLUSH);
591 if (status == Z_STREAM_END) {
592 decompressed_bytes = stream.total_out;
598 if (decompressed_bytes == 0 || decompressed_buffer ==
nullptr) {
599 if (decompressed_buffer)
600 free(decompressed_buffer);
601 m_bytes.erase(0, size_of_first_packet);
605 std::string new_packet;
606 new_packet.reserve(decompressed_bytes + 6);
607 new_packet.push_back(
m_bytes[0]);
608 new_packet.append((
const char *)decompressed_buffer, decompressed_bytes);
609 new_packet.push_back(
'#');
612 llvm::StringRef((
const char *)decompressed_buffer, decompressed_bytes));
613 char decompressed_checksum_str[3];
614 snprintf(decompressed_checksum_str, 3,
"%02x", decompressed_checksum);
615 new_packet.append(decompressed_checksum_str);
617 new_packet.push_back(
'0');
618 new_packet.push_back(
'0');
621 m_bytes.replace(0, size_of_first_packet, new_packet.data(),
624 free(decompressed_buffer);
630static void AddToLog(llvm::StringRef content, llvm::StringRef payload,
631 uint64_t original_packet_size,
633 bool compression_enabled, llvm::StringRef name) {
645 if (payload.front() ==
'$' && payload.size() > 4)
646 for (
char c : payload)
647 if (!llvm::isPrint(c) && !llvm::isSpace(c)) {
652 uint64_t total_length = payload.size();
654 if (compression_enabled)
655 LLDB_LOGF(log,
"%.*s <%4" PRIu64
":%" PRIu64
"> read packet: %.*s",
656 (
int)name.size(), name.data(), original_packet_size,
657 total_length, (
int)(total_length), payload.data());
659 LLDB_LOGF(log,
"%.*s <%4" PRIu64
"> read packet: %.*s", (
int)name.size(),
660 name.data(), total_length, (
int)(total_length), payload.data());
666 if (compression_enabled)
667 strm.
Printf(
"%.*s <%4" PRIu64
":%" PRIu64
"> read packet: %c",
668 (
int)name.size(), name.data(), original_packet_size,
669 total_length, payload[0]);
671 strm.
Printf(
"%.*s <%4" PRIu64
"> read packet: %c", (
int)name.size(),
672 name.data(), total_length, payload[0]);
673 for (
size_t i = 0; i < content.size(); ++i) {
675 const char ch = content[i];
678 const char escapee = content[++i] ^ 0x20;
679 strm.
Printf(
"%2.2x", escapee);
681 strm.
Printf(
"%2.2x", (uint8_t)ch);
685 strm.
Printf(
"%c%c%c", payload[total_length - 3], payload[total_length - 2],
686 payload[total_length - 1]);
698 if (src && src_len > 0) {
700 LLDB_LOGF(log,
"GDBRemoteCommunication::%s adding %u bytes: %.*s",
701 __FUNCTION__, (uint32_t)src_len, (uint32_t)src_len, src);
703 m_bytes.append((
const char *)src, src_len);
706 bool isNotifyPacket =
false;
712 size_t content_start = 0;
713 size_t content_length = 0;
714 size_t total_length = 0;
715 size_t checksum_idx = std::string::npos;
718 size_t original_packet_size =
m_bytes.size();
730 content_length = total_length = 1;
734 isNotifyPacket =
true;
740 size_t hash_pos =
m_bytes.find(
'#');
741 if (hash_pos != std::string::npos) {
742 if (hash_pos + 2 <
m_bytes.size()) {
743 checksum_idx = hash_pos + 1;
748 content_length = hash_pos - 1;
754 content_length = std::string::npos;
765 const size_t bytes_len =
m_bytes.size();
768 for (idx = 1; !done && idx < bytes_len; ++idx) {
782 LLDB_LOGF(log,
"GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'",
783 __FUNCTION__, idx - 1, idx - 1,
m_bytes.c_str());
788 if (content_length == std::string::npos) {
791 }
else if (total_length > 0) {
794 assert(content_length <=
m_bytes.size());
795 assert(total_length <=
m_bytes.size());
796 assert(content_length <= total_length);
797 size_t content_end = content_start + content_length;
800 llvm::StringRef(
m_bytes).take_front(total_length),
808 auto maybe_packet_str =
810 if (!maybe_packet_str) {
811 m_bytes.erase(0, total_length);
819 assert(checksum_idx <
m_bytes.size());
820 if (::isxdigit(
m_bytes[checksum_idx + 0]) ||
821 ::isxdigit(
m_bytes[checksum_idx + 1])) {
823 const char *packet_checksum_cstr = &
m_bytes[checksum_idx];
824 char packet_checksum = strtol(packet_checksum_cstr,
nullptr, 16);
826 llvm::StringRef(
m_bytes).slice(content_start, content_end));
827 success = packet_checksum == actual_checksum;
830 "error: checksum mismatch: %.*s expected 0x%2.2x, "
832 (
int)(total_length),
m_bytes.c_str(),
833 (uint8_t)packet_checksum, (uint8_t)actual_checksum);
843 LLDB_LOGF(log,
"error: invalid checksum in packet: '%s'\n",
848 m_bytes.erase(0, total_length);
886 std::variant<llvm::StringRef, shared_fd_t> comm,
892#if !defined(__APPLE__)
903 llvm::SmallString<128> named_pipe_path;
912 if (
shared_fd_t *comm_fd = std::get_if<shared_fd_t>(&comm)) {
913 LLDB_LOG(log,
"debugserver communicates over fd {0}", comm_fd);
915 debugserver_args.
AppendArgument(llvm::formatv(
"--fd={0}", *comm_fd).str());
920 llvm::StringRef url = std::get<llvm::StringRef>(comm);
921 LLDB_LOG(log,
"debugserver listens on: {0}", url);
924#if defined(__APPLE__)
949 std::string env_debugserver_log_file =
950 host_env.lookup(
"LLDB_DEBUGSERVER_LOG_FILE");
951 if (!env_debugserver_log_file.empty()) {
953 llvm::formatv(
"--log-file={0}", env_debugserver_log_file).str());
956#if defined(__APPLE__)
957 const char *env_debugserver_log_flags = getenv(
"LLDB_DEBUGSERVER_LOG_FLAGS");
958 if (env_debugserver_log_flags) {
960 llvm::formatv(
"--log-flags={0}", env_debugserver_log_flags).str());
963 std::string env_debugserver_log_channels =
964 host_env.lookup(
"LLDB_SERVER_LOG_CHANNELS");
965 if (!env_debugserver_log_channels.empty()) {
967 llvm::formatv(
"--log-channels={0}", env_debugserver_log_channels)
974 uint32_t env_var_index = 1;
977 char env_var_name[64];
978 snprintf(env_var_name,
sizeof(env_var_name),
979 "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++);
980 std::string extra_arg = host_env.lookup(env_var_name);
981 has_env_var = !extra_arg.empty();
986 "GDBRemoteCommunication::%s adding env var %s contents "
987 "to stub command line (%s)",
988 __FUNCTION__, env_var_name, extra_arg.c_str());
990 }
while (has_env_var);
1012 Platform *
const platform =
nullptr;
1013 launch_info.
Dump(string_stream, platform);
1014 LLDB_LOG(log,
"launch info for gdb-remote stub:\n{0}",
1022 if (std::holds_alternative<shared_fd_t>(comm))
1026 if (named_pipe_path.size() > 0) {
1029 LLDB_LOG(log,
"failed to open named pipe {0} for reading: {1}",
1030 named_pipe_path,
error);
1036 assert(socket_pipe.
CanRead());
1039 while (
error.Success()) {
1041 if (llvm::Expected<size_t> num_bytes =
1042 socket_pipe.
Read(buf, std::size(buf), std::chrono::seconds(10))) {
1043 if (*num_bytes == 0)
1050 LLDB_LOG(log,
"failed to synchronize on pipe {0}: {1}", named_pipe_path,
1053 socket_pipe.
Close();
1055 if (named_pipe_path.size() > 0) {
1057 LLDB_LOG(log,
"failed to delete pipe {0}: {1}", named_pipe_path, err);
1071 if (curr_timeout < timeout) {
1083void llvm::format_provider<GDBRemoteCommunication::PacketResult>::format(
1093 Stream <<
"ErrorSendFailed";
1096 Stream <<
"ErrorSendAck";
1099 Stream <<
"ErrorReplyFailed";
1102 Stream <<
"ErrorReplyTimeout";
1105 Stream <<
"ErrorReplyInvalid";
1108 Stream <<
"ErrorReplyAck";
1111 Stream <<
"ErrorDisconnected";
1114 Stream <<
"ErrorNoSequenceLock";
1119std::optional<std::string>
1122 std::string decoded;
1123 decoded.reserve(packet.size());
1124 for (std::string::const_iterator c = packet.begin(); c != packet.end(); ++c) {
1126 if (decoded.empty())
1127 return std::nullopt;
1130 char char_to_repeat = decoded.back();
1132 if (++c == packet.end())
1133 return std::nullopt;
1134 int repeat_count = *c + 3 -
' ';
1137 for (
int i = 0; i < repeat_count; ++i)
1138 decoded.push_back(char_to_repeat);
1139 }
else if (*c == 0x7d) {
1142 if (++c == packet.end())
1143 return std::nullopt;
1144 char escapee = *c ^ 0x20;
1145 decoded.push_back(escapee);
1147 decoded.push_back(*c);
static llvm::raw_ostream & error(Stream &strm)
static void AddToLog(llvm::StringRef content, llvm::StringRef payload, uint64_t original_packet_size, GDBRemoteCommunicationHistory &history, bool compression_enabled, llvm::StringRef name)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_LOGF(log,...)
#define LLDB_LOG_VERBOSE(log,...)
A command line argument class.
void AppendArguments(const Args &rhs)
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
virtual size_t Read(void *dst, size_t dst_len, const Timeout< std::micro > &timeout, lldb::ConnectionStatus &status, Status *error_ptr)
Read bytes from the current connection.
bool IsConnected() const
Check if the connection is valid.
size_t WriteAll(const void *src, size_t src_len, lldb::ConnectionStatus &status, Status *error_ptr)
Repeatedly attempt writing until either src_len bytes are written or a permanent failure occurs.
Communication()
Construct the Communication object.
virtual lldb::ConnectionStatus Disconnect(Status *error_ptr=nullptr)
Disconnect the communications connection if one is currently connected.
static std::string ConnectionStatusAsString(lldb::ConnectionStatus status)
static Status LaunchProcess(ProcessLaunchInfo &launch_info)
Launch the process specified in launch_info.
static Environment GetEnvironment()
void PutString(llvm::StringRef str)
lldb::pipe_t GetWritePipe() const override
void CloseWriteFileDescriptor() override
Status CreateNew() override
bool CanWrite() const override
bool CanRead() const override
llvm::Expected< size_t > Read(void *buf, size_t size, const Timeout< std::micro > &timeout=std::nullopt) override
Status Delete(llvm::StringRef name) override
Status OpenAsReader(llvm::StringRef name) override
Status CreateWithUniqueName(llvm::StringRef prefix, llvm::SmallVectorImpl< char > &name) override
void Dump(Stream &s, Platform *platform) const
Environment & GetEnvironment()
bool AppendSuppressFileAction(int fd, bool read, bool write)
bool AppendCloseFileAction(int fd)
bool AppendDuplicateFileAction(int fd, int dup_fd)
bool GetLaunchInSeparateProcessGroup() const
bool Execute(llvm::StringRef string, llvm::SmallVectorImpl< llvm::StringRef > *matches=nullptr) const
Execute a regular expression match using the compiled regular expression that is already in this obje...
static const shared_fd_t kInvalidFD
bool Fail() const
Test for error condition.
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
const char * GetData() const
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
size_t Write(const void *src, size_t src_len)
Output character bytes to the stream.
size_t size_t PutHex8(uint8_t uvalue)
Append an uint8_t value in the hexadecimal format to the stream.
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
The history keeps a circular buffer of GDB remote packets.
void Dump(Stream &strm) const
bool DidDumpToLog() const
std::chrono::seconds m_saved_timeout
GDBRemoteCommunication & m_gdb_comm
ScopedTimeout(GDBRemoteCommunication &gdb_comm, std::chrono::seconds timeout)
const std::string m_name
The communication channel name included in packet logs.
PacketResult ReadPacket(StringExtractorGDBRemote &response, Timeout< std::micro > timeout, bool sync_on_timeout)
GDBRemoteCommunication(llvm::StringRef name)
Construct a GDB-remote communication channel named name.
char CalculcateChecksum(llvm::StringRef payload)
~GDBRemoteCommunication() override
PacketResult SendNotificationPacketNoLock(llvm::StringRef notify_type, std::deque< std::string > &queue, llvm::StringRef payload)
std::recursive_mutex m_bytes_mutex
PacketResult WaitForPacketNoLock(StringExtractorGDBRemote &response, Timeout< std::micro > timeout, bool sync_on_timeout)
void DumpHistory(Stream &strm)
bool CompressionIsEnabled()
LazyBool m_supports_qEcho
PacketResult SendRawPacketNoLock(llvm::StringRef payload, bool skip_ack=false)
CompressionType m_compression_type
static Status StartDebugserverProcess(std::variant< llvm::StringRef, shared_fd_t > comm, ProcessLaunchInfo &launch_info, const Args *inferior_args)
PacketResult SendPacketNoLock(llvm::StringRef payload)
PacketType CheckForPacketIgnoreNotifications(const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet)
static std::optional< std::string > ExpandRLE(std::string)
Expand GDB run-length encoding.
std::chrono::seconds GetPacketTimeout() const
std::chrono::seconds m_packet_timeout
PacketType CheckForPacket(const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet)
GDBRemoteCommunicationHistory m_history
static std::chrono::milliseconds GetPacketTestDelay()
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
ConnectionStatus
Connection Status Types.
@ eConnectionStatusError
Check GetError() for details.
@ eConnectionStatusInterrupted
Interrupted read.
@ eConnectionStatusTimedOut
Request timed out.
@ eConnectionStatusEndOfFile
End-of-file encountered.
@ eConnectionStatusSuccess
Success.
@ eConnectionStatusLostConnection
Lost connection while connected to a valid connection.
@ eConnectionStatusNoConnection
No connection.