diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
commit | 344a3780b2e33f6ca763666c380202b18aab72a3 (patch) | |
tree | f0b203ee6eb71d7fdd792373e3c81eb18d6934dd /lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | |
parent | b60736ec1405bb0a8dd40989f67ef4c93da068ab (diff) |
vendor/llvm-project/llvmorg-13-init-16847-g88e66fa60ae5vendor/llvm-project/llvmorg-12.0.1-rc2-0-ge7dac564cd0evendor/llvm-project/llvmorg-12.0.1-0-gfed41342a82f
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp')
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | 1007 |
1 files changed, 585 insertions, 422 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 62a09a2a432c..5e69b5793f9f 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -6,13 +6,14 @@ // //===----------------------------------------------------------------------===// -#include <errno.h> +#include <cerrno> #include "lldb/Host/Config.h" #include <chrono> #include <cstring> +#include <limits> #include <thread> #include "GDBRemoteCommunicationServerLLGS.h" @@ -70,6 +71,7 @@ GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS( : GDBRemoteCommunicationServerCommon("gdb-remote.server", "gdb-remote.server.rx_packet"), m_mainloop(mainloop), m_process_factory(process_factory), + m_current_process(nullptr), m_continue_process(nullptr), m_stdio_communication("process.stdio") { RegisterPacketHandlers(); } @@ -113,6 +115,12 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir); RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported, + &GDBRemoteCommunicationServerLLGS::Handle_QThreadSuffixSupported); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply, + &GDBRemoteCommunicationServerLLGS::Handle_QListThreadsInStopReply); + RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo, &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo); RegisterMemberFunctionHandler( @@ -186,27 +194,32 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals); RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_jTraceStart, - &GDBRemoteCommunicationServerLLGS::Handle_jTraceStart); + StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupported, + &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupported); RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_jTraceBufferRead, - &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead); + StringExtractorGDBRemote::eServerPacketType_jLLDBTraceStart, + &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStart); RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_jTraceMetaRead, - &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead); + StringExtractorGDBRemote::eServerPacketType_jLLDBTraceStop, + &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStop); RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_jTraceStop, - &GDBRemoteCommunicationServerLLGS::Handle_jTraceStop); + StringExtractorGDBRemote::eServerPacketType_jLLDBTraceGetState, + &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetState); RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead, - &GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead); - RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupportedType, - &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType); + StringExtractorGDBRemote::eServerPacketType_jLLDBTraceGetBinaryData, + &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetBinaryData); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g, &GDBRemoteCommunicationServerLLGS::Handle_g); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qMemTags, + &GDBRemoteCommunicationServerLLGS::Handle_qMemTags); + + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QMemTags, + &GDBRemoteCommunicationServerLLGS::Handle_QMemTags); + RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k, [this](StringExtractorGDBRemote packet, Status &error, bool &interrupt, bool &quit) { @@ -245,15 +258,18 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { { std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex); - assert(!m_debugged_process_up && "lldb-server creating debugged " - "process but one already exists"); + assert(m_debugged_processes.empty() && "lldb-server creating debugged " + "process but one already exists"); auto process_or = m_process_factory.Launch(m_process_launch_info, *this, m_mainloop); if (!process_or) return Status(process_or.takeError()); - m_debugged_process_up = std::move(*process_or); + m_continue_process = m_current_process = process_or->get(); + m_debugged_processes[m_current_process->GetID()] = std::move(*process_or); } + SetEnabledExtensions(*m_current_process); + // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol as // needed. llgs local-process debugging may specify PTY paths, which will // make these file actions non-null process launch -i/e/o will also make @@ -266,10 +282,10 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { LLDB_LOG(log, "pid = {0}: setting up stdout/stderr redirection via $O " "gdb-remote commands", - m_debugged_process_up->GetID()); + m_current_process->GetID()); // Setup stdout/stderr mapping from inferior to $O - auto terminal_fd = m_debugged_process_up->GetTerminalFileDescriptor(); + auto terminal_fd = m_current_process->GetTerminalFileDescriptor(); if (terminal_fd >= 0) { LLDB_LOGF(log, "ProcessGDBRemoteCommunicationServerLLGS::%s setting " @@ -288,12 +304,12 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { LLDB_LOG(log, "pid = {0} skipping stdout/stderr redirection via $O: inferior " "will communicate over client-provided file descriptors", - m_debugged_process_up->GetID()); + m_current_process->GetID()); } printf("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments().GetArgumentAtIndex(0), - m_debugged_process_up->GetID()); + m_current_process->GetID()); return Status(); } @@ -305,12 +321,11 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { // Before we try to attach, make sure we aren't already monitoring something // else. - if (m_debugged_process_up && - m_debugged_process_up->GetID() != LLDB_INVALID_PROCESS_ID) + if (!m_debugged_processes.empty()) return Status("cannot attach to process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", - pid, m_debugged_process_up->GetID()); + pid, m_current_process->GetID()); // Try to attach. auto process_or = m_process_factory.Attach(pid, *this, m_mainloop); @@ -320,10 +335,12 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { status); return status; } - m_debugged_process_up = std::move(*process_or); + m_continue_process = m_current_process = process_or->get(); + m_debugged_processes[m_current_process->GetID()] = std::move(*process_or); + SetEnabledExtensions(*m_current_process); // Setup stdout/stderr mapping from inferior. - auto terminal_fd = m_debugged_process_up->GetTerminalFileDescriptor(); + auto terminal_fd = m_current_process->GetTerminalFileDescriptor(); if (terminal_fd >= 0) { LLDB_LOGF(log, "ProcessGDBRemoteCommunicationServerLLGS::%s setting " @@ -648,6 +665,14 @@ static const char *GetStopReasonString(StopReason stop_reason) { return "exception"; case eStopReasonExec: return "exec"; + case eStopReasonProcessorTrace: + return "processor trace"; + case eStopReasonFork: + return "fork"; + case eStopReasonVFork: + return "vfork"; + case eStopReasonVForkDone: + return "vforkdone"; case eStopReasonInstrumentation: case eStopReasonInvalid: case eStopReasonPlanComplete: @@ -736,15 +761,15 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Ensure we have a debugged process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(50); LLDB_LOG(log, "preparing packet for pid {0} tid {1}", - m_debugged_process_up->GetID(), tid); + m_current_process->GetID(), tid); // Ensure we can get info on the given thread. - NativeThreadProtocol *thread = m_debugged_process_up->GetThreadByID(tid); + NativeThreadProtocol *thread = m_current_process->GetThreadByID(tid); if (!thread) return SendErrorResponse(51); @@ -767,7 +792,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( LLDB_LOG( log, "pid {0}, tid {1}, got signal signo = {2}, reason = {3}, exc_type = {4}", - m_debugged_process_up->GetID(), tid, signum, int(tid_stop_info.reason), + m_current_process->GetID(), tid, signum, int(tid_stop_info.reason), tid_stop_info.details.exception.type); // Print the signal number. @@ -805,9 +830,9 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( uint32_t thread_index = 0; NativeThreadProtocol *listed_thread; - for (listed_thread = m_debugged_process_up->GetThreadAtIndex(thread_index); + for (listed_thread = m_current_process->GetThreadAtIndex(thread_index); listed_thread; ++thread_index, - listed_thread = m_debugged_process_up->GetThreadAtIndex(thread_index)) { + listed_thread = m_current_process->GetThreadAtIndex(thread_index)) { if (thread_index > 0) response.PutChar(','); response.Printf("%" PRIx64, listed_thread->GetID()); @@ -822,7 +847,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( if (thread_index > 1) { const bool threads_with_valid_stop_info_only = true; llvm::Expected<json::Array> threads_info = GetJSONThreadsInfo( - *m_debugged_process_up, threads_with_valid_stop_info_only); + *m_current_process, threads_with_valid_stop_info_only); if (threads_info) { response.PutCString("jstopinfo:"); StreamString unescaped_response; @@ -832,7 +857,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( } else { LLDB_LOG_ERROR(log, threads_info.takeError(), "failed to prepare a jstopinfo field for pid {1}: {0}", - m_debugged_process_up->GetID()); + m_current_process->GetID()); } } @@ -840,8 +865,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( response.PutCString("thread-pcs"); char delimiter = ':'; for (NativeThreadProtocol *thread; - (thread = m_debugged_process_up->GetThreadAtIndex(i)) != nullptr; - ++i) { + (thread = m_current_process->GetThreadAtIndex(i)) != nullptr; ++i) { NativeRegisterContext& reg_ctx = thread->GetRegisterContext(); uint32_t reg_to_read = reg_ctx.ConvertRegisterKindToRegisterNumber( @@ -924,6 +948,22 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( } } + // Include child process PID/TID for forks. + if (tid_stop_info.reason == eStopReasonFork || + tid_stop_info.reason == eStopReasonVFork) { + assert(bool(m_extensions_supported & + NativeProcessProtocol::Extension::multiprocess)); + if (tid_stop_info.reason == eStopReasonFork) + assert(bool(m_extensions_supported & + NativeProcessProtocol::Extension::fork)); + if (tid_stop_info.reason == eStopReasonVFork) + assert(bool(m_extensions_supported & + NativeProcessProtocol::Extension::vfork)); + response.Printf("%s:p%" PRIx64 ".%" PRIx64 ";", reason_str, + tid_stop_info.details.fork.child_pid, + tid_stop_info.details.fork.child_tid); + } + return SendPacketNoLock(response.GetString()); } @@ -1028,6 +1068,15 @@ void GDBRemoteCommunicationServerLLGS::DidExec(NativeProcessProtocol *process) { ClearProcessSpecificData(); } +void GDBRemoteCommunicationServerLLGS::NewSubprocess( + NativeProcessProtocol *parent_process, + std::unique_ptr<NativeProcessProtocol> child_process) { + lldb::pid_t child_pid = child_process->GetID(); + assert(child_pid != LLDB_INVALID_PROCESS_ID); + assert(m_debugged_processes.find(child_pid) == m_debugged_processes.end()); + m_debugged_processes[child_pid] = std::move(child_process); +} + void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() { Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_COMM)); @@ -1170,266 +1219,110 @@ void GDBRemoteCommunicationServerLLGS::SendProcessOutput() { } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_jTraceStart( +GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupported( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse(68); - - if (!packet.ConsumeFront("jTraceStart:")) - return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet "); - - TraceOptions options; - uint64_t type = std::numeric_limits<uint64_t>::max(); - uint64_t buffersize = std::numeric_limits<uint64_t>::max(); - lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - uint64_t metabuffersize = std::numeric_limits<uint64_t>::max(); - - auto json_object = StructuredData::ParseJSON(packet.Peek()); - - if (!json_object || - json_object->GetType() != lldb::eStructuredDataTypeDictionary) - return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet "); - - auto json_dict = json_object->GetAsDictionary(); - - json_dict->GetValueForKeyAsInteger("metabuffersize", metabuffersize); - options.setMetaDataBufferSize(metabuffersize); - json_dict->GetValueForKeyAsInteger("buffersize", buffersize); - options.setTraceBufferSize(buffersize); - - json_dict->GetValueForKeyAsInteger("type", type); - options.setType(static_cast<lldb::TraceType>(type)); - - json_dict->GetValueForKeyAsInteger("threadid", tid); - options.setThreadID(tid); - - StructuredData::ObjectSP custom_params_sp = - json_dict->GetValueForKey("params"); - if (custom_params_sp && - custom_params_sp->GetType() != lldb::eStructuredDataTypeDictionary) - return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet "); - - options.setTraceParams( - std::static_pointer_cast<StructuredData::Dictionary>(custom_params_sp)); - - if (buffersize == std::numeric_limits<uint64_t>::max() || - type != lldb::TraceType::eTraceTypeProcessorTrace) { - LLDB_LOG(log, "Ill formed packet buffersize = {0} type = {1}", buffersize, - type); - return SendIllFormedResponse(packet, "JTrace:start: Ill formed packet "); - } - - Status error; - lldb::user_id_t uid = LLDB_INVALID_UID; - uid = m_debugged_process_up->StartTrace(options, error); - LLDB_LOG(log, "uid is {0} , error is {1}", uid, error.GetError()); - if (error.Fail()) - return SendErrorResponse(error); + // Fail if we don't have a current process. + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(Status("Process not running.")); - StreamGDBRemote response; - response.Printf("%" PRIx64, uid); - return SendPacketNoLock(response.GetString()); + return SendJSONResponse(m_current_process->TraceSupported()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_jTraceStop( +GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStop( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse(68); - - if (!packet.ConsumeFront("jTraceStop:")) - return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet "); - - lldb::user_id_t uid = LLDB_INVALID_UID; - lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - - auto json_object = StructuredData::ParseJSON(packet.Peek()); - - if (!json_object || - json_object->GetType() != lldb::eStructuredDataTypeDictionary) - return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet "); - - auto json_dict = json_object->GetAsDictionary(); - - if (!json_dict->GetValueForKeyAsInteger("traceid", uid)) - return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet "); + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(Status("Process not running.")); - json_dict->GetValueForKeyAsInteger("threadid", tid); + packet.ConsumeFront("jLLDBTraceStop:"); + Expected<TraceStopRequest> stop_request = + json::parse<TraceStopRequest>(packet.Peek(), "TraceStopRequest"); + if (!stop_request) + return SendErrorResponse(stop_request.takeError()); - Status error = m_debugged_process_up->StopTrace(uid, tid); - - if (error.Fail()) - return SendErrorResponse(error); + if (Error err = m_current_process->TraceStop(*stop_request)) + return SendErrorResponse(std::move(err)); return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType( +GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStart( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(Status("Process not running.")); - llvm::Expected<TraceTypeInfo> supported_trace_type = - m_debugged_process_up->GetSupportedTraceType(); - if (!supported_trace_type) - return SendErrorResponse(supported_trace_type.takeError()); + packet.ConsumeFront("jLLDBTraceStart:"); + Expected<TraceStartRequest> request = + json::parse<TraceStartRequest>(packet.Peek(), "TraceStartRequest"); + if (!request) + return SendErrorResponse(request.takeError()); - StreamGDBRemote escaped_response; - StructuredData::Dictionary json_packet; + if (Error err = m_current_process->TraceStart(packet.Peek(), request->type)) + return SendErrorResponse(std::move(err)); - json_packet.AddStringItem("name", supported_trace_type->name); - json_packet.AddStringItem("description", supported_trace_type->description); - - StreamString json_string; - json_packet.Dump(json_string, false); - escaped_response.PutEscapedBytes(json_string.GetData(), - json_string.GetSize()); - return SendPacketNoLock(escaped_response.GetString()); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead( +GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetState( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse(68); - - if (!packet.ConsumeFront("jTraceConfigRead:")) - return SendIllFormedResponse(packet, - "jTraceConfigRead: Ill formed packet "); - - lldb::user_id_t uid = LLDB_INVALID_UID; - lldb::tid_t threadid = LLDB_INVALID_THREAD_ID; - - auto json_object = StructuredData::ParseJSON(packet.Peek()); - - if (!json_object || - json_object->GetType() != lldb::eStructuredDataTypeDictionary) - return SendIllFormedResponse(packet, - "jTraceConfigRead: Ill formed packet "); - - auto json_dict = json_object->GetAsDictionary(); - - if (!json_dict->GetValueForKeyAsInteger("traceid", uid)) - return SendIllFormedResponse(packet, - "jTraceConfigRead: Ill formed packet "); - - json_dict->GetValueForKeyAsInteger("threadid", threadid); - - TraceOptions options; - StreamGDBRemote response; - - options.setThreadID(threadid); - Status error = m_debugged_process_up->GetTraceConfig(uid, options); - - if (error.Fail()) - return SendErrorResponse(error); - - StreamGDBRemote escaped_response; - StructuredData::Dictionary json_packet; - - json_packet.AddIntegerItem("type", options.getType()); - json_packet.AddIntegerItem("buffersize", options.getTraceBufferSize()); - json_packet.AddIntegerItem("metabuffersize", options.getMetaDataBufferSize()); + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(Status("Process not running.")); - StructuredData::DictionarySP custom_params = options.getTraceParams(); - if (custom_params) - json_packet.AddItem("params", custom_params); + packet.ConsumeFront("jLLDBTraceGetState:"); + Expected<TraceGetStateRequest> request = + json::parse<TraceGetStateRequest>(packet.Peek(), "TraceGetStateRequest"); + if (!request) + return SendErrorResponse(request.takeError()); - StreamString json_string; - json_packet.Dump(json_string, false); - escaped_response.PutEscapedBytes(json_string.GetData(), - json_string.GetSize()); - return SendPacketNoLock(escaped_response.GetString()); + return SendJSONResponse(m_current_process->TraceGetState(request->type)); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_jTraceRead( +GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetBinaryData( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse(68); - - enum PacketType { MetaData, BufferData }; - PacketType tracetype = MetaData; - - if (packet.ConsumeFront("jTraceBufferRead:")) - tracetype = BufferData; - else if (packet.ConsumeFront("jTraceMetaRead:")) - tracetype = MetaData; - else { - return SendIllFormedResponse(packet, "jTrace: Ill formed packet "); - } - - lldb::user_id_t uid = LLDB_INVALID_UID; - - uint64_t byte_count = std::numeric_limits<uint64_t>::max(); - lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - uint64_t offset = std::numeric_limits<uint64_t>::max(); - - auto json_object = StructuredData::ParseJSON(packet.Peek()); - - if (!json_object || - json_object->GetType() != lldb::eStructuredDataTypeDictionary) - return SendIllFormedResponse(packet, "jTrace: Ill formed packet "); - - auto json_dict = json_object->GetAsDictionary(); - - if (!json_dict->GetValueForKeyAsInteger("traceid", uid) || - !json_dict->GetValueForKeyAsInteger("offset", offset) || - !json_dict->GetValueForKeyAsInteger("buffersize", byte_count)) - return SendIllFormedResponse(packet, "jTrace: Ill formed packet "); - - json_dict->GetValueForKeyAsInteger("threadid", tid); - - // Allocate the response buffer. - std::unique_ptr<uint8_t[]> buffer (new (std::nothrow) uint8_t[byte_count]); - if (!buffer) - return SendErrorResponse(0x78); - - StreamGDBRemote response; - Status error; - llvm::MutableArrayRef<uint8_t> buf(buffer.get(), byte_count); - - if (tracetype == BufferData) - error = m_debugged_process_up->GetData(uid, tid, buf, offset); - else if (tracetype == MetaData) - error = m_debugged_process_up->GetMetaData(uid, tid, buf, offset); - - if (error.Fail()) - return SendErrorResponse(error); + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(Status("Process not running.")); - for (auto i : buf) - response.PutHex8(i); + packet.ConsumeFront("jLLDBTraceGetBinaryData:"); + llvm::Expected<TraceGetBinaryDataRequest> request = + llvm::json::parse<TraceGetBinaryDataRequest>(packet.Peek(), + "TraceGetBinaryDataRequest"); + if (!request) + return SendErrorResponse(Status(request.takeError())); - StreamGDBRemote escaped_response; - escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); - return SendPacketNoLock(escaped_response.GetString()); + if (Expected<std::vector<uint8_t>> bytes = + m_current_process->TraceGetBinaryData(*request)) { + StreamGDBRemote response; + response.PutEscapedBytes(bytes->data(), bytes->size()); + return SendPacketNoLock(response.GetString()); + } else + return SendErrorResponse(bytes.takeError()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); - lldb::pid_t pid = m_debugged_process_up->GetID(); + lldb::pid_t pid = m_current_process->GetID(); if (pid == LLDB_INVALID_PROCESS_ID) return SendErrorResponse(1); @@ -1446,16 +1339,16 @@ GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qC(StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); // Make sure we set the current thread so g and p packets return the data the // gdb will expect. - lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID(); + lldb::tid_t tid = m_current_process->GetCurrentThreadID(); SetCurrentThreadID(tid); - NativeThreadProtocol *thread = m_debugged_process_up->GetCurrentThread(); + NativeThreadProtocol *thread = m_current_process->GetCurrentThread(); if (!thread) return SendErrorResponse(69); @@ -1471,15 +1364,15 @@ GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { StopSTDIOForwarding(); - if (!m_debugged_process_up) { + if (!m_current_process) { LLDB_LOG(log, "No debugged process found."); return PacketResult::Success; } - Status error = m_debugged_process_up->Kill(); + Status error = m_current_process->Kill(); if (error.Fail()) LLDB_LOG(log, "Failed to kill debugged process {0}: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); // No OK response for kill packet. // return SendOKResponse (); @@ -1521,12 +1414,26 @@ GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir( } GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_QThreadSuffixSupported( + StringExtractorGDBRemote &packet) { + m_thread_suffix_supported = true; + return SendOKResponse(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_QListThreadsInStopReply( + StringExtractorGDBRemote &packet) { + m_list_threads_in_stop_reply = true; + return SendOKResponse(); +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); // Ensure we have a native process. - if (!m_debugged_process_up) { + if (!m_continue_process) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s no debugged process " "shared pointer", @@ -1579,20 +1486,20 @@ GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { } else { // Send the signal to the process since we weren't targeting a specific // continue thread with the signal. - error = m_debugged_process_up->Signal(signo); + error = m_continue_process->Signal(signo); if (error.Fail()) { LLDB_LOG(log, "failed to send signal for process {0}: {1}", - m_debugged_process_up->GetID(), error); + m_continue_process->GetID(), error); return SendErrorResponse(0x52); } } // Resume the threads. - error = m_debugged_process_up->Resume(resume_actions); + error = m_continue_process->Resume(resume_actions); if (error.Fail()) { LLDB_LOG(log, "failed to resume threads for process {0}: {1}", - m_debugged_process_up->GetID(), error); + m_continue_process->GetID(), error); return SendErrorResponse(0x38); } @@ -1617,7 +1524,7 @@ GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) { } // Ensure we have a native process. - if (!m_debugged_process_up) { + if (!m_continue_process) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s no debugged process " "shared pointer", @@ -1629,14 +1536,14 @@ GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) { ResumeActionList actions(StateType::eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); - Status error = m_debugged_process_up->Resume(actions); + Status error = m_continue_process->Resume(actions); if (error.Fail()) { - LLDB_LOG(log, "c failed for process {0}: {1}", - m_debugged_process_up->GetID(), error); + LLDB_LOG(log, "c failed for process {0}: {1}", m_continue_process->GetID(), + error); return SendErrorResponse(GDBRemoteServerError::eErrorResume); } - LLDB_LOG(log, "continued process {0}", m_debugged_process_up->GetID()); + LLDB_LOG(log, "continued process {0}", m_continue_process->GetID()); // No response required from continue. return PacketResult::Success; } @@ -1679,7 +1586,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont( } // Ensure we have a native process. - if (!m_debugged_process_up) { + if (!m_continue_process) { LLDB_LOG(log, "no debugged process"); return SendErrorResponse(0x36); } @@ -1732,23 +1639,27 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont( // Consume the separator. packet.GetChar(); - thread_action.tid = packet.GetHexMaxU32(false, LLDB_INVALID_THREAD_ID); - if (thread_action.tid == LLDB_INVALID_THREAD_ID) - return SendIllFormedResponse( - packet, "Could not parse thread number in vCont packet"); + llvm::Expected<lldb::tid_t> tid_ret = + ReadTid(packet, /*allow_all=*/true, m_continue_process->GetID()); + if (!tid_ret) + return SendErrorResponse(tid_ret.takeError()); + + thread_action.tid = tid_ret.get(); + if (thread_action.tid == StringExtractorGDBRemote::AllThreads) + thread_action.tid = LLDB_INVALID_THREAD_ID; } thread_actions.Append(thread_action); } - Status error = m_debugged_process_up->Resume(thread_actions); + Status error = m_continue_process->Resume(thread_actions); if (error.Fail()) { LLDB_LOG(log, "vCont failed for process {0}: {1}", - m_debugged_process_up->GetID(), error); + m_continue_process->GetID(), error); return SendErrorResponse(GDBRemoteServerError::eErrorResume); } - LLDB_LOG(log, "continued process {0}", m_debugged_process_up->GetID()); + LLDB_LOG(log, "continued process {0}", m_continue_process->GetID()); // No response required from vCont. return PacketResult::Success; } @@ -1758,8 +1669,8 @@ void GDBRemoteCommunicationServerLLGS::SetCurrentThreadID(lldb::tid_t tid) { LLDB_LOG(log, "setting current thread id to {0}", tid); m_current_tid = tid; - if (m_debugged_process_up) - m_debugged_process_up->SetCurrentThreadID(m_current_tid); + if (m_current_process) + m_current_process->SetCurrentThreadID(m_current_tid); } void GDBRemoteCommunicationServerLLGS::SetContinueThreadID(lldb::tid_t tid) { @@ -1775,10 +1686,10 @@ GDBRemoteCommunicationServerLLGS::Handle_stop_reason( // Handle the $? gdbremote command. // If no process, indicate error - if (!m_debugged_process_up) + if (!m_current_process) return SendErrorResponse(02); - return SendStopReasonForState(m_debugged_process_up->GetState()); + return SendStopReasonForState(m_current_process->GetState()); } GDBRemoteCommunication::PacketResult @@ -1799,8 +1710,8 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState( case eStateSuspended: case eStateStopped: case eStateCrashed: { - assert(m_debugged_process_up != nullptr); - lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID(); + assert(m_current_process != nullptr); + lldb::tid_t tid = m_current_process->GetCurrentThreadID(); // Make sure we set the current thread so g and p packets return the data // the gdb will expect. SetCurrentThreadID(tid); @@ -1810,11 +1721,11 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState( case eStateInvalid: case eStateUnloaded: case eStateExited: - return SendWResponse(m_debugged_process_up.get()); + return SendWResponse(m_current_process); default: LLDB_LOG(log, "pid {0}, current state reporting not handled: {1}", - m_debugged_process_up->GetID(), process_state); + m_current_process->GetID(), process_state); break; } @@ -1825,12 +1736,12 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); // Ensure we have a thread. - NativeThreadProtocol *thread = m_debugged_process_up->GetThreadAtIndex(0); + NativeThreadProtocol *thread = m_current_process->GetThreadAtIndex(0); if (!thread) return SendErrorResponse(69); @@ -1925,11 +1836,11 @@ GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOG(log, "no process ({0}), returning OK", - m_debugged_process_up ? "invalid process id" - : "null m_debugged_process_up"); + m_current_process ? "invalid process id" + : "null m_current_process"); return SendOKResponse(); } @@ -1940,9 +1851,9 @@ GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo( NativeThreadProtocol *thread; uint32_t thread_index; for (thread_index = 0, - thread = m_debugged_process_up->GetThreadAtIndex(thread_index); + thread = m_current_process->GetThreadAtIndex(thread_index); thread; ++thread_index, - thread = m_debugged_process_up->GetThreadAtIndex(thread_index)) { + thread = m_current_process->GetThreadAtIndex(thread_index)) { LLDB_LOG(log, "iterated thread {0}(tid={2})", thread_index, thread->GetID()); if (thread_index > 0) @@ -2163,9 +2074,8 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { // Build the reginfos response. StreamGDBRemote response; - RegisterValue reg_value( - makeArrayRef(reg_bytes, reg_size), - m_debugged_process_up->GetArchitecture().GetByteOrder()); + RegisterValue reg_value(makeArrayRef(reg_bytes, reg_size), + m_current_process->GetArchitecture().GetByteOrder()); Status error = reg_context.WriteRegister(reg_info, reg_value); if (error.Fail()) { LLDB_LOGF(log, @@ -2182,16 +2092,6 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { - LLDB_LOGF( - log, - "GDBRemoteCommunicationServerLLGS::%s failed, no process available", - __FUNCTION__); - return SendErrorResponse(0x15); - } - // Parse out which variant of $H is requested. packet.SetFilePos(strlen("H")); if (packet.GetBytesLeft() < 1) { @@ -2203,11 +2103,14 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { } const char h_variant = packet.GetChar(); + NativeProcessProtocol *default_process; switch (h_variant) { case 'g': + default_process = m_current_process; break; case 'c': + default_process = m_continue_process; break; default: @@ -2220,14 +2123,32 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { } // Parse out the thread number. - // FIXME return a parse success/fail value. All values are valid here. - const lldb::tid_t tid = - packet.GetHexMaxU64(false, std::numeric_limits<lldb::tid_t>::max()); + auto pid_tid = packet.GetPidTid(default_process ? default_process->GetID() + : LLDB_INVALID_PROCESS_ID); + if (!pid_tid) + return SendErrorResponse(llvm::make_error<StringError>( + inconvertibleErrorCode(), "Malformed thread-id")); + + lldb::pid_t pid = pid_tid->first; + lldb::tid_t tid = pid_tid->second; + + if (pid == StringExtractorGDBRemote::AllProcesses) + return SendUnimplementedResponse("Selecting all processes not supported"); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(llvm::make_error<StringError>( + inconvertibleErrorCode(), "No current process and no PID provided")); + + // Check the process ID and find respective process instance. + auto new_process_it = m_debugged_processes.find(pid); + if (new_process_it == m_debugged_processes.end()) + return SendErrorResponse(llvm::make_error<StringError>( + inconvertibleErrorCode(), + llvm::formatv("No process with PID {0} debugged", pid))); // Ensure we have the given thread when not specifying -1 (all threads) or 0 // (any thread). if (tid != LLDB_INVALID_THREAD_ID && tid != 0) { - NativeThreadProtocol *thread = m_debugged_process_up->GetThreadByID(tid); + NativeThreadProtocol *thread = new_process_it->second->GetThreadByID(tid); if (!thread) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64 @@ -2237,13 +2158,15 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { } } - // Now switch the given thread type. + // Now switch the given process and thread type. switch (h_variant) { case 'g': + m_current_process = new_process_it->second.get(); SetCurrentThreadID(tid); break; case 'c': + m_continue_process = new_process_it->second.get(); SetContinueThreadID(tid); break; @@ -2261,8 +2184,8 @@ GDBRemoteCommunicationServerLLGS::Handle_I(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2297,21 +2220,21 @@ GDBRemoteCommunicationServerLLGS::Handle_interrupt( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOG(log, "failed, no process available"); return SendErrorResponse(0x15); } // Interrupt the process. - Status error = m_debugged_process_up->Interrupt(); + Status error = m_current_process->Interrupt(); if (error.Fail()) { - LLDB_LOG(log, "failed for process {0}: {1}", m_debugged_process_up->GetID(), + LLDB_LOG(log, "failed for process {0}: {1}", m_current_process->GetID(), error); return SendErrorResponse(GDBRemoteServerError::eErrorResume); } - LLDB_LOG(log, "stopped process {0}", m_debugged_process_up->GetID()); + LLDB_LOG(log, "stopped process {0}", m_current_process->GetID()); // No response required from stop all. return PacketResult::Success; @@ -2322,8 +2245,8 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2365,13 +2288,13 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( // Retrieve the process memory. size_t bytes_read = 0; - Status error = m_debugged_process_up->ReadMemoryWithoutTrap( + Status error = m_current_process->ReadMemoryWithoutTrap( read_addr, &buf[0], byte_count, bytes_read); if (error.Fail()) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", - __FUNCTION__, m_debugged_process_up->GetID(), read_addr, + __FUNCTION__, m_current_process->GetID(), read_addr, error.AsCString()); return SendErrorResponse(0x08); } @@ -2380,8 +2303,7 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes", - __FUNCTION__, m_debugged_process_up->GetID(), read_addr, - byte_count); + __FUNCTION__, m_current_process->GetID(), read_addr, byte_count); return SendErrorResponse(0x08); } @@ -2403,8 +2325,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2439,8 +2361,7 @@ GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) { } } - llvm::Expected<addr_t> addr = - m_debugged_process_up->AllocateMemory(size, perms); + llvm::Expected<addr_t> addr = m_current_process->AllocateMemory(size, perms); if (!addr) return SendErrorResponse(addr.takeError()); @@ -2453,8 +2374,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle__m(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2471,7 +2392,7 @@ GDBRemoteCommunicationServerLLGS::Handle__m(StringExtractorGDBRemote &packet) { if (addr == LLDB_INVALID_ADDRESS) return SendIllFormedResponse(packet, "Address not valid"); - if (llvm::Error Err = m_debugged_process_up->DeallocateMemory(addr)) + if (llvm::Error Err = m_current_process->DeallocateMemory(addr)) return SendErrorResponse(std::move(Err)); return SendOKResponse(); @@ -2481,8 +2402,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2531,8 +2452,7 @@ GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { LLDB_LOG(log, "pid {0} mem {1:x}: asked to write {2} bytes, but only found {3} " "to convert.", - m_debugged_process_up->GetID(), write_addr, byte_count, - convert_count); + m_current_process->GetID(), write_addr, byte_count, convert_count); return SendIllFormedResponse(packet, "M content byte length specified did " "not match hex-encoded content " "length"); @@ -2540,17 +2460,17 @@ GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { // Write the process memory. size_t bytes_written = 0; - Status error = m_debugged_process_up->WriteMemory(write_addr, &buf[0], - byte_count, bytes_written); + Status error = m_current_process->WriteMemory(write_addr, &buf[0], byte_count, + bytes_written); if (error.Fail()) { LLDB_LOG(log, "pid {0} mem {1:x}: failed to write. Error: {2}", - m_debugged_process_up->GetID(), write_addr, error); + m_current_process->GetID(), write_addr, error); return SendErrorResponse(0x09); } if (bytes_written == 0) { LLDB_LOG(log, "pid {0} mem {1:x}: wrote 0 of {2} requested bytes", - m_debugged_process_up->GetID(), write_addr, byte_count); + m_current_process->GetID(), write_addr, byte_count); return SendErrorResponse(0x09); } @@ -2569,8 +2489,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported( // Ensure we have a process running; otherwise, we can't figure this out // since we won't have a NativeProcessProtocol. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2580,8 +2500,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported( // Test if we can get any region back when asking for the region around NULL. MemoryRegionInfo region_info; - const Status error = - m_debugged_process_up->GetMemoryRegionInfo(0, region_info); + const Status error = m_current_process->GetMemoryRegionInfo(0, region_info); if (error.Fail()) { // We don't support memory region info collection for this // NativeProcessProtocol. @@ -2597,8 +2516,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // Ensure we have a process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2619,7 +2538,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( // Get the memory region info for the target address. MemoryRegionInfo region_info; const Status error = - m_debugged_process_up->GetMemoryRegionInfo(read_addr, region_info); + m_current_process->GetMemoryRegionInfo(read_addr, region_info); if (error.Fail()) { // Return the error message. @@ -2674,8 +2593,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { // Ensure we have a process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); LLDB_LOG(log, "failed, no process available"); return SendErrorResponse(0x15); @@ -2745,22 +2664,22 @@ GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { if (want_breakpoint) { // Try to set the breakpoint. const Status error = - m_debugged_process_up->SetBreakpoint(addr, size, want_hardware); + m_current_process->SetBreakpoint(addr, size, want_hardware); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); LLDB_LOG(log, "pid {0} failed to set breakpoint: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x09); } else { // Try to set the watchpoint. - const Status error = m_debugged_process_up->SetWatchpoint( + const Status error = m_current_process->SetWatchpoint( addr, size, watch_flags, want_hardware); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); LLDB_LOG(log, "pid {0} failed to set watchpoint: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x09); } } @@ -2768,8 +2687,8 @@ GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { // Ensure we have a process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); LLDB_LOG(log, "failed, no process available"); return SendErrorResponse(0x15); @@ -2833,21 +2752,21 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { if (want_breakpoint) { // Try to clear the breakpoint. const Status error = - m_debugged_process_up->RemoveBreakpoint(addr, want_hardware); + m_current_process->RemoveBreakpoint(addr, want_hardware); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); LLDB_LOG(log, "pid {0} failed to remove breakpoint: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x09); } else { // Try to clear the watchpoint. - const Status error = m_debugged_process_up->RemoveWatchpoint(addr); + const Status error = m_current_process->RemoveWatchpoint(addr); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); LLDB_LOG(log, "pid {0} failed to remove watchpoint: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x09); } } @@ -2857,8 +2776,8 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Ensure we have a process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_continue_process || + (m_continue_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2876,7 +2795,7 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { // Double check that we have such a thread. // TODO investigate: on MacOSX we might need to do an UpdateThreads () here. - NativeThreadProtocol *thread = m_debugged_process_up->GetThreadByID(tid); + NativeThreadProtocol *thread = m_continue_process->GetThreadByID(tid); if (!thread) return SendErrorResponse(0x33); @@ -2889,12 +2808,12 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { // All other threads stop while we're single stepping a thread. actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); - Status error = m_debugged_process_up->Resume(actions); + Status error = m_continue_process->Resume(actions); if (error.Fail()) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", - __FUNCTION__, m_debugged_process_up->GetID(), tid, + __FUNCTION__, m_continue_process->GetID(), tid, error.AsCString()); return SendErrorResponse(0x49); } @@ -2906,7 +2825,7 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> GDBRemoteCommunicationServerLLGS::BuildTargetXml() { // Ensure we have a thread. - NativeThreadProtocol *thread = m_debugged_process_up->GetThreadAtIndex(0); + NativeThreadProtocol *thread = m_current_process->GetThreadAtIndex(0); if (!thread) return llvm::createStringError(llvm::inconvertibleErrorCode(), "No thread available"); @@ -2921,7 +2840,7 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() { response.Printf("<target version=\"1.0\">"); response.Printf("<architecture>%s</architecture>", - m_debugged_process_up->GetArchitecture() + m_current_process->GetArchitecture() .GetTriple() .getArchName() .str() @@ -3010,22 +2929,22 @@ llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object, llvm::StringRef annex) { // Make sure we have a valid process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "No process available"); } if (object == "auxv") { // Grab the auxv data. - auto buffer_or_error = m_debugged_process_up->GetAuxvData(); + auto buffer_or_error = m_current_process->GetAuxvData(); if (!buffer_or_error) return llvm::errorCodeToError(buffer_or_error.getError()); return std::move(*buffer_or_error); } if (object == "libraries-svr4") { - auto library_list = m_debugged_process_up->GetLoadedSVR4Libraries(); + auto library_list = m_current_process->GetLoadedSVR4Libraries(); if (!library_list) return library_list.takeError(); @@ -3148,7 +3067,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState( Status error = reg_context.ReadAllRegisterValues(register_data_sp); if (error.Fail()) { LLDB_LOG(log, "pid {0} failed to save all register values: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x75); } @@ -3211,7 +3130,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( if (it == m_saved_registers_map.end()) { LLDB_LOG(log, "pid {0} does not have a register set save buffer for id {1}", - m_debugged_process_up->GetID(), save_id); + m_current_process->GetID(), save_id); return SendErrorResponse(0x77); } register_data_sp = it->second; @@ -3223,7 +3142,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( Status error = reg_context.WriteAllRegisterValues(register_data_sp); if (error.Fail()) { LLDB_LOG(log, "pid {0} failed to restore all register values: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x77); } @@ -3263,7 +3182,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach( } // Notify we attached by sending a stop packet. - return SendStopReasonForState(m_debugged_process_up->GetState()); + return SendStopReasonForState(m_current_process->GetState()); } GDBRemoteCommunication::PacketResult @@ -3293,7 +3212,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttachWait( } // Notify we attached by sending a stop packet. - return SendStopReasonForState(m_debugged_process_up->GetState()); + return SendStopReasonForState(m_current_process->GetState()); } GDBRemoteCommunication::PacketResult @@ -3329,25 +3248,13 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait( } // Notify we attached by sending a stop packet. - return SendStopReasonForState(m_debugged_process_up->GetState()); + return SendStopReasonForState(m_current_process->GetState()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - StopSTDIOForwarding(); - // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { - LLDB_LOGF( - log, - "GDBRemoteCommunicationServerLLGS::%s failed, no process available", - __FUNCTION__); - return SendErrorResponse(0x15); - } - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; // Consume the ';' after D. @@ -3362,19 +3269,32 @@ GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { return SendIllFormedResponse(packet, "D failed to parse the process id"); } - if (pid != LLDB_INVALID_PROCESS_ID && m_debugged_process_up->GetID() != pid) { - return SendIllFormedResponse(packet, "Invalid pid"); - } - - const Status error = m_debugged_process_up->Detach(); - if (error.Fail()) { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s failed to detach from " - "pid %" PRIu64 ": %s\n", - __FUNCTION__, m_debugged_process_up->GetID(), error.AsCString()); - return SendErrorResponse(0x01); + // Detach forked children if their PID was specified *or* no PID was requested + // (i.e. detach-all packet). + llvm::Error detach_error = llvm::Error::success(); + bool detached = false; + for (auto it = m_debugged_processes.begin(); + it != m_debugged_processes.end();) { + if (pid == LLDB_INVALID_PROCESS_ID || pid == it->first) { + if (llvm::Error e = it->second->Detach().ToError()) + detach_error = llvm::joinErrors(std::move(detach_error), std::move(e)); + else { + if (it->second.get() == m_current_process) + m_current_process = nullptr; + if (it->second.get() == m_continue_process) + m_continue_process = nullptr; + it = m_debugged_processes.erase(it); + detached = true; + continue; + } + } + ++it; } + if (detach_error) + return SendErrorResponse(std::move(detach_error)); + if (!detached) + return SendErrorResponse(Status("PID %" PRIu64 " not traced", pid)); return SendOKResponse(); } @@ -3384,7 +3304,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); packet.SetFilePos(strlen("qThreadStopInfo")); - const lldb::tid_t tid = packet.GetHexMaxU32(false, LLDB_INVALID_THREAD_ID); + const lldb::tid_t tid = packet.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID); if (tid == LLDB_INVALID_THREAD_ID) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed, could not " @@ -3401,19 +3321,19 @@ GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Ensure we have a debugged process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(50); - LLDB_LOG(log, "preparing packet for pid {0}", m_debugged_process_up->GetID()); + LLDB_LOG(log, "preparing packet for pid {0}", m_current_process->GetID()); StreamString response; const bool threads_with_valid_stop_info_only = false; - llvm::Expected<json::Value> threads_info = GetJSONThreadsInfo( - *m_debugged_process_up, threads_with_valid_stop_info_only); + llvm::Expected<json::Value> threads_info = + GetJSONThreadsInfo(*m_current_process, threads_with_valid_stop_info_only); if (!threads_info) { LLDB_LOG_ERROR(log, threads_info.takeError(), "failed to prepare a packet for pid {1}: {0}", - m_debugged_process_up->GetID()); + m_current_process->GetID()); return SendErrorResponse(52); } @@ -3427,8 +3347,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID) + if (!m_current_process || + m_current_process->GetID() == LLDB_INVALID_PROCESS_ID) return SendErrorResponse(68); packet.SetFilePos(strlen("qWatchpointSupportInfo")); @@ -3437,7 +3357,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo( if (packet.GetChar() != ':') return SendErrorResponse(67); - auto hw_debug_cap = m_debugged_process_up->GetHardwareDebugSupportInfo(); + auto hw_debug_cap = m_current_process->GetHardwareDebugSupportInfo(); StreamGDBRemote response; if (hw_debug_cap == llvm::None) @@ -3452,8 +3372,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID) + if (!m_current_process || + m_current_process->GetID() == LLDB_INVALID_PROCESS_ID) return SendErrorResponse(67); packet.SetFilePos(strlen("qFileLoadAddress:")); @@ -3465,7 +3385,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress( lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS; Status error = - m_debugged_process_up->GetFileLoadAddress(file_name, file_load_address); + m_current_process->GetFileLoadAddress(file_name, file_load_address); if (error.Fail()) return SendErrorResponse(69); @@ -3501,16 +3421,169 @@ GDBRemoteCommunicationServerLLGS::Handle_QPassSignals( } // Fail if we don't have a current process. - if (!m_debugged_process_up) + if (!m_current_process) return SendErrorResponse(68); - Status error = m_debugged_process_up->IgnoreSignals(signals); + Status error = m_current_process->IgnoreSignals(signals); if (error.Fail()) return SendErrorResponse(69); return SendOKResponse(); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qMemTags( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Ensure we have a process. + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + LLDB_LOGF( + log, + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(1); + } + + // We are expecting + // qMemTags:<hex address>,<hex length>:<hex type> + + // Address + packet.SetFilePos(strlen("qMemTags:")); + const char *current_char = packet.Peek(); + if (!current_char || *current_char == ',') + return SendIllFormedResponse(packet, "Missing address in qMemTags packet"); + const lldb::addr_t addr = packet.GetHexMaxU64(/*little_endian=*/false, 0); + + // Length + char previous_char = packet.GetChar(); + current_char = packet.Peek(); + // If we don't have a separator or the length field is empty + if (previous_char != ',' || (current_char && *current_char == ':')) + return SendIllFormedResponse(packet, + "Invalid addr,length pair in qMemTags packet"); + + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse( + packet, "Too short qMemtags: packet (looking for length)"); + const size_t length = packet.GetHexMaxU64(/*little_endian=*/false, 0); + + // Type + const char *invalid_type_err = "Invalid type field in qMemTags: packet"; + if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':') + return SendIllFormedResponse(packet, invalid_type_err); + + int32_t type = + packet.GetS32(std::numeric_limits<int32_t>::max(), /*base=*/16); + if (type == std::numeric_limits<int32_t>::max() || + // To catch inputs like "123aardvark" that will parse but clearly aren't + // valid in this case. + packet.GetBytesLeft()) { + return SendIllFormedResponse(packet, invalid_type_err); + } + + StreamGDBRemote response; + std::vector<uint8_t> tags; + Status error = m_current_process->ReadMemoryTags(type, addr, length, tags); + if (error.Fail()) + return SendErrorResponse(1); + + // This m is here in case we want to support multi part replies in the future. + // In the same manner as qfThreadInfo/qsThreadInfo. + response.PutChar('m'); + response.PutBytesAsRawHex8(tags.data(), tags.size()); + return SendPacketNoLock(response.GetString()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_QMemTags( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Ensure we have a process. + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + LLDB_LOGF( + log, + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(1); + } + + // We are expecting + // QMemTags:<hex address>,<hex length>:<hex type>:<tags as hex bytes> + + // Address + packet.SetFilePos(strlen("QMemTags:")); + const char *current_char = packet.Peek(); + if (!current_char || *current_char == ',') + return SendIllFormedResponse(packet, "Missing address in QMemTags packet"); + const lldb::addr_t addr = packet.GetHexMaxU64(/*little_endian=*/false, 0); + + // Length + char previous_char = packet.GetChar(); + current_char = packet.Peek(); + // If we don't have a separator or the length field is empty + if (previous_char != ',' || (current_char && *current_char == ':')) + return SendIllFormedResponse(packet, + "Invalid addr,length pair in QMemTags packet"); + + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse( + packet, "Too short QMemtags: packet (looking for length)"); + const size_t length = packet.GetHexMaxU64(/*little_endian=*/false, 0); + + // Type + const char *invalid_type_err = "Invalid type field in QMemTags: packet"; + if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':') + return SendIllFormedResponse(packet, invalid_type_err); + + // Our GetU64 uses strtoull which allows leading +/-, we don't want that. + const char *first_type_char = packet.Peek(); + if (first_type_char && (*first_type_char == '+' || *first_type_char == '-')) + return SendIllFormedResponse(packet, invalid_type_err); + + // The type is a signed integer but is in the packet as its raw bytes. + // So parse first as unsigned then cast to signed later. + // We extract to 64 bit, even though we only expect 32, so that we've + // got some invalid value we can check for. + uint64_t raw_type = + packet.GetU64(std::numeric_limits<uint64_t>::max(), /*base=*/16); + if (raw_type > std::numeric_limits<uint32_t>::max()) + return SendIllFormedResponse(packet, invalid_type_err); + int32_t type = static_cast<int32_t>(raw_type); + + // Tag data + if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':') + return SendIllFormedResponse(packet, + "Missing tag data in QMemTags: packet"); + + // Must be 2 chars per byte + const char *invalid_data_err = "Invalid tag data in QMemTags: packet"; + if (packet.GetBytesLeft() % 2) + return SendIllFormedResponse(packet, invalid_data_err); + + // This is bytes here and is unpacked into target specific tags later + // We cannot assume that number of bytes == length here because the server + // can repeat tags to fill a given range. + std::vector<uint8_t> tag_data; + // Zero length writes will not have any tag data + // (but we pass them on because it will still check that tagging is enabled) + if (packet.GetBytesLeft()) { + size_t byte_count = packet.GetBytesLeft() / 2; + tag_data.resize(byte_count); + size_t converted_bytes = packet.GetHexBytes(tag_data, 0); + if (converted_bytes != byte_count) { + return SendIllFormedResponse(packet, invalid_data_err); + } + } + + Status status = + m_current_process->WriteMemoryTags(type, addr, length, tag_data); + return status.Success() ? SendOKResponse() : SendErrorResponse(1); +} + void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); @@ -3539,8 +3612,8 @@ void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() { NativeThreadProtocol *GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( StringExtractorGDBRemote &packet) { // We have no thread if we don't have a process. - if (!m_debugged_process_up || - m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID) + if (!m_current_process || + m_current_process->GetID() == LLDB_INVALID_PROCESS_ID) return nullptr; // If the client hasn't asked for thread suffix support, there will not be a @@ -3551,9 +3624,9 @@ NativeThreadProtocol *GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( return nullptr; else if (current_tid == 0) { // Pick a thread. - return m_debugged_process_up->GetThreadAtIndex(0); + return m_current_process->GetThreadAtIndex(0); } else - return m_debugged_process_up->GetThreadByID(current_tid); + return m_current_process->GetThreadByID(current_tid); } Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); @@ -3583,7 +3656,7 @@ NativeThreadProtocol *GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( packet.SetFilePos(packet.GetFilePos() + strlen("thread:")); const lldb::tid_t tid = packet.GetHexMaxU64(false, 0); if (tid != 0) - return m_debugged_process_up->GetThreadByID(tid); + return m_current_process->GetThreadByID(tid); return nullptr; } @@ -3593,9 +3666,9 @@ lldb::tid_t GDBRemoteCommunicationServerLLGS::GetCurrentThreadID() const { // Use whatever the debug process says is the current thread id since the // protocol either didn't specify or specified we want any/all threads // marked as the current thread. - if (!m_debugged_process_up) + if (!m_current_process) return LLDB_INVALID_THREAD_ID; - return m_debugged_process_up->GetCurrentThreadID(); + return m_current_process->GetCurrentThreadID(); } // Use the specific current thread id set by the gdb remote protocol. return m_current_tid; @@ -3616,9 +3689,9 @@ void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData() { FileSpec GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string &module_path, const ArchSpec &arch) { - if (m_debugged_process_up) { + if (m_current_process) { FileSpec file_spec; - if (m_debugged_process_up + if (m_current_process ->GetLoadedModuleFileSpec(module_path.c_str(), file_spec) .Success()) { if (FileSystem::Instance().Exists(file_spec)) @@ -3653,3 +3726,93 @@ std::string GDBRemoteCommunicationServerLLGS::XMLEncodeAttributeValue( } return result; } + +llvm::Expected<lldb::tid_t> GDBRemoteCommunicationServerLLGS::ReadTid( + StringExtractorGDBRemote &packet, bool allow_all, lldb::pid_t default_pid) { + assert(m_current_process); + assert(m_current_process->GetID() != LLDB_INVALID_PROCESS_ID); + + auto pid_tid = packet.GetPidTid(default_pid); + if (!pid_tid) + return llvm::make_error<StringError>(inconvertibleErrorCode(), + "Malformed thread-id"); + + lldb::pid_t pid = pid_tid->first; + lldb::tid_t tid = pid_tid->second; + + if (!allow_all && pid == StringExtractorGDBRemote::AllProcesses) + return llvm::make_error<StringError>( + inconvertibleErrorCode(), + llvm::formatv("PID value {0} not allowed", pid == 0 ? 0 : -1)); + + if (!allow_all && tid == StringExtractorGDBRemote::AllThreads) + return llvm::make_error<StringError>( + inconvertibleErrorCode(), + llvm::formatv("TID value {0} not allowed", tid == 0 ? 0 : -1)); + + if (pid != StringExtractorGDBRemote::AllProcesses) { + if (pid != m_current_process->GetID()) + return llvm::make_error<StringError>( + inconvertibleErrorCode(), llvm::formatv("PID {0} not debugged", pid)); + } + + return tid; +} + +std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures( + const llvm::ArrayRef<llvm::StringRef> client_features) { + std::vector<std::string> ret = + GDBRemoteCommunicationServerCommon::HandleFeatures(client_features); + ret.insert(ret.end(), { + "QThreadSuffixSupported+", + "QListThreadsInStopReply+", + "qXfer:features:read+", + }); + + // report server-only features + using Extension = NativeProcessProtocol::Extension; + Extension plugin_features = m_process_factory.GetSupportedExtensions(); + if (bool(plugin_features & Extension::pass_signals)) + ret.push_back("QPassSignals+"); + if (bool(plugin_features & Extension::auxv)) + ret.push_back("qXfer:auxv:read+"); + if (bool(plugin_features & Extension::libraries_svr4)) + ret.push_back("qXfer:libraries-svr4:read+"); + if (bool(plugin_features & Extension::memory_tagging)) + ret.push_back("memory-tagging+"); + + // check for client features + m_extensions_supported = {}; + for (llvm::StringRef x : client_features) + m_extensions_supported |= + llvm::StringSwitch<Extension>(x) + .Case("multiprocess+", Extension::multiprocess) + .Case("fork-events+", Extension::fork) + .Case("vfork-events+", Extension::vfork) + .Default({}); + + m_extensions_supported &= plugin_features; + + // fork & vfork require multiprocess + if (!bool(m_extensions_supported & Extension::multiprocess)) + m_extensions_supported &= ~(Extension::fork | Extension::vfork); + + // report only if actually supported + if (bool(m_extensions_supported & Extension::multiprocess)) + ret.push_back("multiprocess+"); + if (bool(m_extensions_supported & Extension::fork)) + ret.push_back("fork-events+"); + if (bool(m_extensions_supported & Extension::vfork)) + ret.push_back("vfork-events+"); + + for (auto &x : m_debugged_processes) + SetEnabledExtensions(*x.second); + return ret; +} + +void GDBRemoteCommunicationServerLLGS::SetEnabledExtensions( + NativeProcessProtocol &process) { + NativeProcessProtocol::Extension flags = m_extensions_supported; + assert(!bool(flags & ~m_process_factory.GetSupportedExtensions())); + process.SetEnabledExtensions(flags); +} |