mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
[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:
@@ -257,7 +257,8 @@ AND call SWIG_fail at the same time, because it will result in a double free.
|
||||
}
|
||||
// For SBProcess::WriteMemory, SBTarget::GetInstructions and SBDebugger::DispatchInput.
|
||||
%typemap(in) (const void *buf, size_t size),
|
||||
(const void *data, size_t data_len) {
|
||||
(const void *data, size_t data_len),
|
||||
(const void *buf, uint64_t size) {
|
||||
if (PythonString::Check($input)) {
|
||||
PythonString str(PyRefType::Borrowed, $input);
|
||||
$1 = (void *)str.GetString().data();
|
||||
|
||||
@@ -209,6 +209,16 @@ public:
|
||||
|
||||
lldb::addr_t ReadPointerFromMemory(addr_t addr, lldb::SBError &error);
|
||||
|
||||
lldb::SBAddressRangeList FindRangesInMemory(const void *buf, uint64_t size,
|
||||
const SBAddressRangeList &ranges,
|
||||
uint32_t alignment,
|
||||
uint32_t max_matches,
|
||||
SBError &error);
|
||||
|
||||
lldb::addr_t FindInMemory(const void *buf, uint64_t size,
|
||||
const SBAddressRange &range, uint32_t alignment,
|
||||
SBError &error);
|
||||
|
||||
// Events
|
||||
static lldb::StateType GetStateFromEvent(const lldb::SBEvent &event);
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
#include <cstddef>
|
||||
|
||||
namespace lldb {
|
||||
class SBAddressRangeList;
|
||||
class SBBlock;
|
||||
class SBProcess;
|
||||
}
|
||||
|
||||
namespace lldb_private {
|
||||
@@ -39,7 +41,9 @@ public:
|
||||
lldb_private::AddressRange GetAddressRangeAtIndex(size_t index);
|
||||
|
||||
private:
|
||||
friend class lldb::SBAddressRangeList;
|
||||
friend class lldb::SBBlock;
|
||||
friend class lldb::SBProcess;
|
||||
|
||||
AddressRanges &ref();
|
||||
|
||||
|
||||
@@ -2685,6 +2685,15 @@ void PruneThreadPlans();
|
||||
lldb::addr_t FindInMemory(lldb::addr_t low, lldb::addr_t high,
|
||||
const uint8_t *buf, size_t size);
|
||||
|
||||
AddressRanges FindRangesInMemory(const uint8_t *buf, uint64_t size,
|
||||
const AddressRanges &ranges,
|
||||
size_t alignment, size_t max_matches,
|
||||
Status &error);
|
||||
|
||||
lldb::addr_t FindInMemory(const uint8_t *buf, uint64_t size,
|
||||
const AddressRange &range, size_t alignment,
|
||||
Status &error);
|
||||
|
||||
protected:
|
||||
friend class Trace;
|
||||
|
||||
@@ -2800,6 +2809,11 @@ protected:
|
||||
virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
|
||||
Status &error) = 0;
|
||||
|
||||
virtual void DoFindInMemory(lldb::addr_t start_addr, lldb::addr_t end_addr,
|
||||
const uint8_t *buf, size_t size,
|
||||
AddressRanges &matches, size_t alignment,
|
||||
size_t max_matches);
|
||||
|
||||
/// DoGetMemoryRegionInfo is called by GetMemoryRegionInfo after it has
|
||||
/// removed non address bits from load_addr. Override this method in
|
||||
/// subclasses of Process.
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "lldb/lldb-defines.h"
|
||||
#include "lldb/lldb-types.h"
|
||||
|
||||
#include "lldb/Core/AddressRangeListImpl.h"
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
@@ -26,6 +27,7 @@
|
||||
#include "lldb/Target/Target.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
#include "lldb/Utility/Args.h"
|
||||
#include "lldb/Utility/LLDBLog.h"
|
||||
#include "lldb/Utility/ProcessInfo.h"
|
||||
#include "lldb/Utility/State.h"
|
||||
#include "lldb/Utility/Stream.h"
|
||||
@@ -320,8 +322,8 @@ void SBProcess::ReportEventState(const SBEvent &event, FileSP out) const {
|
||||
if (process_sp) {
|
||||
StreamFile stream(out);
|
||||
const StateType event_state = SBProcess::GetStateFromEvent(event);
|
||||
stream.Printf("Process %" PRIu64 " %s\n",
|
||||
process_sp->GetID(), SBDebugger::StateAsCString(event_state));
|
||||
stream.Printf("Process %" PRIu64 " %s\n", process_sp->GetID(),
|
||||
SBDebugger::StateAsCString(event_state));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,7 +380,6 @@ bool SBProcess::SetSelectedThreadByIndexID(uint32_t index_id) {
|
||||
ret_val = process_sp->GetThreadList().SetSelectedThreadByIndexID(index_id);
|
||||
}
|
||||
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
@@ -546,7 +547,6 @@ ByteOrder SBProcess::GetByteOrder() const {
|
||||
if (process_sp)
|
||||
byteOrder = process_sp->GetTarget().GetArchitecture().GetByteOrder();
|
||||
|
||||
|
||||
return byteOrder;
|
||||
}
|
||||
|
||||
@@ -558,7 +558,6 @@ uint32_t SBProcess::GetAddressByteSize() const {
|
||||
if (process_sp)
|
||||
size = process_sp->GetTarget().GetArchitecture().GetAddressByteSize();
|
||||
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -810,6 +809,55 @@ const char *SBProcess::GetBroadcasterClass() {
|
||||
return ConstString(Process::GetStaticBroadcasterClass()).AsCString();
|
||||
}
|
||||
|
||||
lldb::SBAddressRangeList SBProcess::FindRangesInMemory(
|
||||
const void *buf, uint64_t size, const SBAddressRangeList &ranges,
|
||||
uint32_t alignment, uint32_t max_matches, SBError &error) {
|
||||
LLDB_INSTRUMENT_VA(this, buf, size, ranges, alignment, max_matches, error);
|
||||
|
||||
lldb::SBAddressRangeList matches;
|
||||
|
||||
ProcessSP process_sp(GetSP());
|
||||
if (!process_sp) {
|
||||
error.SetErrorString("SBProcess is invalid");
|
||||
return matches;
|
||||
}
|
||||
Process::StopLocker stop_locker;
|
||||
if (!stop_locker.TryLock(&process_sp->GetRunLock())) {
|
||||
error.SetErrorString("process is running");
|
||||
return matches;
|
||||
}
|
||||
std::lock_guard<std::recursive_mutex> guard(
|
||||
process_sp->GetTarget().GetAPIMutex());
|
||||
matches.m_opaque_up->ref() = process_sp->FindRangesInMemory(
|
||||
reinterpret_cast<const uint8_t *>(buf), size, ranges.ref().ref(),
|
||||
alignment, max_matches, error.ref());
|
||||
return matches;
|
||||
}
|
||||
|
||||
lldb::addr_t SBProcess::FindInMemory(const void *buf, uint64_t size,
|
||||
const SBAddressRange &range,
|
||||
uint32_t alignment, SBError &error) {
|
||||
LLDB_INSTRUMENT_VA(this, buf, size, range, alignment, error);
|
||||
|
||||
ProcessSP process_sp(GetSP());
|
||||
|
||||
if (!process_sp) {
|
||||
error.SetErrorString("SBProcess is invalid");
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
Process::StopLocker stop_locker;
|
||||
if (!stop_locker.TryLock(&process_sp->GetRunLock())) {
|
||||
error.SetErrorString("process is running");
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
std::lock_guard<std::recursive_mutex> guard(
|
||||
process_sp->GetTarget().GetAPIMutex());
|
||||
return process_sp->FindInMemory(reinterpret_cast<const uint8_t *>(buf), size,
|
||||
range.ref(), alignment, error.ref());
|
||||
}
|
||||
|
||||
size_t SBProcess::ReadMemory(addr_t addr, void *dst, size_t dst_len,
|
||||
SBError &sb_error) {
|
||||
LLDB_INSTRUMENT_VA(this, addr, dst, dst_len, sb_error);
|
||||
|
||||
@@ -2007,6 +2007,129 @@ size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Status &error) {
|
||||
}
|
||||
}
|
||||
|
||||
void Process::DoFindInMemory(lldb::addr_t start_addr, lldb::addr_t end_addr,
|
||||
const uint8_t *buf, size_t size,
|
||||
AddressRanges &matches, size_t alignment,
|
||||
size_t max_matches) {
|
||||
// Inputs are already validated in FindInMemory() functions.
|
||||
assert(buf != nullptr);
|
||||
assert(size > 0);
|
||||
assert(alignment > 0);
|
||||
assert(max_matches > 0);
|
||||
assert(start_addr != LLDB_INVALID_ADDRESS);
|
||||
assert(end_addr != LLDB_INVALID_ADDRESS);
|
||||
assert(start_addr < end_addr);
|
||||
|
||||
lldb::addr_t start = llvm::alignTo(start_addr, alignment);
|
||||
while (matches.size() < max_matches && (start + size) < end_addr) {
|
||||
const lldb::addr_t found_addr = FindInMemory(start, end_addr, buf, size);
|
||||
if (found_addr == LLDB_INVALID_ADDRESS)
|
||||
break;
|
||||
|
||||
if (found_addr % alignment) {
|
||||
// We need to check the alignment because the FindInMemory uses a special
|
||||
// algorithm to efficiently search mememory but doesn't support alignment.
|
||||
start = llvm::alignTo(start + 1, alignment);
|
||||
continue;
|
||||
}
|
||||
|
||||
matches.emplace_back(found_addr, size);
|
||||
start = found_addr + alignment;
|
||||
}
|
||||
}
|
||||
|
||||
AddressRanges Process::FindRangesInMemory(const uint8_t *buf, uint64_t size,
|
||||
const AddressRanges &ranges,
|
||||
size_t alignment, size_t max_matches,
|
||||
Status &error) {
|
||||
AddressRanges matches;
|
||||
if (buf == nullptr) {
|
||||
error.SetErrorString("buffer is null");
|
||||
return matches;
|
||||
}
|
||||
if (size == 0) {
|
||||
error.SetErrorString("buffer size is zero");
|
||||
return matches;
|
||||
}
|
||||
if (ranges.empty()) {
|
||||
error.SetErrorString("empty ranges");
|
||||
return matches;
|
||||
}
|
||||
if (alignment == 0) {
|
||||
error.SetErrorString("alignment must be greater than zero");
|
||||
return matches;
|
||||
}
|
||||
if (max_matches == 0) {
|
||||
error.SetErrorString("max_matches must be greater than zero");
|
||||
return matches;
|
||||
}
|
||||
|
||||
int resolved_ranges = 0;
|
||||
Target &target = GetTarget();
|
||||
for (size_t i = 0; i < ranges.size(); ++i) {
|
||||
if (matches.size() >= max_matches)
|
||||
break;
|
||||
const AddressRange &range = ranges[i];
|
||||
if (range.IsValid() == false)
|
||||
continue;
|
||||
|
||||
const lldb::addr_t start_addr =
|
||||
range.GetBaseAddress().GetLoadAddress(&target);
|
||||
if (start_addr == LLDB_INVALID_ADDRESS)
|
||||
continue;
|
||||
|
||||
++resolved_ranges;
|
||||
const lldb::addr_t end_addr = start_addr + range.GetByteSize();
|
||||
DoFindInMemory(start_addr, end_addr, buf, size, matches, alignment,
|
||||
max_matches);
|
||||
}
|
||||
|
||||
if (resolved_ranges > 0)
|
||||
error.Clear();
|
||||
else
|
||||
error.SetErrorString("unable to resolve any ranges");
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
lldb::addr_t Process::FindInMemory(const uint8_t *buf, uint64_t size,
|
||||
const AddressRange &range, size_t alignment,
|
||||
Status &error) {
|
||||
if (buf == nullptr) {
|
||||
error.SetErrorString("buffer is null");
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
if (size == 0) {
|
||||
error.SetErrorString("buffer size is zero");
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
if (!range.IsValid()) {
|
||||
error.SetErrorString("range is invalid");
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
if (alignment == 0) {
|
||||
error.SetErrorString("alignment must be greater than zero");
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
Target &target = GetTarget();
|
||||
const lldb::addr_t start_addr =
|
||||
range.GetBaseAddress().GetLoadAddress(&target);
|
||||
if (start_addr == LLDB_INVALID_ADDRESS) {
|
||||
error.SetErrorString("range load address is invalid");
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
const lldb::addr_t end_addr = start_addr + range.GetByteSize();
|
||||
|
||||
AddressRanges matches;
|
||||
DoFindInMemory(start_addr, end_addr, buf, size, matches, alignment, 1);
|
||||
if (matches.empty())
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
error.Clear();
|
||||
return matches[0].GetBaseAddress().GetLoadAddress(&target);
|
||||
}
|
||||
|
||||
size_t Process::ReadCStringFromMemory(addr_t addr, std::string &out_str,
|
||||
Status &error) {
|
||||
char buf[256];
|
||||
|
||||
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