diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
| commit | c0981da47d5696fe36474fcf86b4ce03ae3ff818 (patch) | |
| tree | f42add1021b9f2ac6a69ac7cf6c4499962739a45 /lldb/source/Plugins/Process/scripted | |
| parent | 344a3780b2e33f6ca763666c380202b18aab72a3 (diff) | |
Diffstat (limited to 'lldb/source/Plugins/Process/scripted')
4 files changed, 355 insertions, 49 deletions
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp index 09e9375b6f66..15d3d43d9993 100644 --- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp +++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp @@ -20,9 +20,6 @@ #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/RegisterContext.h" - -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Logging.h" #include "lldb/Utility/State.h" #include <mutex> @@ -32,12 +29,7 @@ LLDB_PLUGIN_DEFINE(ScriptedProcess) using namespace lldb; using namespace lldb_private; -ConstString ScriptedProcess::GetPluginNameStatic() { - static ConstString g_name("ScriptedProcess"); - return g_name; -} - -const char *ScriptedProcess::GetPluginDescriptionStatic() { +llvm::StringRef ScriptedProcess::GetPluginDescriptionStatic() { return "Scripted Process plug-in."; } @@ -109,9 +101,11 @@ ScriptedProcess::ScriptedProcess( return; } - StructuredData::ObjectSP object_sp = GetInterface().CreatePluginObject( - m_scripted_process_info.GetClassName().c_str(), target_sp, - m_scripted_process_info.GetDictionarySP()); + ExecutionContext exe_ctx(target_sp, /*get_process=*/false); + + StructuredData::GenericSP object_sp = GetInterface().CreatePluginObject( + m_scripted_process_info.GetClassName().c_str(), exe_ctx, + m_scripted_process_info.GetArgsSP()); if (!object_sp || !object_sp->IsValid()) { error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s", @@ -145,10 +139,6 @@ void ScriptedProcess::Terminate() { PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance); } -ConstString ScriptedProcess::GetPluginName() { return GetPluginNameStatic(); } - -uint32_t ScriptedProcess::GetPluginVersion() { return 1; } - Status ScriptedProcess::DoLoadCore() { ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo(); @@ -234,26 +224,22 @@ bool ScriptedProcess::IsAlive() { size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { - - auto error_with_message = [&error](llvm::StringRef message) { - error.SetErrorString(message); - return 0; - }; - if (!m_interpreter) - return error_with_message("No interpreter."); + return GetInterface().ErrorWithMessage<size_t>(LLVM_PRETTY_FUNCTION, + "No interpreter.", error); lldb::DataExtractorSP data_extractor_sp = GetInterface().ReadMemoryAtAddress(addr, size, error); - if (!data_extractor_sp || error.Fail()) + if (!data_extractor_sp || !data_extractor_sp->GetByteSize() || error.Fail()) return 0; offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData( 0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder()); if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET) - return error_with_message("Failed to copy read memory to buffer."); + return GetInterface().ErrorWithMessage<size_t>( + LLVM_PRETTY_FUNCTION, "Failed to copy read memory to buffer.", error); return size; } @@ -262,26 +248,36 @@ ArchSpec ScriptedProcess::GetArchitecture() { return GetTarget().GetArchitecture(); } -Status ScriptedProcess::GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo ®ion) { - // TODO: Implement - return Status(); +Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion) { + CheckInterpreterAndScriptObject(); + + Status error; + if (auto region_or_err = + GetInterface().GetMemoryRegionContainingAddress(load_addr, error)) + region = *region_or_err; + + return error; } Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos ®ion_list) { CheckInterpreterAndScriptObject(); + Status error; lldb::addr_t address = 0; - lldb::MemoryRegionInfoSP mem_region_sp = nullptr; - while ((mem_region_sp = - GetInterface().GetMemoryRegionContainingAddress(address))) { - auto range = mem_region_sp->GetRange(); + while (auto region_or_err = + GetInterface().GetMemoryRegionContainingAddress(address, error)) { + if (error.Fail()) + break; + + MemoryRegionInfo &mem_region = *region_or_err; + auto range = mem_region.GetRange(); address += range.GetRangeBase() + range.GetByteSize(); - region_list.push_back(*mem_region_sp.get()); + region_list.push_back(mem_region); } - return {}; + return error; } void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); } @@ -292,9 +288,40 @@ bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list, // This is supposed to get the current set of threads, if any of them are in // old_thread_list then they get copied to new_thread_list, and then any // actually new threads will get added to new_thread_list. + + CheckInterpreterAndScriptObject(); + m_thread_plans.ClearThreadCache(); + + Status error; + ScriptLanguage language = m_interpreter->GetLanguage(); + + if (language != eScriptLanguagePython) + return GetInterface().ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, + llvm::Twine("ScriptInterpreter language (" + + llvm::Twine(m_interpreter->LanguageToString(language)) + + llvm::Twine(") not supported.")) + .str(), + error); + + lldb::ThreadSP thread_sp; + thread_sp = std::make_shared<ScriptedThread>(*this, error); + + if (!thread_sp || error.Fail()) + return GetInterface().ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION, + error.AsCString(), error); + + new_thread_list.AddThread(thread_sp); + return new_thread_list.GetSize(false) > 0; } +void ScriptedProcess::RefreshStateAfterStop() { + // Let all threads recover from stopping and do any clean up based on the + // previous thread state (if any). + m_thread_list.RefreshStateAfterStop(); +} + bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) { info.Clear(); info.SetProcessID(GetID()); diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.h b/lldb/source/Plugins/Process/scripted/ScriptedProcess.h index 98c1a1ca4fe9..c8355f35548a 100644 --- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.h +++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.h @@ -13,6 +13,8 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" +#include "ScriptedThread.h" + #include <mutex> namespace lldb_private { @@ -23,17 +25,15 @@ protected: public: ScriptedProcessInfo(const ProcessLaunchInfo &launch_info) { m_class_name = launch_info.GetScriptedProcessClassName(); - m_dictionary_sp = launch_info.GetScriptedProcessDictionarySP(); + m_args_sp = launch_info.GetScriptedProcessDictionarySP(); } std::string GetClassName() const { return m_class_name; } - StructuredData::DictionarySP GetDictionarySP() const { - return m_dictionary_sp; - } + StructuredData::DictionarySP GetArgsSP() const { return m_args_sp; } private: std::string m_class_name; - StructuredData::DictionarySP m_dictionary_sp; + StructuredData::DictionarySP m_args_sp; }; public: @@ -46,9 +46,9 @@ public: static void Terminate(); - static ConstString GetPluginNameStatic(); + static llvm::StringRef GetPluginNameStatic() { return "ScriptedProcess"; } - static const char *GetPluginDescriptionStatic(); + static llvm::StringRef GetPluginDescriptionStatic(); ScriptedProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const ScriptedProcess::ScriptedProcessInfo &launch_info, @@ -61,9 +61,7 @@ public: DynamicLoader *GetDynamicLoader() override { return nullptr; } - ConstString GetPluginName() override; - - uint32_t GetPluginVersion() override; + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } SystemRuntime *GetSystemRuntime() override { return nullptr; } @@ -77,7 +75,7 @@ public: Status DoDestroy() override; - void RefreshStateAfterStop() override{}; + void RefreshStateAfterStop() override; bool IsAlive() override; @@ -86,9 +84,6 @@ public: ArchSpec GetArchitecture(); - Status GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo &range_info) override; - Status GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) override; @@ -102,7 +97,12 @@ protected: bool DoUpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) override; + Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) override; + private: + friend class ScriptedThread; + void CheckInterpreterAndScriptObject() const; ScriptedProcessInterface &GetInterface() const; static bool IsScriptLanguageSupported(lldb::ScriptLanguage language); diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp new file mode 100644 index 000000000000..1adbd4e7799d --- /dev/null +++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp @@ -0,0 +1,211 @@ +//===-- ScriptedThread.cpp ------------------------------------------------===// +// +// 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 "ScriptedThread.h" + +#include "Plugins/Process/Utility/RegisterContextThreadMemory.h" +#include "lldb/Target/OperatingSystem.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Unwind.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" + +#include <memory> + +using namespace lldb; +using namespace lldb_private; + +void ScriptedThread::CheckInterpreterAndScriptObject() const { + lldbassert(m_script_object_sp && "Invalid Script Object."); + lldbassert(GetInterface() && "Invalid Scripted Thread Interface."); +} + +ScriptedThread::ScriptedThread(ScriptedProcess &process, Status &error) + : Thread(process, LLDB_INVALID_THREAD_ID), m_scripted_process(process) { + if (!process.IsValid()) { + error.SetErrorString("Invalid scripted process"); + return; + } + + process.CheckInterpreterAndScriptObject(); + + auto scripted_thread_interface = GetInterface(); + if (!scripted_thread_interface) { + error.SetErrorString("Failed to get scripted thread interface."); + return; + } + + llvm::Optional<std::string> class_name = + process.GetInterface().GetScriptedThreadPluginName(); + if (!class_name || class_name->empty()) { + error.SetErrorString("Failed to get scripted thread class name."); + return; + } + + ExecutionContext exe_ctx(process); + + StructuredData::GenericSP object_sp = + scripted_thread_interface->CreatePluginObject( + class_name->c_str(), exe_ctx, + process.m_scripted_process_info.GetArgsSP()); + if (!object_sp || !object_sp->IsValid()) { + error.SetErrorString("Failed to create valid script object"); + return; + } + + m_script_object_sp = object_sp; + + SetID(scripted_thread_interface->GetThreadID()); +} + +ScriptedThread::~ScriptedThread() { DestroyThread(); } + +const char *ScriptedThread::GetName() { + CheckInterpreterAndScriptObject(); + llvm::Optional<std::string> thread_name = GetInterface()->GetName(); + if (!thread_name) + return nullptr; + return ConstString(thread_name->c_str()).AsCString(); +} + +const char *ScriptedThread::GetQueueName() { + CheckInterpreterAndScriptObject(); + llvm::Optional<std::string> queue_name = GetInterface()->GetQueue(); + if (!queue_name) + return nullptr; + return ConstString(queue_name->c_str()).AsCString(); +} + +void ScriptedThread::WillResume(StateType resume_state) {} + +void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); } + +RegisterContextSP ScriptedThread::GetRegisterContext() { + if (!m_reg_context_sp) + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); + return m_reg_context_sp; +} + +RegisterContextSP +ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) { + const uint32_t concrete_frame_idx = + frame ? frame->GetConcreteFrameIndex() : 0; + + if (concrete_frame_idx) + return GetUnwinder().CreateRegisterContextForFrame(frame); + + lldb::RegisterContextSP reg_ctx_sp; + Status error; + + llvm::Optional<std::string> reg_data = GetInterface()->GetRegisterContext(); + if (!reg_data) + return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( + LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.", + error, LIBLLDB_LOG_THREAD); + + DataBufferSP data_sp( + std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size())); + + if (!data_sp->GetByteSize()) + return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( + LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error, + LIBLLDB_LOG_THREAD); + + std::shared_ptr<RegisterContextMemory> reg_ctx_memory = + std::make_shared<RegisterContextMemory>( + *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS); + if (!reg_ctx_memory) + return GetInterface()->ErrorWithMessage<lldb::RegisterContextSP>( + LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error, + LIBLLDB_LOG_THREAD); + + reg_ctx_memory->SetAllRegisterData(data_sp); + m_reg_context_sp = reg_ctx_memory; + + return m_reg_context_sp; +} + +bool ScriptedThread::CalculateStopInfo() { + StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); + + Status error; + lldb::StopInfoSP stop_info_sp; + lldb::StopReason stop_reason_type; + + if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type)) + return GetInterface()->ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, + "Couldn't find value for key 'type' in stop reason dictionary.", error, + LIBLLDB_LOG_THREAD); + + StructuredData::Dictionary *data_dict; + if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict)) + return GetInterface()->ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, + "Couldn't find value for key 'type' in stop reason dictionary.", error, + LIBLLDB_LOG_THREAD); + + switch (stop_reason_type) { + case lldb::eStopReasonNone: + break; + case lldb::eStopReasonBreakpoint: { + lldb::break_id_t break_id; + data_dict->GetValueForKeyAsInteger("break_id", break_id, + LLDB_INVALID_BREAK_ID); + stop_info_sp = + StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id); + } break; + case lldb::eStopReasonSignal: { + int signal; + llvm::StringRef description; + data_dict->GetValueForKeyAsInteger("signal", signal, + LLDB_INVALID_SIGNAL_NUMBER); + data_dict->GetValueForKeyAsString("desc", description); + stop_info_sp = + StopInfo::CreateStopReasonWithSignal(*this, signal, description.data()); + } break; + default: + return GetInterface()->ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, + llvm::Twine("Unsupported stop reason type (" + + llvm::Twine(stop_reason_type) + llvm::Twine(").")) + .str(), + error, LIBLLDB_LOG_THREAD); + } + + SetStopInfo(stop_info_sp); + return true; +} + +void ScriptedThread::RefreshStateAfterStop() { + GetRegisterContext()->InvalidateIfNeeded(/*force=*/false); +} + +lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { + return m_scripted_process.GetInterface().GetScriptedThreadInterface(); +} + +std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() { + CheckInterpreterAndScriptObject(); + + if (!m_register_info_sp) { + StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo(); + if (!reg_info) + return nullptr; + + m_register_info_sp = std::make_shared<DynamicRegisterInfo>( + *reg_info, m_scripted_process.GetTarget().GetArchitecture()); + assert(m_register_info_sp->GetNumRegisters() > 0); + assert(m_register_info_sp->GetNumRegisterSets() > 0); + } + + return m_register_info_sp; +} diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.h b/lldb/source/Plugins/Process/scripted/ScriptedThread.h new file mode 100644 index 000000000000..cdcd543702a4 --- /dev/null +++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.h @@ -0,0 +1,68 @@ +//===-- ScriptedThread.h ----------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_SCRIPTED_THREAD_H +#define LLDB_SOURCE_PLUGINS_SCRIPTED_THREAD_H + +#include <string> + +#include "ScriptedProcess.h" + +#include "Plugins/Process/Utility/RegisterContextMemory.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Target//DynamicRegisterInfo.h" +#include "lldb/Target/Thread.h" + +namespace lldb_private { +class ScriptedProcess; +} + +namespace lldb_private { + +class ScriptedThread : public lldb_private::Thread { +public: + ScriptedThread(ScriptedProcess &process, Status &error); + + ~ScriptedThread() override; + + lldb::RegisterContextSP GetRegisterContext() override; + + lldb::RegisterContextSP + CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; + + bool CalculateStopInfo() override; + + const char *GetInfo() override { return nullptr; } + + const char *GetName() override; + + const char *GetQueueName() override; + + void WillResume(lldb::StateType resume_state) override; + + void RefreshStateAfterStop() override; + + void ClearStackFrames() override; + +private: + void CheckInterpreterAndScriptObject() const; + lldb::ScriptedThreadInterfaceSP GetInterface() const; + + ScriptedThread(const ScriptedThread &) = delete; + const ScriptedThread &operator=(const ScriptedThread &) = delete; + + std::shared_ptr<DynamicRegisterInfo> GetDynamicRegisterInfo(); + + const ScriptedProcess &m_scripted_process; + std::shared_ptr<DynamicRegisterInfo> m_register_info_sp = nullptr; + lldb_private::StructuredData::ObjectSP m_script_object_sp = nullptr; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_SCRIPTED_THREAD_H |
