Skip to content

Commit a66550e

Browse files
committed
[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 <[email protected]>
1 parent 3e4b7fd commit a66550e

23 files changed

+340
-48
lines changed

lldb/bindings/interface/SBMemoryRegionInfo.i

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ public:
2020

2121
SBMemoryRegionInfo (const lldb::SBMemoryRegionInfo &rhs);
2222

23+
SBMemoryRegionInfo::SBMemoryRegionInfo(const char *name, lldb::addr_t begin,
24+
lldb::addr_t end, uint32_t permissions, bool mapped, bool stack_memory);
25+
2326
~SBMemoryRegionInfo ();
2427

2528
void

lldb/bindings/interface/SBMemoryRegionInfoList.i

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ public:
2424
uint32_t
2525
GetSize () const;
2626

27+
bool
28+
GetMemoryRegionContainingAddress (lldb::addr_t addr, SBMemoryRegionInfo &region_info);
29+
2730
bool
2831
GetMemoryRegionAtIndex (uint32_t idx, SBMemoryRegionInfo &region_info);
2932

lldb/bindings/python/python-wrapper.swig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,22 @@ LLDBSWIGPython_CastPyObjectToSBValue
974974
return sb_ptr;
975975
}
976976

977+
SWIGEXPORT void*
978+
LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo
979+
(
980+
PyObject* data
981+
)
982+
{
983+
lldb::SBMemoryRegionInfo* sb_ptr = NULL;
984+
985+
int valid_cast = SWIG_ConvertPtr(data, (void**)&sb_ptr, SWIGTYPE_p_lldb__SBMemoryRegionInfo, 0);
986+
987+
if (valid_cast == -1)
988+
return NULL;
989+
990+
return sb_ptr;
991+
}
992+
977993
SWIGEXPORT bool
978994
LLDBSwigPythonCallCommand
979995
(
Binary file not shown.

lldb/examples/python/scripted_process/my_scripted_process.py

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,22 @@
77
from lldb.plugins.scripted_process import ScriptedThread
88

99
class MyScriptedProcess(ScriptedProcess):
10+
memory_regions = [
11+
lldb.SBMemoryRegionInfo("stack", 0x1040b2000, 0x1040b4000, 0b110, True,
12+
True)
13+
]
14+
15+
stack_memory_dump = os.path.join(os.path.dirname(os.path.abspath(__file__)),
16+
'main.stack-dump')
17+
1018
def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
1119
super().__init__(target, args)
1220

1321
def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
14-
return self.memory_regions[0]
22+
for region in self.memory_regions:
23+
if region.GetRegionBase() <= addr < region.GetRegionEnd():
24+
return region
25+
return None
1526

1627
def get_thread_with_id(self, tid: int):
1728
return {}
@@ -20,10 +31,25 @@ def get_registers_for_thread(self, tid: int):
2031
return {}
2132

2233
def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData:
23-
data = lldb.SBData().CreateDataFromCString(
34+
data = lldb.SBData()
35+
36+
with open(self.stack_memory_dump, 'rb') as f:
37+
stack_mem = f.read(-1)
38+
if not stack_mem:
39+
return data
40+
41+
mem_region = self.get_memory_region_containing_address(addr)
42+
43+
if not mem_region or addr + size > mem_region.GetRegionEnd():
44+
return data
45+
46+
offset = addr - mem_region.GetRegionBase()
47+
shrunk_stack_mem = stack_mem[offset:offset + size]
48+
49+
error = lldb.SBError()
50+
data.SetData(error, shrunk_stack_mem,
2451
self.target.GetByteOrder(),
25-
self.target.GetCodeByteSize(),
26-
"Hello, world!")
52+
self.target.GetAddressByteSize())
2753
return data
2854

2955
def get_loaded_images(self):
@@ -43,6 +69,30 @@ def get_scripted_thread_plugin(self):
4369

4470

4571
class MyScriptedThread(ScriptedThread):
72+
registers = {
73+
"rax":0x00000000000006e4,
74+
"rbx":0x00000001040b6060,
75+
"rcx":0x00000001040b2e00,
76+
"rdx":0x00000001040b2ba8,
77+
"rdi":0x000000000000002a,
78+
"rsi":0x00000001040b2b98,
79+
"rbp":0x00000001040b2a20,
80+
"rsp":0x00000001040b2a20,
81+
"r8":0x00000000003e131e,
82+
"r9":0xffffffff00000000,
83+
"r10":0x0000000000000000,
84+
"r11":0x0000000000000246,
85+
"r12":0x000000010007c3a0,
86+
"r13":0x00000001040b2b18,
87+
"r14":0x0000000100003f90,
88+
"r15":0x00000001040b2b88,
89+
"rip":0x0000000100003f61,
90+
"rflags":0x0000000000000206,
91+
"cs":0x000000000000002b,
92+
"fs":0x0000000000000000,
93+
"gs":0x0000000000000000,
94+
}
95+
4696
def __init__(self, target):
4797
super().__init__(target)
4898

@@ -73,8 +123,7 @@ def __init__(idx, cfa, pc, symbol_ctx):
73123
return self.frame_zero[0:0]
74124

75125
def get_register_context(self) -> str:
76-
return struct.pack(
77-
'21Q', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
126+
return struct.pack("{}Q".format(len(self.registers)), *self.registers.values())
78127

79128

80129
def __lldb_init_module(debugger, dict):

lldb/examples/python/scripted_process/scripted_process.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ class ScriptedProcess:
1616
THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE.
1717
"""
1818

19+
memory_regions = None
20+
stack_memory_dump = None
21+
loaded_images = None
22+
1923
@abstractmethod
2024
def __init__(self, target, args):
2125
""" Construct a scripted process.
@@ -91,7 +95,6 @@ def read_memory_at_address(addr, size):
9195
"""
9296
pass
9397

94-
@abstractmethod
9598
def get_loaded_images(self):
9699
""" Get the list of loaded images for the scripted process.
97100
@@ -110,7 +113,7 @@ def __init__(name, file_spec, uuid, load_address):
110113
an `lldb.SBFileSpec` and a load address.
111114
None if the list is empty.
112115
"""
113-
pass
116+
return self.loaded_images
114117

115118
def get_process_id(self):
116119
""" Get the scripted process identifier.

lldb/include/lldb/API/SBMemoryRegionInfo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ class LLDB_API SBMemoryRegionInfo {
2020

2121
SBMemoryRegionInfo(const lldb::SBMemoryRegionInfo &rhs);
2222

23+
SBMemoryRegionInfo(const char *name, lldb::addr_t begin, lldb::addr_t end,
24+
uint32_t permissions, bool mapped,
25+
bool stack_memory = false);
26+
2327
~SBMemoryRegionInfo();
2428

2529
const lldb::SBMemoryRegionInfo &
@@ -117,6 +121,8 @@ class LLDB_API SBMemoryRegionInfo {
117121
friend class SBProcess;
118122
friend class SBMemoryRegionInfoList;
119123

124+
friend class lldb_private::ScriptInterpreter;
125+
120126
lldb_private::MemoryRegionInfo &ref();
121127

122128
const lldb_private::MemoryRegionInfo &ref() const;

lldb/include/lldb/API/SBMemoryRegionInfoList.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ class LLDB_API SBMemoryRegionInfoList {
2727

2828
uint32_t GetSize() const;
2929

30+
bool GetMemoryRegionContainingAddress(lldb::addr_t addr,
31+
SBMemoryRegionInfo &region_info);
32+
3033
bool GetMemoryRegionAtIndex(uint32_t idx, SBMemoryRegionInfo &region_info);
3134

3235
void Append(lldb::SBMemoryRegionInfo &region);

lldb/include/lldb/Interpreter/ScriptInterpreter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "lldb/API/SBData.h"
1313
#include "lldb/API/SBError.h"
14+
#include "lldb/API/SBMemoryRegionInfo.h"
1415
#include "lldb/Breakpoint/BreakpointOptions.h"
1516
#include "lldb/Core/Communication.h"
1617
#include "lldb/Core/PluginInterface.h"
@@ -564,6 +565,9 @@ class ScriptInterpreter : public PluginInterface {
564565

565566
Status GetStatusFromSBError(const lldb::SBError &error) const;
566567

568+
llvm::Optional<MemoryRegionInfo> GetOpaqueTypeFromSBMemoryRegionInfo(
569+
const lldb::SBMemoryRegionInfo &mem_region) const;
570+
567571
protected:
568572
Debugger &m_debugger;
569573
lldb::ScriptLanguage m_script_lang;

lldb/include/lldb/Interpreter/ScriptedProcessInterface.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "lldb/Core/StructuredDataImpl.h"
1313
#include "lldb/Interpreter/ScriptInterpreter.h"
1414
#include "lldb/Interpreter/ScriptedInterface.h"
15+
#include "lldb/Target/MemoryRegionInfo.h"
1516

1617
#include "lldb/lldb-private.h"
1718

@@ -34,9 +35,10 @@ class ScriptedProcessInterface : virtual public ScriptedInterface {
3435

3536
virtual Status Stop() { return Status("ScriptedProcess did not stop"); }
3637

37-
virtual lldb::MemoryRegionInfoSP
38-
GetMemoryRegionContainingAddress(lldb::addr_t address) {
39-
return nullptr;
38+
virtual llvm::Optional<MemoryRegionInfo>
39+
GetMemoryRegionContainingAddress(lldb::addr_t address, Status &error) {
40+
error.SetErrorString("ScriptedProcess have no memory region.");
41+
return {};
4042
}
4143

4244
virtual StructuredData::DictionarySP GetThreadWithID(lldb::tid_t tid) {

lldb/source/API/SBMemoryRegionInfo.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ SBMemoryRegionInfo::SBMemoryRegionInfo() : m_opaque_up(new MemoryRegionInfo()) {
2222
LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBMemoryRegionInfo);
2323
}
2424

25+
SBMemoryRegionInfo::SBMemoryRegionInfo(const char *name, lldb::addr_t begin,
26+
lldb::addr_t end, uint32_t permissions,
27+
bool mapped, bool stack_memory)
28+
: SBMemoryRegionInfo() {
29+
LLDB_RECORD_CONSTRUCTOR(
30+
SBMemoryRegionInfo,
31+
(const char *, lldb::addr_t, lldb::addr_t, uint32_t, bool, bool), name,
32+
begin, end, permissions, mapped, stack_memory);
33+
m_opaque_up->SetName(name);
34+
m_opaque_up->GetRange().SetRangeBase(begin);
35+
m_opaque_up->GetRange().SetRangeEnd(end);
36+
m_opaque_up->SetLLDBPermissions(permissions);
37+
m_opaque_up->SetMapped(mapped ? MemoryRegionInfo::eYes
38+
: MemoryRegionInfo::eNo);
39+
m_opaque_up->SetIsStackMemory(stack_memory ? MemoryRegionInfo::eYes
40+
: MemoryRegionInfo::eNo);
41+
}
42+
2543
SBMemoryRegionInfo::SBMemoryRegionInfo(const MemoryRegionInfo *lldb_object_ptr)
2644
: m_opaque_up(new MemoryRegionInfo()) {
2745
if (lldb_object_ptr)
@@ -178,6 +196,9 @@ void RegisterMethods<SBMemoryRegionInfo>(Registry &R) {
178196
LLDB_REGISTER_CONSTRUCTOR(SBMemoryRegionInfo, ());
179197
LLDB_REGISTER_CONSTRUCTOR(SBMemoryRegionInfo,
180198
(const lldb::SBMemoryRegionInfo &));
199+
LLDB_REGISTER_CONSTRUCTOR(
200+
SBMemoryRegionInfo,
201+
(const char *, lldb::addr_t, lldb::addr_t, uint32_t, bool, bool));
181202
LLDB_REGISTER_METHOD(
182203
const lldb::SBMemoryRegionInfo &,
183204
SBMemoryRegionInfo, operator=,(const lldb::SBMemoryRegionInfo &));

lldb/source/API/SBMemoryRegionInfoList.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ class MemoryRegionInfoListImpl {
4848

4949
void Clear() { m_regions.clear(); }
5050

51+
bool GetMemoryRegionContainingAddress(lldb::addr_t addr,
52+
MemoryRegionInfo &region_info) {
53+
for (auto &region : m_regions) {
54+
if (region.GetRange().Contains(addr)) {
55+
region_info = region;
56+
return true;
57+
}
58+
}
59+
return false;
60+
}
61+
5162
bool GetMemoryRegionInfoAtIndex(size_t index,
5263
MemoryRegionInfo &region_info) {
5364
if (index >= GetSize())
@@ -103,6 +114,15 @@ uint32_t SBMemoryRegionInfoList::GetSize() const {
103114
return m_opaque_up->GetSize();
104115
}
105116

117+
bool SBMemoryRegionInfoList::GetMemoryRegionContainingAddress(
118+
lldb::addr_t addr, SBMemoryRegionInfo &region_info) {
119+
LLDB_RECORD_METHOD(
120+
bool, SBMemoryRegionInfoList, GetMemoryRegionContainingAddress,
121+
(lldb::addr_t, lldb::SBMemoryRegionInfo &), addr, region_info);
122+
123+
return m_opaque_up->GetMemoryRegionContainingAddress(addr, region_info.ref());
124+
}
125+
106126
bool SBMemoryRegionInfoList::GetMemoryRegionAtIndex(
107127
uint32_t idx, SBMemoryRegionInfo &region_info) {
108128
LLDB_RECORD_METHOD(bool, SBMemoryRegionInfoList, GetMemoryRegionAtIndex,
@@ -153,6 +173,9 @@ void RegisterMethods<SBMemoryRegionInfoList>(Registry &R) {
153173
SBMemoryRegionInfoList, operator=,(
154174
const lldb::SBMemoryRegionInfoList &));
155175
LLDB_REGISTER_METHOD_CONST(uint32_t, SBMemoryRegionInfoList, GetSize, ());
176+
LLDB_REGISTER_METHOD(bool, SBMemoryRegionInfoList,
177+
GetMemoryRegionContainingAddress,
178+
(lldb::addr_t, lldb::SBMemoryRegionInfo &));
156179
LLDB_REGISTER_METHOD(bool, SBMemoryRegionInfoList, GetMemoryRegionAtIndex,
157180
(uint32_t, lldb::SBMemoryRegionInfo &));
158181
LLDB_REGISTER_METHOD(void, SBMemoryRegionInfoList, Clear, ());

lldb/source/Interpreter/ScriptInterpreter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const {
8383
return Status();
8484
}
8585

86+
llvm::Optional<MemoryRegionInfo>
87+
ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
88+
const lldb::SBMemoryRegionInfo &mem_region) const {
89+
if (!mem_region.m_opaque_up)
90+
return llvm::None;
91+
return *mem_region.m_opaque_up.get();
92+
}
93+
8694
lldb::ScriptLanguage
8795
ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
8896
if (language.equals_insensitive(LanguageToString(eScriptLanguageNone)))

lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
241241
lldb::DataExtractorSP data_extractor_sp =
242242
GetInterface().ReadMemoryAtAddress(addr, size, error);
243243

244-
if (!data_extractor_sp || error.Fail())
244+
if (!data_extractor_sp || !data_extractor_sp->GetByteSize() || error.Fail())
245245
return 0;
246246

247247
offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData(
@@ -260,24 +260,34 @@ ArchSpec ScriptedProcess::GetArchitecture() {
260260

261261
Status ScriptedProcess::GetMemoryRegionInfo(lldb::addr_t load_addr,
262262
MemoryRegionInfo &region) {
263-
// TODO: Implement
264-
return Status();
263+
CheckInterpreterAndScriptObject();
264+
265+
Status error;
266+
if (auto region_or_err =
267+
GetInterface().GetMemoryRegionContainingAddress(load_addr, error))
268+
region = *region_or_err;
269+
270+
return error;
265271
}
266272

267273
Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos &region_list) {
268274
CheckInterpreterAndScriptObject();
269275

276+
Status error;
270277
lldb::addr_t address = 0;
271-
lldb::MemoryRegionInfoSP mem_region_sp = nullptr;
272278

273-
while ((mem_region_sp =
274-
GetInterface().GetMemoryRegionContainingAddress(address))) {
275-
auto range = mem_region_sp->GetRange();
279+
while (auto region_or_err =
280+
GetInterface().GetMemoryRegionContainingAddress(address, error)) {
281+
if (error.Fail())
282+
break;
283+
284+
MemoryRegionInfo &mem_region = *region_or_err;
285+
auto range = mem_region.GetRange();
276286
address += range.GetRangeBase() + range.GetByteSize();
277-
region_list.push_back(*mem_region_sp.get());
287+
region_list.push_back(mem_region);
278288
}
279289

280-
return {};
290+
return error;
281291
}
282292

283293
void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); }

lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ extern "C" void *LLDBSwigPythonCreateScriptedThread(
5353
extern "C" void *LLDBSWIGPython_CastPyObjectToSBData(void *data);
5454
extern "C" void *LLDBSWIGPython_CastPyObjectToSBError(void *data);
5555
extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data);
56+
extern "C" void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(void *data);
5657

5758
} // namespace lldb_private
5859

0 commit comments

Comments
 (0)