-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[lldb][API] Add Find(Ranges)InMemory() to Process SB API #96569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-lldb Author: Miro Bucko (mbucko) ChangesThis is a second attempt to land #95007 Test Plan: Reviewers: clayborg Tasks: lldb Patch is 29.31 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/96569.diff 11 Files Affected:
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/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..ceaf547ebddaf 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,11 @@ void PruneThreadPlans();
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.
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index c37c111c5a58e..efb3c8def2796 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().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 9b905663a2c32..6fac0df1d7a66 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 = 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];
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..9ab4619b1f8f4
--- /dev/null
+++ b/lldb/test/API/python_api/find_in_memory/TestFindInMemory.py
@@ -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)
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..31bc0e99f4914
--- /dev/null
+++ b/lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py
@@ -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 memor...
[truncated]
|
This is a second attempt to land llvm#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 is a second attempt to land llvm#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 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