diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:09:23 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:09:23 +0000 |
commit | f73363f1dd94996356cefbf24388f561891acf0b (patch) | |
tree | e3c31248bdb36eaec5fd833490d4278162dba2a0 /source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp | |
parent | 160ee69dd7ae18978f4068116777639ea98dc951 (diff) |
Notes
Diffstat (limited to 'source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp')
-rw-r--r-- | source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp | 203 |
1 files changed, 98 insertions, 105 deletions
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 949cf19db658a..c335b60028619 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -150,9 +150,8 @@ GDBRemoteCommunication::~GDBRemoteCommunication() { Disconnect(); } - // Stop the communications read thread which is used to parse all - // incoming packets. This function will block until the read - // thread returns. + // Stop the communications read thread which is used to parse all incoming + // packets. This function will block until the read thread returns. if (m_read_thread_enabled) StopReadThread(); } @@ -217,12 +216,10 @@ GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) { } } - // If logging was just enabled and we have history, then dump out what - // we have to the log so we get the historical context. The Dump() call - // that + // If logging was just enabled and we have history, then dump out what we + // have to the log so we get the historical context. The Dump() call that // logs all of the packet will set a boolean so that we don't dump this - // more - // than once + // more than once if (!m_history.DidDumpToLog()) m_history.Dump(log); @@ -275,6 +272,23 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunication::GetAck() { } GDBRemoteCommunication::PacketResult +GDBRemoteCommunication::ReadPacketWithOutputSupport( + StringExtractorGDBRemote &response, Timeout<std::micro> timeout, + bool sync_on_timeout, + llvm::function_ref<void(llvm::StringRef)> output_callback) { + auto result = ReadPacket(response, timeout, sync_on_timeout); + while (result == PacketResult::Success && response.IsNormalResponse() && + response.PeekChar() == 'O') { + response.GetChar(); + std::string output; + if (response.GetHexByteString(output)) + output_callback(output); + result = ReadPacket(response, timeout, sync_on_timeout); + } + return result; +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::ReadPacket(StringExtractorGDBRemote &response, Timeout<std::micro> timeout, bool sync_on_timeout) { @@ -286,8 +300,8 @@ GDBRemoteCommunication::ReadPacket(StringExtractorGDBRemote &response, // This function is called when a packet is requested. // A whole packet is popped from the packet queue and returned to the caller. -// Packets are placed into this queue from the communication read thread. -// See GDBRemoteCommunication::AppendBytesToCache. +// Packets are placed into this queue from the communication read thread. See +// GDBRemoteCommunication::AppendBytesToCache. GDBRemoteCommunication::PacketResult GDBRemoteCommunication::PopPacketFromQueue(StringExtractorGDBRemote &response, Timeout<std::micro> timeout) { @@ -407,11 +421,9 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, break; } else if (successful_responses == 1) { // We got something else back as the first successful - // response, it probably is - // the response to the packet we actually wanted, so copy it - // over if this - // is the first success and continue to try to get the qEcho - // response + // response, it probably is the response to the packet we + // actually wanted, so copy it over if this is the first + // success and continue to try to get the qEcho response packet = echo_response; got_actual_response = true; } @@ -424,14 +436,13 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, } // We weren't able to sync back up with the server, we must abort - // otherwise - // all responses might not be from the right packets... + // otherwise all responses might not be from the right packets... if (sync_success) { // We timed out, but were able to recover if (got_actual_response) { // We initially timed out, but we did get a response that came in - // before the successful - // reply to our qEcho packet, so lets say everything is fine... + // before the successful reply to our qEcho packet, so lets say + // everything is fine... return PacketResult::Success; } } else { @@ -473,10 +484,9 @@ bool GDBRemoteCommunication::DecompressPacket() { size_t pkt_size = m_bytes.size(); - // Smallest possible compressed packet is $N#00 - an uncompressed empty reply, - // most commonly indicating - // an unsupported packet. Anything less than 5 characters, it's definitely - // not a compressed packet. + // Smallest possible compressed packet is $N#00 - an uncompressed empty + // reply, most commonly indicating an unsupported packet. Anything less than + // 5 characters, it's definitely not a compressed packet. if (pkt_size < 5) return true; @@ -505,17 +515,15 @@ bool GDBRemoteCommunication::DecompressPacket() { 1; // The first character of the two hex checksum characters // Normally size_of_first_packet == m_bytes.size() but m_bytes may contain - // multiple packets. - // size_of_first_packet is the size of the initial packet which we'll replace - // with the decompressed - // version of, leaving the rest of m_bytes unmodified. + // multiple packets. size_of_first_packet is the size of the initial packet + // which we'll replace with the decompressed version of, leaving the rest of + // m_bytes unmodified. size_t size_of_first_packet = hash_mark_idx + 3; // Compressed packets ("$C") start with a base10 number which is the size of - // the uncompressed payload, - // then a : and then the compressed data. e.g. $C1024:<binary>#00 - // Update content_start and content_length to only include the <binary> part - // of the packet. + // the uncompressed payload, then a : and then the compressed data. e.g. + // $C1024:<binary>#00 Update content_start and content_length to only include + // the <binary> part of the packet. uint64_t decompressed_bufsize = ULONG_MAX; if (m_bytes[1] == 'C') { @@ -564,15 +572,14 @@ bool GDBRemoteCommunication::DecompressPacket() { } if (m_bytes[1] == 'N') { - // This packet was not compressed -- delete the 'N' character at the - // start and the packet may be processed as-is. + // This packet was not compressed -- delete the 'N' character at the start + // and the packet may be processed as-is. m_bytes.erase(1, 1); return true; } - // Reverse the gdb-remote binary escaping that was done to the compressed text - // to - // guard characters like '$', '#', '}', etc. + // Reverse the gdb-remote binary escaping that was done to the compressed + // text to guard characters like '$', '#', '}', etc. std::vector<uint8_t> unescaped_content; unescaped_content.reserve(content_length); size_t i = content_start; @@ -613,12 +620,10 @@ bool GDBRemoteCommunication::DecompressPacket() { else if (m_compression_type == CompressionType::LZMA) compression_type = COMPRESSION_LZMA; - // If we have the expected size of the decompressed payload, we can allocate - // the right-sized buffer and do it. If we don't have that information, - // we'll - // need to try decoding into a big buffer and if the buffer wasn't big - // enough, - // increase it and try again. + // If we have the expected size of the decompressed payload, we can + // allocate the right-sized buffer and do it. If we don't have that + // information, we'll need to try decoding into a big buffer and if the + // buffer wasn't big enough, increase it and try again. if (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr) { decompressed_bytes = compression_decode_buffer( @@ -706,9 +711,8 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, // Parse up the packets into gdb remote packets if (!m_bytes.empty()) { - // end_idx must be one past the last valid packet byte. Start - // it off with an invalid value that is the same as the current - // index. + // end_idx must be one past the last valid packet byte. Start it off with + // an invalid value that is the same as the current index. size_t content_start = 0; size_t content_length = 0; size_t total_length = 0; @@ -743,7 +747,8 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, checksum_idx = hash_pos + 1; // Skip the dollar sign content_start = 1; - // Don't include the # in the content or the $ in the content length + // Don't include the # in the content or the $ in the content + // length content_length = hash_pos - 1; total_length = @@ -757,11 +762,10 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, break; default: { - // We have an unexpected byte and we need to flush all bad - // data that is in m_bytes, so we need to find the first - // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt), - // or '$' character (start of packet header) or of course, - // the end of the data in m_bytes... + // We have an unexpected byte and we need to flush all bad data that is + // in m_bytes, so we need to find the first byte that is a '+' (ACK), '-' + // (NACK), \x03 (CTRL+C interrupt), or '$' character (start of packet + // header) or of course, the end of the data in m_bytes... const size_t bytes_len = m_bytes.size(); bool done = false; uint32_t idx; @@ -802,16 +806,14 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, if (log) { // If logging was just enabled and we have history, then dump out what // we have to the log so we get the historical context. The Dump() call - // that - // logs all of the packet will set a boolean so that we don't dump this - // more - // than once + // that logs all of the packet will set a boolean so that we don't dump + // this more than once if (!m_history.DidDumpToLog()) m_history.Dump(log); bool binary = false; - // Only detect binary for packets that start with a '$' and have a '#CC' - // checksum + // Only detect binary for packets that start with a '$' and have a + // '#CC' checksum if (m_bytes[0] == '$' && total_length > 4) { for (size_t i = 0; !binary && i < total_length; ++i) { unsigned char c = m_bytes[i]; @@ -834,8 +836,8 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, // Remove binary escaped bytes when displaying the packet... const char ch = m_bytes[i]; if (ch == 0x7d) { - // 0x7d is the escape character. The next character is to - // be XOR'd with 0x20. + // 0x7d is the escape character. The next character is to be + // XOR'd with 0x20. const char escapee = m_bytes[++i] ^ 0x20; strm.Printf("%2.2x", escapee); } else { @@ -863,26 +865,25 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, // Clear packet_str in case there is some existing data in it. packet_str.clear(); - // Copy the packet from m_bytes to packet_str expanding the - // run-length encoding in the process. - // Reserve enough byte for the most common case (no RLE used) + // Copy the packet from m_bytes to packet_str expanding the run-length + // encoding in the process. Reserve enough byte for the most common case + // (no RLE used) packet_str.reserve(m_bytes.length()); for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_end; ++c) { if (*c == '*') { - // '*' indicates RLE. Next character will give us the - // repeat count and previous character is what is to be - // repeated. + // '*' indicates RLE. Next character will give us the repeat count + // and previous character is what is to be repeated. char char_to_repeat = packet_str.back(); // Number of time the previous character is repeated int repeat_count = *++c + 3 - ' '; - // We have the char_to_repeat and repeat_count. Now push - // it in the packet. + // We have the char_to_repeat and repeat_count. Now push it in the + // packet. for (int i = 0; i < repeat_count; ++i) packet_str.push_back(char_to_repeat); } else if (*c == 0x7d) { - // 0x7d is the escape character. The next character is to - // be XOR'd with 0x20. + // 0x7d is the escape character. The next character is to be XOR'd + // with 0x20. char escapee = *++c ^ 0x20; packet_str.push_back(escapee); } else { @@ -897,7 +898,8 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, if (GetSendAcks()) { const char *packet_checksum_cstr = &m_bytes[checksum_idx]; char packet_checksum = strtol(packet_checksum_cstr, NULL, 16); - char actual_checksum = CalculcateChecksum(packet_str); + char actual_checksum = CalculcateChecksum( + llvm::StringRef(m_bytes).slice(content_start, content_end)); success = packet_checksum == actual_checksum; if (!success) { if (log) @@ -991,11 +993,12 @@ Status GDBRemoteCommunication::StartDebugserverProcess( char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); - // Always check to see if we have an environment override for the path - // to the debugserver to use and use it if we do. + // Always check to see if we have an environment override for the path to the + // debugserver to use and use it if we do. const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); if (env_debugserver_path) { - debugserver_file_spec.SetFile(env_debugserver_path, false); + debugserver_file_spec.SetFile(env_debugserver_path, false, + FileSpec::Style::native); if (log) log->Printf("GDBRemoteCommunication::%s() gdb-remote stub exe path set " "from environment variable: %s", @@ -1004,10 +1007,9 @@ Status GDBRemoteCommunication::StartDebugserverProcess( debugserver_file_spec = g_debugserver_file_spec; bool debugserver_exists = debugserver_file_spec.Exists(); if (!debugserver_exists) { - // The debugserver binary is in the LLDB.framework/Resources - // directory. - if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, - debugserver_file_spec)) { + // The debugserver binary is in the LLDB.framework/Resources directory. + debugserver_file_spec = HostInfo::GetSupportExeDir(); + if (debugserver_file_spec) { debugserver_file_spec.AppendPathComponent(DEBUGSERVER_BASENAME); debugserver_exists = debugserver_file_spec.Exists(); if (debugserver_exists) { @@ -1031,8 +1033,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( __FUNCTION__, debugserver_file_spec.GetPath().c_str()); } // Don't cache the platform specific GDB server binary as it could - // change - // from platform to platform + // change from platform to platform g_debugserver_file_spec.Clear(); } } @@ -1080,14 +1081,14 @@ Status GDBRemoteCommunication::StartDebugserverProcess( // once data is written to the pipe, debug server is up and running. Pipe socket_pipe; - // port is null when debug server should listen on domain socket - - // we're not interested in port value but rather waiting for debug server - // to become available. + // port is null when debug server should listen on domain socket - we're + // not interested in port value but rather waiting for debug server to + // become available. if (pass_comm_fd == -1) { if (url) { -// Create a temporary file to get the stdout/stderr and redirect the -// output of the command into this file. We will later read this file -// if all goes well and fill the data into "command_output_ptr" +// Create a temporary file to get the stdout/stderr and redirect the output of +// the command into this file. We will later read this file if all goes well +// and fill the data into "command_output_ptr" #if defined(__APPLE__) // Binding to port zero, we need to figure out what port it ends up // using using a named pipe... @@ -1120,8 +1121,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( #endif } else { // No host and port given, so lets listen on our end and make the - // debugserver - // connect to us.. + // debugserver connect to us.. error = StartListenThread("127.0.0.1", 0); if (error.Fail()) { if (log) @@ -1134,7 +1134,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection(); // Wait for 10 seconds to resolve the bound port - uint16_t port_ = connection->GetListeningPort(10); + uint16_t port_ = connection->GetListeningPort(std::chrono::seconds(10)); if (port_ > 0) { char port_cstr[32]; snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", port_); @@ -1206,11 +1206,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( } // Copy the current environment to the gdbserver/debugserver instance - StringList env; - if (Host::GetEnvironment(env)) { - for (size_t i = 0; i < env.GetSize(); ++i) - launch_info.GetEnvironmentEntries().AppendArgument(env[i]); - } + launch_info.GetEnvironment() = Host::GetEnvironment(); // Close STDIN, STDOUT and STDERR. launch_info.AppendCloseFileAction(STDIN_FILENO); @@ -1327,14 +1323,11 @@ GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout() { } // This function is called via the Communications class read thread when bytes -// become available -// for this connection. This function will consume all incoming bytes and try to -// parse whole -// packets as they become available. Full packets are placed in a queue, so that -// all packet -// requests can simply pop from this queue. Async notification packets will be -// dispatched -// immediately to the ProcessGDBRemote Async thread via an event. +// become available for this connection. This function will consume all +// incoming bytes and try to parse whole packets as they become available. Full +// packets are placed in a queue, so that all packet requests can simply pop +// from this queue. Async notification packets will be dispatched immediately +// to the ProcessGDBRemote Async thread via an event. void GDBRemoteCommunication::AppendBytesToCache(const uint8_t *bytes, size_t len, bool broadcast, lldb::ConnectionStatus status) { @@ -1343,8 +1336,8 @@ void GDBRemoteCommunication::AppendBytesToCache(const uint8_t *bytes, while (true) { PacketType type = CheckForPacket(bytes, len, packet); - // scrub the data so we do not pass it back to CheckForPacket - // on future passes of the loop + // scrub the data so we do not pass it back to CheckForPacket on future + // passes of the loop bytes = nullptr; len = 0; @@ -1368,8 +1361,8 @@ void GDBRemoteCommunication::AppendBytesToCache(const uint8_t *bytes, // put this packet into an event const char *pdata = packet.GetStringRef().c_str(); - // as the communication class, we are a broadcaster and the - // async thread is tuned to listen to us + // as the communication class, we are a broadcaster and the async thread + // is tuned to listen to us BroadcastEvent(eBroadcastBitGdbReadThreadGotNotify, new EventDataBytes(pdata)); } |