diff options
Diffstat (limited to 'source/Target/Process.cpp')
-rw-r--r-- | source/Target/Process.cpp | 850 |
1 files changed, 352 insertions, 498 deletions
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp index fb3b758912eb..6c634dba00c7 100644 --- a/source/Target/Process.cpp +++ b/source/Target/Process.cpp @@ -1,13 +1,13 @@ //===-- Process.cpp ---------------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include <atomic> +#include <memory> #include <mutex> #include "llvm/Support/ScopedPrinter.h" @@ -22,7 +22,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamFile.h" #include "lldb/Expression/DiagnosticManager.h" -#include "lldb/Expression/IRDynamicChecks.h" +#include "lldb/Expression/DynamicCheckerFunctions.h" #include "lldb/Expression/UserExpression.h" #include "lldb/Expression/UtilityFunction.h" #include "lldb/Host/ConnectionFileDescriptor.h" @@ -39,15 +39,14 @@ #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ABI.h" -#include "lldb/Target/CPPLanguageRuntime.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/InstrumentationRuntime.h" #include "lldb/Target/JITLoader.h" #include "lldb/Target/JITLoaderList.h" +#include "lldb/Target/Language.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/MemoryHistory.h" #include "lldb/Target/MemoryRegionInfo.h" -#include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/OperatingSystem.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" @@ -64,6 +63,7 @@ #include "lldb/Utility/Event.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/NameMatches.h" +#include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/SelectHelper.h" #include "lldb/Utility/State.h" @@ -83,7 +83,7 @@ using namespace std::chrono; class ProcessOptionValueProperties : public OptionValueProperties { public: - ProcessOptionValueProperties(const ConstString &name) + ProcessOptionValueProperties(ConstString name) : OptionValueProperties(name) {} // This constructor is used when creating ProcessOptionValueProperties when @@ -143,7 +143,11 @@ static constexpr PropertyDefinition g_properties[] = { "stepping and variable availability may not behave as expected."}, {"stop-on-exec", OptionValue::eTypeBoolean, true, true, nullptr, {}, - "If true, stop when a shared library is loaded or unloaded."}}; + "If true, stop when a shared library is loaded or unloaded."}, + {"utility-expression-timeout", OptionValue::eTypeUInt64, false, 15, + nullptr, {}, + "The time in seconds to wait for LLDB-internal utility expressions."} +}; enum { ePropertyDisableMemCache, @@ -155,7 +159,8 @@ enum { ePropertyDetachKeepsStopped, ePropertyMemCacheLineSize, ePropertyWarningOptimization, - ePropertyStopOnExec + ePropertyStopOnExec, + ePropertyUtilityExpressionTimeout, }; ProcessProperties::ProcessProperties(lldb_private::Process *process) @@ -164,15 +169,15 @@ ProcessProperties::ProcessProperties(lldb_private::Process *process) { if (process == nullptr) { // Global process properties, set them up one time - m_collection_sp.reset( - new ProcessOptionValueProperties(ConstString("process"))); + m_collection_sp = + std::make_shared<ProcessOptionValueProperties>(ConstString("process")); m_collection_sp->Initialize(g_properties); m_collection_sp->AppendProperty( ConstString("thread"), ConstString("Settings specific to threads."), true, Thread::GetGlobalProperties()->GetValueProperties()); } else { - m_collection_sp.reset( - new ProcessOptionValueProperties(Process::GetGlobalProperties().get())); + m_collection_sp = std::make_shared<ProcessOptionValueProperties>( + Process::GetGlobalProperties().get()); m_collection_sp->SetValueChangedCallback( ePropertyPythonOSPluginPath, ProcessProperties::OptionValueChangedCallback, this); @@ -278,138 +283,11 @@ bool ProcessProperties::GetStopOnExec() const { nullptr, idx, g_properties[idx].default_uint_value != 0); } -void ProcessInstanceInfo::Dump(Stream &s, Platform *platform) const { - const char *cstr; - if (m_pid != LLDB_INVALID_PROCESS_ID) - s.Printf(" pid = %" PRIu64 "\n", m_pid); - - if (m_parent_pid != LLDB_INVALID_PROCESS_ID) - s.Printf(" parent = %" PRIu64 "\n", m_parent_pid); - - if (m_executable) { - s.Printf(" name = %s\n", m_executable.GetFilename().GetCString()); - s.PutCString(" file = "); - m_executable.Dump(&s); - s.EOL(); - } - const uint32_t argc = m_arguments.GetArgumentCount(); - if (argc > 0) { - for (uint32_t i = 0; i < argc; i++) { - const char *arg = m_arguments.GetArgumentAtIndex(i); - if (i < 10) - s.Printf(" arg[%u] = %s\n", i, arg); - else - s.Printf("arg[%u] = %s\n", i, arg); - } - } - - s.Format("{0}", m_environment); - - if (m_arch.IsValid()) { - s.Printf(" arch = "); - m_arch.DumpTriple(s); - s.EOL(); - } - - if (m_uid != UINT32_MAX) { - cstr = platform->GetUserName(m_uid); - s.Printf(" uid = %-5u (%s)\n", m_uid, cstr ? cstr : ""); - } - if (m_gid != UINT32_MAX) { - cstr = platform->GetGroupName(m_gid); - s.Printf(" gid = %-5u (%s)\n", m_gid, cstr ? cstr : ""); - } - if (m_euid != UINT32_MAX) { - cstr = platform->GetUserName(m_euid); - s.Printf(" euid = %-5u (%s)\n", m_euid, cstr ? cstr : ""); - } - if (m_egid != UINT32_MAX) { - cstr = platform->GetGroupName(m_egid); - s.Printf(" egid = %-5u (%s)\n", m_egid, cstr ? cstr : ""); - } -} - -void ProcessInstanceInfo::DumpTableHeader(Stream &s, Platform *platform, - bool show_args, bool verbose) { - const char *label; - if (show_args || verbose) - label = "ARGUMENTS"; - else - label = "NAME"; - - if (verbose) { - s.Printf("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE " - " %s\n", - label); - s.PutCString("====== ====== ========== ========== ========== ========== " - "======================== ============================\n"); - } else { - s.Printf("PID PARENT USER TRIPLE %s\n", label); - s.PutCString("====== ====== ========== ======================== " - "============================\n"); - } -} - -void ProcessInstanceInfo::DumpAsTableRow(Stream &s, Platform *platform, - bool show_args, bool verbose) const { - if (m_pid != LLDB_INVALID_PROCESS_ID) { - const char *cstr; - s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid); - - StreamString arch_strm; - if (m_arch.IsValid()) - m_arch.DumpTriple(arch_strm); - - if (verbose) { - cstr = platform->GetUserName(m_uid); - if (cstr && - cstr[0]) // Watch for empty string that indicates lookup failed - s.Printf("%-10s ", cstr); - else - s.Printf("%-10u ", m_uid); - - cstr = platform->GetGroupName(m_gid); - if (cstr && - cstr[0]) // Watch for empty string that indicates lookup failed - s.Printf("%-10s ", cstr); - else - s.Printf("%-10u ", m_gid); - - cstr = platform->GetUserName(m_euid); - if (cstr && - cstr[0]) // Watch for empty string that indicates lookup failed - s.Printf("%-10s ", cstr); - else - s.Printf("%-10u ", m_euid); - - cstr = platform->GetGroupName(m_egid); - if (cstr && - cstr[0]) // Watch for empty string that indicates lookup failed - s.Printf("%-10s ", cstr); - else - s.Printf("%-10u ", m_egid); - - s.Printf("%-24s ", arch_strm.GetData()); - } else { - s.Printf("%-10s %-24s ", platform->GetUserName(m_euid), - arch_strm.GetData()); - } - - if (verbose || show_args) { - const uint32_t argc = m_arguments.GetArgumentCount(); - if (argc > 0) { - for (uint32_t i = 0; i < argc; i++) { - if (i > 0) - s.PutChar(' '); - s.PutCString(m_arguments.GetArgumentAtIndex(i)); - } - } - } else { - s.PutCString(GetName()); - } - - s.EOL(); - } +std::chrono::seconds ProcessProperties::GetUtilityExpressionTimeout() const { + const uint32_t idx = ePropertyUtilityExpressionTimeout; + uint64_t value = m_collection_sp->GetPropertyAtIndexAsUInt64( + nullptr, idx, g_properties[idx].default_uint_value); + return std::chrono::seconds(value); } Status ProcessLaunchCommandOptions::SetOptionValue( @@ -581,89 +459,6 @@ llvm::ArrayRef<OptionDefinition> ProcessLaunchCommandOptions::GetDefinitions() { return llvm::makeArrayRef(g_process_launch_options); } -bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const { - if (m_name_match_type == NameMatch::Ignore || process_name == nullptr) - return true; - const char *match_name = m_match_info.GetName(); - if (!match_name) - return true; - - return lldb_private::NameMatches(process_name, m_name_match_type, match_name); -} - -bool ProcessInstanceInfoMatch::Matches( - const ProcessInstanceInfo &proc_info) const { - if (!NameMatches(proc_info.GetName())) - return false; - - if (m_match_info.ProcessIDIsValid() && - m_match_info.GetProcessID() != proc_info.GetProcessID()) - return false; - - if (m_match_info.ParentProcessIDIsValid() && - m_match_info.GetParentProcessID() != proc_info.GetParentProcessID()) - return false; - - if (m_match_info.UserIDIsValid() && - m_match_info.GetUserID() != proc_info.GetUserID()) - return false; - - if (m_match_info.GroupIDIsValid() && - m_match_info.GetGroupID() != proc_info.GetGroupID()) - return false; - - if (m_match_info.EffectiveUserIDIsValid() && - m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID()) - return false; - - if (m_match_info.EffectiveGroupIDIsValid() && - m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID()) - return false; - - if (m_match_info.GetArchitecture().IsValid() && - !m_match_info.GetArchitecture().IsCompatibleMatch( - proc_info.GetArchitecture())) - return false; - return true; -} - -bool ProcessInstanceInfoMatch::MatchAllProcesses() const { - if (m_name_match_type != NameMatch::Ignore) - return false; - - if (m_match_info.ProcessIDIsValid()) - return false; - - if (m_match_info.ParentProcessIDIsValid()) - return false; - - if (m_match_info.UserIDIsValid()) - return false; - - if (m_match_info.GroupIDIsValid()) - return false; - - if (m_match_info.EffectiveUserIDIsValid()) - return false; - - if (m_match_info.EffectiveGroupIDIsValid()) - return false; - - if (m_match_info.GetArchitecture().IsValid()) - return false; - - if (m_match_all_users) - return false; - - return true; -} - -void ProcessInstanceInfoMatch::Clear() { - m_match_info.Clear(); - m_name_match_type = NameMatch::Ignore; - m_match_all_users = false; -} - ProcessSP Process::FindPlugin(lldb::TargetSP target_sp, llvm::StringRef plugin_name, ListenerSP listener_sp, @@ -734,13 +529,13 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, m_thread_list(this), m_extended_thread_list(this), m_extended_thread_stop_id(0), m_queue_list(this), m_queue_list_stop_id(0), m_notifications(), m_image_tokens(), m_listener_sp(listener_sp), - m_breakpoint_site_list(), m_dynamic_checkers_ap(), + m_breakpoint_site_list(), m_dynamic_checkers_up(), m_unix_signals_sp(unix_signals_sp), m_abi_sp(), m_process_input_reader(), m_stdio_communication("process.stdio"), m_stdio_communication_mutex(), m_stdin_forward(false), m_stdout_data(), m_stderr_data(), m_profile_data_comm_mutex(), m_profile_data(), m_iohandler_sync(0), m_memory_cache(*this), m_allocated_memory_cache(*this), - m_should_detach(false), m_next_event_action_ap(), m_public_run_lock(), + m_should_detach(false), m_next_event_action_up(), m_public_run_lock(), m_private_run_lock(), m_finalizing(false), m_finalize_called(false), m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false), m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false), @@ -848,12 +643,12 @@ void Process::Finalize() { // We need to destroy the loader before the derived Process class gets // destroyed since it is very likely that undoing the loader will require // access to the real process. - m_dynamic_checkers_ap.reset(); + m_dynamic_checkers_up.reset(); m_abi_sp.reset(); - m_os_ap.reset(); - m_system_runtime_ap.reset(); - m_dyld_ap.reset(); - m_jit_loaders_ap.reset(); + m_os_up.reset(); + m_system_runtime_up.reset(); + m_dyld_up.reset(); + m_jit_loaders_up.reset(); m_thread_list_real.Destroy(); m_thread_list.Destroy(); m_extended_thread_list.Destroy(); @@ -864,9 +659,12 @@ void Process::Finalize() { m_image_tokens.clear(); m_memory_cache.Clear(); m_allocated_memory_cache.Clear(); - m_language_runtimes.clear(); + { + std::lock_guard<std::recursive_mutex> guard(m_language_runtimes_mutex); + m_language_runtimes.clear(); + } m_instrumentation_runtimes.clear(); - m_next_event_action_ap.reset(); + m_next_event_action_up.reset(); // Clear the last natural stop ID since it has a strong reference to this // process m_mod_id.SetStopEventForLastNaturalStopID(EventSP()); @@ -1506,12 +1304,12 @@ void Process::UpdateThreadListIfNeeded() { } void Process::UpdateQueueListIfNeeded() { - if (m_system_runtime_ap) { + if (m_system_runtime_up) { if (m_queue_list.GetSize() == 0 || m_queue_list_stop_id != GetLastNaturalStopID()) { const StateType state = GetPrivateState(); if (StateIsStoppedState(state, true)) { - m_system_runtime_ap->PopulateQueueList(m_queue_list); + m_system_runtime_up->PopulateQueueList(m_queue_list); m_queue_list_stop_id = GetLastNaturalStopID(); } } @@ -1552,16 +1350,6 @@ StateType Process::GetState() { return m_public_state.GetValue(); } -bool Process::StateChangedIsExternallyHijacked() { - if (IsHijackedForEvent(eBroadcastBitStateChanged)) { - const char *hijacking_name = GetHijackingListenerName(); - if (hijacking_name && - strcmp(hijacking_name, "lldb.Process.ResumeSynchronous.hijack")) - return true; - } - return false; -} - void Process::SetPublicState(StateType new_state, bool restarted) { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS)); @@ -1615,6 +1403,8 @@ Status Process::Resume() { return error; } +static const char *g_resume_sync_name = "lldb.Process.ResumeSynchronous.hijack"; + Status Process::ResumeSynchronous(Stream *stream) { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS)); @@ -1628,13 +1418,13 @@ Status Process::ResumeSynchronous(Stream *stream) { } ListenerSP listener_sp( - Listener::MakeListener("lldb.Process.ResumeSynchronous.hijack")); + Listener::MakeListener(g_resume_sync_name)); HijackProcessEvents(listener_sp); Status error = PrivateResume(); if (error.Success()) { StateType state = - WaitForProcessToStop(llvm::None, NULL, true, listener_sp, stream); + WaitForProcessToStop(llvm::None, nullptr, true, listener_sp, stream); const bool must_be_alive = false; // eStateExited is ok, so this must be false if (!StateIsStoppedState(state, must_be_alive)) @@ -1652,6 +1442,26 @@ Status Process::ResumeSynchronous(Stream *stream) { return error; } +bool Process::StateChangedIsExternallyHijacked() { + if (IsHijackedForEvent(eBroadcastBitStateChanged)) { + const char *hijacking_name = GetHijackingListenerName(); + if (hijacking_name && + strcmp(hijacking_name, g_resume_sync_name)) + return true; + } + return false; +} + +bool Process::StateChangedIsHijackedForSynchronousResume() { + if (IsHijackedForEvent(eBroadcastBitStateChanged)) { + const char *hijacking_name = GetHijackingListenerName(); + if (hijacking_name && + strcmp(hijacking_name, g_resume_sync_name) == 0) + return true; + } + return false; +} + StateType Process::GetPrivateState() { return m_private_state.GetValue(); } void Process::SetPrivateState(StateType new_state) { @@ -1736,38 +1546,54 @@ const lldb::ABISP &Process::GetABI() { return m_abi_sp; } +std::vector<LanguageRuntime *> +Process::GetLanguageRuntimes(bool retry_if_null) { + std::vector<LanguageRuntime *> language_runtimes; + + if (m_finalizing) + return language_runtimes; + + std::lock_guard<std::recursive_mutex> guard(m_language_runtimes_mutex); + // Before we pass off a copy of the language runtimes, we must make sure that + // our collection is properly populated. It's possible that some of the + // language runtimes were not loaded yet, either because nobody requested it + // yet or the proper condition for loading wasn't yet met (e.g. libc++.so + // hadn't been loaded). + for (const lldb::LanguageType lang_type : Language::GetSupportedLanguages()) { + if (LanguageRuntime *runtime = GetLanguageRuntime(lang_type, retry_if_null)) + language_runtimes.emplace_back(runtime); + } + + return language_runtimes; +} + LanguageRuntime *Process::GetLanguageRuntime(lldb::LanguageType language, bool retry_if_null) { if (m_finalizing) return nullptr; + LanguageRuntime *runtime = nullptr; + + std::lock_guard<std::recursive_mutex> guard(m_language_runtimes_mutex); LanguageRuntimeCollection::iterator pos; pos = m_language_runtimes.find(language); - if (pos == m_language_runtimes.end() || (retry_if_null && !(*pos).second)) { + if (pos == m_language_runtimes.end() || (retry_if_null && !pos->second)) { lldb::LanguageRuntimeSP runtime_sp( LanguageRuntime::FindPlugin(this, language)); m_language_runtimes[language] = runtime_sp; - return runtime_sp.get(); + runtime = runtime_sp.get(); } else - return (*pos).second.get(); -} + runtime = pos->second.get(); -CPPLanguageRuntime *Process::GetCPPLanguageRuntime(bool retry_if_null) { - LanguageRuntime *runtime = - GetLanguageRuntime(eLanguageTypeC_plus_plus, retry_if_null); - if (runtime != nullptr && - runtime->GetLanguageType() == eLanguageTypeC_plus_plus) - return static_cast<CPPLanguageRuntime *>(runtime); - return nullptr; -} + if (runtime) + // It's possible that a language runtime can support multiple LanguageTypes, + // for example, CPPLanguageRuntime will support eLanguageTypeC_plus_plus, + // eLanguageTypeC_plus_plus_03, etc. Because of this, we should get the + // primary language type and make sure that our runtime supports it. + assert(runtime->GetLanguageType() == Language::GetPrimaryLanguage(language)); -ObjCLanguageRuntime *Process::GetObjCLanguageRuntime(bool retry_if_null) { - LanguageRuntime *runtime = - GetLanguageRuntime(eLanguageTypeObjC, retry_if_null); - if (runtime != nullptr && runtime->GetLanguageType() == eLanguageTypeObjC) - return static_cast<ObjCLanguageRuntime *>(runtime); - return nullptr; + return runtime; } bool Process::IsPossibleDynamicValue(ValueObject &in_value) { @@ -1783,16 +1609,16 @@ bool Process::IsPossibleDynamicValue(ValueObject &in_value) { return runtime ? runtime->CouldHaveDynamicValue(in_value) : false; } - LanguageRuntime *cpp_runtime = GetLanguageRuntime(eLanguageTypeC_plus_plus); - if (cpp_runtime && cpp_runtime->CouldHaveDynamicValue(in_value)) - return true; + for (LanguageRuntime *runtime : GetLanguageRuntimes()) { + if (runtime->CouldHaveDynamicValue(in_value)) + return true; + } - LanguageRuntime *objc_runtime = GetLanguageRuntime(eLanguageTypeObjC); - return objc_runtime ? objc_runtime->CouldHaveDynamicValue(in_value) : false; + return false; } void Process::SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers) { - m_dynamic_checkers_ap.reset(dynamic_checkers); + m_dynamic_checkers_up.reset(dynamic_checkers); } BreakpointSiteList &Process::GetBreakpointSiteList() { @@ -2413,67 +2239,64 @@ size_t Process::WriteMemory(addr_t addr, const void *buf, size_t size, // may have placed in our tasks memory. BreakpointSiteList bp_sites_in_range; + if (!m_breakpoint_site_list.FindInRange(addr, addr + size, bp_sites_in_range)) + return WriteMemoryPrivate(addr, buf, size, error); - if (m_breakpoint_site_list.FindInRange(addr, addr + size, - bp_sites_in_range)) { - // No breakpoint sites overlap - if (bp_sites_in_range.IsEmpty()) - return WriteMemoryPrivate(addr, buf, size, error); - else { - const uint8_t *ubuf = (const uint8_t *)buf; - uint64_t bytes_written = 0; + // No breakpoint sites overlap + if (bp_sites_in_range.IsEmpty()) + return WriteMemoryPrivate(addr, buf, size, error); - bp_sites_in_range.ForEach([this, addr, size, &bytes_written, &ubuf, - &error](BreakpointSite *bp) -> void { + const uint8_t *ubuf = (const uint8_t *)buf; + uint64_t bytes_written = 0; - if (error.Success()) { - addr_t intersect_addr; - size_t intersect_size; - size_t opcode_offset; - const bool intersects = bp->IntersectsRange( - addr, size, &intersect_addr, &intersect_size, &opcode_offset); - UNUSED_IF_ASSERT_DISABLED(intersects); - assert(intersects); - assert(addr <= intersect_addr && intersect_addr < addr + size); - assert(addr < intersect_addr + intersect_size && - intersect_addr + intersect_size <= addr + size); - assert(opcode_offset + intersect_size <= bp->GetByteSize()); - - // Check for bytes before this breakpoint - const addr_t curr_addr = addr + bytes_written; - if (intersect_addr > curr_addr) { - // There are some bytes before this breakpoint that we need to just - // write to memory - size_t curr_size = intersect_addr - curr_addr; - size_t curr_bytes_written = WriteMemoryPrivate( - curr_addr, ubuf + bytes_written, curr_size, error); - bytes_written += curr_bytes_written; - if (curr_bytes_written != curr_size) { - // We weren't able to write all of the requested bytes, we are - // done looping and will return the number of bytes that we have - // written so far. - if (error.Success()) - error.SetErrorToGenericError(); - } - } - // Now write any bytes that would cover up any software breakpoints - // directly into the breakpoint opcode buffer - ::memcpy(bp->GetSavedOpcodeBytes() + opcode_offset, - ubuf + bytes_written, intersect_size); - bytes_written += intersect_size; - } - }); + bp_sites_in_range.ForEach([this, addr, size, &bytes_written, &ubuf, + &error](BreakpointSite *bp) -> void { + if (error.Fail()) + return; - if (bytes_written < size) - WriteMemoryPrivate(addr + bytes_written, ubuf + bytes_written, - size - bytes_written, error); + addr_t intersect_addr; + size_t intersect_size; + size_t opcode_offset; + const bool intersects = bp->IntersectsRange( + addr, size, &intersect_addr, &intersect_size, &opcode_offset); + UNUSED_IF_ASSERT_DISABLED(intersects); + assert(intersects); + assert(addr <= intersect_addr && intersect_addr < addr + size); + assert(addr < intersect_addr + intersect_size && + intersect_addr + intersect_size <= addr + size); + assert(opcode_offset + intersect_size <= bp->GetByteSize()); + + // Check for bytes before this breakpoint + const addr_t curr_addr = addr + bytes_written; + if (intersect_addr > curr_addr) { + // There are some bytes before this breakpoint that we need to just + // write to memory + size_t curr_size = intersect_addr - curr_addr; + size_t curr_bytes_written = + WriteMemoryPrivate(curr_addr, ubuf + bytes_written, curr_size, error); + bytes_written += curr_bytes_written; + if (curr_bytes_written != curr_size) { + // We weren't able to write all of the requested bytes, we are + // done looping and will return the number of bytes that we have + // written so far. + if (error.Success()) + error.SetErrorToGenericError(); + } } - } else { - return WriteMemoryPrivate(addr, buf, size, error); - } + // Now write any bytes that would cover up any software breakpoints + // directly into the breakpoint opcode buffer + ::memcpy(bp->GetSavedOpcodeBytes() + opcode_offset, ubuf + bytes_written, + intersect_size); + bytes_written += intersect_size; + }); // Write any remaining bytes after the last breakpoint if we have any left - return 0; // bytes_written; + if (bytes_written < size) + bytes_written += + WriteMemoryPrivate(addr + bytes_written, ubuf + bytes_written, + size - bytes_written, error); + + return bytes_written; } size_t Process::WriteScalarToMemory(addr_t addr, const Scalar &scalar, @@ -2708,7 +2531,7 @@ Process::WaitForProcessStopPrivate(EventSP &event_sp, void Process::LoadOperatingSystemPlugin(bool flush) { if (flush) m_thread_list.Clear(); - m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr)); + m_os_up.reset(OperatingSystem::FindPlugin(this, nullptr)); if (flush) Flush(); } @@ -2716,115 +2539,119 @@ void Process::LoadOperatingSystemPlugin(bool flush) { Status Process::Launch(ProcessLaunchInfo &launch_info) { Status error; m_abi_sp.reset(); - m_dyld_ap.reset(); - m_jit_loaders_ap.reset(); - m_system_runtime_ap.reset(); - m_os_ap.reset(); + m_dyld_up.reset(); + m_jit_loaders_up.reset(); + m_system_runtime_up.reset(); + m_os_up.reset(); m_process_input_reader.reset(); Module *exe_module = GetTarget().GetExecutableModulePointer(); - if (exe_module) { - char local_exec_file_path[PATH_MAX]; - char platform_exec_file_path[PATH_MAX]; - exe_module->GetFileSpec().GetPath(local_exec_file_path, - sizeof(local_exec_file_path)); - exe_module->GetPlatformFileSpec().GetPath(platform_exec_file_path, - sizeof(platform_exec_file_path)); - if (FileSystem::Instance().Exists(exe_module->GetFileSpec())) { - // Install anything that might need to be installed prior to launching. - // For host systems, this will do nothing, but if we are connected to a - // remote platform it will install any needed binaries - error = GetTarget().Install(&launch_info); - if (error.Fail()) - return error; + if (!exe_module) { + error.SetErrorString("executable module does not exist"); + return error; + } - if (PrivateStateThreadIsValid()) - PausePrivateStateThread(); + char local_exec_file_path[PATH_MAX]; + char platform_exec_file_path[PATH_MAX]; + exe_module->GetFileSpec().GetPath(local_exec_file_path, + sizeof(local_exec_file_path)); + exe_module->GetPlatformFileSpec().GetPath(platform_exec_file_path, + sizeof(platform_exec_file_path)); + if (FileSystem::Instance().Exists(exe_module->GetFileSpec())) { + // Install anything that might need to be installed prior to launching. + // For host systems, this will do nothing, but if we are connected to a + // remote platform it will install any needed binaries + error = GetTarget().Install(&launch_info); + if (error.Fail()) + return error; - error = WillLaunch(exe_module); - if (error.Success()) { - const bool restarted = false; - SetPublicState(eStateLaunching, restarted); - m_should_detach = false; + if (PrivateStateThreadIsValid()) + PausePrivateStateThread(); - if (m_public_run_lock.TrySetRunning()) { - // Now launch using these arguments. - error = DoLaunch(exe_module, launch_info); - } else { - // This shouldn't happen - error.SetErrorString("failed to acquire process run lock"); + error = WillLaunch(exe_module); + if (error.Success()) { + const bool restarted = false; + SetPublicState(eStateLaunching, restarted); + m_should_detach = false; + + if (m_public_run_lock.TrySetRunning()) { + // Now launch using these arguments. + error = DoLaunch(exe_module, launch_info); + } else { + // This shouldn't happen + error.SetErrorString("failed to acquire process run lock"); + } + + if (error.Fail()) { + if (GetID() != LLDB_INVALID_PROCESS_ID) { + SetID(LLDB_INVALID_PROCESS_ID); + const char *error_string = error.AsCString(); + if (error_string == nullptr) + error_string = "launch failed"; + SetExitStatus(-1, error_string); } + } else { + EventSP event_sp; + + // Now wait for the process to launch and return control to us, and then + // call DidLaunch: + StateType state = WaitForProcessStopPrivate(event_sp, seconds(10)); + + if (state == eStateInvalid || !event_sp) { + // We were able to launch the process, but we failed to catch the + // initial stop. + error.SetErrorString("failed to catch stop after launch"); + SetExitStatus(0, "failed to catch stop after launch"); + Destroy(false); + } else if (state == eStateStopped || state == eStateCrashed) { + DidLaunch(); + + DynamicLoader *dyld = GetDynamicLoader(); + if (dyld) + dyld->DidLaunch(); + + GetJITLoaders().DidLaunch(); + + SystemRuntime *system_runtime = GetSystemRuntime(); + if (system_runtime) + system_runtime->DidLaunch(); + + if (!m_os_up) + LoadOperatingSystemPlugin(false); + + // We successfully launched the process and stopped, now it the + // right time to set up signal filters before resuming. + UpdateAutomaticSignalFiltering(); + + // Note, the stop event was consumed above, but not handled. This + // was done to give DidLaunch a chance to run. The target is either + // stopped or crashed. Directly set the state. This is done to + // prevent a stop message with a bunch of spurious output on thread + // status, as well as not pop a ProcessIOHandler. + SetPublicState(state, false); + + if (PrivateStateThreadIsValid()) + ResumePrivateStateThread(); + else + StartPrivateStateThread(); - if (error.Fail()) { - if (GetID() != LLDB_INVALID_PROCESS_ID) { - SetID(LLDB_INVALID_PROCESS_ID); - const char *error_string = error.AsCString(); - if (error_string == nullptr) - error_string = "launch failed"; - SetExitStatus(-1, error_string); - } - } else { - EventSP event_sp; - - // Now wait for the process to launch and return control to us, and then call - // DidLaunch: - StateType state = WaitForProcessStopPrivate(event_sp, seconds(10)); - - if (state == eStateInvalid || !event_sp) { - // We were able to launch the process, but we failed to catch the - // initial stop. - error.SetErrorString("failed to catch stop after launch"); - SetExitStatus(0, "failed to catch stop after launch"); - Destroy(false); - } else if (state == eStateStopped || state == eStateCrashed) { - DidLaunch(); - - DynamicLoader *dyld = GetDynamicLoader(); - if (dyld) - dyld->DidLaunch(); - - GetJITLoaders().DidLaunch(); - - SystemRuntime *system_runtime = GetSystemRuntime(); - if (system_runtime) - system_runtime->DidLaunch(); - - if (!m_os_ap) - LoadOperatingSystemPlugin(false); - - // We successfully launched the process and stopped, now it the - // right time to set up signal filters before resuming. - UpdateAutomaticSignalFiltering(); - - // Note, the stop event was consumed above, but not handled. This - // was done to give DidLaunch a chance to run. The target is either - // stopped or crashed. Directly set the state. This is done to - // prevent a stop message with a bunch of spurious output on thread - // status, as well as not pop a ProcessIOHandler. - SetPublicState(state, false); - - if (PrivateStateThreadIsValid()) - ResumePrivateStateThread(); - else - StartPrivateStateThread(); - - // Target was stopped at entry as was intended. Need to notify the - // listeners about it. - if (state == eStateStopped && - launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) - HandlePrivateEvent(event_sp); - } else if (state == eStateExited) { - // We exited while trying to launch somehow. Don't call DidLaunch - // as that's not likely to work, and return an invalid pid. + // Target was stopped at entry as was intended. Need to notify the + // listeners about it. + if (state == eStateStopped && + launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) HandlePrivateEvent(event_sp); - } + } else if (state == eStateExited) { + // We exited while trying to launch somehow. Don't call DidLaunch + // as that's not likely to work, and return an invalid pid. + HandlePrivateEvent(event_sp); } } - } else { - error.SetErrorStringWithFormat("file doesn't exist: '%s'", - local_exec_file_path); } + } else { + error.SetErrorStringWithFormat("file doesn't exist: '%s'", + local_exec_file_path); } + return error; } @@ -2850,7 +2677,7 @@ Status Process::LoadCore() { if (system_runtime) system_runtime->DidAttach(); - if (!m_os_ap) + if (!m_os_up) LoadOperatingSystemPlugin(false); // We successfully loaded a core file, now pretend we stopped so we can @@ -2860,7 +2687,7 @@ Status Process::LoadCore() { // Wait for a stopped event since we just posted one above... lldb::EventSP event_sp; StateType state = - WaitForProcessToStop(seconds(10), &event_sp, true, listener_sp); + WaitForProcessToStop(llvm::None, &event_sp, true, listener_sp); if (!StateIsStoppedState(state, false)) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); @@ -2876,25 +2703,25 @@ Status Process::LoadCore() { } DynamicLoader *Process::GetDynamicLoader() { - if (!m_dyld_ap) - m_dyld_ap.reset(DynamicLoader::FindPlugin(this, nullptr)); - return m_dyld_ap.get(); + if (!m_dyld_up) + m_dyld_up.reset(DynamicLoader::FindPlugin(this, nullptr)); + return m_dyld_up.get(); } -const lldb::DataBufferSP Process::GetAuxvData() { return DataBufferSP(); } +DataExtractor Process::GetAuxvData() { return DataExtractor(); } JITLoaderList &Process::GetJITLoaders() { - if (!m_jit_loaders_ap) { - m_jit_loaders_ap.reset(new JITLoaderList()); - JITLoader::LoadPlugins(this, *m_jit_loaders_ap); + if (!m_jit_loaders_up) { + m_jit_loaders_up.reset(new JITLoaderList()); + JITLoader::LoadPlugins(this, *m_jit_loaders_up); } - return *m_jit_loaders_ap; + return *m_jit_loaders_up; } SystemRuntime *Process::GetSystemRuntime() { - if (!m_system_runtime_ap) - m_system_runtime_ap.reset(SystemRuntime::FindPlugin(this)); - return m_system_runtime_ap.get(); + if (!m_system_runtime_up) + m_system_runtime_up.reset(SystemRuntime::FindPlugin(this)); + return m_system_runtime_up.get(); } Process::AttachCompletionHandler::AttachCompletionHandler(Process *process, @@ -2984,10 +2811,10 @@ ListenerSP ProcessAttachInfo::GetListenerForProcess(Debugger &debugger) { Status Process::Attach(ProcessAttachInfo &attach_info) { m_abi_sp.reset(); m_process_input_reader.reset(); - m_dyld_ap.reset(); - m_jit_loaders_ap.reset(); - m_system_runtime_ap.reset(); - m_os_ap.reset(); + m_dyld_up.reset(); + m_jit_loaders_up.reset(); + m_system_runtime_up.reset(); + m_os_up.reset(); lldb::pid_t attach_pid = attach_info.GetProcessID(); Status error; @@ -3045,11 +2872,10 @@ Status Process::Attach(ProcessAttachInfo &attach_info) { process_name, sizeof(process_name)); if (num_matches > 1) { StreamString s; - ProcessInstanceInfo::DumpTableHeader(s, platform_sp.get(), true, - false); + ProcessInstanceInfo::DumpTableHeader(s, true, false); for (size_t i = 0; i < num_matches; i++) { process_infos.GetProcessInfoAtIndex(i).DumpAsTableRow( - s, platform_sp.get(), true, false); + s, platform_sp->GetUserIDResolver(), true, false); } error.SetErrorStringWithFormat( "more than one process named %s:\n%s", process_name, @@ -3193,8 +3019,16 @@ void Process::CompleteAttach() { } } - if (!m_os_ap) + if (!m_os_up) { LoadOperatingSystemPlugin(false); + if (m_os_up) { + // Somebody might have gotten threads before now, but we need to force the + // update after we've loaded the OperatingSystem plugin or it won't get a + // chance to process the threads. + m_thread_list.Clear(); + UpdateThreadListIfNeeded(); + } + } // Figure out which one is the executable, and set that in our target: const ModuleList &target_modules = GetTarget().GetImages(); std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); @@ -3754,14 +3588,20 @@ bool Process::StartPrivateStateThread(bool is_secondary_thread) { // Create the private state thread, and start it running. PrivateStateThreadArgs *args_ptr = new PrivateStateThreadArgs(this, is_secondary_thread); - m_private_state_thread = + llvm::Expected<HostThread> private_state_thread = ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread, - (void *)args_ptr, nullptr, 8 * 1024 * 1024); - if (m_private_state_thread.IsJoinable()) { - ResumePrivateStateThread(); - return true; - } else + (void *)args_ptr, 8 * 1024 * 1024); + if (!private_state_thread) { + LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), + "failed to launch host thread: {}", + llvm::toString(private_state_thread.takeError())); return false; + } + + assert(private_state_thread->IsJoinable()); + m_private_state_thread = *private_state_thread; + ResumePrivateStateThread(); + return true; } void Process::PausePrivateStateThread() { @@ -3810,10 +3650,10 @@ void Process::ControlPrivateStateThread(uint32_t signal) { bool receipt_received = false; if (PrivateStateThreadIsValid()) { while (!receipt_received) { - // Check for a receipt for 2 seconds and then check if the private + // Check for a receipt for n seconds and then check if the private // state thread is still around. receipt_received = - event_receipt_sp->WaitForEventReceived(std::chrono::seconds(2)); + event_receipt_sp->WaitForEventReceived(GetUtilityExpressionTimeout()); if (!receipt_received) { // Check if the private state thread is still around. If it isn't // then we are done waiting @@ -3824,7 +3664,7 @@ void Process::ControlPrivateStateThread(uint32_t signal) { } if (signal == eBroadcastInternalStateControlStop) { - thread_result_t result = NULL; + thread_result_t result = {}; m_private_state_thread.Join(&result); m_private_state_thread.Reset(); } @@ -3851,9 +3691,9 @@ void Process::HandlePrivateEvent(EventSP &event_sp) { Process::ProcessEventData::GetStateFromEvent(event_sp.get()); // First check to see if anybody wants a shot at this event: - if (m_next_event_action_ap) { + if (m_next_event_action_up) { NextEventAction::EventActionResult action_result = - m_next_event_action_ap->PerformAction(event_sp); + m_next_event_action_up->PerformAction(event_sp); if (log) log->Printf("Ran next event action, result was %d.", action_result); @@ -3871,7 +3711,7 @@ void Process::HandlePrivateEvent(EventSP &event_sp) { // to exit so the next event will kill us. if (new_state != eStateExited) { // FIXME: should cons up an exited event, and discard this one. - SetExitStatus(0, m_next_event_action_ap->GetExitString()); + SetExitStatus(0, m_next_event_action_up->GetExitString()); SetNextEventAction(nullptr); return; } @@ -4099,12 +3939,10 @@ thread_result_t Process::RunPrivateStateThread(bool is_secondary_thread) { // it was doing yet, so don't try to change it on the way out. if (!is_secondary_thread) m_public_run_lock.SetStopped(); - return NULL; + return {}; } -//------------------------------------------------------------------ // Process Event Data -//------------------------------------------------------------------ Process::ProcessEventData::ProcessEventData() : EventData(), m_process_wp(), m_state(eStateInvalid), m_restarted(false), @@ -4120,12 +3958,12 @@ Process::ProcessEventData::ProcessEventData(const ProcessSP &process_sp, Process::ProcessEventData::~ProcessEventData() = default; -const ConstString &Process::ProcessEventData::GetFlavorString() { +ConstString Process::ProcessEventData::GetFlavorString() { static ConstString g_flavor("Process::ProcessEventData"); return g_flavor; } -const ConstString &Process::ProcessEventData::GetFlavor() const { +ConstString Process::ProcessEventData::GetFlavor() const { return ProcessEventData::GetFlavorString(); } @@ -4260,15 +4098,24 @@ void Process::ProcessEventData::DoOnRemoval(Event *event_ptr) { // public resume. process_sp->PrivateResume(); } else { - // If we didn't restart, run the Stop Hooks here: They might also - // restart the target, so watch for that. - process_sp->GetTarget().RunStopHooks(); - if (process_sp->GetPrivateState() == eStateRunning) - SetRestarted(true); + bool hijacked = + process_sp->IsHijackedForEvent(eBroadcastBitStateChanged) && + !process_sp->StateChangedIsHijackedForSynchronousResume(); + + if (!hijacked) { + // If we didn't restart, run the Stop Hooks here. + // Don't do that if state changed events aren't hooked up to the + // public (or SyncResume) broadcasters. StopHooks are just for + // real public stops. They might also restart the target, + // so watch for that. + process_sp->GetTarget().RunStopHooks(); + if (process_sp->GetPrivateState() == eStateRunning) + SetRestarted(true); } } } } +} void Process::ProcessEventData::Dump(Stream *s) const { ProcessSP process_sp(m_process_wp.lock()); @@ -4439,7 +4286,7 @@ void Process::BroadcastStructuredData(const StructuredData::ObjectSP &object_sp, } StructuredDataPluginSP -Process::GetStructuredDataPlugin(const ConstString &type_name) const { +Process::GetStructuredDataPlugin(ConstString type_name) const { auto find_it = m_structured_data_plugin_map.find(type_name); if (find_it != m_structured_data_plugin_map.end()) return find_it->second; @@ -4471,9 +4318,7 @@ size_t Process::GetAsyncProfileData(char *buf, size_t buf_size, Status &error) { return bytes_available; } -//------------------------------------------------------------------ // Process STDIO -//------------------------------------------------------------------ size_t Process::GetSTDOUT(char *buf, size_t buf_size, Status &error) { std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex); @@ -4658,11 +4503,11 @@ protected: void Process::SetSTDIOFileDescriptor(int fd) { // First set up the Read Thread for reading/handling process I/O - std::unique_ptr<ConnectionFileDescriptor> conn_ap( + std::unique_ptr<ConnectionFileDescriptor> conn_up( new ConnectionFileDescriptor(fd, true)); - if (conn_ap) { - m_stdio_communication.SetConnection(conn_ap.release()); + if (conn_up) { + m_stdio_communication.SetConnection(conn_up.release()); if (m_stdio_communication.IsConnected()) { m_stdio_communication.SetReadThreadBytesReceivedCallback( STDIOReadThreadBytesReceived, this); @@ -4671,7 +4516,8 @@ void Process::SetSTDIOFileDescriptor(int fd) { // Now read thread is set up, set up input reader. if (!m_process_input_reader) - m_process_input_reader.reset(new IOHandlerProcessSTDIO(this, fd)); + m_process_input_reader = + std::make_shared<IOHandlerProcessSTDIO>(this, fd); } } } @@ -5096,7 +4942,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, } got_event = - listener_sp->GetEvent(event_sp, std::chrono::milliseconds(500)); + listener_sp->GetEvent(event_sp, GetUtilityExpressionTimeout()); if (!got_event) { if (log) log->Printf("Process::RunThreadPlan(): didn't get any event after " @@ -5327,7 +5173,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, log->PutCString("Process::RunThreadPlan(): Halt succeeded."); got_event = - listener_sp->GetEvent(event_sp, std::chrono::milliseconds(500)); + listener_sp->GetEvent(event_sp, GetUtilityExpressionTimeout()); if (got_event) { stop_state = @@ -5530,7 +5376,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, event_explanation = ts.GetData(); } - } while (0); + } while (false); if (event_explanation) log->Printf("Process::RunThreadPlan(): execution interrupted: %s %s", @@ -5782,15 +5628,18 @@ void Process::DidExec() { Target &target = GetTarget(); target.CleanupProcess(); target.ClearModules(false); - m_dynamic_checkers_ap.reset(); + m_dynamic_checkers_up.reset(); m_abi_sp.reset(); - m_system_runtime_ap.reset(); - m_os_ap.reset(); - m_dyld_ap.reset(); - m_jit_loaders_ap.reset(); + m_system_runtime_up.reset(); + m_os_up.reset(); + m_dyld_up.reset(); + m_jit_loaders_up.reset(); m_image_tokens.clear(); m_allocated_memory_cache.Clear(); - m_language_runtimes.clear(); + { + std::lock_guard<std::recursive_mutex> guard(m_language_runtimes_mutex); + m_language_runtimes.clear(); + } m_instrumentation_runtimes.clear(); m_thread_list.DiscardThreadPlans(); m_memory_cache.Clear(true); @@ -5859,19 +5708,22 @@ void Process::ModulesDidLoad(ModuleList &module_list) { // Iterate over a copy of this language runtime list in case the language // runtime ModulesDidLoad somehow causes the language runtime to be // unloaded. - LanguageRuntimeCollection language_runtimes(m_language_runtimes); - for (const auto &pair : language_runtimes) { - // We must check language_runtime_sp to make sure it is not nullptr as we - // might cache the fact that we didn't have a language runtime for a - // language. - LanguageRuntimeSP language_runtime_sp = pair.second; - if (language_runtime_sp) - language_runtime_sp->ModulesDidLoad(module_list); + { + std::lock_guard<std::recursive_mutex> guard(m_language_runtimes_mutex); + LanguageRuntimeCollection language_runtimes(m_language_runtimes); + for (const auto &pair : language_runtimes) { + // We must check language_runtime_sp to make sure it is not nullptr as we + // might cache the fact that we didn't have a language runtime for a + // language. + LanguageRuntimeSP language_runtime_sp = pair.second; + if (language_runtime_sp) + language_runtime_sp->ModulesDidLoad(module_list); + } } // If we don't have an operating system plug-in, try to load one since // loading shared libraries might cause a new one to try and load - if (!m_os_ap) + if (!m_os_up) LoadOperatingSystemPlugin(false); // Give structured-data plugins a chance to see the modified modules. @@ -5945,7 +5797,8 @@ ThreadCollectionSP Process::GetHistoryThreads(lldb::addr_t addr) { return threads; } - threads.reset(new ThreadCollection(memory_history->GetHistoryThreads(addr))); + threads = std::make_shared<ThreadCollection>( + memory_history->GetHistoryThreads(addr)); return threads; } @@ -6017,7 +5870,8 @@ Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr, } uint32_t branch_index = - insn_list->GetIndexOfNextBranchInstruction(insn_offset, target); + insn_list->GetIndexOfNextBranchInstruction(insn_offset, target, + false /* ignore_calls*/); if (branch_index == UINT32_MAX) { return retval; } @@ -6061,7 +5915,7 @@ Process::GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) { } Status -Process::ConfigureStructuredData(const ConstString &type_name, +Process::ConfigureStructuredData(ConstString type_name, const StructuredData::ObjectSP &config_sp) { // If you get this, the Process-derived class needs to implement a method to // enable an already-reported asynchronous structured data feature. See |