diff --git a/lldb/examples/python/scripted_process/scripted_process.py b/lldb/examples/python/scripted_process/scripted_process.py --- a/lldb/examples/python/scripted_process/scripted_process.py +++ b/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: diff --git a/lldb/include/lldb/Target/StackFrameList.h b/lldb/include/lldb/Target/StackFrameList.h --- a/lldb/include/lldb/Target/StackFrameList.h +++ b/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); 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 @@ -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) { diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.h b/lldb/source/Plugins/Process/scripted/ScriptedThread.h --- a/lldb/source/Plugins/Process/scripted/ScriptedThread.h +++ b/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; } diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp --- a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp +++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp @@ -147,6 +147,73 @@ return m_reg_context_sp; } +bool ScriptedThread::LoadArtificialStackFrames() { + StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames(); + + Status error; + if (!arr_sp) + return GetInterface()->ErrorWithMessage( + LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.", + error, LLDBLog::Thread); + + size_t arr_size = arr_sp->GetSize(); + if (arr_size > std::numeric_limits::max()) + return GetInterface()->ErrorWithMessage( + LLVM_PRETTY_FUNCTION, + llvm::Twine( + "StackFrame array size (" + llvm::Twine(arr_size) + + llvm::Twine( + ") is greater than maximum autorized for a StackFrameList.")) + .str(), + error, LLDBLog::Thread); + + StackFrameListSP frames = GetStackFrameList(); + + for (size_t idx = 0; idx < arr_size; idx++) { + + StructuredData::Dictionary *dict; + + if (!arr_sp->GetItemAtIndexAsDictionary(idx, dict) || !dict) + return GetInterface()->ErrorWithMessage( + LLVM_PRETTY_FUNCTION, + llvm::Twine( + "Couldn't get artificial stackframe dictionary at index (" + + llvm::Twine(idx) + llvm::Twine(") from stackframe array.")) + .str(), + error, LLDBLog::Thread); + + lldb::addr_t pc; + if (!dict->GetValueForKeyAsInteger("pc", pc)) + return ScriptedInterface::ErrorWithMessage( + 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( + this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc, + StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc); + + if (!frames->SetFrameAtIndex(static_cast(idx), synth_frame_sp)) + return GetInterface()->ErrorWithMessage( + LLVM_PRETTY_FUNCTION, + llvm::Twine("Couldn't add frame (" + llvm::Twine(idx) + + llvm::Twine(") to ScriptedThread StackFrameList.")) + .str(), + error, LLDBLog::Thread); + } + + return true; +} + bool ScriptedThread::CalculateStopInfo() { StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); @@ -216,6 +283,7 @@ void ScriptedThread::RefreshStateAfterStop() { GetRegisterContext()->InvalidateIfNeeded(/*force=*/false); + LoadArtificialStackFrames(); } lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h @@ -126,6 +126,11 @@ ScriptInterpreterPythonImpl &m_interpreter; }; +template <> +StructuredData::ArraySP +ScriptedPythonInterface::ExtractValueFromPythonObject( + python::PythonObject &p, Status &error); + template <> StructuredData::DictionarySP ScriptedPythonInterface::ExtractValueFromPythonObject< diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp @@ -34,6 +34,14 @@ return error; } +template <> +StructuredData::ArraySP +ScriptedPythonInterface::ExtractValueFromPythonObject( + python::PythonObject &p, Status &error) { + python::PythonList result_list(python::PyRefType::Borrowed, p.get()); + return result_list.CreateStructuredArray(); +} + template <> StructuredData::DictionarySP ScriptedPythonInterface::ExtractValueFromPythonObject< diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp @@ -112,7 +112,14 @@ } StructuredData::ArraySP ScriptedThreadPythonInterface::GetStackFrames() { - return nullptr; + Status error; + StructuredData::ArraySP arr = + Dispatch("get_stackframes", error); + + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr, error)) + return {}; + + return arr; } StructuredData::DictionarySP ScriptedThreadPythonInterface::GetRegisterInfo() { 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 @@ -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) diff --git a/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py b/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py --- a/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py +++ b/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({"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) @@ -88,4 +74,4 @@ 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 + % (__name__, DummyScriptedProcess.__name__)) diff --git a/lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py b/lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py --- a/lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py +++ b/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 diff --git a/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py b/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py --- a/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py +++ b/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