diff options
Diffstat (limited to 'source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp')
-rw-r--r-- | source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | 210 |
1 files changed, 134 insertions, 76 deletions
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index cdb63e72f6bd..196607665bba 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1,9 +1,8 @@ //===-- GDBRemoteCommunicationServerLLGS.cpp --------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -21,6 +20,7 @@ #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Debug.h" #include "lldb/Host/File.h" +#include "lldb/Host/FileAction.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" @@ -28,7 +28,6 @@ #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/common/NativeThreadProtocol.h" -#include "lldb/Target/FileAction.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/DataBuffer.h" @@ -52,9 +51,7 @@ using namespace lldb_private; using namespace lldb_private::process_gdb_remote; using namespace llvm; -//---------------------------------------------------------------------- // GDBRemote Errors -//---------------------------------------------------------------------- namespace { enum GDBRemoteServerError { @@ -66,9 +63,7 @@ enum GDBRemoteServerError { }; } -//---------------------------------------------------------------------- // GDBRemoteCommunicationServerLLGS constructor -//---------------------------------------------------------------------- GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS( MainLoop &mainloop, const NativeProcessProtocol::Factory &process_factory) : GDBRemoteCommunicationServerCommon("gdb-remote.server", @@ -149,8 +144,8 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { 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( @@ -192,6 +187,9 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead, &GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g, + &GDBRemoteCommunicationServerLLGS::Handle_g); + RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k, [this](StringExtractorGDBRemote packet, Status &error, bool &interrupt, bool &quit) { @@ -623,7 +621,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( } else { // The thread name contains special chars, send as hex bytes. response.PutCString("hexname:"); - response.PutCStringAsRawHex8(thread_name.c_str()); + response.PutStringAsRawHex8(thread_name); } response.PutChar(';'); } @@ -663,7 +661,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( response.PutCString("jstopinfo:"); StreamString unescaped_response; threads_info_sp->Write(unescaped_response); - response.PutCStringAsRawHex8(unescaped_response.GetData()); + response.PutStringAsRawHex8(unescaped_response.GetData()); response.PutChar(';'); } else LLDB_LOG(log, "failed to prepare a jstopinfo field for pid {0}", @@ -764,7 +762,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( if (!description.empty()) { // Description may contains special chars, send as hex bytes. response.PutCString("description:"); - response.PutCStringAsRawHex8(description.c_str()); + response.PutStringAsRawHex8(description); response.PutChar(';'); } else if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) { @@ -1341,7 +1339,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir( FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()}; if (working_dir) { StreamString response; - response.PutCStringAsRawHex8(working_dir.GetCString()); + response.PutStringAsRawHex8(working_dir.GetCString()); return SendPacketNoLock(response.GetString()); } @@ -1897,6 +1895,61 @@ GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo( } GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_g(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Move past packet name. + packet.SetFilePos(strlen("g")); + + // Get the thread to use. + NativeThreadProtocol *thread = GetThreadFromSuffix(packet); + if (!thread) { + LLDB_LOG(log, "failed, no thread available"); + return SendErrorResponse(0x15); + } + + // Get the thread's register context. + NativeRegisterContext ®_ctx = thread->GetRegisterContext(); + + std::vector<uint8_t> regs_buffer; + for (uint32_t reg_num = 0; reg_num < reg_ctx.GetUserRegisterCount(); + ++reg_num) { + const RegisterInfo *reg_info = reg_ctx.GetRegisterInfoAtIndex(reg_num); + + if (reg_info == nullptr) { + LLDB_LOG(log, "failed to get register info for register index {0}", + reg_num); + return SendErrorResponse(0x15); + } + + if (reg_info->value_regs != nullptr) + continue; // skip registers that are contained in other registers + + RegisterValue reg_value; + Status error = reg_ctx.ReadRegister(reg_info, reg_value); + if (error.Fail()) { + LLDB_LOG(log, "failed to read register at index {0}", reg_num); + return SendErrorResponse(0x15); + } + + if (reg_info->byte_offset + reg_info->byte_size >= regs_buffer.size()) + // Resize the buffer to guarantee it can store the register offsetted + // data. + regs_buffer.resize(reg_info->byte_offset + reg_info->byte_size); + + // Copy the register offsetted data to the buffer. + memcpy(regs_buffer.data() + reg_info->byte_offset, reg_value.GetBytes(), + reg_info->byte_size); + } + + // Write the response. + StreamGDBRemote response; + response.PutBytesAsRawHex8(regs_buffer.data(), regs_buffer.size()); + + return SendPacketNoLock(response.GetString()); +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); @@ -2426,7 +2479,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( // Return the error message. response.PutCString("error:"); - response.PutCStringAsRawHex8(error.AsCString()); + response.PutStringAsRawHex8(error.AsCString()); response.PutChar(';'); } else { // Range start and size. @@ -2454,7 +2507,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( ConstString name = region_info.GetName(); if (name) { response.PutCString("name:"); - response.PutCStringAsRawHex8(name.AsCString()); + response.PutStringAsRawHex8(name.AsCString()); response.PutChar(';'); } } @@ -2694,94 +2747,99 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { return PacketResult::Success; } -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read( - 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.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); - if (auxv_offset == std::numeric_limits<uint64_t>::max()) - return SendIllFormedResponse(packet, - "qXfer:auxv:read:: packet missing offset"); - - // Parse out comma. - if (packet.GetBytesLeft() < 1 || packet.GetChar() != ',') - return SendIllFormedResponse( - packet, "qXfer:auxv:read:: packet missing comma after offset"); - - // Parse out the length. - const uint64_t auxv_length = - packet.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); - if (auxv_length == std::numeric_limits<uint64_t>::max()) - return SendIllFormedResponse(packet, - "qXfer:auxv:read:: packet missing length"); - - // Grab the auxv data if we need it. - if (!m_active_auxv_buffer_up) { +llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> +GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object, + llvm::StringRef annex) { + if (object == "auxv") { // 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); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No process available"); } // 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); + if (!buffer_or_error) + return llvm::errorCodeToError(buffer_or_error.getError()); + return std::move(*buffer_or_error); } + return llvm::make_error<PacketUnimplementedError>( + "Xfer object not supported"); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qXfer( + StringExtractorGDBRemote &packet) { + SmallVector<StringRef, 5> fields; + // The packet format is "qXfer:<object>:<action>:<annex>:offset,length" + StringRef(packet.GetStringRef()).split(fields, ':', 4); + if (fields.size() != 5) + return SendIllFormedResponse(packet, "malformed qXfer packet"); + StringRef &xfer_object = fields[1]; + StringRef &xfer_action = fields[2]; + StringRef &xfer_annex = fields[3]; + StringExtractor offset_data(fields[4]); + if (xfer_action != "read") + return SendUnimplementedResponse("qXfer action not supported"); + // Parse offset. + const uint64_t xfer_offset = + offset_data.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); + if (xfer_offset == std::numeric_limits<uint64_t>::max()) + return SendIllFormedResponse(packet, "qXfer packet missing offset"); + // Parse out comma. + if (offset_data.GetChar() != ',') + return SendIllFormedResponse(packet, + "qXfer packet missing comma after offset"); + // Parse out the length. + const uint64_t xfer_length = + offset_data.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); + if (xfer_length == std::numeric_limits<uint64_t>::max()) + return SendIllFormedResponse(packet, "qXfer packet missing length"); + + // Get a previously constructed buffer if it exists or create it now. + std::string buffer_key = (xfer_object + xfer_action + xfer_annex).str(); + auto buffer_it = m_xfer_buffer_map.find(buffer_key); + if (buffer_it == m_xfer_buffer_map.end()) { + auto buffer_up = ReadXferObject(xfer_object, xfer_annex); + if (!buffer_up) + return SendErrorResponse(buffer_up.takeError()); + buffer_it = m_xfer_buffer_map + .insert(std::make_pair(buffer_key, std::move(*buffer_up))) + .first; + } + + // Send back the response StreamGDBRemote response; bool done_with_buffer = false; - - llvm::StringRef buffer = m_active_auxv_buffer_up->getBuffer(); - if (auxv_offset >= buffer.size()) { + llvm::StringRef buffer = buffer_it->second->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); } - // 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_it); return SendPacketNoLock(response.GetString()); -#else - return SendUnimplementedResponse("not implemented on this platform"); -#endif } GDBRemoteCommunication::PacketResult @@ -3206,8 +3264,8 @@ uint32_t GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID() { 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 |