diff --git a/lldb/bindings/interface/SBMemoryRegionInfo.i b/lldb/bindings/interface/SBMemoryRegionInfo.i --- a/lldb/bindings/interface/SBMemoryRegionInfo.i +++ b/lldb/bindings/interface/SBMemoryRegionInfo.i @@ -20,6 +20,9 @@ SBMemoryRegionInfo (const lldb::SBMemoryRegionInfo &rhs); + SBMemoryRegionInfo::SBMemoryRegionInfo(const char *name, lldb::addr_t begin, + lldb::addr_t end, uint32_t permissions, bool mapped, bool stack_memory); + ~SBMemoryRegionInfo (); void diff --git a/lldb/bindings/interface/SBMemoryRegionInfoList.i b/lldb/bindings/interface/SBMemoryRegionInfoList.i --- a/lldb/bindings/interface/SBMemoryRegionInfoList.i +++ b/lldb/bindings/interface/SBMemoryRegionInfoList.i @@ -24,6 +24,9 @@ uint32_t GetSize () const; + bool + GetMemoryRegionContainingAddress (lldb::addr_t addr, SBMemoryRegionInfo ®ion_info); + bool GetMemoryRegionAtIndex (uint32_t idx, SBMemoryRegionInfo ®ion_info); diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig --- a/lldb/bindings/python/python-wrapper.swig +++ b/lldb/bindings/python/python-wrapper.swig @@ -288,7 +288,6 @@ if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) Py_RETURN_NONE; - PyErr_Cleaner py_err_cleaner(true); auto dict = PythonModule::MainModule().ResolveName(session_dictionary_name); diff --git a/lldb/examples/python/scripted_process/main.stack-dump b/lldb/examples/python/scripted_process/main.stack-dump new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ lldb.SBMemoryRegionInfo: - return self.memory_regions[0] + for region in self.memory_regions: + if region.GetRegionBase() <= addr < region.GetRegionEnd(): + return region + return None def get_thread_with_id(self, tid: int): return {} @@ -20,10 +31,25 @@ return {} def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData: - data = lldb.SBData().CreateDataFromCString( + data = lldb.SBData() + + with open(self.stack_memory_dump, 'rb') as f: + stack_mem = f.read(-1) + if not stack_mem: + return data + + mem_region = self.get_memory_region_containing_address(addr) + + if not mem_region or addr + size > mem_region.GetRegionEnd(): + return data + + offset = addr - mem_region.GetRegionBase() + shrunk_stack_mem = stack_mem[offset:offset + size] + + error = lldb.SBError() + data.SetData(error, shrunk_stack_mem, self.target.GetByteOrder(), - self.target.GetCodeByteSize(), - "Hello, world!") + self.target.GetAddressByteSize()) return data def get_loaded_images(self): @@ -43,6 +69,30 @@ class MyScriptedThread(ScriptedThread): + registers = { + "rax":0x00000000000006e4, + "rbx":0x00000001040b6060, + "rcx":0x00000001040b2e00, + "rdx":0x00000001040b2ba8, + "rdi":0x000000000000002a, + "rsi":0x00000001040b2b98, + "rbp":0x00000001040b2a20, + "rsp":0x00000001040b2a20, + "r8":0x00000000003e131e, + "r9":0xffffffff00000000, + "r10":0x0000000000000000, + "r11":0x0000000000000246, + "r12":0x000000010007c3a0, + "r13":0x00000001040b2b18, + "r14":0x0000000100003f90, + "r15":0x00000001040b2b88, + "rip":0x0000000100003f61, + "rflags":0x0000000000000206, + "cs":0x000000000000002b, + "fs":0x0000000000000000, + "gs":0x0000000000000000, + } + def __init__(self, target): super().__init__(target) @@ -76,8 +126,7 @@ return self.frame_zero[0:0] def get_register_context(self) -> str: - return struct.pack( - '21Q', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) + return struct.pack(f"{len(self.registers)}Q", *self.registers.values()) def __lldb_init_module(debugger, dict): diff --git a/lldb/include/lldb/API/SBMemoryRegionInfo.h b/lldb/include/lldb/API/SBMemoryRegionInfo.h --- a/lldb/include/lldb/API/SBMemoryRegionInfo.h +++ b/lldb/include/lldb/API/SBMemoryRegionInfo.h @@ -20,6 +20,10 @@ SBMemoryRegionInfo(const lldb::SBMemoryRegionInfo &rhs); + SBMemoryRegionInfo(const char *name, lldb::addr_t begin, lldb::addr_t end, + uint32_t permissions, bool mapped, + bool stack_memory = false); + ~SBMemoryRegionInfo(); const lldb::SBMemoryRegionInfo & @@ -117,6 +121,8 @@ friend class SBProcess; friend class SBMemoryRegionInfoList; + friend class lldb_private::ScriptInterpreter; + lldb_private::MemoryRegionInfo &ref(); const lldb_private::MemoryRegionInfo &ref() const; @@ -124,7 +130,7 @@ // Unused. SBMemoryRegionInfo(const lldb_private::MemoryRegionInfo *lldb_object_ptr); - lldb::MemoryRegionInfoUP m_opaque_up; + lldb::MemoryRegionInfoSP m_opaque_sp; }; } // namespace lldb diff --git a/lldb/include/lldb/API/SBMemoryRegionInfoList.h b/lldb/include/lldb/API/SBMemoryRegionInfoList.h --- a/lldb/include/lldb/API/SBMemoryRegionInfoList.h +++ b/lldb/include/lldb/API/SBMemoryRegionInfoList.h @@ -27,6 +27,9 @@ uint32_t GetSize() const; + bool GetMemoryRegionContainingAddress(lldb::addr_t addr, + SBMemoryRegionInfo ®ion_info); + bool GetMemoryRegionAtIndex(uint32_t idx, SBMemoryRegionInfo ®ion_info); void Append(lldb::SBMemoryRegionInfo ®ion); diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -11,6 +11,7 @@ #include "lldb/API/SBData.h" #include "lldb/API/SBError.h" +#include "lldb/API/SBMemoryRegionInfo.h" #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Core/Communication.h" #include "lldb/Core/PluginInterface.h" @@ -564,6 +565,9 @@ Status GetStatusFromSBError(const lldb::SBError &error) const; + lldb::MemoryRegionInfoSP GetOpaquePtrFromSBMemoryRegionInfo( + const lldb::SBMemoryRegionInfo &mem_region) const; + protected: Debugger &m_debugger; lldb::ScriptLanguage m_script_lang; diff --git a/lldb/include/lldb/Interpreter/ScriptedInterface.h b/lldb/include/lldb/Interpreter/ScriptedInterface.h new file mode 100644 --- /dev/null +++ b/lldb/include/lldb/Interpreter/ScriptedInterface.h @@ -0,0 +1,32 @@ +//===-- ScriptedInterface.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_INTERPRETER_SCRIPTEDINTERFACE_H +#define LLDB_INTERPRETER_SCRIPTEDINTERFACE_H + +#include "lldb/Core/StructuredDataImpl.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/lldb-private.h" + +#include + +namespace lldb_private { +class ScriptedInterface { +public: + ScriptedInterface() = default; + virtual ~ScriptedInterface() = default; + + virtual StructuredData::GenericSP + CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx, + StructuredData::DictionarySP args_sp) = 0; + +protected: + StructuredData::GenericSP m_object_instance_sp; +}; +} // namespace lldb_private +#endif // LLDB_INTERPRETER_SCRIPTEDINTERFACE_H diff --git a/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h b/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h --- a/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h +++ b/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h @@ -11,20 +11,18 @@ #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Interpreter/ScriptedInterface.h" + #include "lldb/lldb-private.h" #include namespace lldb_private { -class ScriptedProcessInterface { +class ScriptedProcessInterface : virtual public ScriptedInterface { public: - ScriptedProcessInterface() : m_object_instance_sp(nullptr) {} - - virtual ~ScriptedProcessInterface() = default; - - virtual StructuredData::GenericSP - CreatePluginObject(const llvm::StringRef class_name, lldb::TargetSP target_sp, - StructuredData::DictionarySP args_sp) { + StructuredData::GenericSP + CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx, + StructuredData::DictionarySP args_sp) override { return nullptr; } @@ -59,9 +57,6 @@ virtual lldb::pid_t GetProcessID() { return LLDB_INVALID_PROCESS_ID; } virtual bool IsAlive() { return true; } - -private: - StructuredData::ObjectSP m_object_instance_sp; }; } // namespace lldb_private diff --git a/lldb/source/API/SBMemoryRegionInfo.cpp b/lldb/source/API/SBMemoryRegionInfo.cpp --- a/lldb/source/API/SBMemoryRegionInfo.cpp +++ b/lldb/source/API/SBMemoryRegionInfo.cpp @@ -18,21 +18,39 @@ using namespace lldb; using namespace lldb_private; -SBMemoryRegionInfo::SBMemoryRegionInfo() : m_opaque_up(new MemoryRegionInfo()) { +SBMemoryRegionInfo::SBMemoryRegionInfo() : m_opaque_sp(new MemoryRegionInfo()) { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBMemoryRegionInfo); } +SBMemoryRegionInfo::SBMemoryRegionInfo(const char *name, lldb::addr_t begin, + lldb::addr_t end, uint32_t permissions, + bool mapped, bool stack_memory) + : SBMemoryRegionInfo() { + LLDB_RECORD_CONSTRUCTOR( + SBMemoryRegionInfo, + (const char *, lldb::addr_t, lldb::addr_t, uint32_t, bool, bool), name, + begin, end, permissions, mapped, stack_memory); + m_opaque_sp->SetName(name); + m_opaque_sp->GetRange().SetRangeBase(begin); + m_opaque_sp->GetRange().SetRangeEnd(end); + m_opaque_sp->SetLLDBPermissions(permissions); + m_opaque_sp->SetMapped(mapped ? MemoryRegionInfo::eYes + : MemoryRegionInfo::eNo); + m_opaque_sp->SetIsStackMemory(stack_memory ? MemoryRegionInfo::eYes + : MemoryRegionInfo::eNo); +} + SBMemoryRegionInfo::SBMemoryRegionInfo(const MemoryRegionInfo *lldb_object_ptr) - : m_opaque_up(new MemoryRegionInfo()) { + : m_opaque_sp(new MemoryRegionInfo()) { if (lldb_object_ptr) ref() = *lldb_object_ptr; } SBMemoryRegionInfo::SBMemoryRegionInfo(const SBMemoryRegionInfo &rhs) - : m_opaque_up() { + : m_opaque_sp() { LLDB_RECORD_CONSTRUCTOR(SBMemoryRegionInfo, (const lldb::SBMemoryRegionInfo &), rhs); - m_opaque_up = clone(rhs.m_opaque_up); + m_opaque_sp = clone(rhs.m_opaque_sp); } const SBMemoryRegionInfo &SBMemoryRegionInfo:: @@ -42,7 +60,7 @@ SBMemoryRegionInfo, operator=,(const lldb::SBMemoryRegionInfo &), rhs); if (this != &rhs) - m_opaque_up = clone(rhs.m_opaque_up); + m_opaque_sp = clone(rhs.m_opaque_sp); return LLDB_RECORD_RESULT(*this); } @@ -51,7 +69,7 @@ void SBMemoryRegionInfo::Clear() { LLDB_RECORD_METHOD_NO_ARGS(void, SBMemoryRegionInfo, Clear); - m_opaque_up->Clear(); + m_opaque_sp->Clear(); } bool SBMemoryRegionInfo::operator==(const SBMemoryRegionInfo &rhs) const { @@ -70,56 +88,56 @@ return ref() != rhs.ref(); } -MemoryRegionInfo &SBMemoryRegionInfo::ref() { return *m_opaque_up; } +MemoryRegionInfo &SBMemoryRegionInfo::ref() { return *m_opaque_sp; } -const MemoryRegionInfo &SBMemoryRegionInfo::ref() const { return *m_opaque_up; } +const MemoryRegionInfo &SBMemoryRegionInfo::ref() const { return *m_opaque_sp; } lldb::addr_t SBMemoryRegionInfo::GetRegionBase() { LLDB_RECORD_METHOD_NO_ARGS(lldb::addr_t, SBMemoryRegionInfo, GetRegionBase); - return m_opaque_up->GetRange().GetRangeBase(); + return m_opaque_sp->GetRange().GetRangeBase(); } lldb::addr_t SBMemoryRegionInfo::GetRegionEnd() { LLDB_RECORD_METHOD_NO_ARGS(lldb::addr_t, SBMemoryRegionInfo, GetRegionEnd); - return m_opaque_up->GetRange().GetRangeEnd(); + return m_opaque_sp->GetRange().GetRangeEnd(); } bool SBMemoryRegionInfo::IsReadable() { LLDB_RECORD_METHOD_NO_ARGS(bool, SBMemoryRegionInfo, IsReadable); - return m_opaque_up->GetReadable() == MemoryRegionInfo::eYes; + return m_opaque_sp->GetReadable() == MemoryRegionInfo::eYes; } bool SBMemoryRegionInfo::IsWritable() { LLDB_RECORD_METHOD_NO_ARGS(bool, SBMemoryRegionInfo, IsWritable); - return m_opaque_up->GetWritable() == MemoryRegionInfo::eYes; + return m_opaque_sp->GetWritable() == MemoryRegionInfo::eYes; } bool SBMemoryRegionInfo::IsExecutable() { LLDB_RECORD_METHOD_NO_ARGS(bool, SBMemoryRegionInfo, IsExecutable); - return m_opaque_up->GetExecutable() == MemoryRegionInfo::eYes; + return m_opaque_sp->GetExecutable() == MemoryRegionInfo::eYes; } bool SBMemoryRegionInfo::IsMapped() { LLDB_RECORD_METHOD_NO_ARGS(bool, SBMemoryRegionInfo, IsMapped); - return m_opaque_up->GetMapped() == MemoryRegionInfo::eYes; + return m_opaque_sp->GetMapped() == MemoryRegionInfo::eYes; } const char *SBMemoryRegionInfo::GetName() { LLDB_RECORD_METHOD_NO_ARGS(const char *, SBMemoryRegionInfo, GetName); - return m_opaque_up->GetName().AsCString(); + return m_opaque_sp->GetName().AsCString(); } bool SBMemoryRegionInfo::HasDirtyMemoryPageList() { LLDB_RECORD_METHOD_NO_ARGS(bool, SBMemoryRegionInfo, HasDirtyMemoryPageList); - return m_opaque_up->GetDirtyPageList().hasValue(); + return m_opaque_sp->GetDirtyPageList().hasValue(); } uint32_t SBMemoryRegionInfo::GetNumDirtyPages() { @@ -127,7 +145,7 @@ uint32_t num_dirty_pages = 0; llvm::Optional> dirty_page_list = - m_opaque_up->GetDirtyPageList(); + m_opaque_sp->GetDirtyPageList(); if (dirty_page_list.hasValue()) num_dirty_pages = dirty_page_list.getValue().size(); @@ -140,7 +158,7 @@ addr_t dirty_page_addr = LLDB_INVALID_ADDRESS; const llvm::Optional> &dirty_page_list = - m_opaque_up->GetDirtyPageList(); + m_opaque_sp->GetDirtyPageList(); if (dirty_page_list.hasValue() && idx < dirty_page_list.getValue().size()) dirty_page_addr = dirty_page_list.getValue()[idx]; @@ -150,7 +168,7 @@ int SBMemoryRegionInfo::GetPageSize() { LLDB_RECORD_METHOD_NO_ARGS(int, SBMemoryRegionInfo, GetPageSize); - return m_opaque_up->GetPageSize(); + return m_opaque_sp->GetPageSize(); } bool SBMemoryRegionInfo::GetDescription(SBStream &description) { @@ -158,13 +176,13 @@ (lldb::SBStream &), description); Stream &strm = description.ref(); - const addr_t load_addr = m_opaque_up->GetRange().base; + const addr_t load_addr = m_opaque_sp->GetRange().base; strm.Printf("[0x%16.16" PRIx64 "-0x%16.16" PRIx64 " ", load_addr, - load_addr + m_opaque_up->GetRange().size); - strm.Printf(m_opaque_up->GetReadable() ? "R" : "-"); - strm.Printf(m_opaque_up->GetWritable() ? "W" : "-"); - strm.Printf(m_opaque_up->GetExecutable() ? "X" : "-"); + load_addr + m_opaque_sp->GetRange().size); + strm.Printf(m_opaque_sp->GetReadable() ? "R" : "-"); + strm.Printf(m_opaque_sp->GetWritable() ? "W" : "-"); + strm.Printf(m_opaque_sp->GetExecutable() ? "X" : "-"); strm.Printf("]"); return true; @@ -178,6 +196,9 @@ LLDB_REGISTER_CONSTRUCTOR(SBMemoryRegionInfo, ()); LLDB_REGISTER_CONSTRUCTOR(SBMemoryRegionInfo, (const lldb::SBMemoryRegionInfo &)); + LLDB_REGISTER_CONSTRUCTOR( + SBMemoryRegionInfo, + (const char *, lldb::addr_t, lldb::addr_t, uint32_t, bool, bool)); LLDB_REGISTER_METHOD( const lldb::SBMemoryRegionInfo &, SBMemoryRegionInfo, operator=,(const lldb::SBMemoryRegionInfo &)); diff --git a/lldb/source/API/SBMemoryRegionInfoList.cpp b/lldb/source/API/SBMemoryRegionInfoList.cpp --- a/lldb/source/API/SBMemoryRegionInfoList.cpp +++ b/lldb/source/API/SBMemoryRegionInfoList.cpp @@ -48,6 +48,17 @@ void Clear() { m_regions.clear(); } + bool GetMemoryRegionContainingAddress(lldb::addr_t addr, + MemoryRegionInfo ®ion_info) { + for (auto ®ion : m_regions) { + if (region.GetRange().Contains(addr)) { + region_info = region; + return true; + } + } + return false; + } + bool GetMemoryRegionInfoAtIndex(size_t index, MemoryRegionInfo ®ion_info) { if (index >= GetSize()) @@ -103,6 +114,15 @@ return m_opaque_up->GetSize(); } +bool SBMemoryRegionInfoList::GetMemoryRegionContainingAddress( + lldb::addr_t addr, SBMemoryRegionInfo ®ion_info) { + LLDB_RECORD_METHOD( + bool, SBMemoryRegionInfoList, GetMemoryRegionContainingAddress, + (lldb::addr_t, lldb::SBMemoryRegionInfo &), addr, region_info); + + return m_opaque_up->GetMemoryRegionContainingAddress(addr, region_info.ref()); +} + bool SBMemoryRegionInfoList::GetMemoryRegionAtIndex( uint32_t idx, SBMemoryRegionInfo ®ion_info) { LLDB_RECORD_METHOD(bool, SBMemoryRegionInfoList, GetMemoryRegionAtIndex, @@ -153,6 +173,9 @@ SBMemoryRegionInfoList, operator=,( const lldb::SBMemoryRegionInfoList &)); LLDB_REGISTER_METHOD_CONST(uint32_t, SBMemoryRegionInfoList, GetSize, ()); + LLDB_REGISTER_METHOD(bool, SBMemoryRegionInfoList, + GetMemoryRegionContainingAddress, + (lldb::addr_t, lldb::SBMemoryRegionInfo &)); LLDB_REGISTER_METHOD(bool, SBMemoryRegionInfoList, GetMemoryRegionAtIndex, (uint32_t, lldb::SBMemoryRegionInfo &)); LLDB_REGISTER_METHOD(void, SBMemoryRegionInfoList, Clear, ()); diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp --- a/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -83,6 +83,11 @@ return Status(); } +lldb::MemoryRegionInfoSP ScriptInterpreter::GetOpaquePtrFromSBMemoryRegionInfo( + const lldb::SBMemoryRegionInfo &mem_region) const { + return mem_region.m_opaque_sp; +} + lldb::ScriptLanguage ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) { if (language.equals_insensitive(LanguageToString(eScriptLanguageNone))) diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp --- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp +++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp @@ -109,8 +109,10 @@ return; } - StructuredData::ObjectSP object_sp = GetInterface().CreatePluginObject( - m_scripted_process_info.GetClassName().c_str(), target_sp, + 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.GetDictionarySP()); if (!object_sp || !object_sp->IsValid()) { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -11,6 +11,7 @@ PythonDataObjects.cpp PythonReadline.cpp ScriptInterpreterPython.cpp + ScriptedPythonInterface.cpp ScriptedProcessPythonInterface.cpp SWIGPythonBridge.cpp diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h --- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -53,6 +53,7 @@ extern "C" void *LLDBSWIGPython_CastPyObjectToSBData(void *data); extern "C" void *LLDBSWIGPython_CastPyObjectToSBError(void *data); extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data); +extern "C" void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(void *data); } // namespace lldb_private diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -13,8 +13,6 @@ #if LLDB_ENABLE_PYTHON -#include "ScriptedProcessPythonInterface.h" - #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Core/IOHandler.h" #include "lldb/Core/StructuredDataImpl.h" diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h @@ -13,17 +13,18 @@ #if LLDB_ENABLE_PYTHON +#include "ScriptedPythonInterface.h" #include "lldb/Interpreter/ScriptedProcessInterface.h" namespace lldb_private { -class ScriptInterpreterPythonImpl; -class ScriptedProcessPythonInterface : public ScriptedProcessInterface { +class ScriptedProcessPythonInterface : public ScriptedProcessInterface, + public ScriptedPythonInterface { public: - ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter) - : ScriptedProcessInterface(), m_interpreter(interpreter) {} + ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter); StructuredData::GenericSP - CreatePluginObject(const llvm::StringRef class_name, lldb::TargetSP target_sp, + CreatePluginObject(const llvm::StringRef class_name, + ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp) override; Status Launch() override; @@ -49,16 +50,6 @@ lldb::pid_t GetProcessID() override; bool IsAlive() override; - -protected: - llvm::Optional - GetGenericInteger(llvm::StringRef method_name); - Status GetStatusFromMethod(llvm::StringRef method_name); - -private: - // The lifetime is managed by the ScriptInterpreter - ScriptInterpreterPythonImpl &m_interpreter; - StructuredData::GenericSP m_object_instance_sp; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" #include "lldb/lldb-enumerations.h" #if LLDB_ENABLE_PYTHON @@ -23,30 +25,33 @@ using namespace lldb_private::python; using Locker = ScriptInterpreterPythonImpl::Locker; +ScriptedProcessPythonInterface::ScriptedProcessPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : ScriptedProcessInterface(), ScriptedPythonInterface(interpreter) {} + StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject( - const llvm::StringRef class_name, lldb::TargetSP target_sp, + llvm::StringRef class_name, ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp) { if (class_name.empty()) return {}; - std::string error_string; + TargetSP target_sp = exe_ctx.GetTargetSP(); StructuredDataImpl *args_impl = nullptr; if (args_sp) { args_impl = new StructuredDataImpl(); args_impl->SetObjectSP(args_sp); } + std::string error_string; - void *ret_val; - - { + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); + void *ret_val = LLDBSwigPythonCreateScriptedProcess( + class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp, + args_impl, error_string); - ret_val = LLDBSwigPythonCreateScriptedProcess( - class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp, - args_impl, error_string); - } + if (!ret_val) + return {}; m_object_instance_sp = StructuredData::GenericSP(new StructuredPythonObject(ret_val)); @@ -63,244 +68,117 @@ } bool ScriptedProcessPythonInterface::ShouldStop() { - llvm::Optional should_stop = - GetGenericInteger("should_stop"); + Status error; + StructuredData::ObjectSP obj = Dispatch("is_alive", error); - if (!should_stop) + auto error_with_message = [](llvm::StringRef message) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), + "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data()); return false; + }; - return static_cast(*should_stop); -} - -Status ScriptedProcessPythonInterface::Stop() { - return GetStatusFromMethod("stop"); -} - -Status ScriptedProcessPythonInterface::GetStatusFromMethod( - llvm::StringRef method_name) { - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - if (!m_object_instance_sp) - return Status("Python object ill-formed."); - - if (!m_object_instance_sp) - return Status("Cannot convert Python object to StructuredData::Generic."); - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)m_object_instance_sp->GetValue()); - - if (!implementor.IsAllocated()) - return Status("Python implementor not allocated."); - - PythonObject pmeth( - PyRefType::Owned, - PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); - - if (PyErr_Occurred()) - PyErr_Clear(); - - if (!pmeth.IsAllocated()) - return Status("Python method not allocated."); - - if (PyCallable_Check(pmeth.get()) == 0) { - if (PyErr_Occurred()) - PyErr_Clear(); - return Status("Python method not callable."); - } - - if (PyErr_Occurred()) - PyErr_Clear(); - - PythonObject py_return(PyRefType::Owned, - PyObject_CallMethod(implementor.get(), - method_name.str().c_str(), - nullptr)); - - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - return Status("Python method could not be called."); - } - - if (PyObject *py_ret_ptr = py_return.get()) { - lldb::SBError *sb_error = - (lldb::SBError *)LLDBSWIGPython_CastPyObjectToSBError(py_ret_ptr); - - if (!sb_error) - return Status("Couldn't cast lldb::SBError to lldb::Status."); - - Status status = m_interpreter.GetStatusFromSBError(*sb_error); - - if (status.Fail()) - return Status("error: %s", status.AsCString()); - - return status; + if (!obj || !obj->IsValid() || error.Fail()) { + return error_with_message(llvm::Twine("Null or invalid object (" + + llvm::Twine(error.AsCString()) + + llvm::Twine(").")) + .str()); } - return Status("Returned object is null."); + return obj->GetBooleanValue(); } -llvm::Optional -ScriptedProcessPythonInterface::GetGenericInteger(llvm::StringRef method_name) { - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - if (!m_object_instance_sp) - return llvm::None; - - if (!m_object_instance_sp) - return llvm::None; - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)m_object_instance_sp->GetValue()); - - if (!implementor.IsAllocated()) - return llvm::None; - - PythonObject pmeth( - PyRefType::Owned, - PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); - - if (PyErr_Occurred()) - PyErr_Clear(); - - if (!pmeth.IsAllocated()) - return llvm::None; - - if (PyCallable_Check(pmeth.get()) == 0) { - if (PyErr_Occurred()) - PyErr_Clear(); - return llvm::None; - } - - if (PyErr_Occurred()) - PyErr_Clear(); - - PythonObject py_return(PyRefType::Owned, - PyObject_CallMethod(implementor.get(), - method_name.str().c_str(), - nullptr)); - - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - } - - if (!py_return.get()) - return llvm::None; - - llvm::Expected size = py_return.AsUnsignedLongLong(); - // FIXME: Handle error. - if (!size) - return llvm::None; - - return *size; +Status ScriptedProcessPythonInterface::Stop() { + return GetStatusFromMethod("stop"); } lldb::MemoryRegionInfoSP ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress( lldb::addr_t address) { // TODO: Implement - return nullptr; + return {}; } StructuredData::DictionarySP ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) { - // TODO: Implement - return nullptr; -} - -StructuredData::DictionarySP -ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) { - // TODO: Implement - return nullptr; -} - -lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress( - lldb::addr_t address, size_t size, Status &error) { Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); - auto error_with_message = [&error](llvm::StringRef message) { - error.SetErrorString(message); - return nullptr; + auto error_with_message = [](llvm::StringRef message) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), + "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data()); + return StructuredData::DictionarySP(); }; - static char callee_name[] = "read_memory_at_address"; - std::string param_format = GetPythonValueFormatString(address); - param_format += GetPythonValueFormatString(size); - - if (!m_object_instance_sp) - return error_with_message("Python object ill-formed."); - - if (!m_object_instance_sp) - return error_with_message("Python method not callable."); - - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)m_object_instance_sp->GetValue()); - - if (!implementor.IsAllocated()) - return error_with_message("Python implementor not allocated."); - - PythonObject pmeth(PyRefType::Owned, - PyObject_GetAttrString(implementor.get(), callee_name)); + Status error; + StructuredData::ObjectSP obj = Dispatch("get_thread_with_id", error, tid); - if (PyErr_Occurred()) - PyErr_Clear(); - - if (!pmeth.IsAllocated()) - return error_with_message("Python method not allocated."); - - if (PyCallable_Check(pmeth.get()) == 0) { - if (PyErr_Occurred()) - PyErr_Clear(); - return error_with_message("Python method not callable."); - } - - if (PyErr_Occurred()) - PyErr_Clear(); - - PythonObject py_return(PyRefType::Owned, - PyObject_CallMethod(implementor.get(), callee_name, - param_format.c_str(), address, - size)); - - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - return error_with_message("Python method could not be called."); + if (!obj || !obj->IsValid() || error.Fail()) { + return error_with_message(llvm::Twine("Null or invalid object (" + + llvm::Twine(error.AsCString()) + + llvm::Twine(").")) + .str()); } - if (PyObject *py_ret_ptr = py_return.get()) { - lldb::SBData *sb_data = - (lldb::SBData *)LLDBSWIGPython_CastPyObjectToSBData(py_ret_ptr); + StructuredData::DictionarySP dict{obj->GetAsDictionary()}; - if (!sb_data) - return error_with_message( - "Couldn't cast lldb::SBData to lldb::DataExtractor."); + return dict; +} - return m_interpreter.GetDataExtractorFromSBData(*sb_data); - } +StructuredData::DictionarySP +ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) { + // TODO: Implement + return {}; +} - return error_with_message("Returned object is null."); +lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress( + lldb::addr_t address, size_t size, Status &error) { + return Dispatch("read_memory_at_address", error, + address, size); } StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() { // TODO: Implement - return nullptr; + return {}; } lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() { - llvm::Optional pid = GetGenericInteger("get_process_id"); - return (!pid) ? LLDB_INVALID_PROCESS_ID : *pid; + Status error; + StructuredData::ObjectSP obj = Dispatch("get_process_id", error); + + auto error_with_message = [](llvm::StringRef message) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), + "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data()); + return LLDB_INVALID_PROCESS_ID; + }; + + if (!obj || !obj->IsValid() || error.Fail()) { + return error_with_message(llvm::Twine("Null or invalid object (" + + llvm::Twine(error.AsCString()) + + llvm::Twine(").")) + .str()); + } + + return obj->GetIntegerValue(LLDB_INVALID_PROCESS_ID); } bool ScriptedProcessPythonInterface::IsAlive() { - llvm::Optional is_alive = GetGenericInteger("is_alive"); + Status error; + StructuredData::ObjectSP obj = Dispatch("is_alive", error); - if (!is_alive) + auto error_with_message = [](llvm::StringRef message) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), + "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data()); return false; + }; + + if (!obj || !obj->IsValid() || error.Fail()) { + return error_with_message(llvm::Twine("Null or invalid object (" + + llvm::Twine(error.AsCString()) + + llvm::Twine(").")) + .str()); + } - return static_cast(*is_alive); + return obj->GetBooleanValue(); } #endif diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h @@ -0,0 +1,151 @@ +//===-- ScriptedPythonInterface.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_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H + +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_PYTHON + +#include "lldb/Interpreter/ScriptedInterface.h" +#include "lldb/Utility/DataBufferHeap.h" + +#include "PythonDataObjects.h" +#include "SWIGPythonBridge.h" +#include "ScriptInterpreterPythonImpl.h" + +namespace lldb_private { +class ScriptInterpreterPythonImpl; +class ScriptedPythonInterface : virtual public ScriptedInterface { +public: + ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); + virtual ~ScriptedPythonInterface() = default; + +protected: + template + T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { + return p.CreateStructuredObject(); + } + + template <> + Status ExtractValueFromPythonObject(python::PythonObject &p, + Status &error) { + if (lldb::SBError *sb_error = reinterpret_cast( + LLDBSWIGPython_CastPyObjectToSBError(p.get()))) + error = m_interpreter.GetStatusFromSBError(*sb_error); + else + error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status."); + + return error; + } + + template <> + lldb::DataExtractorSP + ExtractValueFromPythonObject(python::PythonObject &p, + Status &error) { + lldb::SBData *sb_data = reinterpret_cast( + LLDBSWIGPython_CastPyObjectToSBData(p.get())); + + if (!sb_data) { + error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status."); + return nullptr; + } + + return m_interpreter.GetDataExtractorFromSBData(*sb_data); + } + + template + T Dispatch(llvm::StringRef method_name, Status &error, Args... args) { + using namespace python; + using Locker = ScriptInterpreterPythonImpl::Locker; + + auto error_with_message = [&method_name, &error](llvm::StringRef message) { + error.SetErrorStringWithFormatv( + "ScriptedPythonInterface::{0} ({1}) ERROR = {2}", __FUNCTION__, + method_name, message); + return T(); + }; + + if (!m_object_instance_sp) + return error_with_message("Python object ill-formed"); + + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)m_object_instance_sp->GetValue()); + + if (!implementor.IsAllocated()) + return error_with_message("Python implementor not allocated."); + + PythonObject pmeth( + PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); + + if (PyErr_Occurred()) + PyErr_Clear(); + + if (!pmeth.IsAllocated()) + return error_with_message("Python method not allocated."); + + if (PyCallable_Check(pmeth.get()) == 0) { + if (PyErr_Occurred()) + PyErr_Clear(); + return error_with_message("Python method not callable."); + } + + if (PyErr_Occurred()) + PyErr_Clear(); + + const char *format = nullptr; + std::string format_buffer; + + if (sizeof...(Args) > 0) { + FormatArgs(format_buffer, args...); + format = format_buffer.c_str(); + } + + PythonObject py_return(PyRefType::Owned, + PyObject_CallMethod(implementor.get(), + method_name.data(), format, + args...)); + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + return error_with_message("Python method could not be called."); + } + + if (!py_return.IsAllocated()) + return error_with_message("Returned object is null."); + + return ExtractValueFromPythonObject(py_return, error); + } + + Status GetStatusFromMethod(llvm::StringRef method_name); + + template + void FormatArgs(std::string &fmt, T arg, Args... args) const { + FormatArgs(fmt, arg); + FormatArgs(fmt, args...); + } + + template void FormatArgs(std::string &fmt, T arg) const { + fmt += GetPythonValueFormatString(arg); + } + + void FormatArgs(std::string &fmt) const {} + + // The lifetime is managed by the ScriptInterpreter + ScriptInterpreterPythonImpl &m_interpreter; +}; +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp @@ -0,0 +1,38 @@ +//===-- ScriptedPythonInterface.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 "lldb/Host/Config.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" +#include "lldb/lldb-enumerations.h" + +#if LLDB_ENABLE_PYTHON + +// LLDB Python header must be included first +#include "lldb-python.h" + +#include "SWIGPythonBridge.h" +#include "ScriptInterpreterPythonImpl.h" +#include "ScriptedPythonInterface.h" + +using namespace lldb; +using namespace lldb_private; + +ScriptedPythonInterface::ScriptedPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : ScriptedInterface(), m_interpreter(interpreter) {} + +Status +ScriptedPythonInterface::GetStatusFromMethod(llvm::StringRef method_name) { + Status error; + Dispatch(method_name, error); + + return error; +} + +#endif diff --git a/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py b/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py --- a/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py +++ b/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py @@ -43,41 +43,35 @@ self.expect('script dir(ScriptedProcess)', substrs=["launch"]) - def test_launch_scripted_process_sbapi(self): + def test_scripted_process_and_scripted_thread(self): """Test that we can launch an lldb scripted process using the SBAPI, - check its process ID and read string from memory.""" + check its process ID, read string from memory, check scripted thread + id, name stop reason and register context. + """ self.build() target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) self.assertTrue(target, VALID_TARGET) - scripted_process_example_relpath = ['..','..','..','..','examples','python','scripted_process','my_scripted_process.py'] + scripted_process_example_relpath = 'dummy_scripted_process.py' os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1' self.runCmd("command script import " + os.path.join(self.getSourceDir(), - *scripted_process_example_relpath)) + scripted_process_example_relpath)) launch_info = lldb.SBLaunchInfo(None) launch_info.SetProcessPluginName("ScriptedProcess") - launch_info.SetScriptedProcessClassName("my_scripted_process.MyScriptedProcess") + launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess") error = lldb.SBError() process = target.Launch(launch_info, error) self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID) self.assertEqual(process.GetProcessID(), 42) - hello_world = "Hello, world!" - memory_read = process.ReadCStringFromMemory(0x50000000000, - len(hello_world) + 1, # NULL byte - error) - - self.assertTrue(error.Success(), "Failed to read memory from scripted process.") - self.assertEqual(hello_world, memory_read) - self.assertEqual(process.GetNumThreads(), 1) thread = process.GetSelectedThread() self.assertTrue(thread, "Invalid thread.") self.assertEqual(thread.GetThreadID(), 0x19) - self.assertEqual(thread.GetName(), "MyScriptedThread.thread-1") + self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1") self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal) self.assertGreater(thread.GetNumFrames(), 0) @@ -94,13 +88,21 @@ for idx, reg in enumerate(registers, start=1): self.assertEqual(idx, int(reg.value, 16)) - def test_launch_scripted_process_cli(self): + def test_launch_scripted_process_stack_frames(self): """Test that we can launch an lldb scripted process from the command line, check its process ID and read string from memory.""" self.build() target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) self.assertTrue(target, VALID_TARGET) + for module in target.modules: + if 'a.out' in module.GetFileSpec().GetFilename(): + main_module = module + + self.assertTrue(main_module, "Invalid main module.") + error = target.SetModuleLoadAddress(main_module, 0) + self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.") + scripted_process_example_relpath = ['..','..','..','..','examples','python','scripted_process','my_scripted_process.py'] self.runCmd("command script import " + os.path.join(self.getSourceDir(), *scripted_process_example_relpath)) @@ -108,12 +110,21 @@ process = target.GetProcess() self.assertTrue(process, PROCESS_IS_VALID) self.assertEqual(process.GetProcessID(), 42) + self.assertEqual(process.GetNumThreads(), 1) error = lldb.SBError() hello_world = "Hello, world!" memory_read = process.ReadCStringFromMemory(0x50000000000, len(hello_world) + 1, # NULL byte error) + thread = process.GetSelectedThread() + self.assertTrue(thread, "Invalid thread.") + self.assertEqual(thread.GetThreadID(), 0x19) + self.assertEqual(thread.GetName(), "MyScriptedThread.thread-1") - self.assertTrue(error.Success(), "Failed to read memory from scripted process.") - self.assertEqual(hello_world, memory_read) + self.assertEqual(thread.GetNumFrames(), 4) + frame = thread.GetSelectedFrame() + self.assertTrue(frame, "Invalid frame.") + self.assertEqual(frame.GetFunctionName(), "bar") + self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42) + self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42) diff --git a/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py b/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py @@ -0,0 +1,90 @@ +import os,struct, signal + +from typing import Any, Dict + +import lldb +from lldb.plugins.scripted_process import ScriptedProcess +from lldb.plugins.scripted_process import ScriptedThread + +class DummyScriptedProcess(ScriptedProcess): + def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData): + super().__init__(target, args) + + def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo: + return self.memory_regions[0] + + def get_thread_with_id(self, tid: int): + return {} + + def get_registers_for_thread(self, tid: int): + return {} + + def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData: + data = lldb.SBData().CreateDataFromCString( + self.target.GetByteOrder(), + self.target.GetCodeByteSize(), + "Hello, world!") + return data + + def get_loaded_images(self): + return self.loaded_images + + def get_process_id(self) -> int: + return 42 + + def should_stop(self) -> bool: + return True + + def is_alive(self) -> bool: + return True + + def get_scripted_thread_plugin(self): + return DummyScriptedThread.__module__ + "." + DummyScriptedThread.__name__ + + +class DummyScriptedThread(ScriptedThread): + def __init__(self, target): + super().__init__(target) + + def get_thread_id(self) -> int: + return 0x19 + + def get_name(self) -> str: + return DummyScriptedThread.__name__ + ".thread-1" + + def get_state(self) -> int: + return lldb.eStateStopped + + def get_stop_reason(self) -> Dict[str, Any]: + return { "type": lldb.eStopReasonSignal, "data": { + "signal": signal.SIGINT + } } + + def get_stackframes(self): + class ScriptedStackFrame: + def __init__(idx, cfa, pc, symbol_ctx): + self.idx = idx + self.cfa = cfa + self.pc = pc + self.symbol_ctx = symbol_ctx + + + symbol_ctx = lldb.SBSymbolContext() + frame_zero = ScriptedStackFrame(0, 0x42424242, 0x5000000, symbol_ctx) + self.frames.append(frame_zero) + + return self.frame_zero[0:0] + + def get_register_context(self) -> str: + return struct.pack( + '21Q', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) + + +def __lldb_init_module(debugger, dict): + if not 'SKIP_SCRIPTED_PROCESS_LAUNCH' in os.environ: + debugger.HandleCommand( + "process launch -C %s.%s" % (__name__, + DummyScriptedProcess.__name__)) + else: + print("Name of the class that will manage the scripted process: '%s.%s'" + % (__name__, DummyScriptedProcess.__name__)) \ No newline at end of file diff --git a/lldb/test/API/functionalities/scripted_process/main.c b/lldb/test/API/functionalities/scripted_process/main.c --- a/lldb/test/API/functionalities/scripted_process/main.c +++ b/lldb/test/API/functionalities/scripted_process/main.c @@ -1,5 +1,8 @@ -#include - -int main() { - return 0; // break here +int bar(int i) { + int j = i * i; + return j; // break here } + +int foo(int i) { return bar(i); } + +int main() { return foo(42); } diff --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp --- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -12,7 +12,7 @@ #include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h" #include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h" -#include "lldb/API/SBError.h" + #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h"