llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Miro Bucko (mbucko) <details> <summary>Changes</summary> 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 --- Patch is 22.90 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/95007.diff 11 Files Affected: - (modified) lldb/bindings/python/python-typemaps.swig (+2-1) - (modified) lldb/include/lldb/API/SBProcess.h (+8) - (modified) lldb/include/lldb/Core/AddressRangeListImpl.h (+2) - (modified) lldb/include/lldb/Target/Process.h (+11) - (modified) lldb/source/API/SBProcess.cpp (+110-5) - (modified) lldb/source/Target/Process.cpp (+117) - (added) lldb/test/API/python_api/find_in_memory/Makefile (+3) - (added) lldb/test/API/python_api/find_in_memory/TestFindInMemory.py (+85) - (added) lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py (+120) - (added) lldb/test/API/python_api/find_in_memory/address_ranges_helper.py (+30) - (added) lldb/test/API/python_api/find_in_memory/main.cpp (+21) ``````````diff diff --git a/lldb/bindings/python/python-typemaps.swig b/lldb/bindings/python/python-typemaps.swig index 8d4b740e5f35c..923a787e77c88 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..eb7441629108c 100644 --- a/lldb/include/lldb/API/SBProcess.h +++ b/lldb/include/lldb/API/SBProcess.h @@ -209,6 +209,14 @@ class LLDB_API SBProcess { lldb::addr_t ReadPointerFromMemory(addr_t addr, lldb::SBError &error); + lldb::SBAddressRangeList FindRangesInMemory(const void *buf, uint64_t size, + SBAddressRangeList &ranges, + uint32_t alignment, + uint32_t max_matches); + + lldb::addr_t FindInMemory(const void *buf, uint64_t size, + SBAddressRange &range, uint32_t alignment); + // 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..777cf81e2b1c3 100644 --- a/lldb/include/lldb/Core/AddressRangeListImpl.h +++ b/lldb/include/lldb/Core/AddressRangeListImpl.h @@ -14,6 +14,7 @@ namespace lldb { class SBBlock; +class SBProcess; } namespace lldb_private { @@ -40,6 +41,7 @@ class AddressRangeListImpl { private: 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..176eb2b19f226 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2685,6 +2685,13 @@ void PruneThreadPlans(); lldb::addr_t FindInMemory(lldb::addr_t low, lldb::addr_t high, const uint8_t *buf, size_t size); + Status FindInMemory(AddressRanges &matches, const uint8_t *buf, size_t size, + const AddressRanges &ranges, size_t alignment, + size_t max_count); + + lldb::addr_t FindInMemory(const AddressRange &range, const uint8_t *buf, + size_t size, size_t alignment); + protected: friend class Trace; @@ -2800,6 +2807,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_count); + /// 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..d935c5d23653e 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,112 @@ const char *SBProcess::GetBroadcasterClass() { return ConstString(Process::GetStaticBroadcasterClass()).AsCString(); } +lldb::SBAddressRangeList +SBProcess::FindRangesInMemory(const void *buf, uint64_t size, + SBAddressRangeList &ranges, uint32_t alignment, + uint32_t max_matches) { + LLDB_INSTRUMENT_VA(this, buf, size, ranges, alignment, max_matches); + + Log *log = GetLog(LLDBLog::Process); + lldb::SBAddressRangeList matches; + + if (alignment == 0) { + LLDB_LOGF(log, "SBProcess::%s allignmet is 0, Must be greater than 0.", + __FUNCTION__); + return matches; + } + + if (buf == nullptr) { + LLDB_LOGF(log, "SBProcess::%s provided 'buffer' is nullptr.", __FUNCTION__); + return matches; + } + + if (size == 0) { + LLDB_LOGF(log, "SBProcess::%s buffer size is 0.", __FUNCTION__); + return matches; + } + + if (ranges.GetSize() == 0) { + LLDB_LOGF(log, "SBProcess::%s provided 'range' is invalid.", __FUNCTION__); + return matches; + } + + ProcessSP process_sp(GetSP()); + if (!process_sp) { + LLDB_LOGF(log, "SBProcess::%s SBProcess is invalid.", __FUNCTION__); + return matches; + } + Process::StopLocker stop_locker; + if (!stop_locker.TryLock(&process_sp->GetRunLock())) { + LLDB_LOGF( + log, + "SBProcess::%s Cannot find process in memory while process is running.", + __FUNCTION__); + return matches; + } + std::lock_guard<std::recursive_mutex> guard( + process_sp->GetTarget().GetAPIMutex()); + lldb::SBError error; + error.ref() = process_sp->FindInMemory( + matches.m_opaque_up->ref(), static_cast<const uint8_t *>(buf), size, + ranges.m_opaque_up->ref(), alignment, max_matches); + if (error.Fail()) { + LLDB_LOGF(log, "SBProcess::%s failed to find pattern in memory.", + __FUNCTION__); + } + return matches; +} + +lldb::addr_t SBProcess::FindInMemory(const void *buf, uint64_t size, + SBAddressRange &range, + uint32_t alignment) { + LLDB_INSTRUMENT_VA(this, buf, size, range, alignment); + + Log *log = GetLog(LLDBLog::Process); + + if (alignment == 0) { + LLDB_LOGF(log, "SBProcess::%s allignmet is 0, Must be greater than 0.", + __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + + if (buf == nullptr) { + LLDB_LOGF(log, "SBProcess::%s provided 'buffer' is nullptr.", __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + + if (size == 0) { + LLDB_LOGF(log, "SBProcess::%s buffer size is 0.", __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + + if (!range.IsValid()) { + LLDB_LOGF(log, "SBProcess::%s provided 'range' is invalid.", __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + + ProcessSP process_sp(GetSP()); + + if (!process_sp) { + LLDB_LOGF(log, "SBProcess::%s SBProcess is invalid.", __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + + Process::StopLocker stop_locker; + if (!stop_locker.TryLock(&process_sp->GetRunLock())) { + LLDB_LOGF( + log, + "SBProcess::%s Cannot find process in memory while process is running.", + __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + + std::lock_guard<std::recursive_mutex> guard( + process_sp->GetTarget().GetAPIMutex()); + return process_sp->FindInMemory( + *range.m_opaque_up, static_cast<const uint8_t *>(buf), size, alignment); +} + 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..06120be7979f9 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_count) { + // Inputs are already validated in FindInMemory() functions. + assert(buf != nullptr); + assert(size > 0); + assert(alignment > 0); + assert(max_count > 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_count && (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; + } +} + +Status Process::FindInMemory(AddressRanges &matches, const uint8_t *buf, + size_t size, const AddressRanges &ranges, + size_t alignment, size_t max_count) { + Status error; + if (alignment == 0) { + error.SetErrorStringWithFormat( + "invalid alignment %zu, must be greater than 0", alignment); + return error; + } + if (buf == nullptr) { + error.SetErrorStringWithFormat("buffer is null"); + return error; + } + if (size == 0) { + error.SetErrorStringWithFormat("size is zero"); + return error; + } + if (ranges.empty()) { + error.SetErrorStringWithFormat("ranges in empty"); + return error; + } + if (max_count == 0) { + error.SetErrorStringWithFormat( + "invalid max_count %zu, must be greater than 0", max_count); + return error; + } + + Target &target = GetTarget(); + Log *log = GetLog(LLDBLog::Process); + for (size_t i = 0; i < ranges.size(); ++i) { + if (matches.size() >= max_count) { + break; + } + const AddressRange &range = ranges[i]; + if (range.IsValid() == false) { + LLDB_LOGF(log, "Process::%s range is invalid", __FUNCTION__); + continue; + } + + const lldb::addr_t start_addr = + range.GetBaseAddress().GetLoadAddress(&target); + if (start_addr == LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "Process::%s range load start address is invalid, skipping", + __FUNCTION__); + continue; + } + const lldb::addr_t end_addr = start_addr + range.GetByteSize(); + DoFindInMemory(start_addr, end_addr, buf, size, matches, alignment, + max_count); + } + + return Status(); +} + +lldb::addr_t Process::FindInMemory(const AddressRange &range, + const uint8_t *buf, size_t size, + size_t alignment) { + Log *log = GetLog(LLDBLog::Process); + if (buf == nullptr) { + LLDB_LOGF(log, "Process::%s buffer is null", __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + if (size == 0) { + LLDB_LOGF(log, "Process::%s size is zero", __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + if (alignment == 0) { + LLDB_LOGF(log, "Process::%s alignment is zero, returning", __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + if (range.IsValid() == false) { + LLDB_LOGF(log, "Process::%s range is invalid", __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + + Target &target = GetTarget(); + const lldb::addr_t start_addr = + range.GetBaseAddress().GetLoadAddress(&target); + if (start_addr == LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, "Process::%s range load start address is invalid, returning", + __FUNCTION__); + 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; + + 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..95ea9b75cdc31 --- /dev/null +++ b/lldb/test/API/python_api/find_in_memory/TestFindInMemory.py @@ -0,0 +1,85 @@ +""" +Test Process::FindInMemory. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +from address_ranges_helper import GetAddressRanges +from address_ranges_helper import SINGLE_INSTANCE_PATTERN + +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) + + addr_ranges = GetAddressRanges(self) + + for addr_range in addr_ranges: + addr = self.process.FindInMemory( + SINGLE_INSTANCE_PATTERN, + addr_range, + 1, + ) + + if addr != lldb.LLDB_INVALID_ADDRESS: + break + + 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) + + addr_ranges = GetAddressRanges(self) + + addr = self.process.FindInMemory( + SINGLE_INSTANCE_PATTERN, + addr_ranges[0], + 0, + ) + + 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) + + addr = self.process.FindInMemory( + SINGLE_INSTANCE_PATTERN, + lldb.SBAddressRange(), + 1, + ) + + 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) + + addr_ranges = GetAddressRanges(self) + + addr = self.process.FindInMemory( + "", + addr_ranges[0], + 1, + ) + + 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..ac4b4b8c481b6 --- /dev/null +++ b/lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py @@ -0,0 +1,120 @@ +""" +Test Process::FindRangesInMemory. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +from address_ranges_helper import GetAddressRanges +from address_ranges_helper import SINGLE_INSTANCE_PATTERN +from address_ranges_helper import DOUBLE_INSTANCE_PATTERN + + +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 = GetAddressRanges(self) + + matches = self.process.FindRangesInMemory( + DOUBLE_INSTANCE_PATTERN, + addr_ranges, + 1, + 10, + ) + + 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 = GetAddressRanges(self) + + matches = self.process.FindRangesInMemory( + SINGLE_INSTANCE_PATTERN, + addr_ranges, + 1, + 10, + ) + + 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 = GetAddressRanges(self) + + matches = self.process.FindRangesInMemory( + DOUBLE_INSTANCE_PATTERN, + addr_ranges, + 1, + 1, + ) + + 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 = GetAddressRanges(self) + + matches = self.process.FindRangesInMemory( + DOUBLE_INSTANCE_PATTERN, + addr_ranges, + 0, + 10, + ) + + 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() + matches = self.process.FindRangesInMemory( + DOUBLE_INSTANCE_PATTERN, + addr_ranges, + 1, + 10, + ) + + self.assertEqual(matches.GetSize(), 0) + + def test_find_ranges_in_memory_invalid_buffer(self): + """Make sure t... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/95007 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits