aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Target/Process.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
commit344a3780b2e33f6ca763666c380202b18aab72a3 (patch)
treef0b203ee6eb71d7fdd792373e3c81eb18d6934dd /lldb/source/Target/Process.cpp
parentb60736ec1405bb0a8dd40989f67ef4c93da068ab (diff)
Diffstat (limited to 'lldb/source/Target/Process.cpp')
-rw-r--r--lldb/source/Target/Process.cpp238
1 files changed, 176 insertions, 62 deletions
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 518a6934059e..8ecc66b592ea 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -10,6 +10,7 @@
#include <memory>
#include <mutex>
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/Threading.h"
@@ -68,6 +69,7 @@
#include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/SelectHelper.h"
#include "lldb/Utility/State.h"
+#include "lldb/Utility/Timer.h"
using namespace lldb;
using namespace lldb_private;
@@ -83,16 +85,10 @@ using namespace std::chrono;
#define DISABLE_MEM_CACHE_DEFAULT true
#endif
-class ProcessOptionValueProperties : public OptionValueProperties {
+class ProcessOptionValueProperties
+ : public Cloneable<ProcessOptionValueProperties, OptionValueProperties> {
public:
- ProcessOptionValueProperties(ConstString name)
- : OptionValueProperties(name) {}
-
- // This constructor is used when creating ProcessOptionValueProperties when
- // it is part of a new lldb_private::Process instance. It will copy all
- // current global property values as needed
- ProcessOptionValueProperties(ProcessProperties *global_properties)
- : OptionValueProperties(*global_properties->GetValueProperties()) {}
+ ProcessOptionValueProperties(ConstString name) : Cloneable(name) {}
const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx,
bool will_modify,
@@ -131,10 +127,12 @@ enum {
#include "TargetPropertiesEnum.inc"
};
-class ProcessExperimentalOptionValueProperties : public OptionValueProperties {
+class ProcessExperimentalOptionValueProperties
+ : public Cloneable<ProcessExperimentalOptionValueProperties,
+ OptionValueProperties> {
public:
ProcessExperimentalOptionValueProperties()
- : OptionValueProperties(
+ : Cloneable(
ConstString(Properties::GetExperimentalSettingsName())) {}
};
@@ -157,8 +155,8 @@ ProcessProperties::ProcessProperties(lldb_private::Process *process)
ConstString("thread"), ConstString("Settings specific to threads."),
true, Thread::GetGlobalProperties()->GetValueProperties());
} else {
- m_collection_sp = std::make_shared<ProcessOptionValueProperties>(
- Process::GetGlobalProperties().get());
+ m_collection_sp =
+ OptionValueProperties::CreateLocalCopy(*Process::GetGlobalProperties());
m_collection_sp->SetValueChangedCallback(
ePropertyPythonOSPluginPath,
[this] { m_process->LoadOperatingSystemPlugin(true); });
@@ -204,6 +202,16 @@ FileSpec ProcessProperties::GetPythonOSPluginPath() const {
return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx);
}
+uint32_t ProcessProperties::GetVirtualAddressableBits() const {
+ const uint32_t idx = ePropertyVirtualAddressableBits;
+ return m_collection_sp->GetPropertyAtIndexAsUInt64(
+ nullptr, idx, g_process_properties[idx].default_uint_value);
+}
+
+void ProcessProperties::SetVirtualAddressableBits(uint32_t bits) {
+ const uint32_t idx = ePropertyVirtualAddressableBits;
+ m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, bits);
+}
void ProcessProperties::SetPythonOSPluginPath(const FileSpec &file) {
const uint32_t idx = ePropertyPythonOSPluginPath;
m_collection_sp->SetPropertyAtIndexAsFileSpec(nullptr, idx, file);
@@ -242,6 +250,18 @@ void ProcessProperties::SetStopOnSharedLibraryEvents(bool stop) {
m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop);
}
+bool ProcessProperties::GetDisableLangRuntimeUnwindPlans() const {
+ const uint32_t idx = ePropertyDisableLangRuntimeUnwindPlans;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_process_properties[idx].default_uint_value != 0);
+}
+
+void ProcessProperties::SetDisableLangRuntimeUnwindPlans(bool disable) {
+ const uint32_t idx = ePropertyDisableLangRuntimeUnwindPlans;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, disable);
+ m_process->Flush();
+}
+
bool ProcessProperties::GetDetachKeepsStopped() const {
const uint32_t idx = ePropertyDetachKeepsStopped;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
@@ -278,6 +298,13 @@ std::chrono::seconds ProcessProperties::GetUtilityExpressionTimeout() const {
return std::chrono::seconds(value);
}
+std::chrono::seconds ProcessProperties::GetInterruptTimeout() const {
+ const uint32_t idx = ePropertyInterruptTimeout;
+ uint64_t value = m_collection_sp->GetPropertyAtIndexAsUInt64(
+ nullptr, idx, g_process_properties[idx].default_uint_value);
+ return std::chrono::seconds(value);
+}
+
bool ProcessProperties::GetSteppingRunsAllThreads() const {
const uint32_t idx = ePropertySteppingRunsAllThreads;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
@@ -466,25 +493,9 @@ void Process::Finalize() {
if (m_finalizing.exchange(true))
return;
- // Destroy this process if needed
- switch (GetPrivateState()) {
- case eStateConnected:
- case eStateAttaching:
- case eStateLaunching:
- case eStateStopped:
- case eStateRunning:
- case eStateStepping:
- case eStateCrashed:
- case eStateSuspended:
- DestroyImpl(false);
- break;
-
- case eStateInvalid:
- case eStateUnloaded:
- case eStateDetached:
- case eStateExited:
- break;
- }
+ // Destroy the process. This will call the virtual function DoDestroy under
+ // the hood, giving our derived class a chance to do the ncessary tear down.
+ DestroyImpl(false);
// Clear our broadcaster before we proceed with destroying
Broadcaster::Clear();
@@ -766,13 +777,30 @@ bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp,
ThreadSP curr_thread(thread_list.GetSelectedThread());
ThreadSP thread;
StopReason curr_thread_stop_reason = eStopReasonInvalid;
- if (curr_thread) {
+ bool prefer_curr_thread = false;
+ if (curr_thread && curr_thread->IsValid()) {
curr_thread_stop_reason = curr_thread->GetStopReason();
+ switch (curr_thread_stop_reason) {
+ case eStopReasonNone:
+ case eStopReasonInvalid:
+ // Don't prefer the current thread if it didn't stop for a reason.
+ break;
+ case eStopReasonSignal: {
+ // We need to do the same computation we do for other threads
+ // below in case the current thread happens to be the one that
+ // stopped for the no-stop signal.
+ uint64_t signo = curr_thread->GetStopInfo()->GetValue();
+ if (process_sp->GetUnixSignals()->GetShouldStop(signo))
+ prefer_curr_thread = true;
+ } break;
+ default:
+ prefer_curr_thread = true;
+ break;
+ }
curr_thread_stop_info_sp = curr_thread->GetStopInfo();
}
- if (!curr_thread || !curr_thread->IsValid() ||
- curr_thread_stop_reason == eStopReasonInvalid ||
- curr_thread_stop_reason == eStopReasonNone) {
+
+ if (!prefer_curr_thread) {
// Prefer a thread that has just completed its plan over another
// thread as current thread.
ThreadSP plan_thread;
@@ -804,8 +832,12 @@ bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp,
case eStopReasonWatchpoint:
case eStopReasonException:
case eStopReasonExec:
+ case eStopReasonFork:
+ case eStopReasonVFork:
+ case eStopReasonVForkDone:
case eStopReasonThreadExiting:
case eStopReasonInstrumentation:
+ case eStopReasonProcessorTrace:
if (!other_thread)
other_thread = thread;
break;
@@ -1311,8 +1343,8 @@ Status Process::ResumeSynchronous(Stream *stream) {
Status error = PrivateResume();
if (error.Success()) {
- StateType state =
- WaitForProcessToStop(llvm::None, nullptr, true, listener_sp, stream);
+ StateType state = 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))
@@ -1356,8 +1388,8 @@ void Process::SetPrivateState(StateType new_state) {
if (m_finalizing)
return;
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE |
- LIBLLDB_LOG_PROCESS));
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(
+ LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_UNWIND));
bool state_changed = false;
LLDB_LOGF(log, "Process::SetPrivateState (%s)", StateAsCString(new_state));
@@ -2022,6 +2054,8 @@ size_t Process::ReadCStringFromMemory(addr_t addr, char *dst,
size_t Process::ReadMemoryFromInferior(addr_t addr, void *buf, size_t size,
Status &error) {
+ LLDB_SCOPED_TIMER();
+
if (buf == nullptr || size == 0)
return 0;
@@ -2448,6 +2482,11 @@ Status Process::Launch(ProcessLaunchInfo &launch_info) {
if (error.Fail())
return error;
+ // Listen and queue events that are broadcasted during the process launch.
+ ListenerSP listener_sp(Listener::MakeListener("LaunchEventHijack"));
+ HijackProcessEvents(listener_sp);
+ auto on_exit = llvm::make_scope_exit([this]() { RestoreProcessEvents(); });
+
if (PrivateStateThreadIsValid())
PausePrivateStateThread();
@@ -2856,8 +2895,10 @@ void Process::CompleteAttach() {
ProcessInstanceInfo process_info;
GetProcessInfo(process_info);
const ArchSpec &process_arch = process_info.GetArchitecture();
+ const ArchSpec &target_arch = GetTarget().GetArchitecture();
if (process_arch.IsValid() &&
- !GetTarget().GetArchitecture().IsExactMatch(process_arch)) {
+ target_arch.IsCompatibleMatch(process_arch) &&
+ !target_arch.IsExactMatch(process_arch)) {
GetTarget().SetArchitecture(process_arch);
LLDB_LOGF(log,
"Process::%s switching architecture to %s based on info "
@@ -3050,9 +3091,10 @@ Status Process::Halt(bool clear_thread_plans, bool use_run_lock) {
return Status();
}
- // Wait for 10 second for the process to stop.
- StateType state = WaitForProcessToStop(
- seconds(10), &event_sp, true, halt_listener_sp, nullptr, use_run_lock);
+ // Wait for the process halt timeout seconds for the process to stop.
+ StateType state =
+ WaitForProcessToStop(GetInterruptTimeout(), &event_sp, true,
+ halt_listener_sp, nullptr, use_run_lock);
RestoreProcessEvents();
if (state == eStateInvalid || !event_sp) {
@@ -3083,8 +3125,8 @@ Status Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) {
SendAsyncInterrupt();
// Consume the interrupt event.
- StateType state =
- WaitForProcessToStop(seconds(10), &exit_event_sp, true, listener_sp);
+ StateType state = WaitForProcessToStop(GetInterruptTimeout(),
+ &exit_event_sp, true, listener_sp);
RestoreProcessEvents();
@@ -3203,7 +3245,7 @@ Status Process::DestroyImpl(bool force_kill) {
error = StopForDestroyOrDetach(exit_event_sp);
}
- if (m_public_state.GetValue() != eStateRunning) {
+ if (m_public_state.GetValue() == eStateStopped) {
// Ditch all thread plans, and remove all our breakpoints: in case we
// have to restart the target to kill it, we don't want it hitting a
// breakpoint... Only do this if we've stopped, however, since if we
@@ -3374,14 +3416,14 @@ bool Process::ShouldBroadcastEvent(Event *event_ptr) {
should_resume = !m_thread_list.ShouldStop(event_ptr);
if (was_restarted || should_resume || m_resume_requested) {
- Vote stop_vote = m_thread_list.ShouldReportStop(event_ptr);
+ Vote report_stop_vote = m_thread_list.ShouldReportStop(event_ptr);
LLDB_LOGF(log,
"Process::ShouldBroadcastEvent: should_resume: %i state: "
- "%s was_restarted: %i stop_vote: %d.",
+ "%s was_restarted: %i report_stop_vote: %d.",
should_resume, StateAsCString(state), was_restarted,
- stop_vote);
+ report_stop_vote);
- switch (stop_vote) {
+ switch (report_stop_vote) {
case eVoteYes:
return_value = true;
break;
@@ -3819,9 +3861,7 @@ thread_result_t Process::RunPrivateStateThread(bool is_secondary_thread) {
// Process Event Data
-Process::ProcessEventData::ProcessEventData()
- : EventData(), m_process_wp(), m_state(eStateInvalid), m_restarted(false),
- m_update_state(0), m_interrupted(false) {}
+Process::ProcessEventData::ProcessEventData() : EventData(), m_process_wp() {}
Process::ProcessEventData::ProcessEventData(const ProcessSP &process_sp,
StateType state)
@@ -5536,6 +5576,26 @@ void Process::Flush() {
m_queue_list_stop_id = 0;
}
+lldb::addr_t Process::GetCodeAddressMask() {
+ if (m_code_address_mask == 0) {
+ if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) {
+ lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1);
+ SetCodeAddressMask(address_mask);
+ }
+ }
+ return m_code_address_mask;
+}
+
+lldb::addr_t Process::GetDataAddressMask() {
+ if (m_data_address_mask == 0) {
+ if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) {
+ lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1);
+ SetDataAddressMask(address_mask);
+ }
+ }
+ return m_data_address_mask;
+}
+
void Process::DidExec() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
LLDB_LOGF(log, "Process::%s()", __FUNCTION__);
@@ -5591,6 +5651,8 @@ addr_t Process::ResolveIndirectFunction(const Address *address, Status &error) {
symbol ? symbol->GetName().AsCString() : "<UNKNOWN>");
function_addr = LLDB_INVALID_ADDRESS;
} else {
+ if (ABISP abi_sp = GetABI())
+ function_addr = abi_sp->FixCodeAddress(function_addr);
m_resolved_indirect_addresses.insert(
std::pair<addr_t, addr_t>(addr, function_addr));
}
@@ -5684,12 +5746,12 @@ void Process::PrintWarningUnsupportedLanguage(const SymbolContext &sc) {
LanguageType language = sc.GetLanguage();
if (language == eLanguageTypeUnknown)
return;
- auto type_system_or_err = sc.module_sp->GetTypeSystemForLanguage(language);
- if (auto err = type_system_or_err.takeError()) {
- llvm::consumeError(std::move(err));
+ LanguageSet plugins =
+ PluginManager::GetAllTypeSystemSupportedLanguagesForTypes();
+ if (!plugins[language]) {
PrintWarning(Process::Warnings::eWarningsUnsupportedLanguage,
sc.module_sp.get(),
- "This version of LLDB has no plugin for the %s language. "
+ "This version of LLDB has no plugin for the language \"%s\". "
"Inspection of frame variables will be limited.\n",
Language::GetNameForLanguageType(language));
}
@@ -5769,10 +5831,8 @@ Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr,
const char *plugin_name = nullptr;
const char *flavor = nullptr;
- const bool prefer_file_cache = true;
disassembler_sp = Disassembler::DisassembleRange(
- target.GetArchitecture(), plugin_name, flavor, GetTarget(), range_bounds,
- prefer_file_cache);
+ target.GetArchitecture(), plugin_name, flavor, GetTarget(), range_bounds);
if (disassembler_sp)
insn_list = &disassembler_sp->GetInstructionList();
@@ -5962,7 +6022,7 @@ UtilityFunction *Process::GetLoadImageUtilityFunction(
return m_dlopen_utility_func_up.get();
}
-llvm::Expected<TraceTypeInfo> Process::GetSupportedTraceType() {
+llvm::Expected<TraceSupportedResponse> Process::TraceSupported() {
if (!IsLiveDebugSession())
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Can't trace a non-live process.");
@@ -6023,3 +6083,57 @@ bool Process::CallVoidArgVoidPtrReturn(const Address *address,
return false;
}
+
+llvm::Expected<const MemoryTagManager *> Process::GetMemoryTagManager() {
+ Architecture *arch = GetTarget().GetArchitecturePlugin();
+ const MemoryTagManager *tag_manager =
+ arch ? arch->GetMemoryTagManager() : nullptr;
+ if (!arch || !tag_manager) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "This architecture does not support memory tagging",
+ GetPluginName().GetCString());
+ }
+
+ if (!SupportsMemoryTagging()) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Process does not support memory tagging");
+ }
+
+ return tag_manager;
+}
+
+llvm::Expected<std::vector<lldb::addr_t>>
+Process::ReadMemoryTags(lldb::addr_t addr, size_t len) {
+ llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
+ GetMemoryTagManager();
+ if (!tag_manager_or_err)
+ return tag_manager_or_err.takeError();
+
+ const MemoryTagManager *tag_manager = *tag_manager_or_err;
+ llvm::Expected<std::vector<uint8_t>> tag_data =
+ DoReadMemoryTags(addr, len, tag_manager->GetAllocationTagType());
+ if (!tag_data)
+ return tag_data.takeError();
+
+ return tag_manager->UnpackTagsData(*tag_data,
+ len / tag_manager->GetGranuleSize());
+}
+
+Status Process::WriteMemoryTags(lldb::addr_t addr, size_t len,
+ const std::vector<lldb::addr_t> &tags) {
+ llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
+ GetMemoryTagManager();
+ if (!tag_manager_or_err)
+ return Status(tag_manager_or_err.takeError());
+
+ const MemoryTagManager *tag_manager = *tag_manager_or_err;
+ llvm::Expected<std::vector<uint8_t>> packed_tags =
+ tag_manager->PackTags(tags);
+ if (!packed_tags) {
+ return Status(packed_tags.takeError());
+ }
+
+ return DoWriteMemoryTags(addr, len, tag_manager->GetAllocationTagType(),
+ *packed_tags);
+}