diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2023-04-14 21:41:27 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2023-06-22 18:20:56 +0000 |
| commit | bdd1243df58e60e85101c09001d9812a789b6bc4 (patch) | |
| tree | a1ce621c7301dd47ba2ddc3b8eaa63b441389481 /contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | |
| parent | 781624ca2d054430052c828ba8d2c2eaf2d733e7 (diff) | |
| parent | e3b557809604d036af6e00c60f012c2025b59a5e (diff) | |
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
| -rw-r--r-- | contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 824 |
1 files changed, 397 insertions, 427 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 3e1a6fb6620a..de8f2df52f23 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -60,7 +60,6 @@ #include "lldb/Utility/Args.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" @@ -69,6 +68,7 @@ #include <map> #include <memory> #include <mutex> +#include <optional> #include <sstream> #include <thread> @@ -85,6 +85,7 @@ #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/FormatAdapters.h" #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" @@ -166,13 +167,13 @@ public: } }; +} // namespace + static PluginProperties &GetGlobalPluginProperties() { static PluginProperties g_settings; return g_settings; } -} // namespace - // TODO Randomly assigning a port is unsafe. We should get an unused // ephemeral port from the kernel and make sure we reserve it before passing it // to debugserver. @@ -193,14 +194,13 @@ void ProcessGDBRemote::Terminate() { PluginManager::UnregisterPlugin(ProcessGDBRemote::CreateInstance); } -lldb::ProcessSP -ProcessGDBRemote::CreateInstance(lldb::TargetSP target_sp, - ListenerSP listener_sp, - const FileSpec *crash_file_path, - bool can_connect) { +lldb::ProcessSP ProcessGDBRemote::CreateInstance( + lldb::TargetSP target_sp, ListenerSP listener_sp, + const FileSpec *crash_file_path, bool can_connect) { lldb::ProcessSP process_sp; if (crash_file_path == nullptr) - process_sp = std::make_shared<ProcessGDBRemote>(target_sp, listener_sp); + process_sp = std::shared_ptr<ProcessGDBRemote>( + new ProcessGDBRemote(target_sp, listener_sp)); return process_sp; } @@ -267,12 +267,6 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadDidExit, "async thread did exit"); - if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { - repro::GDBRemoteProvider &provider = - g->GetOrCreate<repro::GDBRemoteProvider>(); - m_gdb_comm.SetPacketRecorder(provider.GetNewPacketRecorder()); - } - Log *log = GetLog(GDBRLog::Async); const uint32_t async_event_mask = @@ -286,14 +280,6 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, __FUNCTION__); } - const uint32_t gdb_event_mask = Communication::eBroadcastBitReadThreadDidExit; - if (m_async_listener_sp->StartListeningForEvents( - &m_gdb_comm, gdb_event_mask) != gdb_event_mask) { - LLDB_LOGF(log, - "ProcessGDBRemote::%s failed to listen for m_gdb_comm events", - __FUNCTION__); - } - const uint64_t timeout_seconds = GetGlobalPluginProperties().GetPacketTimeout(); if (timeout_seconds > 0) @@ -519,16 +505,16 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { AddRemoteRegisters(registers, arch_to_use); } -Status ProcessGDBRemote::WillLaunch(lldb_private::Module *module) { +Status ProcessGDBRemote::DoWillLaunch(lldb_private::Module *module) { return WillLaunchOrAttach(); } -Status ProcessGDBRemote::WillAttachToProcessWithID(lldb::pid_t pid) { +Status ProcessGDBRemote::DoWillAttachToProcessWithID(lldb::pid_t pid) { return WillLaunchOrAttach(); } -Status ProcessGDBRemote::WillAttachToProcessWithName(const char *process_name, - bool wait_for_launch) { +Status ProcessGDBRemote::DoWillAttachToProcessWithName(const char *process_name, + bool wait_for_launch) { return WillLaunchOrAttach(); } @@ -569,95 +555,6 @@ Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) { } } - // The remote stub may know about the "main binary" in - // the context of a firmware debug session, and can - // give us a UUID and an address/slide of where the - // binary is loaded in memory. - UUID standalone_uuid; - addr_t standalone_value; - bool standalone_value_is_offset; - if (m_gdb_comm.GetProcessStandaloneBinary( - standalone_uuid, standalone_value, standalone_value_is_offset)) { - ModuleSP module_sp; - - if (standalone_uuid.IsValid()) { - ModuleSpec module_spec; - module_spec.GetUUID() = standalone_uuid; - - // Look up UUID in global module cache before attempting - // a more expensive search. - Status error = ModuleList::GetSharedModule(module_spec, module_sp, - nullptr, nullptr, nullptr); - - if (!module_sp) { - // Force a an external lookup, if that tool is available. - if (!module_spec.GetSymbolFileSpec()) { - Status error; - Symbols::DownloadObjectAndSymbolFile(module_spec, error, true); - } - - if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { - module_sp = std::make_shared<Module>(module_spec); - } - } - - // If we couldn't find the binary anywhere else, as a last resort, - // read it out of memory. - if (!module_sp.get() && standalone_value != LLDB_INVALID_ADDRESS && - !standalone_value_is_offset) { - char namebuf[80]; - snprintf(namebuf, sizeof(namebuf), "mem-image-0x%" PRIx64, - standalone_value); - module_sp = - ReadModuleFromMemory(FileSpec(namebuf), standalone_value); - } - - Log *log = GetLog(LLDBLog::DynamicLoader); - if (module_sp.get()) { - target.GetImages().AppendIfNeeded(module_sp, false); - - bool changed = false; - if (module_sp->GetObjectFile()) { - if (standalone_value != LLDB_INVALID_ADDRESS) { - if (log) - log->Printf("Loading binary UUID %s at %s 0x%" PRIx64, - standalone_uuid.GetAsString().c_str(), - standalone_value_is_offset ? "offset" : "address", - standalone_value); - module_sp->SetLoadAddress(target, standalone_value, - standalone_value_is_offset, changed); - } else { - // No address/offset/slide, load the binary at file address, - // offset 0. - if (log) - log->Printf("Loading binary UUID %s at file address", - standalone_uuid.GetAsString().c_str()); - const bool value_is_slide = true; - module_sp->SetLoadAddress(target, 0, value_is_slide, changed); - } - } else { - // In-memory image, load at its true address, offset 0. - if (log) - log->Printf("Loading binary UUID %s from memory", - standalone_uuid.GetAsString().c_str()); - const bool value_is_slide = true; - module_sp->SetLoadAddress(target, 0, value_is_slide, changed); - } - - ModuleList added_module; - added_module.Append(module_sp, false); - target.ModulesDidLoad(added_module); - } else { - if (log) - log->Printf("Unable to find binary with UUID %s and load it at " - "%s 0x%" PRIx64, - standalone_uuid.GetAsString().c_str(), - standalone_value_is_offset ? "offset" : "address", - standalone_value); - } - } - } - const StateType state = SetThreadStopInfo(response); if (state != eStateInvalid) { SetPrivateState(state); @@ -745,9 +642,9 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module, "ProcessGDBRemote::%s provided with STDIO paths via " "launch_info: stdin=%s, stdout=%s, stderr=%s", __FUNCTION__, - stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", - stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", - stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); + stdin_file_spec ? stdin_file_spec.GetPath().c_str() : "<null>", + stdout_file_spec ? stdout_file_spec.GetPath().c_str() : "<null>", + stderr_file_spec ? stderr_file_spec.GetPath().c_str() : "<null>"); else LLDB_LOGF(log, "ProcessGDBRemote::%s no STDIO paths given via launch_info", @@ -810,18 +707,18 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module, "(IsHost() is true) using secondary: stdin=%s, stdout=%s, " "stderr=%s", __FUNCTION__, - stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", - stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", - stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); + stdin_file_spec ? stdin_file_spec.GetPath().c_str() : "<null>", + stdout_file_spec ? stdout_file_spec.GetPath().c_str() : "<null>", + stderr_file_spec ? stderr_file_spec.GetPath().c_str() : "<null>"); } LLDB_LOGF(log, "ProcessGDBRemote::%s final STDIO paths after all " "adjustments: stdin=%s, stdout=%s, stderr=%s", __FUNCTION__, - stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", - stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", - stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); + stdin_file_spec ? stdin_file_spec.GetPath().c_str() : "<null>", + stdout_file_spec ? stdout_file_spec.GetPath().c_str() : "<null>", + stderr_file_spec ? stderr_file_spec.GetPath().c_str() : "<null>"); if (stdin_file_spec) m_gdb_comm.SetSTDIN(stdin_file_spec); @@ -852,17 +749,17 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module, GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm, std::chrono::seconds(10)); - int arg_packet_err = m_gdb_comm.SendArgumentsPacket(launch_info); - if (arg_packet_err == 0) { - std::string error_str; - if (m_gdb_comm.GetLaunchSuccess(error_str)) { - SetID(m_gdb_comm.GetCurrentProcessID()); - } else { - error.SetErrorString(error_str.c_str()); - } + // Since we can't send argv0 separate from the executable path, we need to + // make sure to use the actual executable path found in the launch_info... + Args args = launch_info.GetArguments(); + if (FileSpec exe_file = launch_info.GetExecutableFile()) + args.ReplaceArgumentAtIndex(0, exe_file.GetPath(false)); + if (llvm::Error err = m_gdb_comm.LaunchProcess(args)) { + error.SetErrorStringWithFormatv("Cannot launch '{0}': {1}", + args.GetArgumentAtIndex(0), + llvm::fmt_consume(std::move(err))); } else { - error.SetErrorStringWithFormat("'A' packet returned an error: %i", - arg_packet_err); + SetID(m_gdb_comm.GetCurrentProcessID()); } } @@ -962,12 +859,12 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) { entry.c_str(), response); } }; - + PlatformSP platform_sp = GetTarget().GetPlatform(); if (platform_sp) { handle_cmds(platform_sp->GetExtraStartupCommands()); } - + // Then dispatch any process commands: handle_cmds(GetExtraStartupCommands()); @@ -996,8 +893,8 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { process_arch.GetTriple().getTriple()); } - if (int addresssable_bits = m_gdb_comm.GetAddressingBits()) { - lldb::addr_t address_mask = ~((1ULL << addresssable_bits) - 1); + if (int addressable_bits = m_gdb_comm.GetAddressingBits()) { + lldb::addr_t address_mask = ~((1ULL << addressable_bits) - 1); SetCodeAddressMask(address_mask); SetDataAddressMask(address_mask); } @@ -1058,6 +955,9 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { } } + // Target and Process are reasonably initailized; + // load any binaries we have metadata for / set load address. + LoadStubBinaries(); MaybeLoadExecutableModule(); // Find out which StructuredDataPlugins are supported by the debug monitor. @@ -1079,12 +979,65 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { } } +void ProcessGDBRemote::LoadStubBinaries() { + // The remote stub may know about the "main binary" in + // the context of a firmware debug session, and can + // give us a UUID and an address/slide of where the + // binary is loaded in memory. + UUID standalone_uuid; + addr_t standalone_value; + bool standalone_value_is_offset; + if (m_gdb_comm.GetProcessStandaloneBinary(standalone_uuid, standalone_value, + standalone_value_is_offset)) { + ModuleSP module_sp; + + if (standalone_uuid.IsValid()) { + const bool force_symbol_search = true; + const bool notify = true; + DynamicLoader::LoadBinaryWithUUIDAndAddress( + this, "", standalone_uuid, standalone_value, + standalone_value_is_offset, force_symbol_search, notify); + } + } + + // The remote stub may know about a list of binaries to + // force load into the process -- a firmware type situation + // where multiple binaries are present in virtual memory, + // and we are only given the addresses of the binaries. + // Not intended for use with userland debugging, when we use + // a DynamicLoader plugin that knows how to find the loaded + // binaries, and will track updates as binaries are added. + + std::vector<addr_t> bin_addrs = m_gdb_comm.GetProcessStandaloneBinaries(); + if (bin_addrs.size()) { + UUID uuid; + const bool value_is_slide = false; + for (addr_t addr : bin_addrs) { + const bool notify = true; + // First see if this is a special platform + // binary that may determine the DynamicLoader and + // Platform to be used in this Process and Target. + if (GetTarget() + .GetDebugger() + .GetPlatformList() + .LoadPlatformBinaryAndSetup(this, addr, notify)) + continue; + + const bool force_symbol_search = true; + // Second manually load this binary into the Target. + DynamicLoader::LoadBinaryWithUUIDAndAddress(this, llvm::StringRef(), uuid, + addr, value_is_slide, + force_symbol_search, notify); + } + } +} + void ProcessGDBRemote::MaybeLoadExecutableModule() { ModuleSP module_sp = GetTarget().GetExecutableModule(); if (!module_sp) return; - llvm::Optional<QOffsets> offsets = m_gdb_comm.GetQOffsets(); + std::optional<QOffsets> offsets = m_gdb_comm.GetQOffsets(); if (!offsets) return; @@ -1226,7 +1179,7 @@ Status ProcessGDBRemote::DoResume() { ListenerSP listener_sp( Listener::MakeListener("gdb-remote.resume-packet-sent")); if (listener_sp->StartListeningForEvents( - &m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent)) { + &m_gdb_comm, GDBRemoteClientBase::eBroadcastBitRunPacketSent)) { listener_sp->StartListeningForEvents( &m_async_broadcaster, ProcessGDBRemote::eBroadcastBitAsyncThreadDidExit); @@ -1236,11 +1189,18 @@ Status ProcessGDBRemote::DoResume() { StreamString continue_packet; bool continue_packet_error = false; if (m_gdb_comm.HasAnyVContSupport()) { + std::string pid_prefix; + if (m_gdb_comm.GetMultiprocessSupported()) + pid_prefix = llvm::formatv("p{0:x-}.", GetID()); + if (m_continue_c_tids.size() == num_threads || (m_continue_c_tids.empty() && m_continue_C_tids.empty() && m_continue_s_tids.empty() && m_continue_S_tids.empty())) { - // All threads are continuing, just send a "c" packet - continue_packet.PutCString("c"); + // All threads are continuing + if (m_gdb_comm.GetMultiprocessSupported()) + continue_packet.Format("vCont;c:{0}-1", pid_prefix); + else + continue_packet.PutCString("c"); } else { continue_packet.PutCString("vCont"); @@ -1250,7 +1210,7 @@ Status ProcessGDBRemote::DoResume() { t_pos = m_continue_c_tids.begin(), t_end = m_continue_c_tids.end(); t_pos != t_end; ++t_pos) - continue_packet.Printf(";c:%4.4" PRIx64, *t_pos); + continue_packet.Format(";c:{0}{1:x-}", pid_prefix, *t_pos); } else continue_packet_error = true; } @@ -1261,8 +1221,8 @@ Status ProcessGDBRemote::DoResume() { s_pos = m_continue_C_tids.begin(), s_end = m_continue_C_tids.end(); s_pos != s_end; ++s_pos) - continue_packet.Printf(";C%2.2x:%4.4" PRIx64, s_pos->second, - s_pos->first); + continue_packet.Format(";C{0:x-2}:{1}{2:x-}", s_pos->second, + pid_prefix, s_pos->first); } else continue_packet_error = true; } @@ -1273,7 +1233,7 @@ Status ProcessGDBRemote::DoResume() { t_pos = m_continue_s_tids.begin(), t_end = m_continue_s_tids.end(); t_pos != t_end; ++t_pos) - continue_packet.Printf(";s:%4.4" PRIx64, *t_pos); + continue_packet.Format(";s:{0}{1:x-}", pid_prefix, *t_pos); } else continue_packet_error = true; } @@ -1284,8 +1244,8 @@ Status ProcessGDBRemote::DoResume() { s_pos = m_continue_S_tids.begin(), s_end = m_continue_S_tids.end(); s_pos != s_end; ++s_pos) - continue_packet.Printf(";S%2.2x:%4.4" PRIx64, s_pos->second, - s_pos->first); + continue_packet.Format(";S{0:x-2}:{1}{2:x-}", s_pos->second, + pid_prefix, s_pos->first); } else continue_packet_error = true; } @@ -1652,281 +1612,276 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( // queue_serial are valid LazyBool associated_with_dispatch_queue, addr_t dispatch_queue_t, std::string &queue_name, QueueKind queue_kind, uint64_t queue_serial) { - ThreadSP thread_sp; - if (tid != LLDB_INVALID_THREAD_ID) { - // Scope for "locker" below - { - // m_thread_list_real does have its own mutex, but we need to hold onto - // the mutex between the call to m_thread_list_real.FindThreadByID(...) - // and the m_thread_list_real.AddThread(...) so it doesn't change on us - std::lock_guard<std::recursive_mutex> guard( - m_thread_list_real.GetMutex()); - thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false); - - if (!thread_sp) { - // Create the thread if we need to - thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid); - m_thread_list_real.AddThread(thread_sp); - } - } - - if (thread_sp) { - ThreadGDBRemote *gdb_thread = - static_cast<ThreadGDBRemote *>(thread_sp.get()); - RegisterContextSP gdb_reg_ctx_sp(gdb_thread->GetRegisterContext()); - - gdb_reg_ctx_sp->InvalidateIfNeeded(true); - auto iter = std::find(m_thread_ids.begin(), m_thread_ids.end(), tid); - if (iter != m_thread_ids.end()) { - SetThreadPc(thread_sp, iter - m_thread_ids.begin()); - } + if (tid == LLDB_INVALID_THREAD_ID) + return nullptr; - for (const auto &pair : expedited_register_map) { - StringExtractor reg_value_extractor(pair.second); - WritableDataBufferSP buffer_sp(new DataBufferHeap( - reg_value_extractor.GetStringRef().size() / 2, 0)); - reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc'); - uint32_t lldb_regnum = - gdb_reg_ctx_sp->ConvertRegisterKindToRegisterNumber( - eRegisterKindProcessPlugin, pair.first); - gdb_thread->PrivateSetRegisterValue(lldb_regnum, buffer_sp->GetData()); - } + ThreadSP thread_sp; + // Scope for "locker" below + { + // m_thread_list_real does have its own mutex, but we need to hold onto the + // mutex between the call to m_thread_list_real.FindThreadByID(...) and the + // m_thread_list_real.AddThread(...) so it doesn't change on us + std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); + thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false); + + if (!thread_sp) { + // Create the thread if we need to + thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid); + m_thread_list_real.AddThread(thread_sp); + } + } - // AArch64 SVE specific code below calls AArch64SVEReconfigure to update - // SVE register sizes and offsets if value of VG register has changed - // since last stop. - const ArchSpec &arch = GetTarget().GetArchitecture(); - if (arch.IsValid() && arch.GetTriple().isAArch64()) { - GDBRemoteRegisterContext *reg_ctx_sp = - static_cast<GDBRemoteRegisterContext *>( - gdb_thread->GetRegisterContext().get()); - - if (reg_ctx_sp) - reg_ctx_sp->AArch64SVEReconfigure(); - } + ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>(thread_sp.get()); + RegisterContextSP gdb_reg_ctx_sp(gdb_thread->GetRegisterContext()); - thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str()); + gdb_reg_ctx_sp->InvalidateIfNeeded(true); - gdb_thread->SetThreadDispatchQAddr(thread_dispatch_qaddr); - // Check if the GDB server was able to provide the queue name, kind and - // serial number - if (queue_vars_valid) - gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, - queue_serial, dispatch_queue_t, - associated_with_dispatch_queue); - else - gdb_thread->ClearQueueInfo(); + auto iter = std::find(m_thread_ids.begin(), m_thread_ids.end(), tid); + if (iter != m_thread_ids.end()) + SetThreadPc(thread_sp, iter - m_thread_ids.begin()); - gdb_thread->SetAssociatedWithLibdispatchQueue( - associated_with_dispatch_queue); + for (const auto &pair : expedited_register_map) { + StringExtractor reg_value_extractor(pair.second); + WritableDataBufferSP buffer_sp( + new DataBufferHeap(reg_value_extractor.GetStringRef().size() / 2, 0)); + reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc'); + uint32_t lldb_regnum = gdb_reg_ctx_sp->ConvertRegisterKindToRegisterNumber( + eRegisterKindProcessPlugin, pair.first); + gdb_thread->PrivateSetRegisterValue(lldb_regnum, buffer_sp->GetData()); + } - if (dispatch_queue_t != LLDB_INVALID_ADDRESS) - gdb_thread->SetQueueLibdispatchQueueAddress(dispatch_queue_t); + // AArch64 SVE specific code below calls AArch64SVEReconfigure to update + // SVE register sizes and offsets if value of VG register has changed + // since last stop. + const ArchSpec &arch = GetTarget().GetArchitecture(); + if (arch.IsValid() && arch.GetTriple().isAArch64()) { + GDBRemoteRegisterContext *reg_ctx_sp = + static_cast<GDBRemoteRegisterContext *>( + gdb_thread->GetRegisterContext().get()); - // Make sure we update our thread stop reason just once - if (!thread_sp->StopInfoIsUpToDate()) { - thread_sp->SetStopInfo(StopInfoSP()); - // If there's a memory thread backed by this thread, we need to use it - // to calculate StopInfo. - if (ThreadSP memory_thread_sp = - m_thread_list.GetBackingThread(thread_sp)) - thread_sp = memory_thread_sp; + if (reg_ctx_sp) + reg_ctx_sp->AArch64SVEReconfigure(); + } - if (exc_type != 0) { - const size_t exc_data_size = exc_data.size(); + thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str()); - thread_sp->SetStopInfo( - StopInfoMachException::CreateStopReasonWithMachException( - *thread_sp, exc_type, exc_data_size, - exc_data_size >= 1 ? exc_data[0] : 0, - exc_data_size >= 2 ? exc_data[1] : 0, - exc_data_size >= 3 ? exc_data[2] : 0)); - } else { - bool handled = false; - bool did_exec = false; - if (!reason.empty()) { - if (reason == "trace") { - addr_t pc = thread_sp->GetRegisterContext()->GetPC(); - lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() - ->GetBreakpointSiteList() - .FindByAddress(pc); - - // If the current pc is a breakpoint site then the StopInfo - // should be set to Breakpoint Otherwise, it will be set to - // Trace. - if (bp_site_sp && bp_site_sp->ValidForThisThread(*thread_sp)) { - thread_sp->SetStopInfo( - StopInfo::CreateStopReasonWithBreakpointSiteID( - *thread_sp, bp_site_sp->GetID())); - } else - thread_sp->SetStopInfo( - StopInfo::CreateStopReasonToTrace(*thread_sp)); - handled = true; - } else if (reason == "breakpoint") { - addr_t pc = thread_sp->GetRegisterContext()->GetPC(); - lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() - ->GetBreakpointSiteList() - .FindByAddress(pc); - if (bp_site_sp) { - // If the breakpoint is for this thread, then we'll report the - // hit, but if it is for another thread, we can just report no - // reason. We don't need to worry about stepping over the - // breakpoint here, that will be taken care of when the thread - // resumes and notices that there's a breakpoint under the pc. - handled = true; - if (bp_site_sp->ValidForThisThread(*thread_sp)) { - thread_sp->SetStopInfo( - StopInfo::CreateStopReasonWithBreakpointSiteID( - *thread_sp, bp_site_sp->GetID())); - } else { - StopInfoSP invalid_stop_info_sp; - thread_sp->SetStopInfo(invalid_stop_info_sp); - } - } - } else if (reason == "trap") { - // Let the trap just use the standard signal stop reason below... - } else if (reason == "watchpoint") { - StringExtractor desc_extractor(description.c_str()); - addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); - uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32); - addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); - watch_id_t watch_id = LLDB_INVALID_WATCH_ID; - if (wp_addr != LLDB_INVALID_ADDRESS) { - WatchpointSP wp_sp; - ArchSpec::Core core = GetTarget().GetArchitecture().GetCore(); - if ((core >= ArchSpec::kCore_mips_first && - core <= ArchSpec::kCore_mips_last) || - (core >= ArchSpec::eCore_arm_generic && - core <= ArchSpec::eCore_arm_aarch64)) - wp_sp = GetTarget().GetWatchpointList().FindByAddress( - wp_hit_addr); - if (!wp_sp) - wp_sp = - GetTarget().GetWatchpointList().FindByAddress(wp_addr); - if (wp_sp) { - wp_sp->SetHardwareIndex(wp_index); - watch_id = wp_sp->GetID(); - } - } - if (watch_id == LLDB_INVALID_WATCH_ID) { - Log *log(GetLog(GDBRLog::Watchpoints)); - LLDB_LOGF(log, "failed to find watchpoint"); - } - thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID( - *thread_sp, watch_id, wp_hit_addr)); - handled = true; - } else if (reason == "exception") { - thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException( - *thread_sp, description.c_str())); - handled = true; - } else if (reason == "exec") { - did_exec = true; - thread_sp->SetStopInfo( - StopInfo::CreateStopReasonWithExec(*thread_sp)); - handled = true; - } else if (reason == "processor trace") { - thread_sp->SetStopInfo(StopInfo::CreateStopReasonProcessorTrace( - *thread_sp, description.c_str())); - } else if (reason == "fork") { - StringExtractor desc_extractor(description.c_str()); - lldb::pid_t child_pid = desc_extractor.GetU64( - LLDB_INVALID_PROCESS_ID); - lldb::tid_t child_tid = desc_extractor.GetU64( - LLDB_INVALID_THREAD_ID); - thread_sp->SetStopInfo(StopInfo::CreateStopReasonFork( - *thread_sp, child_pid, child_tid)); - handled = true; - } else if (reason == "vfork") { - StringExtractor desc_extractor(description.c_str()); - lldb::pid_t child_pid = desc_extractor.GetU64( - LLDB_INVALID_PROCESS_ID); - lldb::tid_t child_tid = desc_extractor.GetU64( - LLDB_INVALID_THREAD_ID); - thread_sp->SetStopInfo(StopInfo::CreateStopReasonVFork( - *thread_sp, child_pid, child_tid)); - handled = true; - } else if (reason == "vforkdone") { - thread_sp->SetStopInfo( - StopInfo::CreateStopReasonVForkDone(*thread_sp)); - handled = true; - } - } else if (!signo) { - addr_t pc = thread_sp->GetRegisterContext()->GetPC(); - lldb::BreakpointSiteSP bp_site_sp = - thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress( - pc); - - // If the current pc is a breakpoint site then the StopInfo should - // be set to Breakpoint even though the remote stub did not set it - // as such. This can happen when the thread is involuntarily - // interrupted (e.g. due to stops on other threads) just as it is - // about to execute the breakpoint instruction. - if (bp_site_sp && bp_site_sp->ValidForThisThread(*thread_sp)) { + gdb_thread->SetThreadDispatchQAddr(thread_dispatch_qaddr); + // Check if the GDB server was able to provide the queue name, kind and serial + // number + if (queue_vars_valid) + gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial, + dispatch_queue_t, associated_with_dispatch_queue); + else + gdb_thread->ClearQueueInfo(); + + gdb_thread->SetAssociatedWithLibdispatchQueue(associated_with_dispatch_queue); + + if (dispatch_queue_t != LLDB_INVALID_ADDRESS) + gdb_thread->SetQueueLibdispatchQueueAddress(dispatch_queue_t); + + // Make sure we update our thread stop reason just once, but don't overwrite + // the stop info for threads that haven't moved: + StopInfoSP current_stop_info_sp = thread_sp->GetPrivateStopInfo(false); + if (thread_sp->GetTemporaryResumeState() == eStateSuspended && + current_stop_info_sp) { + thread_sp->SetStopInfo(current_stop_info_sp); + return thread_sp; + } + + if (!thread_sp->StopInfoIsUpToDate()) { + thread_sp->SetStopInfo(StopInfoSP()); + // If there's a memory thread backed by this thread, we need to use it to + // calculate StopInfo. + if (ThreadSP memory_thread_sp = m_thread_list.GetBackingThread(thread_sp)) + thread_sp = memory_thread_sp; + + if (exc_type != 0) { + const size_t exc_data_size = exc_data.size(); + + thread_sp->SetStopInfo( + StopInfoMachException::CreateStopReasonWithMachException( + *thread_sp, exc_type, exc_data_size, + exc_data_size >= 1 ? exc_data[0] : 0, + exc_data_size >= 2 ? exc_data[1] : 0, + exc_data_size >= 3 ? exc_data[2] : 0)); + } else { + bool handled = false; + bool did_exec = false; + if (!reason.empty()) { + if (reason == "trace") { + addr_t pc = thread_sp->GetRegisterContext()->GetPC(); + lldb::BreakpointSiteSP bp_site_sp = + thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress( + pc); + + // If the current pc is a breakpoint site then the StopInfo should be + // set to Breakpoint Otherwise, it will be set to Trace. + if (bp_site_sp && bp_site_sp->ValidForThisThread(*thread_sp)) { + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread_sp, bp_site_sp->GetID())); + } else + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonToTrace(*thread_sp)); + handled = true; + } else if (reason == "breakpoint") { + addr_t pc = thread_sp->GetRegisterContext()->GetPC(); + lldb::BreakpointSiteSP bp_site_sp = + thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress( + pc); + if (bp_site_sp) { + // If the breakpoint is for this thread, then we'll report the hit, + // but if it is for another thread, we can just report no reason. + // We don't need to worry about stepping over the breakpoint here, + // that will be taken care of when the thread resumes and notices + // that there's a breakpoint under the pc. + handled = true; + if (bp_site_sp->ValidForThisThread(*thread_sp)) { thread_sp->SetStopInfo( StopInfo::CreateStopReasonWithBreakpointSiteID( *thread_sp, bp_site_sp->GetID())); - handled = true; + } else { + StopInfoSP invalid_stop_info_sp; + thread_sp->SetStopInfo(invalid_stop_info_sp); } } - - if (!handled && signo && !did_exec) { - if (signo == SIGTRAP) { - // Currently we are going to assume SIGTRAP means we are either - // hitting a breakpoint or hardware single stepping. - handled = true; - addr_t pc = thread_sp->GetRegisterContext()->GetPC() + - m_breakpoint_pc_offset; - lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() - ->GetBreakpointSiteList() - .FindByAddress(pc); - - if (bp_site_sp) { - // If the breakpoint is for this thread, then we'll report the - // hit, but if it is for another thread, we can just report no - // reason. We don't need to worry about stepping over the - // breakpoint here, that will be taken care of when the thread - // resumes and notices that there's a breakpoint under the pc. - if (bp_site_sp->ValidForThisThread(*thread_sp)) { - if (m_breakpoint_pc_offset != 0) - thread_sp->GetRegisterContext()->SetPC(pc); - thread_sp->SetStopInfo( - StopInfo::CreateStopReasonWithBreakpointSiteID( - *thread_sp, bp_site_sp->GetID())); - } else { - StopInfoSP invalid_stop_info_sp; - thread_sp->SetStopInfo(invalid_stop_info_sp); - } - } else { - // If we were stepping then assume the stop was the result of - // the trace. If we were not stepping then report the SIGTRAP. - // FIXME: We are still missing the case where we single step - // over a trap instruction. - if (thread_sp->GetTemporaryResumeState() == eStateStepping) - thread_sp->SetStopInfo( - StopInfo::CreateStopReasonToTrace(*thread_sp)); - else - thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithSignal( - *thread_sp, signo, description.c_str())); - } + } else if (reason == "trap") { + // Let the trap just use the standard signal stop reason below... + } else if (reason == "watchpoint") { + StringExtractor desc_extractor(description.c_str()); + addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); + uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32); + addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); + watch_id_t watch_id = LLDB_INVALID_WATCH_ID; + if (wp_addr != LLDB_INVALID_ADDRESS) { + WatchpointSP wp_sp; + ArchSpec::Core core = GetTarget().GetArchitecture().GetCore(); + if ((core >= ArchSpec::kCore_mips_first && + core <= ArchSpec::kCore_mips_last) || + (core >= ArchSpec::eCore_arm_generic && + core <= ArchSpec::eCore_arm_aarch64)) + wp_sp = + GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr); + if (!wp_sp) + wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr); + if (wp_sp) { + wp_sp->SetHardwareIndex(wp_index); + watch_id = wp_sp->GetID(); } - if (!handled) - thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithSignal( - *thread_sp, signo, description.c_str())); } + if (watch_id == LLDB_INVALID_WATCH_ID) { + Log *log(GetLog(GDBRLog::Watchpoints)); + LLDB_LOGF(log, "failed to find watchpoint"); + } + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID( + *thread_sp, watch_id, wp_hit_addr)); + handled = true; + } else if (reason == "exception") { + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException( + *thread_sp, description.c_str())); + handled = true; + } else if (reason == "exec") { + did_exec = true; + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithExec(*thread_sp)); + handled = true; + } else if (reason == "processor trace") { + thread_sp->SetStopInfo(StopInfo::CreateStopReasonProcessorTrace( + *thread_sp, description.c_str())); + } else if (reason == "fork") { + StringExtractor desc_extractor(description.c_str()); + lldb::pid_t child_pid = + desc_extractor.GetU64(LLDB_INVALID_PROCESS_ID); + lldb::tid_t child_tid = desc_extractor.GetU64(LLDB_INVALID_THREAD_ID); + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonFork(*thread_sp, child_pid, child_tid)); + handled = true; + } else if (reason == "vfork") { + StringExtractor desc_extractor(description.c_str()); + lldb::pid_t child_pid = + desc_extractor.GetU64(LLDB_INVALID_PROCESS_ID); + lldb::tid_t child_tid = desc_extractor.GetU64(LLDB_INVALID_THREAD_ID); + thread_sp->SetStopInfo(StopInfo::CreateStopReasonVFork( + *thread_sp, child_pid, child_tid)); + handled = true; + } else if (reason == "vforkdone") { + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonVForkDone(*thread_sp)); + handled = true; + } + } else if (!signo) { + addr_t pc = thread_sp->GetRegisterContext()->GetPC(); + lldb::BreakpointSiteSP bp_site_sp = + thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); + + // If the current pc is a breakpoint site then the StopInfo should be + // set to Breakpoint even though the remote stub did not set it as such. + // This can happen when the thread is involuntarily interrupted (e.g. + // due to stops on other threads) just as it is about to execute the + // breakpoint instruction. + if (bp_site_sp && bp_site_sp->ValidForThisThread(*thread_sp)) { + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread_sp, bp_site_sp->GetID())); + handled = true; + } + } - if (!description.empty()) { - lldb::StopInfoSP stop_info_sp(thread_sp->GetStopInfo()); - if (stop_info_sp) { - const char *stop_info_desc = stop_info_sp->GetDescription(); - if (!stop_info_desc || !stop_info_desc[0]) - stop_info_sp->SetDescription(description.c_str()); + if (!handled && signo && !did_exec) { + if (signo == SIGTRAP) { + // Currently we are going to assume SIGTRAP means we are either + // hitting a breakpoint or hardware single stepping. + handled = true; + addr_t pc = + thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset; + lldb::BreakpointSiteSP bp_site_sp = + thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress( + pc); + + if (bp_site_sp) { + // If the breakpoint is for this thread, then we'll report the hit, + // but if it is for another thread, we can just report no reason. + // We don't need to worry about stepping over the breakpoint here, + // that will be taken care of when the thread resumes and notices + // that there's a breakpoint under the pc. + if (bp_site_sp->ValidForThisThread(*thread_sp)) { + if (m_breakpoint_pc_offset != 0) + thread_sp->GetRegisterContext()->SetPC(pc); + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread_sp, bp_site_sp->GetID())); } else { - thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException( - *thread_sp, description.c_str())); + StopInfoSP invalid_stop_info_sp; + thread_sp->SetStopInfo(invalid_stop_info_sp); } + } else { + // If we were stepping then assume the stop was the result of the + // trace. If we were not stepping then report the SIGTRAP. + // FIXME: We are still missing the case where we single step over a + // trap instruction. + if (thread_sp->GetTemporaryResumeState() == eStateStepping) + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonToTrace(*thread_sp)); + else + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *thread_sp, signo, description.c_str())); } } + if (!handled) + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *thread_sp, signo, description.c_str())); + } + + if (!description.empty()) { + lldb::StopInfoSP stop_info_sp(thread_sp->GetStopInfo()); + if (stop_info_sp) { + const char *stop_info_desc = stop_info_sp->GetDescription(); + if (!stop_info_desc || !stop_info_desc[0]) + stop_info_sp->SetDescription(description.c_str()); + } else { + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException( + *thread_sp, description.c_str())); + } } } } @@ -2915,7 +2870,7 @@ size_t ProcessGDBRemote::PutSTDIN(const char *src, size_t src_len, Status &error) { if (m_stdio_communication.IsConnected()) { ConnectionStatus status; - m_stdio_communication.Write(src, src_len, status, nullptr); + m_stdio_communication.WriteAll(src, src_len, status, nullptr); } else if (m_stdin_forward) { m_gdb_comm.SendStdinNotification(src, src_len); } @@ -3498,7 +3453,7 @@ thread_result_t ProcessGDBRemote::AsyncThread() { ") listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, GetID()); - if (m_async_listener_sp->GetEvent(event_sp, llvm::None)) { + if (m_async_listener_sp->GetEvent(event_sp, std::nullopt)) { const uint32_t event_type = event_sp->GetType(); if (event_sp->BroadcasterIs(&m_async_broadcaster)) { LLDB_LOGF(log, @@ -3610,21 +3565,6 @@ thread_result_t ProcessGDBRemote::AsyncThread() { done = true; break; } - } else if (event_sp->BroadcasterIs(&m_gdb_comm)) { - switch (event_type) { - case Communication::eBroadcastBitReadThreadDidExit: - SetExitStatus(-1, "lost connection"); - done = true; - break; - - default: - LLDB_LOGF(log, - "ProcessGDBRemote::%s(pid = %" PRIu64 - ") got unknown event 0x%8.8x", - __FUNCTION__, GetID(), event_type); - done = true; - break; - } } } else { LLDB_LOGF(log, @@ -3894,6 +3834,29 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos_sender( return object_sp; } +StructuredData::ObjectSP ProcessGDBRemote::GetDynamicLoaderProcessState() { + StructuredData::ObjectSP object_sp; + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + + if (m_gdb_comm.GetDynamicLoaderProcessStateSupported()) { + StringExtractorGDBRemote response; + response.SetResponseValidatorToJSON(); + if (m_gdb_comm.SendPacketAndWaitForResponse("jGetDyldProcessState", + response) == + GDBRemoteCommunication::PacketResult::Success) { + StringExtractorGDBRemote::ResponseType response_type = + response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) { + if (!response.Empty()) { + object_sp = + StructuredData::ParseJSON(std::string(response.GetStringRef())); + } + } + } + } + return object_sp; +} + StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() { StructuredData::ObjectSP object_sp; StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); @@ -4075,8 +4038,10 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, if (!feature_node) return false; + Log *log(GetLog(GDBRLog::Process)); + feature_node.ForEachChildElementWithName( - "reg", [&target_info, ®isters](const XMLNode ®_node) -> bool { + "reg", [&target_info, ®isters, log](const XMLNode ®_node) -> bool { std::string gdb_group; std::string gdb_type; DynamicRegisterInfo::Register reg_info; @@ -4085,9 +4050,9 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, // FIXME: we're silently ignoring invalid data here reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, - &encoding_set, &format_set, ®_info]( - const llvm::StringRef &name, - const llvm::StringRef &value) -> bool { + &encoding_set, &format_set, ®_info, + log](const llvm::StringRef &name, + const llvm::StringRef &value) -> bool { if (name == "name") { reg_info.name.SetString(value); } else if (name == "bitsize") { @@ -4144,10 +4109,10 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, SplitCommaSeparatedRegisterNumberString( value, reg_info.invalidate_regs, 0); } else { - Log *log(GetLog(GDBRLog::Process)); LLDB_LOGF(log, - "ProcessGDBRemote::%s unhandled reg attribute %s = %s", - __FUNCTION__, name.data(), value.data()); + "ProcessGDBRemote::ParseRegisters unhandled reg " + "attribute %s = %s", + name.data(), value.data()); } return true; // Keep iterating through all attributes }); @@ -4169,6 +4134,12 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, // them as vector (similarly to xmm/ymm) reg_info.format = eFormatVectorOfUInt8; reg_info.encoding = eEncodingVector; + } else { + LLDB_LOGF( + log, + "ProcessGDBRemote::ParseRegisters Could not determine lldb" + "format and encoding for gdb type %s", + gdb_type.c_str()); } } @@ -4186,7 +4157,6 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, } if (reg_info.byte_size == 0) { - Log *log(GetLog(GDBRLog::Process)); LLDB_LOGF(log, "ProcessGDBRemote::%s Skipping zero bitsize register %s", __FUNCTION__, reg_info.name.AsCString()); |
