[lldb][API] Add Find(Ranges)InMemory() to Process SB API (#96569)
This is a second attempt to land #95007 Test Plan: llvm-lit llvm-project/lldb/test/API/python_api/find_in_memory/TestFindInMemory.py llvm-project/lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py Reviewers: clayborg Tasks: lldb
This commit is contained in:
3
lldb/test/API/python_api/find_in_memory/Makefile
Normal file
3
lldb/test/API/python_api/find_in_memory/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
||||
154
lldb/test/API/python_api/find_in_memory/TestFindInMemory.py
Normal file
154
lldb/test/API/python_api/find_in_memory/TestFindInMemory.py
Normal file
@@ -0,0 +1,154 @@
|
||||
"""
|
||||
Test Process::FindInMemory.
|
||||
"""
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
from address_ranges_helper import *
|
||||
|
||||
|
||||
class FindInMemoryTestCase(TestBase):
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
def setUp(self):
|
||||
TestBase.setUp(self)
|
||||
|
||||
self.build()
|
||||
(
|
||||
self.target,
|
||||
self.process,
|
||||
self.thread,
|
||||
self.bp,
|
||||
) = lldbutil.run_to_source_breakpoint(
|
||||
self,
|
||||
"break here",
|
||||
lldb.SBFileSpec("main.cpp"),
|
||||
)
|
||||
self.assertTrue(self.bp.IsValid())
|
||||
|
||||
def test_check_stack_pointer(self):
|
||||
"""Make sure the 'stack_pointer' variable lives on the stack"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
frame = self.thread.GetSelectedFrame()
|
||||
ex = frame.EvaluateExpression("&stack_pointer")
|
||||
variable_region = lldb.SBMemoryRegionInfo()
|
||||
self.assertTrue(
|
||||
self.process.GetMemoryRegionInfo(
|
||||
ex.GetValueAsUnsigned(), variable_region
|
||||
).Success(),
|
||||
)
|
||||
|
||||
stack_region = lldb.SBMemoryRegionInfo()
|
||||
self.assertTrue(
|
||||
self.process.GetMemoryRegionInfo(frame.GetSP(), stack_region).Success(),
|
||||
)
|
||||
|
||||
self.assertEqual(variable_region, stack_region)
|
||||
|
||||
def test_find_in_memory_ok(self):
|
||||
"""Make sure a match exists in the heap memory and the right address ranges are provided"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
error = lldb.SBError()
|
||||
addr = self.process.FindInMemory(
|
||||
SINGLE_INSTANCE_PATTERN_STACK,
|
||||
GetStackRange(self),
|
||||
1,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertSuccess(error)
|
||||
self.assertNotEqual(addr, lldb.LLDB_INVALID_ADDRESS)
|
||||
|
||||
def test_find_in_memory_double_instance_ok(self):
|
||||
"""Make sure a match exists in the heap memory and the right address ranges are provided"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
error = lldb.SBError()
|
||||
addr = self.process.FindInMemory(
|
||||
DOUBLE_INSTANCE_PATTERN_HEAP,
|
||||
GetHeapRanges(self)[0],
|
||||
1,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertSuccess(error)
|
||||
self.assertNotEqual(addr, lldb.LLDB_INVALID_ADDRESS)
|
||||
|
||||
def test_find_in_memory_invalid_alignment(self):
|
||||
"""Make sure the alignment 0 is failing"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
error = lldb.SBError()
|
||||
addr = self.process.FindInMemory(
|
||||
SINGLE_INSTANCE_PATTERN_STACK,
|
||||
GetStackRange(self),
|
||||
0,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertFailure(error)
|
||||
self.assertEqual(addr, lldb.LLDB_INVALID_ADDRESS)
|
||||
|
||||
def test_find_in_memory_invalid_address_range(self):
|
||||
"""Make sure invalid address range is failing"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
error = lldb.SBError()
|
||||
addr = self.process.FindInMemory(
|
||||
SINGLE_INSTANCE_PATTERN_STACK,
|
||||
lldb.SBAddressRange(),
|
||||
1,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertFailure(error)
|
||||
self.assertEqual(addr, lldb.LLDB_INVALID_ADDRESS)
|
||||
|
||||
def test_find_in_memory_invalid_buffer(self):
|
||||
"""Make sure the empty buffer is failing"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
error = lldb.SBError()
|
||||
addr = self.process.FindInMemory(
|
||||
"",
|
||||
GetStackRange(self),
|
||||
1,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertFailure(error)
|
||||
self.assertEqual(addr, lldb.LLDB_INVALID_ADDRESS)
|
||||
|
||||
def test_find_in_memory_unaligned(self):
|
||||
"""Make sure the unaligned match exists in the heap memory and is not found with alignment 8"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
error = lldb.SBError()
|
||||
range = GetAlignedRange(self)
|
||||
|
||||
# First we make sure the pattern is found with alignment 1
|
||||
addr = self.process.FindInMemory(
|
||||
UNALIGNED_INSTANCE_PATTERN_HEAP,
|
||||
range,
|
||||
1,
|
||||
error,
|
||||
)
|
||||
self.assertSuccess(error)
|
||||
self.assertNotEqual(addr, lldb.LLDB_INVALID_ADDRESS)
|
||||
|
||||
# With alignment 8 the pattern should not be found
|
||||
addr = self.process.FindInMemory(
|
||||
UNALIGNED_INSTANCE_PATTERN_HEAP,
|
||||
range,
|
||||
8,
|
||||
error,
|
||||
)
|
||||
self.assertSuccess(error)
|
||||
self.assertEqual(addr, lldb.LLDB_INVALID_ADDRESS)
|
||||
@@ -0,0 +1,221 @@
|
||||
"""
|
||||
Test Process::FindRangesInMemory.
|
||||
"""
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
from address_ranges_helper import *
|
||||
|
||||
|
||||
class FindRangesInMemoryTestCase(TestBase):
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
def setUp(self):
|
||||
TestBase.setUp(self)
|
||||
|
||||
self.build()
|
||||
(
|
||||
self.target,
|
||||
self.process,
|
||||
self.thread,
|
||||
self.bp,
|
||||
) = lldbutil.run_to_source_breakpoint(
|
||||
self, "break here", lldb.SBFileSpec("main.cpp")
|
||||
)
|
||||
self.assertTrue(self.bp.IsValid())
|
||||
|
||||
def test_find_ranges_in_memory_two_matches(self):
|
||||
"""Make sure two matches exist in the heap memory and the right address ranges are provided"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
addr_ranges = GetHeapRanges(self)
|
||||
error = lldb.SBError()
|
||||
matches = self.process.FindRangesInMemory(
|
||||
DOUBLE_INSTANCE_PATTERN_HEAP,
|
||||
addr_ranges,
|
||||
1,
|
||||
10,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertSuccess(error)
|
||||
self.assertEqual(matches.GetSize(), 2)
|
||||
|
||||
def test_find_ranges_in_memory_one_match(self):
|
||||
"""Make sure exactly one match exists in the heap memory and the right address ranges are provided"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
addr_ranges = GetStackRanges(self)
|
||||
error = lldb.SBError()
|
||||
matches = self.process.FindRangesInMemory(
|
||||
SINGLE_INSTANCE_PATTERN_STACK,
|
||||
addr_ranges,
|
||||
1,
|
||||
10,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertSuccess(error)
|
||||
self.assertEqual(matches.GetSize(), 1)
|
||||
|
||||
def test_find_ranges_in_memory_one_match_multiple_ranges(self):
|
||||
"""Make sure exactly one match exists in the heap memory and multiple address ranges are provided"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
addr_ranges = GetRanges(self)
|
||||
addr_ranges.Append(lldb.SBAddressRange())
|
||||
self.assertGreater(addr_ranges.GetSize(), 2)
|
||||
error = lldb.SBError()
|
||||
matches = self.process.FindRangesInMemory(
|
||||
SINGLE_INSTANCE_PATTERN_STACK,
|
||||
addr_ranges,
|
||||
1,
|
||||
10,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertSuccess(error)
|
||||
self.assertEqual(matches.GetSize(), 1)
|
||||
|
||||
def test_find_ranges_in_memory_one_match_max(self):
|
||||
"""Make sure at least one matche exists in the heap memory and the right address ranges are provided"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
addr_ranges = GetHeapRanges(self)
|
||||
error = lldb.SBError()
|
||||
matches = self.process.FindRangesInMemory(
|
||||
DOUBLE_INSTANCE_PATTERN_HEAP,
|
||||
addr_ranges,
|
||||
1,
|
||||
1,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertSuccess(error)
|
||||
self.assertEqual(matches.GetSize(), 1)
|
||||
|
||||
def test_find_ranges_in_memory_invalid_alignment(self):
|
||||
"""Make sure the alignment 0 is failing"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
addr_ranges = GetHeapRanges(self)
|
||||
error = lldb.SBError()
|
||||
matches = self.process.FindRangesInMemory(
|
||||
DOUBLE_INSTANCE_PATTERN_HEAP,
|
||||
addr_ranges,
|
||||
0,
|
||||
10,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertFailure(error)
|
||||
self.assertEqual(matches.GetSize(), 0)
|
||||
|
||||
def test_find_ranges_in_memory_invalid_range(self):
|
||||
"""Make sure the alignment 0 is failing"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
addr_ranges = lldb.SBAddressRangeList()
|
||||
addr_ranges.Append(lldb.SBAddressRange())
|
||||
error = lldb.SBError()
|
||||
matches = self.process.FindRangesInMemory(
|
||||
DOUBLE_INSTANCE_PATTERN_HEAP,
|
||||
addr_ranges,
|
||||
1,
|
||||
10,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertFailure(error)
|
||||
self.assertIn("unable to resolve any ranges", str(error))
|
||||
self.assertEqual(matches.GetSize(), 0)
|
||||
|
||||
def test_find_ranges_in_memory_empty_ranges(self):
|
||||
"""Make sure the empty ranges is failing"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
addr_ranges = lldb.SBAddressRangeList()
|
||||
error = lldb.SBError()
|
||||
matches = self.process.FindRangesInMemory(
|
||||
DOUBLE_INSTANCE_PATTERN_HEAP,
|
||||
addr_ranges,
|
||||
1,
|
||||
10,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertFailure(error)
|
||||
self.assertEqual(matches.GetSize(), 0)
|
||||
|
||||
def test_find_ranges_in_memory_invalid_buffer(self):
|
||||
"""Make sure the empty buffer is failing"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
addr_ranges = GetHeapRanges(self)
|
||||
error = lldb.SBError()
|
||||
matches = self.process.FindRangesInMemory(
|
||||
"",
|
||||
addr_ranges,
|
||||
1,
|
||||
10,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertFailure(error)
|
||||
self.assertEqual(matches.GetSize(), 0)
|
||||
|
||||
def test_find_ranges_in_memory_invalid_max_matches(self):
|
||||
"""Make sure the empty buffer is failing"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
addr_ranges = GetHeapRanges(self)
|
||||
error = lldb.SBError()
|
||||
matches = self.process.FindRangesInMemory(
|
||||
DOUBLE_INSTANCE_PATTERN_HEAP,
|
||||
addr_ranges,
|
||||
1,
|
||||
0,
|
||||
error,
|
||||
)
|
||||
|
||||
self.assertFailure(error)
|
||||
self.assertEqual(matches.GetSize(), 0)
|
||||
|
||||
def test_find_in_memory_unaligned(self):
|
||||
"""Make sure the unaligned match exists in the heap memory and is not found with alignment 8"""
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
||||
|
||||
addr_ranges = lldb.SBAddressRangeList()
|
||||
addr_ranges.Append(GetAlignedRange(self))
|
||||
error = lldb.SBError()
|
||||
|
||||
matches = self.process.FindRangesInMemory(
|
||||
UNALIGNED_INSTANCE_PATTERN_HEAP,
|
||||
addr_ranges,
|
||||
1,
|
||||
10,
|
||||
error,
|
||||
)
|
||||
self.assertSuccess(error)
|
||||
self.assertEqual(matches.GetSize(), 1)
|
||||
|
||||
matches = self.process.FindRangesInMemory(
|
||||
UNALIGNED_INSTANCE_PATTERN_HEAP,
|
||||
addr_ranges,
|
||||
8,
|
||||
10,
|
||||
error,
|
||||
)
|
||||
self.assertSuccess(error)
|
||||
self.assertEqual(matches.GetSize(), 0)
|
||||
@@ -0,0 +1,73 @@
|
||||
import lldb
|
||||
|
||||
SINGLE_INSTANCE_PATTERN_STACK = "stack_there_is_only_one_of_me"
|
||||
DOUBLE_INSTANCE_PATTERN_HEAP = "heap_there_is_exactly_two_of_me"
|
||||
ALIGNED_INSTANCE_PATTERN_HEAP = "i_am_unaligned_string_on_the_heap"
|
||||
UNALIGNED_INSTANCE_PATTERN_HEAP = ALIGNED_INSTANCE_PATTERN_HEAP[1:]
|
||||
|
||||
|
||||
def GetAlignedRange(test_base):
|
||||
frame = test_base.thread.GetSelectedFrame()
|
||||
ex = frame.EvaluateExpression("aligned_string_ptr")
|
||||
test_base.assertTrue(ex.IsValid())
|
||||
return GetRangeFromAddrValue(test_base, ex)
|
||||
|
||||
|
||||
def GetStackRange(test_base):
|
||||
frame = test_base.thread.GetSelectedFrame()
|
||||
ex = frame.EvaluateExpression("&stack_pointer")
|
||||
test_base.assertTrue(ex.IsValid())
|
||||
return GetRangeFromAddrValue(test_base, ex)
|
||||
|
||||
|
||||
def GetStackRanges(test_base):
|
||||
addr_ranges = lldb.SBAddressRangeList()
|
||||
addr_ranges.Append(GetStackRange(test_base))
|
||||
return addr_ranges
|
||||
|
||||
|
||||
def GetRangeFromAddrValue(test_base, addr):
|
||||
region = lldb.SBMemoryRegionInfo()
|
||||
test_base.assertTrue(
|
||||
test_base.process.GetMemoryRegionInfo(
|
||||
addr.GetValueAsUnsigned(), region
|
||||
).Success(),
|
||||
)
|
||||
|
||||
test_base.assertTrue(region.IsReadable())
|
||||
test_base.assertFalse(region.IsExecutable())
|
||||
|
||||
address_start = lldb.SBAddress(region.GetRegionBase(), test_base.target)
|
||||
stack_size = region.GetRegionEnd() - region.GetRegionBase()
|
||||
return lldb.SBAddressRange(address_start, stack_size)
|
||||
|
||||
|
||||
def IsWithinRange(addr, range, target):
|
||||
start_addr = range.GetBaseAddress().GetLoadAddress(target)
|
||||
end_addr = start_addr + range.GetByteSize()
|
||||
addr = addr.GetValueAsUnsigned()
|
||||
return addr >= start_addr and addr < end_addr
|
||||
|
||||
|
||||
def GetHeapRanges(test_base):
|
||||
frame = test_base.thread.GetSelectedFrame()
|
||||
|
||||
ex = frame.EvaluateExpression("heap_pointer1")
|
||||
test_base.assertTrue(ex.IsValid())
|
||||
range = GetRangeFromAddrValue(test_base, ex)
|
||||
addr_ranges = lldb.SBAddressRangeList()
|
||||
addr_ranges.Append(range)
|
||||
|
||||
ex = frame.EvaluateExpression("heap_pointer2")
|
||||
test_base.assertTrue(ex.IsValid())
|
||||
if not IsWithinRange(ex, addr_ranges[0], test_base.target):
|
||||
addr_ranges.Append(GetRangeFromAddrValue(test_base, ex))
|
||||
|
||||
return addr_ranges
|
||||
|
||||
|
||||
def GetRanges(test_base):
|
||||
ranges = GetHeapRanges(test_base)
|
||||
ranges.Append(GetStackRanges(test_base))
|
||||
|
||||
return ranges
|
||||
40
lldb/test/API/python_api/find_in_memory/main.cpp
Normal file
40
lldb/test/API/python_api/find_in_memory/main.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
int main() {
|
||||
// Stack
|
||||
const char stack_pointer[] = "stack_there_is_only_one_of_me";
|
||||
|
||||
// Heap
|
||||
// This test relies on std::string objects with size over 22 characters being
|
||||
// allocated on the heap.
|
||||
const std::string heap_string1("heap_there_is_exactly_two_of_me");
|
||||
const std::string heap_string2("heap_there_is_exactly_two_of_me");
|
||||
const char *heap_pointer1 = heap_string1.data();
|
||||
const char *heap_pointer2 = heap_string2.data();
|
||||
|
||||
// Aligned Heap
|
||||
constexpr char aligned_string[] = "i_am_unaligned_string_on_the_heap";
|
||||
constexpr size_t buffer_size = 100;
|
||||
constexpr size_t len = sizeof(aligned_string) + 1;
|
||||
// Allocate memory aligned to 8-byte boundary
|
||||
void *aligned_string_ptr = new size_t[buffer_size];
|
||||
if (aligned_string_ptr == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
// Zero out the memory
|
||||
memset(aligned_string_ptr, 0, buffer_size);
|
||||
|
||||
// Align the pointer to a multiple of 8 bytes
|
||||
size_t size = buffer_size;
|
||||
aligned_string_ptr = std::align(8, len, aligned_string_ptr, size);
|
||||
|
||||
// Copy the string to aligned memory
|
||||
memcpy(aligned_string_ptr, aligned_string, len);
|
||||
|
||||
(void)stack_pointer;
|
||||
(void)heap_pointer1;
|
||||
(void)heap_pointer2; // break here
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user