https://github.com/mbucko updated https://github.com/llvm/llvm-project/pull/95007
>From 71866d9a1f1b646021d56b576ddc74863ed3cb76 Mon Sep 17 00:00:00 2001 From: Miro Bucko <mbu...@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 | 117 ++++++++++ .../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 | 61 +++++ .../API/python_api/find_in_memory/main.cpp | 11 + 15 files changed, 599 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..f5895709226c6 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2007,6 +2007,123 @@ 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; + 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..9e617ebed0de4 --- /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, + 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, + 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, + 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, + 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..61e0227e2b766 --- /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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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..7717b3a2ac0d2 --- /dev/null +++ b/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py @@ -0,0 +1,61 @@ +import lldb + +SINGLE_INSTANCE_PATTERN = "there_is_only_one_of_me" +DOUBLE_INSTANCE_PATTERN = "there_is_exactly_two_of_me" + + +def GetStackRange(test_base): + frame = test_base.thread.GetSelectedFrame() + stack_string_ptr = frame.FindValue( + "stack_string_ptr", + lldb.eValueTypeVariableLocal, + ) + test_base.assertTrue(stack_string_ptr.IsValid()) + return GetRangeFromAddrValue(test_base, stack_string_ptr) + + +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(), + ) + + 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): + addr_ranges = lldb.SBAddressRangeList() + frame = test_base.thread.GetSelectedFrame() + + ex = frame.EvaluateExpression("heap_string1.data()") + addr_ranges.Append(GetRangeFromAddrValue(test_base, ex)) + + ex = frame.EvaluateExpression("heap_string2.data()") + 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..1d90f73a957a4 --- /dev/null +++ b/lldb/test/API/python_api/find_in_memory/main.cpp @@ -0,0 +1,11 @@ +#include <string> + +int main() { + const char *stack_string_ptr = "there_is_only_one_of_me"; + (void)stack_string_ptr; + const std::string heap_string1("there_is_exactly_two_of_me"); + const std::string heap_string2("there_is_exactly_two_of_me"); + heap_string1.data(); // force instantiation of string::data() + + return 0; // break here +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits