Index: include/lldb/Core/Event.h =================================================================== --- include/lldb/Core/Event.h +++ include/lldb/Core/Event.h @@ -24,6 +24,8 @@ #include "lldb/Host/Predicate.h" #include "lldb/Core/Broadcaster.h" +#include "llvm/ADT/StringRef.h" + namespace lldb_private { //---------------------------------------------------------------------- @@ -65,6 +67,8 @@ //------------------------------------------------------------------ EventDataBytes (); + EventDataBytes::EventDataBytes(llvm::StringRef str); + EventDataBytes (const char *cstr); EventDataBytes (const void *src, size_t src_len); Index: include/lldb/Core/RegularExpression.h =================================================================== --- include/lldb/Core/RegularExpression.h +++ include/lldb/Core/RegularExpression.h @@ -11,6 +11,7 @@ #define liblldb_RegularExpression_h_ #ifdef _WIN32 +// TODO: We should not be including LLDB private headers. #include "../lib/Support/regex_impl.h" typedef llvm_regmatch_t regmatch_t; Index: include/lldb/Utility/StringExtractor.h =================================================================== --- include/lldb/Utility/StringExtractor.h +++ include/lldb/Utility/StringExtractor.h @@ -44,6 +44,13 @@ operator=(const StringExtractor& rhs); void + Reset() + { + m_packet.clear(); + m_index = 0; + } + + void Reset(llvm::StringRef str) { m_packet = str; @@ -80,16 +87,11 @@ void SkipSpaces (); - std::string & - GetStringRef () - { - return m_packet; - } - - const std::string & - GetStringRef () const + void + SetString(llvm::StringRef str) { - return m_packet; + m_packet = str; + m_index = 0; } bool @@ -99,18 +101,27 @@ } size_t - GetBytesLeft () + GetTotalBytes() const + { + return m_packet.size(); + } + + size_t + GetBytesLeft() const { if (m_index < m_packet.size()) return m_packet.size() - m_index; return 0; } + bool + Consume(llvm::StringRef Str); + char GetChar (char fail_value = '\0'); char - PeekChar (char fail_value = '\0') + PeekChar(char fail_value = '\0') const { llvm::StringRef str = Peek(); if (str.empty()) @@ -172,6 +183,12 @@ return llvm::StringRef(m_packet).drop_front(m_index); } + llvm::StringRef + PeekFullPacket() const + { + return m_packet; + } + protected: bool fail() Index: source/Core/Event.cpp =================================================================== --- source/Core/Event.cpp +++ source/Core/Event.cpp @@ -138,6 +138,11 @@ { } +EventDataBytes::EventDataBytes(llvm::StringRef str) : m_bytes() +{ + SetBytes(str.data(), str.size()); +} + EventDataBytes::EventDataBytes (const char *cstr) : m_bytes() { Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -891,7 +891,7 @@ response.GetResponseType() != response.eResponse) return m_remote_signals_sp; - auto object_sp = StructuredData::ParseJSON(response.GetStringRef()); + auto object_sp = StructuredData::ParseJSON(response.Peek()); if (!object_sp || !object_sp->IsValid()) return m_remote_signals_sp; Index: source/Plugins/Process/Utility/DynamicRegisterInfo.cpp =================================================================== --- source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -303,9 +303,7 @@ std::vector dwarf_opcode_bytes(reg_info.dynamic_size_dwarf_len); uint32_t j; - StringExtractor opcode_extractor; - // Swap "dwarf_opcode_string" over into "opcode_extractor" - opcode_extractor.GetStringRef ().swap (dwarf_opcode_string); + StringExtractor opcode_extractor(dwarf_opcode_string); uint32_t ret_val = opcode_extractor.GetHexBytesAvail (dwarf_opcode_bytes); assert (ret_val == reg_info.dynamic_size_dwarf_len); Index: source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -77,7 +77,8 @@ const char stop_type = response.GetChar(); if (log) - log->Printf("GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__, response.GetStringRef().c_str()); + log->Printf("GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__, + response.PeekFullPacket().str().c_str()); switch (stop_type) { @@ -99,27 +100,29 @@ break; } case 'A': - delegate.HandleAsyncMisc(llvm::StringRef(response.GetStringRef()).substr(1)); + delegate.HandleAsyncMisc(response.Peek().drop_front()); break; case 'J': + { // Asynchronous JSON packet, destined for a // StructuredDataPlugin. - { - // Parse the content into a StructuredData instance. - auto payload_index = strlen("JSON-async:"); - StructuredData::ObjectSP json_sp = - StructuredData::ParseJSON(response.GetStringRef() - .substr(payload_index)); + + StructuredData::ObjectSP json_sp; + llvm::StringRef json_text; + // The 'J' was already consumed. + if (response.Consume("SON-async:")) + { + // Parse the content into a StructuredData instance. + json_sp = StructuredData::ParseJSON(json_text = response.Peek()); + } + if (log) { if (json_sp) - log->Printf( - "GDBRemoteCommmunicationClientBase::%s() " + log->Printf("GDBRemoteCommmunicationClientBase::%s() " "received Async StructuredData packet: %s", - __FUNCTION__, - response.GetStringRef(). - substr(payload_index).c_str()); + __FUNCTION__, json_text.str().c_str()); else log->Printf("GDBRemoteCommmunicationClientBase::%s" "() received StructuredData packet:" @@ -234,7 +237,7 @@ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS); if (log) log->Printf("error: packet with payload \"%.*s\" got invalid response \"%s\": %s", int(payload.size()), - payload.data(), response.GetStringRef().c_str(), + payload.data(), response.Peek().str().c_str(), (i == (max_response_retries - 1)) ? "using invalid response and giving up" : "ignoring response and waiting for another"); } Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -467,7 +467,7 @@ if (echo_packet_result == PacketResult::Success) { ++successful_responses; - if (response_regex.Execute(echo_response.GetStringRef().c_str())) + if (response_regex.Execute(echo_response.Peek().str().c_str())) { sync_success = true; break; @@ -896,7 +896,6 @@ size_t content_end = content_start + content_length; bool success = true; - std::string &packet_str = packet.GetStringRef(); if (log) { // If logging was just enabled and we have history, then dump out what @@ -957,8 +956,7 @@ m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length); - // Clear packet_str in case there is some existing data in it. - packet_str.clear(); + std::string packet_str; // 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) @@ -1026,9 +1024,9 @@ log->Printf ("error: invalid checksum in packet: '%s'\n", m_bytes.c_str()); } } - + m_bytes.erase(0, total_length); - packet.SetFilePos(0); + packet.SetString(packet_str); if (isNotifyPacket) return GDBRemoteCommunication::PacketType::Notify; @@ -1476,14 +1474,9 @@ if (type == PacketType::Notify) { - // 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 - BroadcastEvent( - eBroadcastBitGdbReadThreadGotNotify, - new EventDataBytes(pdata)); + BroadcastEvent(eBroadcastBitGdbReadThreadGotNotify, new EventDataBytes(packet.Peek())); } } } Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -676,7 +676,7 @@ // Given the list of compression types that the remote debug stub can support, // possibly enable compression if we find an encoding we can handle. void - MaybeEnableCompression (std::vector supported_compressions); + MaybeEnableCompression(std::vector supported_compressions); bool DecodeProcessInfoResponse (StringExtractorGDBRemote &response, Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -42,6 +42,7 @@ #include "lldb/Host/Config.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/raw_ostream.h" #if defined (HAVE_LIBCOMPRESSION) #include @@ -419,93 +420,55 @@ } StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetData(), - response, + if (SendPacketAndWaitForResponse(packet.GetData(), response, /*send_async=*/false) == PacketResult::Success) { - const char *response_cstr = response.GetStringRef().c_str(); + llvm::StringRef response_str = response.Peek(); // Hang on to the qSupported packet, so that platforms can do custom // configuration of the transport before attaching/launching the // process. - m_qSupported_response = response_cstr; + m_qSupported_response = response_str; - if (::strstr (response_cstr, "qXfer:auxv:read+")) + if (response_str.contains("qXfer:auxv:read+")) m_supports_qXfer_auxv_read = eLazyBoolYes; - if (::strstr (response_cstr, "qXfer:libraries-svr4:read+")) + if (response_str.contains("qXfer:libraries-svr4:read+")) m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; - if (::strstr (response_cstr, "augmented-libraries-svr4-read")) + if (response_str.contains("augmented-libraries-svr4-read")) { m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied m_supports_augmented_libraries_svr4_read = eLazyBoolYes; } - if (::strstr (response_cstr, "qXfer:libraries:read+")) + if (response_str.contains("qXfer:libraries:read+")) m_supports_qXfer_libraries_read = eLazyBoolYes; - if (::strstr (response_cstr, "qXfer:features:read+")) + if (response_str.contains("qXfer:features:read+")) m_supports_qXfer_features_read = eLazyBoolYes; // Look for a list of compressions in the features list e.g. // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-deflate,lzma - const char *features_list = ::strstr (response_cstr, "qXfer:features:"); - if (features_list) + llvm::StringRef compressions = + response_str.scan_between("qXfer:features:", "").scan_between("SupportedCompressions=", ";"); + std::vector supported_compressions; + while (!compressions.empty()) { - const char *compressions = ::strstr (features_list, "SupportedCompressions="); - if (compressions) - { - std::vector supported_compressions; - compressions += sizeof ("SupportedCompressions=") - 1; - const char *end_of_compressions = strchr (compressions, ';'); - if (end_of_compressions == NULL) - { - end_of_compressions = strchr (compressions, '\0'); - } - const char *current_compression = compressions; - while (current_compression < end_of_compressions) - { - const char *next_compression_name = strchr (current_compression, ','); - const char *end_of_this_word = next_compression_name; - if (next_compression_name == NULL || end_of_compressions < next_compression_name) - { - end_of_this_word = end_of_compressions; - } - - if (end_of_this_word) - { - if (end_of_this_word == current_compression) - { - current_compression++; - } - else - { - std::string this_compression (current_compression, end_of_this_word - current_compression); - supported_compressions.push_back (this_compression); - current_compression = end_of_this_word + 1; - } - } - else - { - supported_compressions.push_back (current_compression); - current_compression = end_of_compressions; - } - } - - if (supported_compressions.size() > 0) - { - MaybeEnableCompression (supported_compressions); - } - } + llvm::StringRef this_compression; + std::tie(this_compression, compressions) = compressions.split(','); + supported_compressions.push_back(this_compression); } - if (::strstr (response_cstr, "qEcho")) + if (!supported_compressions.empty()) + MaybeEnableCompression(supported_compressions); + + if (response_str.contains("qEcho")) m_supports_qEcho = eLazyBoolYes; else m_supports_qEcho = eLazyBoolNo; - const char *packet_size_str = ::strstr (response_cstr, "PacketSize="); - if (packet_size_str) + llvm::StringRef packet_size_str = response_str.scan_between("PacketSize=", ""); + if (!packet_size_str.empty()) { - StringExtractorGDBRemote packet_response(packet_size_str + strlen("PacketSize=")); + StringExtractorGDBRemote packet_response(packet_size_str); m_max_packet_size = packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX); if (m_max_packet_size == 0) { @@ -553,17 +516,17 @@ m_supports_vCont_S = eLazyBoolNo; if (SendPacketAndWaitForResponse("vCont?", response, false) == PacketResult::Success) { - const char *response_cstr = response.GetStringRef().c_str(); - if (::strstr (response_cstr, ";c")) + llvm::StringRef response_str = response.Peek(); + if (response_str.contains(";c")) m_supports_vCont_c = eLazyBoolYes; - if (::strstr (response_cstr, ";C")) + if (response_str.contains(";C")) m_supports_vCont_C = eLazyBoolYes; - if (::strstr (response_cstr, ";s")) + if (response_str.contains(";s")) m_supports_vCont_s = eLazyBoolYes; - if (::strstr (response_cstr, ";S")) + if (response_str.contains(";S")) m_supports_vCont_S = eLazyBoolYes; if (m_supports_vCont_c == eLazyBoolYes && @@ -664,7 +627,7 @@ } else if (!response.Empty()) { - object_sp = StructuredData::ParseJSON (response.GetStringRef()); + object_sp = StructuredData::ParseJSON(response.Peek()); } } } @@ -778,16 +741,13 @@ if (result != PacketResult::Success) return result; - const std::string &this_string = this_response.GetStringRef(); - // Check for m or l as first character; l seems to mean this is the last chunk - char first_char = *this_string.c_str(); + char first_char = this_response.GetChar(); if (first_char != 'm' && first_char != 'l') - { return PacketResult::ErrorReplyInvalid; - } + // Concatenate the result so far (skipping 'm' or 'l') - response_string.append(this_string, 1, std::string::npos); + response_string.append(this_response.Peek()); if (first_char == 'l') // We're done return PacketResult::Success; @@ -861,7 +821,7 @@ if (response.GetChar() == 'E') { // A string the describes what failed when launching... - error_str = response.GetStringRef().substr(1); + error_str = response.Peek(); } else { @@ -1172,7 +1132,7 @@ } void -GDBRemoteCommunicationClient::MaybeEnableCompression (std::vector supported_compressions) +GDBRemoteCommunicationClient::MaybeEnableCompression(std::vector supported_compressions) { CompressionType avail_type = CompressionType::None; std::string avail_name; @@ -2380,8 +2340,7 @@ if (!DecodeProcessInfoResponse (response, process_info)) break; process_infos.Append(process_info); - response.GetStringRef().clear(); - response.SetFilePos(0); + response.Reset(); } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false) == PacketResult::Success); } else @@ -2410,7 +2369,7 @@ // Make sure we parsed the right number of characters. The response is // the hex encoded user name and should make up the entire packet. // If there are any non-hex ASCII bytes, the length won't match below.. - if (response.GetHexByteString (name) * 2 == response.GetStringRef().size()) + if (response.GetHexByteString(name) && !response.GetBytesLeft()) return true; } } @@ -2435,14 +2394,14 @@ StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { - if (response.IsNormalResponse()) - { - // Make sure we parsed the right number of characters. The response is - // the hex encoded group name and should make up the entire packet. - // If there are any non-hex ASCII bytes, the length won't match below.. - if (response.GetHexByteString (name) * 2 == response.GetStringRef().size()) - return true; - } + if (!response.IsNormalResponse()) + return false; + + // Make sure we parsed the right number of characters. The response is + // the hex encoded group name and should make up the entire packet. + // If there are any non-hex ASCII bytes, the length won't match below.. + if (response.GetHexByteString(name) * 2 == response.GetTotalBytes()) + return true; } else { @@ -2720,7 +2679,7 @@ if (SendPacketAndWaitForResponse("qQueryGDBServer", response, false) != PacketResult::Success) return 0; - StructuredData::ObjectSP data = StructuredData::ParseJSON(response.GetStringRef()); + StructuredData::ObjectSP data = StructuredData::ParseJSON(response.Peek()); if (!data) return 0; @@ -3482,7 +3441,7 @@ !response.IsNormalResponse()) return nullptr; - DataBufferSP buffer_sp(new DataBufferHeap(response.GetStringRef().size() / 2, 0)); + DataBufferSP buffer_sp(new DataBufferHeap(response.GetBytesLeft() / 2, 0)); response.GetHexBytes(buffer_sp->GetData(), '\xcc'); return buffer_sp; } @@ -3497,7 +3456,7 @@ !response.IsNormalResponse()) return nullptr; - DataBufferSP buffer_sp(new DataBufferHeap(response.GetStringRef().size() / 2, 0)); + DataBufferSP buffer_sp(new DataBufferHeap(response.GetBytesLeft() / 2, 0)); response.GetHexBytes(buffer_sp->GetData(), '\xcc'); return buffer_sp; } @@ -3695,7 +3654,7 @@ std::string & out, lldb_private::Error & err) { - std::stringstream output; + llvm::raw_string_ostream output(out); StringExtractorGDBRemote chunk; uint64_t size = GetRemoteMaxPacketSize(); @@ -3726,15 +3685,16 @@ return false; } - const std::string & str = chunk.GetStringRef( ); - if ( str.length() == 0 ) { + if (chunk.GetBytesLeft() == 0) + { // should have some data in chunk err.SetErrorString( "Empty response from $qXfer packet" ); return false; } // check packet code - switch ( str[0] ) { + switch (chunk.GetChar()) + { // last chunk case ( 'l' ): active = false; @@ -3742,8 +3702,7 @@ // more chunks case ( 'm' ) : - if ( str.length() > 1 ) - output << &str[1]; + output << chunk.Peek(); offset += size; break; @@ -3754,7 +3713,7 @@ } } - out = output.str( ); + output.flush(); err.Success( ); return true; } @@ -3831,10 +3790,8 @@ } else { - llvm::StringRef response_str(response.GetStringRef()); - if (response_str.startswith("qSymbol:")) + if (response.Consume("qSymbol:")) { - response.SetFilePos(strlen("qSymbol:")); std::string symbol_name; if (response.GetHexByteString(symbol_name)) { @@ -3946,8 +3903,7 @@ if (SendPacketAndWaitForResponse("qStructuredDataPlugins", response, send_async) == PacketResult::Success) { - m_supported_async_json_packets_sp = StructuredData::ParseJSON( - response.GetStringRef()); + m_supported_async_json_packets_sp = StructuredData::ParseJSON(response.Peek()); if (m_supported_async_json_packets_sp && !m_supported_async_json_packets_sp->GetAsArray()) { @@ -3956,8 +3912,8 @@ if (log) log->Printf("GDBRemoteCommunicationClient::%s(): " "QSupportedAsyncJSONPackets returned invalid " - "result: %s", __FUNCTION__, - response.GetStringRef().c_str()); + "result: %s", + __FUNCTION__, response.Peek().str().c_str()); m_supported_async_json_packets_sp.reset(); } } @@ -4024,7 +3980,7 @@ if (result == PacketResult::Success) { // We failed if the config result comes back other than OK. - if (strcmp(response.GetStringRef().c_str(), "OK") == 0) + if (response.Peek().equals("OK")) { // Okay! error.Clear(); @@ -4033,8 +3989,7 @@ { error.SetErrorStringWithFormat("configuring StructuredData feature " "%s failed with error %s", - type_name.AsCString(), - response.GetStringRef().c_str()); + type_name.AsCString(), response.Peek().str().c_str()); } } else Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -60,7 +60,7 @@ bool m_exit_now; // use in asynchronous handling to indicate process should exit. PacketResult - SendUnimplementedResponse (const char *packet); + SendUnimplementedResponse(llvm::StringRef packet); PacketResult SendErrorResponse (uint8_t error); Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -67,13 +67,13 @@ break; case StringExtractorGDBRemote::eServerPacketType_unimplemented: - packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); + packet_result = SendUnimplementedResponse(packet.PeekFullPacket()); break; default: auto handler_it = m_packet_handlers.find(packet_type); if (handler_it == m_packet_handlers.end()) - packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); + packet_result = SendUnimplementedResponse(packet.PeekFullPacket()); else packet_result = handler_it->second (packet, error, interrupt, quit); break; @@ -99,8 +99,7 @@ return packet_result; } -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *) +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendUnimplementedResponse(llvm::StringRef) { // TODO: Log the packet we aren't handling... return SendPacketNoLock (""); @@ -121,7 +120,8 @@ { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); if (log) - log->Printf ("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", __FUNCTION__, failed_packet.GetStringRef ().c_str (), message ? message : ""); + log->Printf("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", __FUNCTION__, + failed_packet.PeekFullPacket().str().c_str(), message ? message : ""); return SendErrorResponse (0x03); } Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -1081,7 +1081,7 @@ GDBRemoteCommunicationServerCommon::Handle_qEcho (StringExtractorGDBRemote &packet) { // Just echo back the exact same packet for qEcho... - return SendPacketNoLock(packet.GetStringRef()); + return SendPacketNoLock(packet.PeekFullPacket()); } GDBRemoteCommunication::PacketResult Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1187,7 +1187,7 @@ { // FIXME add continue at address support for $C{signo}[;{continue-address}]. if (packet.PeekChar() == ';') - return SendUnimplementedResponse (packet.GetStringRef().c_str()); + return SendUnimplementedResponse(packet.PeekFullPacket()); else return SendIllFormedResponse (packet, "unexpected content after $C{signal-number}"); } @@ -1258,7 +1258,7 @@ { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s not implemented for c{address} variant [%s remains]", __FUNCTION__, packet.Peek ()); - return SendUnimplementedResponse (packet.GetStringRef().c_str()); + return SendUnimplementedResponse(packet.PeekFullPacket()); } // Ensure we have a native process. @@ -1694,7 +1694,9 @@ if (reg_index == std::numeric_limits::max ()) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", + __FUNCTION__, packet.Peek().str().c_str()); return SendErrorResponse (0x15); } @@ -1775,7 +1777,9 @@ if (reg_index == std::numeric_limits::max ()) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", + __FUNCTION__, packet.Peek().str().c_str()); return SendErrorResponse (0x29); } @@ -2772,7 +2776,8 @@ if (tid == LLDB_INVALID_THREAD_ID) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse thread id from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, could not parse thread id from request \"%s\"", + __FUNCTION__, packet.Peek().str().c_str()); return SendErrorResponse (0x15); } return SendStopReplyPacketForThread (tid); @@ -2918,7 +2923,9 @@ if (packet.GetBytesLeft () < 1 || packet.GetChar () != ';') { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected ';' prior to start of thread suffix: packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); + log->Printf("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected ';' prior to start of " + "thread suffix: packet contents = '%s'", + __FUNCTION__, packet.Peek().str().c_str()); return thread_sp; } @@ -2929,7 +2936,9 @@ if (packet.Peek().startswith("thread:")) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected 'thread:' but not found, packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); + log->Printf("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected 'thread:' but not " + "found, packet contents = '%s'", + __FUNCTION__, packet.Peek().str().c_str()); return thread_sp; } packet.SetFilePos (packet.GetFilePos () + strlen("thread:")); Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -407,10 +407,10 @@ CalculateThreadStopInfo (ThreadGDBRemote *thread); size_t - UpdateThreadPCsFromStopReplyThreadsValue (std::string &value); + UpdateThreadPCsFromStopReplyThreadsValue(llvm::StringRef value); size_t - UpdateThreadIDsFromStopReplyThreadsValue (std::string &value); + UpdateThreadIDsFromStopReplyThreadsValue(llvm::StringRef value); bool HandleNotifyPacket(StringExtractorGDBRemote &packet); Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1672,44 +1672,32 @@ } size_t -ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue (std::string &value) +ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue(llvm::StringRef value) { m_thread_ids.clear(); - m_thread_pcs.clear(); - size_t comma_pos; - lldb::tid_t tid; - while ((comma_pos = value.find(',')) != std::string::npos) - { - value[comma_pos] = '\0'; - // thread in big endian hex - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); - if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back (tid); - value.erase(0, comma_pos + 1); - } - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); - if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back (tid); + lldb::addr_t tid; + llvm::StringRef tid_str; + while (!value.empty()) + { + std::tie(tid_str, value) = value.split(','); + if (!tid_str.getAsInteger(16, tid)) + m_thread_ids.push_back(tid); + } return m_thread_ids.size(); } size_t -ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue (std::string &value) +ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue(llvm::StringRef value) { m_thread_pcs.clear(); - size_t comma_pos; lldb::addr_t pc; - while ((comma_pos = value.find(',')) != std::string::npos) + llvm::StringRef pc_str; + while (!value.empty()) { - value[comma_pos] = '\0'; - pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - if (pc != LLDB_INVALID_ADDRESS) + std::tie(pc_str, value) = value.split(','); + if (!pc_str.getAsInteger(16, pc)) m_thread_pcs.push_back (pc); - value.erase(0, comma_pos + 1); } - pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - if (pc != LLDB_INVALID_THREAD_ID) - m_thread_pcs.push_back (pc); return m_thread_pcs.size(); } @@ -1759,32 +1747,17 @@ { // Get the thread stop info StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i]; - const std::string &stop_info_str = stop_info.GetStringRef(); m_thread_pcs.clear(); - const size_t thread_pcs_pos = stop_info_str.find(";thread-pcs:"); - if (thread_pcs_pos != std::string::npos) - { - const size_t start = thread_pcs_pos + strlen(";thread-pcs:"); - const size_t end = stop_info_str.find(';', start); - if (end != std::string::npos) - { - std::string value = stop_info_str.substr(start, end - start); - UpdateThreadPCsFromStopReplyThreadsValue(value); - } - } + llvm::StringRef threads_value = stop_info.Peek().scan_between(";thread-pcs:", ";"); + if (!threads_value.empty()) + UpdateThreadPCsFromStopReplyThreadsValue(threads_value); - const size_t threads_pos = stop_info_str.find(";threads:"); - if (threads_pos != std::string::npos) + threads_value = stop_info.Peek().scan_between(";threads:", ";"); + if (!threads_value.empty()) { - const size_t start = threads_pos + strlen(";threads:"); - const size_t end = stop_info_str.find(';', start); - if (end != std::string::npos) - { - std::string value = stop_info_str.substr(start, end - start); - if (UpdateThreadIDsFromStopReplyThreadsValue(value)) - return true; - } + if (UpdateThreadIDsFromStopReplyThreadsValue(threads_value)) + return true; } } } @@ -1982,9 +1955,8 @@ for (const auto &pair : expedited_register_map) { - StringExtractor reg_value_extractor; - reg_value_extractor.GetStringRef() = pair.second; - DataBufferSP buffer_sp(new DataBufferHeap(reg_value_extractor.GetStringRef().size() / 2, 0)); + StringExtractor reg_value_extractor(pair.second); + DataBufferSP buffer_sp(new DataBufferHeap(reg_value_extractor.GetBytesLeft() / 2, 0)); reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc'); gdb_thread->PrivateSetRegisterValue(pair.first, buffer_sp->GetData()); } @@ -2357,12 +2329,12 @@ { if (mem_cache_addr != LLDB_INVALID_ADDRESS) { - StringExtractor bytes; - if (mem_cache_dict->GetValueForKeyAsString("bytes", bytes.GetStringRef())) + std::string bytes_str; + if (mem_cache_dict->GetValueForKeyAsString("bytes", bytes_str)) { - bytes.SetFilePos(0); + StringExtractor bytes(bytes_str); - const size_t byte_size = bytes.GetStringRef().size()/2; + const size_t byte_size = bytes_str.size() / 2; DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); const size_t bytes_copied = bytes.GetHexBytes (data_buffer_sp->GetData(), 0); if (bytes_copied == byte_size) @@ -2912,9 +2884,10 @@ else { if (log) - log->Printf ("ProcessGDBRemote::DoDestroy - got unexpected response to k packet: %s", response.GetStringRef().c_str()); + log->Printf("ProcessGDBRemote::DoDestroy - got unexpected response to k packet: %s", + response.PeekFullPacket().str().c_str()); exit_string.assign("got unexpected response to k packet: "); - exit_string.append(response.GetStringRef()); + exit_string.append(response.PeekFullPacket().str()); } } else @@ -2948,7 +2921,7 @@ void ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response) { - const bool did_exec = response.GetStringRef().find(";reason:exec;") != std::string::npos; + const bool did_exec = response.Peek().find(";reason:exec;") != llvm::StringRef::npos; if (did_exec) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); @@ -3079,7 +3052,7 @@ // much data for some reason. data_received_size = size; } - memcpy (buf, response.GetStringRef().data(), data_received_size); + memcpy(buf, response.Peek().data(), data_received_size); return data_received_size; } else @@ -3092,7 +3065,8 @@ else if (response.IsUnsupportedResponse()) error.SetErrorStringWithFormat("GDB server does not support reading memory"); else - error.SetErrorStringWithFormat("unexpected response to GDB server memory read packet '%s': '%s'", packet, response.GetStringRef().c_str()); + error.SetErrorStringWithFormat("unexpected response to GDB server memory read packet '%s': '%s'", packet, + response.PeekFullPacket().str().c_str()); } else { @@ -3129,7 +3103,8 @@ else if (response.IsUnsupportedResponse()) error.SetErrorStringWithFormat("GDB server does not support writing memory"); else - error.SetErrorStringWithFormat("unexpected response to GDB server memory write packet '%s': '%s'", packet.GetString().c_str(), response.GetStringRef().c_str()); + error.SetErrorStringWithFormat("unexpected response to GDB server memory write packet '%s': '%s'", + packet.GetString().c_str(), response.PeekFullPacket().str().c_str()); } else { @@ -3831,10 +3806,8 @@ bool ProcessGDBRemote::HandleNotifyPacket (StringExtractorGDBRemote &packet) { - // get the packet at a string - const std::string &pkt = packet.GetStringRef(); // skip %stop: - StringExtractorGDBRemote stop_info(pkt.c_str() + 5); + StringExtractorGDBRemote stop_info(packet.Peek().drop_front(5)); // pass as a thread stop info packet SetLastStopPacket(stop_info); @@ -4194,7 +4167,7 @@ { if (!response.Empty()) { - object_sp = StructuredData::ParseJSON (response.GetStringRef()); + object_sp = StructuredData::ParseJSON(response.Peek().str()); } } } @@ -4270,7 +4243,7 @@ { if (!response.Empty()) { - object_sp = StructuredData::ParseJSON (response.GetStringRef()); + object_sp = StructuredData::ParseJSON(response.Peek().str()); } } } @@ -4309,7 +4282,7 @@ { if (!response.Empty()) { - object_sp = StructuredData::ParseJSON (response.GetStringRef()); + object_sp = StructuredData::ParseJSON(response.Peek().str()); } } } @@ -4577,14 +4550,13 @@ } else if (name == "dynamic_size_dwarf_expr_bytes") { - StringExtractor opcode_extractor; std::string opcode_string = value.str (); size_t dwarf_opcode_len = opcode_string.length () / 2; assert (dwarf_opcode_len > 0); dwarf_opcode_bytes.resize (dwarf_opcode_len); reg_info.dynamic_size_dwarf_len = dwarf_opcode_len; - opcode_extractor.GetStringRef ().swap (opcode_string); + StringExtractor opcode_extractor(opcode_string); uint32_t ret_val = opcode_extractor.GetHexBytesAvail (dwarf_opcode_bytes); assert (dwarf_opcode_len == ret_val); @@ -5426,17 +5398,16 @@ result.SetStatus (eReturnStatusSuccessFinishResult); Stream &output_strm = result.GetOutputStream(); output_strm.Printf (" packet: %s\n", packet_cstr); - std::string &response_str = response.GetStringRef(); if (strstr(packet_cstr, "qGetProfileData") != NULL) { - response_str = process->HarmonizeThreadIdsForProfileData(response); + response.SetString(process->HarmonizeThreadIdsForProfileData(response)); } - if (response_str.empty()) + if (response.GetBytesLeft() == 0) output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n"); else - output_strm.Printf ("response: %s\n", response.GetStringRef().c_str()); + output_strm.Printf("response: %s\n", response.Peek().str().c_str()); } } return true; @@ -5477,20 +5448,18 @@ StreamString packet; packet.PutCString("qRcmd,"); packet.PutBytesAsRawHex8(command, strlen(command)); - const char *packet_cstr = packet.GetString().c_str(); bool send_async = true; StringExtractorGDBRemote response; - process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async); + process->GetGDBRemote().SendPacketAndWaitForResponse(packet.GetString(), response, send_async); result.SetStatus (eReturnStatusSuccessFinishResult); Stream &output_strm = result.GetOutputStream(); - output_strm.Printf (" packet: %s\n", packet_cstr); - const std::string &response_str = response.GetStringRef(); + output_strm.Printf(" packet: %s\n", packet.GetString().c_str()); - if (response_str.empty()) + if (response.GetBytesLeft() == 0) output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n"); else - output_strm.Printf ("response: %s\n", response.GetStringRef().c_str()); + output_strm.Printf("response: %s\n", response.Peek().str().c_str()); } return true; } Index: source/Utility/StringExtractor.cpp =================================================================== --- source/Utility/StringExtractor.cpp +++ source/Utility/StringExtractor.cpp @@ -110,6 +110,15 @@ return (uint8_t)((hi_nibble << 4) + lo_nibble); } +bool +StringExtractor::Consume(llvm::StringRef str) +{ + if (!Peek().startswith(str)) + return false; + m_index += str.size(); + return true; +} + //---------------------------------------------------------------------- // If a pair of valid hex digits exist at the head of the // StringExtractor they are decoded into an unsigned byte and returned Index: source/Utility/StringExtractorGDBRemote.cpp =================================================================== --- source/Utility/StringExtractorGDBRemote.cpp +++ source/Utility/StringExtractorGDBRemote.cpp @@ -427,7 +427,7 @@ // starts with a '['. This is a quick validator to just make sure the // response could be valid JSON without having to validate all of the // JSON content. - switch (response.GetStringRef()[0]) + switch (response.PeekChar()) { case '{': return true; case '[': return true; @@ -456,7 +456,7 @@ case StringExtractorGDBRemote::eResponse: { uint32_t valid_count = 0; - for (const char ch : response.GetStringRef()) + for (const char ch : response.PeekFullPacket()) { if (!isxdigit(ch)) { Index: unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp =================================================================== --- unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp +++ unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp @@ -41,7 +41,7 @@ { StringExtractorGDBRemote request; ASSERT_EQ(PacketResult::Success, server.GetPacket(request)); - ASSERT_EQ("QThreadSuffixSupported", request.GetStringRef()); + ASSERT_EQ("QThreadSuffixSupported", request.Peek()); if (supported) ASSERT_EQ(PacketResult::Success, server.SendOKResponse()); else @@ -53,7 +53,7 @@ { StringExtractorGDBRemote request; ASSERT_EQ(PacketResult::Success, server.GetPacket(request)); - ASSERT_EQ(expected, request.GetStringRef()); + ASSERT_EQ(expected, request.Peek()); ASSERT_EQ(PacketResult::Success, server.SendPacket(response)); } Index: unittests/Utility/StringExtractorTest.cpp =================================================================== --- unittests/Utility/StringExtractorTest.cpp +++ unittests/Utility/StringExtractorTest.cpp @@ -17,7 +17,7 @@ ASSERT_EQ (true, ex.IsGood()); ASSERT_EQ (0u, ex.GetFilePos()); - ASSERT_STREQ (kEmptyString, ex.GetStringRef().c_str()); + ASSERT_EQ(kEmptyString, ex.Peek()); ASSERT_EQ (true, ex.Empty()); ASSERT_EQ (0u, ex.GetBytesLeft()); } @@ -29,12 +29,53 @@ ASSERT_EQ (true, ex.IsGood()); ASSERT_EQ (0u, ex.GetFilePos()); - ASSERT_STREQ (kInitMiscString, ex.GetStringRef().c_str()); + ASSERT_EQ(kInitMiscString, ex.Peek()); ASSERT_EQ (false, ex.Empty()); ASSERT_EQ (sizeof(kInitMiscString)-1, ex.GetBytesLeft()); ASSERT_EQ(kInitMiscString[0], ex.PeekChar()); } +TEST_F(StringExtractorTest, PeekAndGetSize) +{ + llvm::StringRef Str("StringExtractorTest::Size()"); + StringExtractor ex(Str); + + EXPECT_EQ(true, ex.IsGood()); + EXPECT_EQ(0u, ex.GetFilePos()); + EXPECT_EQ(Str.size(), ex.GetTotalBytes()); + EXPECT_EQ(Str.size(), ex.GetBytesLeft()); + + EXPECT_EQ('S', ex.PeekChar()); + EXPECT_EQ(Str.size(), ex.GetTotalBytes()); + EXPECT_EQ(Str.size(), ex.GetBytesLeft()); + EXPECT_EQ(Str, ex.Peek()); + + EXPECT_EQ('S', ex.GetChar()); + EXPECT_EQ(Str.size(), ex.GetTotalBytes()); + EXPECT_EQ(Str.size() - 1, ex.GetBytesLeft()); + EXPECT_EQ(Str.drop_front(1), ex.Peek()); +} + +TEST_F(StringExtractorTest, Consume) +{ + llvm::StringRef Str("StringExtractorTest::Consume()"); + llvm::StringRef ConsumeStr("String"); + StringExtractor ex(Str); + + ASSERT_TRUE(ex.IsGood()); + ASSERT_EQ(0u, ex.GetFilePos()); + + EXPECT_EQ(Str.size(), ex.GetBytesLeft()); + EXPECT_FALSE(ex.Consume("Blah")); + EXPECT_EQ(Str.size(), ex.GetBytesLeft()); + EXPECT_EQ(Str, ex.Peek()); + + EXPECT_TRUE(ex.Consume(ConsumeStr)); + EXPECT_EQ(Str.size() - ConsumeStr.size(), ex.GetBytesLeft()); + EXPECT_EQ("ExtractorTest::Consume()", ex.Peek()); + ; +} + TEST_F (StringExtractorTest, DecodeHexU8_Underflow) { const char kEmptyString[] = "";