mib created this revision. mib added reviewers: JDevlieghere, jingham. mib added a project: LLDB. mib requested review of this revision. Herald added a subscriber: lldb-commits.
This patch adds the ability for ScriptedThread to load artificial stack frames. To do so, the interpreter instance can create a list that will contain the frame index and its pc address. Then, when the Scripted Process plugin stops, it will refresh its Scripted Threads state by invalidating their register context and load to list from the interpreter object and reconstruct each frame. This patch also removes all of the default implementation for `get_stackframes` from the derived ScriptedThread classes, and add the interface code for the Scripted Thread Interface. Signed-off-by: Med Ismail Bennani <medismail.benn...@gmail.com> Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D119388 Files: lldb/examples/python/scripted_process/scripted_process.py lldb/include/lldb/Target/StackFrameList.h lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp lldb/source/Plugins/Process/scripted/ScriptedThread.cpp lldb/source/Plugins/Process/scripted/ScriptedThread.h lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
Index: lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py =================================================================== --- lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py +++ lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py @@ -139,21 +139,6 @@ return stop_reason - 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: if not self.corefile_thread or self.corefile_thread.GetNumFrames() == 0: return None Index: lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py =================================================================== --- lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py +++ lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py @@ -57,21 +57,6 @@ "signal": signal.SIGTRAP } } - 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 None Index: lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py =================================================================== --- lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py +++ lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py @@ -46,6 +46,7 @@ class DummyScriptedThread(ScriptedThread): def __init__(self, process, args): super().__init__(process, args) + self.frames.append({"idx": 0, "pc": 0x0100001b00 }) def get_thread_id(self) -> int: return 0x19 @@ -61,21 +62,6 @@ "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) Index: lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py =================================================================== --- lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py +++ lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py @@ -133,3 +133,6 @@ break self.assertEqual(idx, int(reg.value, 16)) + self.assertTrue(frame.IsArtificial(), "Frame is not artificial") + pc = frame.GetPCAddress().GetLoadAddress(target) + self.assertEqual(pc, 0x0100001b00) Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp @@ -112,7 +112,14 @@ } StructuredData::ArraySP ScriptedThreadPythonInterface::GetStackFrames() { - return nullptr; + Status error; + StructuredData::ArraySP arr = + Dispatch<StructuredData::ArraySP>("get_stackframes", error); + + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr, error)) + return {}; + + return arr; } StructuredData::DictionarySP ScriptedThreadPythonInterface::GetRegisterInfo() { Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h @@ -126,6 +126,11 @@ ScriptInterpreterPythonImpl &m_interpreter; }; +template <> +StructuredData::ArraySP +ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( + python::PythonObject &p, Status &error); + template <> StructuredData::DictionarySP ScriptedPythonInterface::ExtractValueFromPythonObject< Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp @@ -34,6 +34,14 @@ return error; } +template <> +StructuredData::ArraySP +ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( + python::PythonObject &p, Status &error) { + python::PythonList result_list(python::PyRefType::Borrowed, p.get()); + return result_list.CreateStructuredArray(); +} + template <> StructuredData::DictionarySP ScriptedPythonInterface::ExtractValueFromPythonObject< Index: lldb/source/Plugins/Process/scripted/ScriptedThread.h =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedThread.h +++ lldb/source/Plugins/Process/scripted/ScriptedThread.h @@ -42,6 +42,8 @@ lldb::RegisterContextSP CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; + bool LoadArtificialStackFrames(); + bool CalculateStopInfo() override; const char *GetInfo() override { return nullptr; } Index: lldb/source/Plugins/Process/scripted/ScriptedThread.cpp =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedThread.cpp +++ lldb/source/Plugins/Process/scripted/ScriptedThread.cpp @@ -147,6 +147,60 @@ return m_reg_context_sp; } +bool ScriptedThread::LoadArtificialStackFrames() { + StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames(); + + Status error; + if (!arr_sp) + return GetInterface()->ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.", + error, LLDBLog::Thread); + + StackFrameListSP frames = GetStackFrameList(); + + auto create_artificial_stackframe = + [this, &frames, &error](StructuredData::Object *obj) -> bool { + StructuredData::Dictionary *dict = obj->GetAsDictionary(); + + if (!dict) + return ScriptedInterface::ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, + "Couldn't find value for key 'type' in stop reason dictionary.", + error, LLDBLog::Thread); + + uint32_t frame_idx = GetStackFrameCount(); + if (!dict->GetValueForKeyAsInteger("idx", frame_idx)) + return ScriptedInterface::ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, + "Couldn't find value for key 'idx' in stackframe dictionary.", error, + LLDBLog::Thread); + + lldb::addr_t pc; + if (!dict->GetValueForKeyAsInteger("pc", pc)) + return ScriptedInterface::ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, + "Couldn't find value for key 'pc' in stackframe dictionary.", error, + LLDBLog::Thread); + + Address symbol_addr; + symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget()); + + lldb::addr_t cfa = LLDB_INVALID_ADDRESS; + bool cfa_is_valid = false; + const bool behaves_like_zeroth_frame = false; + SymbolContext sc; + symbol_addr.CalculateSymbolContext(&sc); + + StackFrameSP synth_frame_sp = std::make_shared<StackFrame>( + this->shared_from_this(), frame_idx, frame_idx, cfa, cfa_is_valid, pc, + StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc); + + return frames->SetFrameAtIndex(frame_idx, synth_frame_sp); + }; + + return arr_sp->ForEach(create_artificial_stackframe); +} + bool ScriptedThread::CalculateStopInfo() { StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); @@ -216,6 +270,7 @@ void ScriptedThread::RefreshStateAfterStop() { GetRegisterContext()->InvalidateIfNeeded(/*force=*/false); + LoadArtificialStackFrames(); } lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp +++ lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp @@ -359,6 +359,7 @@ 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) { Index: lldb/include/lldb/Target/StackFrameList.h =================================================================== --- lldb/include/lldb/Target/StackFrameList.h +++ lldb/include/lldb/Target/StackFrameList.h @@ -17,6 +17,8 @@ namespace lldb_private { +class ScriptedThread; + class StackFrameList { public: // Constructors and Destructors @@ -86,6 +88,7 @@ protected: friend class Thread; + friend class ScriptedThread; bool SetFrameAtIndex(uint32_t idx, lldb::StackFrameSP &frame_sp); Index: lldb/examples/python/scripted_process/scripted_process.py =================================================================== --- lldb/examples/python/scripted_process/scripted_process.py +++ lldb/examples/python/scripted_process/scripted_process.py @@ -306,9 +306,9 @@ containing for each entry, the frame index, the canonical frame address, the program counter value for that frame and a symbol context. - None if the list is empty. + The list can be empty. """ - return 0 + return self.frames def get_register_info(self): if self.register_info is None:
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits