diff --git a/lldb/include/lldb/Utility/StringExtractor.h b/lldb/include/lldb/Utility/StringExtractor.h --- a/lldb/include/lldb/Utility/StringExtractor.h +++ b/lldb/include/lldb/Utility/StringExtractor.h @@ -100,6 +100,8 @@ size_t GetHexByteStringTerminatedBy(std::string &str, char terminator); + size_t GetStringBeforeChar(std::string &str, char next_char); + bool ConsumeFront(const llvm::StringRef &str); const char *Peek() { diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h --- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -128,7 +128,7 @@ eServerPacketType_qVAttachOrWaitSupported, eServerPacketType_qWatchpointSupportInfo, eServerPacketType_qWatchpointSupportInfoSupported, - eServerPacketType_qXfer_auxv_read, + eServerPacketType_qXfer, eServerPacketType_jSignalsInfo, eServerPacketType_jModulesInfo, diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -82,7 +82,8 @@ MainLoop::ReadHandleUP m_stdio_handle_up; lldb::StateType m_inferior_prev_state = lldb::StateType::eStateInvalid; - std::unique_ptr m_active_auxv_buffer_up; + std::unordered_map> + m_xfer_buffer_map; std::mutex m_saved_registers_mutex; std::unordered_map m_saved_registers_map; uint32_t m_next_saved_registers_id = 1; @@ -150,7 +151,7 @@ PacketResult Handle_s(StringExtractorGDBRemote &packet); - PacketResult Handle_qXfer_auxv_read(StringExtractorGDBRemote &packet); + PacketResult Handle_qXfer(StringExtractorGDBRemote &packet); PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -144,8 +144,8 @@ StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo, &GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo); RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read, - &GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read); + StringExtractorGDBRemote::eServerPacketType_qXfer, + &GDBRemoteCommunicationServerLLGS::Handle_qXfer); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_s, &GDBRemoteCommunicationServerLLGS::Handle_s); RegisterMemberFunctionHandler( @@ -2690,93 +2690,112 @@ } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read( +GDBRemoteCommunicationServerLLGS::Handle_qXfer( StringExtractorGDBRemote &packet) { -// *BSD impls should be able to do this too. -#if defined(__linux__) || defined(__NetBSD__) - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Parse out the offset. - packet.SetFilePos(strlen("qXfer:auxv:read::")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, - "qXfer:auxv:read:: packet missing offset"); - - const uint64_t auxv_offset = + packet.ConsumeFront("qXfer:"); + // Parse object name. + std::string xfer_object; + if (packet.GetStringBeforeChar(xfer_object, ':') == 0) + return SendIllFormedResponse(packet, "qXfer packet missing object name"); + // Consume ':' + packet.GetChar(); + // Parse action (read/write). + std::string xfer_action; + if (packet.GetStringBeforeChar(xfer_action, ':') == 0) + return SendIllFormedResponse(packet, "qXfer packet missing action"); + if (xfer_action != "read") + return SendUnimplementedResponse("qXfer action not supported"); + // Consume ':' + packet.GetChar(); + // Parse annex (can be empty). + std::string xfer_annex; + packet.GetStringBeforeChar(xfer_annex, ':'); + if (packet.GetChar() != ':') + return SendIllFormedResponse(packet, "qXfer packet malformed annex"); + // The key for the buffer map is in the form of + // qXfer:::. + std::string buffer_key = packet.GetStringRef().substr(0, packet.GetFilePos()); + // Parse offset. + const uint64_t xfer_offset = packet.GetHexMaxU64(false, std::numeric_limits::max()); - if (auxv_offset == std::numeric_limits::max()) - return SendIllFormedResponse(packet, - "qXfer:auxv:read:: packet missing offset"); - + if (xfer_offset == std::numeric_limits::max()) + return SendIllFormedResponse(packet, "qXfer packet missing offset"); // Parse out comma. - if (packet.GetBytesLeft() < 1 || packet.GetChar() != ',') - return SendIllFormedResponse( - packet, "qXfer:auxv:read:: packet missing comma after offset"); - + if (packet.GetChar() != ',') + return SendIllFormedResponse(packet, + "qXfer packet missing comma after offset"); // Parse out the length. - const uint64_t auxv_length = + const uint64_t xfer_length = packet.GetHexMaxU64(false, std::numeric_limits::max()); - if (auxv_length == std::numeric_limits::max()) - return SendIllFormedResponse(packet, - "qXfer:auxv:read:: packet missing length"); - - // Grab the auxv data if we need it. - if (!m_active_auxv_buffer_up) { - // Make sure we have a valid process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s failed, no process available", - __FUNCTION__); - return SendErrorResponse(0x10); - } + if (xfer_length == std::numeric_limits::max()) + return SendIllFormedResponse(packet, "qXfer packet missing length"); + std::shared_ptr memory_buffer_sp; + auto it = m_xfer_buffer_map.find(buffer_key); + if (it != m_xfer_buffer_map.end()) + memory_buffer_sp = it->second; + + if (!memory_buffer_sp) { + if (xfer_object == "auxv") { +// *BSD impls should be able to do this too. +#if defined(__linux__) || defined(__NetBSD__) + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + // Make sure we have a valid process. + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, no process " + "available", + __FUNCTION__); + return SendErrorResponse(0x10); + } - // Grab the auxv data. - auto buffer_or_error = m_debugged_process_up->GetAuxvData(); - if (!buffer_or_error) { - std::error_code ec = buffer_or_error.getError(); - LLDB_LOG(log, "no auxv data retrieved: {0}", ec.message()); - return SendErrorResponse(ec.value()); - } - m_active_auxv_buffer_up = std::move(*buffer_or_error); + // Grab the auxv data. + auto buffer_or_error = m_debugged_process_up->GetAuxvData(); + if (!buffer_or_error) { + std::error_code ec = buffer_or_error.getError(); + LLDB_LOG(log, "no auxv data retrieved: {0}", ec.message()); + return SendErrorResponse(ec.value()); + } + memory_buffer_sp = std::move(*buffer_or_error); +#else + return SendUnimplementedResponse("not implemented on this platform"); +#endif + } else + return SendUnimplementedResponse("Xfer object not supported"); } StreamGDBRemote response; bool done_with_buffer = false; - llvm::StringRef buffer = m_active_auxv_buffer_up->getBuffer(); - if (auxv_offset >= buffer.size()) { + llvm::StringRef buffer = memory_buffer_sp->getBuffer(); + if (xfer_offset >= buffer.size()) { // We have nothing left to send. Mark the buffer as complete. response.PutChar('l'); done_with_buffer = true; } else { // Figure out how many bytes are available starting at the given offset. - buffer = buffer.drop_front(auxv_offset); + buffer = buffer.drop_front(xfer_offset); // Mark the response type according to whether we're reading the remainder - // of the auxv data. - if (auxv_length >= buffer.size()) { + // of the data. + if (xfer_length >= buffer.size()) { // There will be nothing left to read after this response.PutChar('l'); done_with_buffer = true; } else { // There will still be bytes to read after this request. response.PutChar('m'); - buffer = buffer.take_front(auxv_length); + buffer = buffer.take_front(xfer_length); + m_xfer_buffer_map[buffer_key] = memory_buffer_sp; } - // Now write the data in encoded binary form. response.PutEscapedBytes(buffer.data(), buffer.size()); } if (done_with_buffer) - m_active_auxv_buffer_up.reset(); + m_xfer_buffer_map.erase(buffer_key); return SendPacketNoLock(response.GetString()); -#else - return SendUnimplementedResponse("not implemented on this platform"); -#endif } GDBRemoteCommunication::PacketResult @@ -3201,8 +3220,8 @@ void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData() { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - LLDB_LOG(log, "clearing auxv buffer: {0}", m_active_auxv_buffer_up.get()); - m_active_auxv_buffer_up.reset(); + LLDB_LOG(log, "clearing {0} xfer buffers", m_xfer_buffer_map.size()); + m_xfer_buffer_map.clear(); } FileSpec diff --git a/lldb/source/Utility/StringExtractor.cpp b/lldb/source/Utility/StringExtractor.cpp --- a/lldb/source/Utility/StringExtractor.cpp +++ b/lldb/source/Utility/StringExtractor.cpp @@ -359,6 +359,15 @@ return str.size(); } +size_t StringExtractor::GetStringBeforeChar(std::string &str, char next_char) { + str.clear(); + while (Peek() && *Peek() != next_char) + str.append(1, GetChar()); + if (!Peek()) + str.clear(); + return str.size(); +} + bool StringExtractor::GetNameColonValue(llvm::StringRef &name, llvm::StringRef &value) { // Read something in the form of NNNN:VVVV; where NNNN is any character that diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -285,8 +285,8 @@ break; case 'X': - if (PACKET_STARTS_WITH("qXfer:auxv:read::")) - return eServerPacketType_qXfer_auxv_read; + if (PACKET_STARTS_WITH("qXfer:")) + return eServerPacketType_qXfer; break; } break;