[Lldb-commits] [lldb] 7066584 - [lldb/Plugin] Add artificial stackframe loading in ScriptedThread

Med Ismail Bennani via lldb-commits lldb-commits at lists.llvm.org
Wed Feb 16 11:45:12 PST 2022


Author: Med Ismail Bennani
Date: 2022-02-16T11:44:07-08:00
New Revision: 70665844915eeb66273a84f131ffc33a202539d5

URL: https://github.com/llvm/llvm-project/commit/70665844915eeb66273a84f131ffc33a202539d5
DIFF: https://github.com/llvm/llvm-project/commit/70665844915eeb66273a84f131ffc33a202539d5.diff

LOG: [lldb/Plugin] Add artificial stackframe loading in ScriptedThread

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.

rdar://88721095

Differential Revision: https://reviews.llvm.org/D119388

Signed-off-by: Med Ismail Bennani <medismail.bennani at gmail.com>

Added: 
    

Modified: 
    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

Removed: 
    


################################################################################
diff  --git a/lldb/examples/python/scripted_process/scripted_process.py b/lldb/examples/python/scripted_process/scripted_process.py
index 88df73147d5a6..2d3092d70e8e0 100644
--- a/lldb/examples/python/scripted_process/scripted_process.py
+++ b/lldb/examples/python/scripted_process/scripted_process.py
@@ -306,9 +306,9 @@ def __init__(idx, cfa, pc, symbol_ctx):
                 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
index c98995cad36fd..e05a398e3c0bc 100644
--- 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 @@ class StackFrameList {
 
 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
index f98c415c2bdb9..1abf0f1409c57 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -359,6 +359,7 @@ bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
 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.cpp b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
index 173f503f279d0..8174a8bde3315 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
@@ -147,6 +147,73 @@ ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {
   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);
+
+  size_t arr_size = arr_sp->GetSize();
+  if (arr_size > std::numeric_limits<uint32_t>::max())
+    return GetInterface()->ErrorWithMessage<bool>(
+        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<bool>(
+          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<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(), idx, idx, cfa, cfa_is_valid, pc,
+        StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc);
+
+    if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))
+      return GetInterface()->ErrorWithMessage<bool>(
+          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 @@ bool ScriptedThread::CalculateStopInfo() {
 
 void ScriptedThread::RefreshStateAfterStop() {
   GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
+  LoadArtificialStackFrames();
 }
 
 lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {

diff  --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.h b/lldb/source/Plugins/Process/scripted/ScriptedThread.h
index 8d8a7c2a3df90..959f498edf240 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedThread.h
+++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.h
@@ -42,6 +42,8 @@ class ScriptedThread : public lldb_private::Thread {
   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/ScriptInterpreter/Python/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
index 7c1f6405389e0..d5c527c61a5cb 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
@@ -34,6 +34,14 @@ ScriptedPythonInterface::GetStatusFromMethod(llvm::StringRef method_name) {
   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<

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
index da112eb72022b..f2ac30627a5b2 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
@@ -126,6 +126,11 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
   ScriptInterpreterPythonImpl &m_interpreter;
 };
 
+template <>
+StructuredData::ArraySP
+ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
+    python::PythonObject &p, Status &error);
+
 template <>
 StructuredData::DictionarySP
 ScriptedPythonInterface::ExtractValueFromPythonObject<

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp
index 8321d3e7ba522..3ff592fb83cd7 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp
@@ -112,7 +112,14 @@ StructuredData::DictionarySP ScriptedThreadPythonInterface::GetStopReason() {
 }
 
 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() {

diff  --git a/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py b/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
index d21326321ef0e..a622722cd92e1 100644
--- a/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
+++ b/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
@@ -133,3 +133,6 @@ def cleanup():
                 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
index 67850cf57a73d..a687870e1f89a 100644
--- 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 @@ def get_scripted_thread_plugin(self):
 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 @@ def get_stop_reason(self) -> Dict[str, Any]:
             "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 @@ def __lldb_init_module(debugger, dict):
                                      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
index b5e8ece8b10f7..62623d5679198 100644
--- 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 @@ def get_stop_reason(self) -> Dict[str, Any]:
             "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
index b0ea6f68e9c75..5ac4e8d68a9df 100644
--- 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 @@ def get_stop_reason(self) -> Dict[str, Any]:
 
         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


        


More information about the lldb-commits mailing list