[Lldb-commits] [lldb] a758c9f - [lldb/Plugins] Add memory region support in ScriptedProcess

Med Ismail Bennani via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 8 05:55:05 PDT 2021


Author: Med Ismail Bennani
Date: 2021-10-08T14:54:07+02:00
New Revision: a758c9f7204c41d8791e76d24f9bc4791534f1b8

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

LOG: [lldb/Plugins] Add memory region support in ScriptedProcess

This patch adds support for memory regions in Scripted Processes.
This is necessary to read the stack memory region in order to
reconstruct each stackframe of the program.

In order to do so, this patch makes some changes to the SBAPI, namely:
- Add a new constructor for `SBMemoryRegionInfo` that takes arguments
  such as the memory region name, address range, permissions ...
  This is used when reading memory at some address to compute the offset
  in the binary blob provided by the user.
- Add a `GetMemoryRegionContainingAddress` method to `SBMemoryRegionInfoList`
  to simplify the access to a specific memory region.

With these changes, lldb is now able to unwind the stack and reconstruct
each frame. On top of that, reloading the target module at offset 0 allows
lldb to symbolicate the `ScriptedProcess` using debug info, similarly to an
ordinary Process.

To test this, I wrote a simple program with multiple function calls, ran it in
lldb, stopped at a leaf function and read the registers values and copied
the stack memory into a binary file. These are then used in the python script.

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

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

Added: 
    lldb/examples/python/scripted_process/main.stack-dump
    lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py

Modified: 
    lldb/bindings/interface/SBMemoryRegionInfo.i
    lldb/bindings/interface/SBMemoryRegionInfoList.i
    lldb/bindings/python/python-wrapper.swig
    lldb/examples/python/scripted_process/my_scripted_process.py
    lldb/examples/python/scripted_process/scripted_process.py
    lldb/include/lldb/API/SBMemoryRegionInfo.h
    lldb/include/lldb/API/SBMemoryRegionInfoList.h
    lldb/include/lldb/Interpreter/ScriptInterpreter.h
    lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
    lldb/source/API/SBMemoryRegionInfo.cpp
    lldb/source/API/SBMemoryRegionInfoList.cpp
    lldb/source/Interpreter/ScriptInterpreter.cpp
    lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
    lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
    lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
    lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
    lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
    lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
    lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
    lldb/test/API/functionalities/scripted_process/main.c
    lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/bindings/interface/SBMemoryRegionInfo.i b/lldb/bindings/interface/SBMemoryRegionInfo.i
index 3460dc0d06e22..0316c5a5be1d8 100644
--- a/lldb/bindings/interface/SBMemoryRegionInfo.i
+++ b/lldb/bindings/interface/SBMemoryRegionInfo.i
@@ -20,6 +20,9 @@ public:
 
     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
index c2e74f1cd0dcd..0097512775421 100644
--- a/lldb/bindings/interface/SBMemoryRegionInfoList.i
+++ b/lldb/bindings/interface/SBMemoryRegionInfoList.i
@@ -24,6 +24,9 @@ public:
     uint32_t
     GetSize () const;
 
+    bool
+    GetMemoryRegionContainingAddress (lldb::addr_t addr, SBMemoryRegionInfo &region_info);
+
     bool
     GetMemoryRegionAtIndex (uint32_t idx, SBMemoryRegionInfo &region_info);
 

diff  --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig
index feb4e54240bc1..5a950e259e993 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -974,6 +974,22 @@ LLDBSWIGPython_CastPyObjectToSBValue
     return sb_ptr;
 }
 
+SWIGEXPORT void*
+LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo
+(
+    PyObject* data
+)
+{
+    lldb::SBMemoryRegionInfo* sb_ptr = NULL;
+
+    int valid_cast = SWIG_ConvertPtr(data, (void**)&sb_ptr, SWIGTYPE_p_lldb__SBMemoryRegionInfo, 0);
+
+    if (valid_cast == -1)
+        return NULL;
+
+    return sb_ptr;
+}
+
 SWIGEXPORT bool
 LLDBSwigPythonCallCommand
 (

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 0000000000000..3df66384f4431
Binary files /dev/null and b/lldb/examples/python/scripted_process/main.stack-dump 
diff er

diff  --git a/lldb/examples/python/scripted_process/my_scripted_process.py b/lldb/examples/python/scripted_process/my_scripted_process.py
index 9257cd9c85126..224b772845a7f 100644
--- a/lldb/examples/python/scripted_process/my_scripted_process.py
+++ b/lldb/examples/python/scripted_process/my_scripted_process.py
@@ -7,11 +7,22 @@
 from lldb.plugins.scripted_process import ScriptedThread
 
 class MyScriptedProcess(ScriptedProcess):
+    memory_regions = [
+        lldb.SBMemoryRegionInfo("stack", 0x1040b2000, 0x1040b4000, 0b110, True,
+                                True)
+    ]
+
+    stack_memory_dump = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                                     'main.stack-dump')
+
     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]
+        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 @@ 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(
+        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 @@ def get_scripted_thread_plugin(self):
 
 
 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)
 
@@ -73,8 +123,7 @@ def __init__(idx, cfa, pc, symbol_ctx):
         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("{}Q".format(len(self.registers)), *self.registers.values())
 
 
 def __lldb_init_module(debugger, dict):

diff  --git a/lldb/examples/python/scripted_process/scripted_process.py b/lldb/examples/python/scripted_process/scripted_process.py
index d3474fbcf0a08..5869ca03e20bd 100644
--- a/lldb/examples/python/scripted_process/scripted_process.py
+++ b/lldb/examples/python/scripted_process/scripted_process.py
@@ -16,6 +16,10 @@ class ScriptedProcess:
                 THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE.
     """
 
+    memory_regions = None
+    stack_memory_dump = None
+    loaded_images = None
+
     @abstractmethod
     def __init__(self, target, args):
         """ Construct a scripted process.
@@ -91,7 +95,6 @@ def read_memory_at_address(addr, size):
         """
         pass
 
-    @abstractmethod
     def get_loaded_images(self):
         """ Get the list of loaded images for the scripted process.
 
@@ -110,7 +113,7 @@ def __init__(name, file_spec, uuid, load_address):
                 an `lldb.SBFileSpec` and a load address.
                 None if the list is empty.
         """
-        pass
+        return self.loaded_images
 
     def get_process_id(self):
         """ Get the scripted process identifier.

diff  --git a/lldb/include/lldb/API/SBMemoryRegionInfo.h b/lldb/include/lldb/API/SBMemoryRegionInfo.h
index 122226b9a0c5c..be55de4ead1fa 100644
--- a/lldb/include/lldb/API/SBMemoryRegionInfo.h
+++ b/lldb/include/lldb/API/SBMemoryRegionInfo.h
@@ -20,6 +20,10 @@ class LLDB_API SBMemoryRegionInfo {
 
   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 @@ class LLDB_API SBMemoryRegionInfo {
   friend class SBProcess;
   friend class SBMemoryRegionInfoList;
 
+  friend class lldb_private::ScriptInterpreter;
+
   lldb_private::MemoryRegionInfo &ref();
 
   const lldb_private::MemoryRegionInfo &ref() const;

diff  --git a/lldb/include/lldb/API/SBMemoryRegionInfoList.h b/lldb/include/lldb/API/SBMemoryRegionInfoList.h
index a7122ee9108a3..1d939dff55faa 100644
--- a/lldb/include/lldb/API/SBMemoryRegionInfoList.h
+++ b/lldb/include/lldb/API/SBMemoryRegionInfoList.h
@@ -27,6 +27,9 @@ class LLDB_API SBMemoryRegionInfoList {
 
   uint32_t GetSize() const;
 
+  bool GetMemoryRegionContainingAddress(lldb::addr_t addr,
+                                        SBMemoryRegionInfo &region_info);
+
   bool GetMemoryRegionAtIndex(uint32_t idx, SBMemoryRegionInfo &region_info);
 
   void Append(lldb::SBMemoryRegionInfo &region);

diff  --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 80a054b32ce65..56cfb5cb8dd54 100644
--- 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 @@ class ScriptInterpreter : public PluginInterface {
 
   Status GetStatusFromSBError(const lldb::SBError &error) const;
 
+  llvm::Optional<MemoryRegionInfo> GetOpaqueTypeFromSBMemoryRegionInfo(
+      const lldb::SBMemoryRegionInfo &mem_region) const;
+
 protected:
   Debugger &m_debugger;
   lldb::ScriptLanguage m_script_lang;

diff  --git a/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h b/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
index 31d6e1476a6ed..26fd956f96bbc 100644
--- a/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
+++ b/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
@@ -12,6 +12,7 @@
 #include "lldb/Core/StructuredDataImpl.h"
 #include "lldb/Interpreter/ScriptInterpreter.h"
 #include "lldb/Interpreter/ScriptedInterface.h"
+#include "lldb/Target/MemoryRegionInfo.h"
 
 #include "lldb/lldb-private.h"
 
@@ -34,9 +35,10 @@ class ScriptedProcessInterface : virtual public ScriptedInterface {
 
   virtual Status Stop() { return Status("ScriptedProcess did not stop"); }
 
-  virtual lldb::MemoryRegionInfoSP
-  GetMemoryRegionContainingAddress(lldb::addr_t address) {
-    return nullptr;
+  virtual llvm::Optional<MemoryRegionInfo>
+  GetMemoryRegionContainingAddress(lldb::addr_t address, Status &error) {
+    error.SetErrorString("ScriptedProcess have no memory region.");
+    return {};
   }
 
   virtual StructuredData::DictionarySP GetThreadWithID(lldb::tid_t tid) {

diff  --git a/lldb/source/API/SBMemoryRegionInfo.cpp b/lldb/source/API/SBMemoryRegionInfo.cpp
index c0f5456223da5..9cf7874b54a3b 100644
--- a/lldb/source/API/SBMemoryRegionInfo.cpp
+++ b/lldb/source/API/SBMemoryRegionInfo.cpp
@@ -22,6 +22,24 @@ SBMemoryRegionInfo::SBMemoryRegionInfo() : m_opaque_up(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_up->SetName(name);
+  m_opaque_up->GetRange().SetRangeBase(begin);
+  m_opaque_up->GetRange().SetRangeEnd(end);
+  m_opaque_up->SetLLDBPermissions(permissions);
+  m_opaque_up->SetMapped(mapped ? MemoryRegionInfo::eYes
+                                : MemoryRegionInfo::eNo);
+  m_opaque_up->SetIsStackMemory(stack_memory ? MemoryRegionInfo::eYes
+                                             : MemoryRegionInfo::eNo);
+}
+
 SBMemoryRegionInfo::SBMemoryRegionInfo(const MemoryRegionInfo *lldb_object_ptr)
     : m_opaque_up(new MemoryRegionInfo()) {
   if (lldb_object_ptr)
@@ -178,6 +196,9 @@ void RegisterMethods<SBMemoryRegionInfo>(Registry &R) {
   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
index 0f3f9c1b8177f..cd8fc00ffce06 100644
--- a/lldb/source/API/SBMemoryRegionInfoList.cpp
+++ b/lldb/source/API/SBMemoryRegionInfoList.cpp
@@ -48,6 +48,17 @@ class MemoryRegionInfoListImpl {
 
   void Clear() { m_regions.clear(); }
 
+  bool GetMemoryRegionContainingAddress(lldb::addr_t addr,
+                                        MemoryRegionInfo &region_info) {
+    for (auto &region : m_regions) {
+      if (region.GetRange().Contains(addr)) {
+        region_info = region;
+        return true;
+      }
+    }
+    return false;
+  }
+
   bool GetMemoryRegionInfoAtIndex(size_t index,
                                   MemoryRegionInfo &region_info) {
     if (index >= GetSize())
@@ -103,6 +114,15 @@ uint32_t SBMemoryRegionInfoList::GetSize() const {
   return m_opaque_up->GetSize();
 }
 
+bool SBMemoryRegionInfoList::GetMemoryRegionContainingAddress(
+    lldb::addr_t addr, SBMemoryRegionInfo &region_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 &region_info) {
   LLDB_RECORD_METHOD(bool, SBMemoryRegionInfoList, GetMemoryRegionAtIndex,
@@ -153,6 +173,9 @@ void RegisterMethods<SBMemoryRegionInfoList>(Registry &R) {
       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
index ac0a52d7d2d19..53e57ad59893d 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -83,6 +83,14 @@ ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const {
   return Status();
 }
 
+llvm::Optional<MemoryRegionInfo>
+ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
+    const lldb::SBMemoryRegionInfo &mem_region) const {
+  if (!mem_region.m_opaque_up)
+    return llvm::None;
+  return *mem_region.m_opaque_up.get();
+}
+
 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
index 4af107b00a968..551a0f752c9c3 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -239,7 +239,7 @@ size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
   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(
@@ -258,24 +258,34 @@ ArchSpec ScriptedProcess::GetArchitecture() {
 
 Status ScriptedProcess::GetMemoryRegionInfo(lldb::addr_t load_addr,
                                             MemoryRegionInfo &region) {
-  // TODO: Implement
-  return Status();
+  CheckInterpreterAndScriptObject();
+
+  Status error;
+  if (auto region_or_err =
+          GetInterface().GetMemoryRegionContainingAddress(load_addr, error))
+    region = *region_or_err;
+
+  return error;
 }
 
 Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos &region_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(); }

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index 8d6e7dc4ee789..81e25128b2c7d 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -53,6 +53,7 @@ extern "C" void *LLDBSwigPythonCreateScriptedThread(
 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/ScriptedProcessPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
index 32be169f0d1de..ffaee26147933 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
@@ -82,11 +82,18 @@ Status ScriptedProcessPythonInterface::Stop() {
   return GetStatusFromMethod("stop");
 }
 
-lldb::MemoryRegionInfoSP
+llvm::Optional<MemoryRegionInfo>
 ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress(
-    lldb::addr_t address) {
-  // TODO: Implement
-  return {};
+    lldb::addr_t address, Status &error) {
+  auto mem_region = Dispatch<llvm::Optional<MemoryRegionInfo>>(
+      "get_memory_region_containing_address", error, address);
+
+  if (error.Fail()) {
+    return ErrorWithMessage<MemoryRegionInfo>(__PRETTY_FUNCTION__,
+                                              error.AsCString(), error);
+  }
+
+  return mem_region;
 }
 
 StructuredData::DictionarySP

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
index eb3d2f3424436..421bdd59887ce 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
@@ -35,8 +35,9 @@ class ScriptedProcessPythonInterface : public ScriptedProcessInterface,
 
   Status Stop() override;
 
-  lldb::MemoryRegionInfoSP
-  GetMemoryRegionContainingAddress(lldb::addr_t address) override;
+  llvm::Optional<MemoryRegionInfo>
+  GetMemoryRegionContainingAddress(lldb::addr_t address,
+                                   Status &error) override;
 
   StructuredData::DictionarySP GetThreadWithID(lldb::tid_t tid) override;
 

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
index e8fb38e6492f1..07bf952bf840e 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
@@ -63,11 +63,30 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
       LLDBSWIGPython_CastPyObjectToSBData(p.get()));
 
   if (!sb_data) {
-    error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status.");
+    error.SetErrorString(
+        "Couldn't cast lldb::SBData to lldb::DataExtractorSP.");
     return nullptr;
   }
 
   return m_interpreter.GetDataExtractorFromSBData(*sb_data);
 }
 
+template <>
+llvm::Optional<MemoryRegionInfo>
+ScriptedPythonInterface::ExtractValueFromPythonObject<
+    llvm::Optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error) {
+
+  lldb::SBMemoryRegionInfo *sb_mem_reg_info =
+      reinterpret_cast<lldb::SBMemoryRegionInfo *>(
+          LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(p.get()));
+
+  if (!sb_mem_reg_info) {
+    error.SetErrorString(
+        "Couldn't cast lldb::SBMemoryRegionInfo to lldb::MemoryRegionInfoSP.");
+    return {};
+  }
+
+  return m_interpreter.GetOpaqueTypeFromSBMemoryRegionInfo(*sb_mem_reg_info);
+}
+
 #endif

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
index 9f76ed8fba687..9b81555dacb60 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
@@ -140,6 +140,11 @@ lldb::DataExtractorSP
 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
     python::PythonObject &p, Status &error);
 
+template <>
+llvm::Optional<MemoryRegionInfo>
+ScriptedPythonInterface::ExtractValueFromPythonObject<
+    llvm::Optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error);
+
 } // namespace lldb_private
 
 #endif // LLDB_ENABLE_PYTHON

diff  --git a/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py b/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
index 70ee1a4d6592b..b595d3dba32e5 100644
--- a/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
+++ b/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
@@ -43,41 +43,35 @@ def test_python_plugin_package(self):
         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 @@ def test_launch_scripted_process_sbapi(self):
         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 @@ def test_launch_scripted_process_cli(self):
         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
index 0000000000000..31a52f28c6c00
--- /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 None
+
+    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
index 3e82b70c8f4d3..67d3732441da2 100644
--- a/lldb/test/API/functionalities/scripted_process/main.c
+++ b/lldb/test/API/functionalities/scripted_process/main.c
@@ -1,5 +1,8 @@
-#include <stdlib.h>
-
-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
index e636b8cf597ee..ea6d6be7dbd5e 100644
--- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -166,6 +166,10 @@ extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data) {
   return nullptr;
 }
 
+extern "C" void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(void *data) {
+  return nullptr;
+}
+
 extern lldb::ValueObjectSP
 LLDBSWIGPython_GetValueObjectSPFromSBValue(void *data) {
   return nullptr;


        


More information about the lldb-commits mailing list