[Lldb-commits] [lldb] [lldb][API] Add Find(Ranges)InMemory() to Process SB API (PR #95007)
Miro Bucko via lldb-commits
lldb-commits at lists.llvm.org
Tue Jun 18 14:24:53 PDT 2024
https://github.com/mbucko updated https://github.com/llvm/llvm-project/pull/95007
>From b9b8d8d918076ba9133103cb9ce7328d5e872d32 Mon Sep 17 00:00:00 2001
From: Miro Bucko <mbucko at meta.com>
Date: Tue, 4 Jun 2024 12:01:48 -0700
Subject: [PATCH] [lldb][API] Add Find(Ranges)InMemory() to Process SB API
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
---
lldb/bindings/python/python-typemaps.swig | 3 +-
lldb/include/lldb/API/SBAddressRange.h | 2 +
lldb/include/lldb/API/SBAddressRangeList.h | 2 +
lldb/include/lldb/API/SBProcess.h | 10 +
lldb/include/lldb/Core/AddressRangeListImpl.h | 4 +
lldb/include/lldb/Target/Process.h | 13 ++
lldb/source/API/SBAddressRange.cpp | 4 +-
lldb/source/API/SBAddressRangeList.cpp | 4 +
lldb/source/API/SBProcess.cpp | 58 ++++-
lldb/source/Target/Process.cpp | 123 ++++++++++
.../API/python_api/find_in_memory/Makefile | 3 +
.../find_in_memory/TestFindInMemory.py | 104 +++++++++
.../find_in_memory/TestFindRangesInMemory.py | 210 ++++++++++++++++++
.../find_in_memory/address_ranges_helper.py | 64 ++++++
.../API/python_api/find_in_memory/main.cpp | 13 ++
15 files changed, 610 insertions(+), 7 deletions(-)
create mode 100644 lldb/test/API/python_api/find_in_memory/Makefile
create mode 100644 lldb/test/API/python_api/find_in_memory/TestFindInMemory.py
create mode 100644 lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py
create mode 100644 lldb/test/API/python_api/find_in_memory/address_ranges_helper.py
create mode 100644 lldb/test/API/python_api/find_in_memory/main.cpp
diff --git a/lldb/bindings/python/python-typemaps.swig b/lldb/bindings/python/python-typemaps.swig
index c39594c7df041..f8c33e15c03e6 100644
--- a/lldb/bindings/python/python-typemaps.swig
+++ b/lldb/bindings/python/python-typemaps.swig
@@ -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();
diff --git a/lldb/include/lldb/API/SBAddressRange.h b/lldb/include/lldb/API/SBAddressRange.h
index 152bd82426af1..ef8ce9ba9977d 100644
--- a/lldb/include/lldb/API/SBAddressRange.h
+++ b/lldb/include/lldb/API/SBAddressRange.h
@@ -58,6 +58,8 @@ class LLDB_API SBAddressRange {
friend class SBFunction;
friend class SBProcess;
+ lldb_private::AddressRange &ref() const;
+
AddressRangeUP m_opaque_up;
};
diff --git a/lldb/include/lldb/API/SBAddressRangeList.h b/lldb/include/lldb/API/SBAddressRangeList.h
index a123287ef1b4f..9e4d747685e63 100644
--- a/lldb/include/lldb/API/SBAddressRangeList.h
+++ b/lldb/include/lldb/API/SBAddressRangeList.h
@@ -46,6 +46,8 @@ class LLDB_API SBAddressRangeList {
friend class SBBlock;
friend class SBProcess;
+ lldb_private::AddressRanges &ref() const;
+
std::unique_ptr<lldb_private::AddressRangeListImpl> m_opaque_up;
};
diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h
index f1b5d1fb92ce2..a6ab7ae759918 100644
--- a/lldb/include/lldb/API/SBProcess.h
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -209,6 +209,16 @@ class LLDB_API SBProcess {
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);
diff --git a/lldb/include/lldb/Core/AddressRangeListImpl.h b/lldb/include/lldb/Core/AddressRangeListImpl.h
index 46ebfe73d4d92..6742e6ead87de 100644
--- a/lldb/include/lldb/Core/AddressRangeListImpl.h
+++ b/lldb/include/lldb/Core/AddressRangeListImpl.h
@@ -13,7 +13,9 @@
#include <cstddef>
namespace lldb {
+class SBAddressRangeList;
class SBBlock;
+class SBProcess;
}
namespace lldb_private {
@@ -39,7 +41,9 @@ class AddressRangeListImpl {
lldb_private::AddressRange GetAddressRangeAtIndex(size_t index);
private:
+ friend class lldb::SBAddressRangeList;
friend class lldb::SBBlock;
+ friend class lldb::SBProcess;
AddressRanges &ref();
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index eec337c15f7ed..a9840d889db89 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -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,10 @@ void PruneThreadPlans();
virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
Status &error) = 0;
+ 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.
diff --git a/lldb/source/API/SBAddressRange.cpp b/lldb/source/API/SBAddressRange.cpp
index 9b1affdade439..6301fbdaf45e6 100644
--- a/lldb/source/API/SBAddressRange.cpp
+++ b/lldb/source/API/SBAddressRange.cpp
@@ -64,7 +64,7 @@ bool SBAddressRange::operator!=(const SBAddressRange &rhs) {
void SBAddressRange::Clear() {
LLDB_INSTRUMENT_VA(this);
- m_opaque_up.reset();
+ m_opaque_up->Clear();
}
bool SBAddressRange::IsValid() const {
@@ -101,3 +101,5 @@ bool SBAddressRange::GetDescription(SBStream &description,
m_opaque_up->GetDescription(&stream, target.GetSP().get());
return true;
}
+
+lldb_private::AddressRange &SBAddressRange::ref() const { return *m_opaque_up; }
diff --git a/lldb/source/API/SBAddressRangeList.cpp b/lldb/source/API/SBAddressRangeList.cpp
index 20660b3ff2088..96ea018b0fba3 100644
--- a/lldb/source/API/SBAddressRangeList.cpp
+++ b/lldb/source/API/SBAddressRangeList.cpp
@@ -92,3 +92,7 @@ bool SBAddressRangeList::GetDescription(SBStream &description,
stream << "]";
return true;
}
+
+lldb_private::AddressRanges &SBAddressRangeList::ref() const {
+ return m_opaque_up->ref();
+}
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index c37c111c5a58e..44cc18c387a49 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -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(), 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);
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 1e321f8bde391..eec0e599eb1a6 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -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 = start_addr;
+ if (alignment > 1) {
+ // Align to an address alignment boundary
+ const uint64_t align_offset = start % alignment;
+ if (align_offset > 0)
+ start += alignment - align_offset;
+ }
+ 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;
+ 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.SetErrorStringWithFormat("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];
diff --git a/lldb/test/API/python_api/find_in_memory/Makefile b/lldb/test/API/python_api/find_in_memory/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/python_api/find_in_memory/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/python_api/find_in_memory/TestFindInMemory.py b/lldb/test/API/python_api/find_in_memory/TestFindInMemory.py
new file mode 100644
index 0000000000000..2a7869a733bb1
--- /dev/null
+++ b/lldb/test/API/python_api/find_in_memory/TestFindInMemory.py
@@ -0,0 +1,104 @@
+"""
+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_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)
diff --git a/lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py b/lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py
new file mode 100644
index 0000000000000..e6b4f65a11577
--- /dev/null
+++ b/lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py
@@ -0,0 +1,210 @@
+"""
+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_with_alignment_8(self):
+ """Make sure exactly one match exists in the heap memory and the right address ranges are provided with alignment 8"""
+ 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,
+ 8,
+ 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)
diff --git a/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py b/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py
new file mode 100644
index 0000000000000..ecb5f008c7592
--- /dev/null
+++ b/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py
@@ -0,0 +1,64 @@
+import lldb
+
+SINGLE_INSTANCE_PATTERN_STACK = "stack_there_is_only_one_of_me"
+DOUBLE_INSTANCE_PATTERN_HEAP = "heap_there_is_exactly_two_of_me"
+
+
+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
diff --git a/lldb/test/API/python_api/find_in_memory/main.cpp b/lldb/test/API/python_api/find_in_memory/main.cpp
new file mode 100644
index 0000000000000..c284af5c0c100
--- /dev/null
+++ b/lldb/test/API/python_api/find_in_memory/main.cpp
@@ -0,0 +1,13 @@
+#include <string>
+
+int main() {
+ const char *stack_pointer = "stack_there_is_only_one_of_me";
+ (void)stack_pointer;
+ 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();
+ (void)heap_pointer1;
+ (void)heap_pointer2; // break here
+ return 0;
+}
More information about the lldb-commits
mailing list