Skip to content

Commit 37ef59b

Browse files
author
Miro Bucko
committed
[lldb] Add 'FindInMemory()' overload for PostMortemProcess.
Summary: The current implementation of 'Process::FindInMemory()' utilizes a slow ReadMemory() API to search for 1 byte at a time in memory. This new overload takes advantage of the fact that the process core is already loaded into memory, allowing for a direct and more efficient search. Test Plan: llvm-lit ./llvm-project/lldb/test/API/python_api/find_in_memory/TestFindInMemoryCore.py ./llvm-project/lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py ./llvm-project/lldb/test/API/python_api/find_in_memory/TestFindInMemory.py Reviewers: Subscribers: Tasks: Tags:
1 parent 1ea0865 commit 37ef59b

19 files changed

+685
-183
lines changed

lldb/include/lldb/Symbol/ObjectFile.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,11 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
668668
// transparent decompression of section contents.
669669
size_t CopyData(lldb::offset_t offset, size_t length, void *dst) const;
670670

671+
// Returns an ArrayRef of the data at the specified offset. If the offset is
672+
// invalid, this function will return an empty ArrayRef. The length of the
673+
// returned ArrayRef will be at most 'length' bytes.
674+
llvm::ArrayRef<uint8_t> PeekData(lldb::addr_t offset, size_t length) const;
675+
671676
// This function will transparently decompress section data if the section if
672677
// compressed.
673678
virtual size_t ReadSectionData(Section *section,

lldb/include/lldb/Target/PostMortemProcess.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLDB_TARGET_POSTMORTEMPROCESS_H
1111

1212
#include "lldb/Target/Process.h"
13+
#include "lldb/Utility/RangeMap.h"
1314

1415
namespace lldb_private {
1516

@@ -33,6 +34,22 @@ class PostMortemProcess : public Process {
3334
FileSpec GetCoreFile() const override { return m_core_file; }
3435

3536
protected:
37+
typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
38+
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange>
39+
VMRangeToFileOffset;
40+
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t>
41+
VMRangeToPermissions;
42+
43+
virtual llvm::ArrayRef<uint8_t> PeekMemory(lldb::addr_t low,
44+
lldb::addr_t high);
45+
46+
lldb::addr_t FindInMemory(lldb::addr_t low, lldb::addr_t high,
47+
const uint8_t *buf, size_t size) override;
48+
49+
llvm::ArrayRef<uint8_t> DoPeekMemory(lldb::ModuleSP &core_module_sp,
50+
VMRangeToFileOffset &core_aranges,
51+
lldb::addr_t low, lldb::addr_t high);
52+
3653
FileSpec m_core_file;
3754
};
3855

lldb/include/lldb/Target/Process.h

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2703,8 +2703,8 @@ void PruneThreadPlans();
27032703
///
27042704
/// \return The address where the pattern was found or LLDB_INVALID_ADDRESS if
27052705
/// not found.
2706-
lldb::addr_t FindInMemory(lldb::addr_t low, lldb::addr_t high,
2707-
const uint8_t *buf, size_t size);
2706+
virtual lldb::addr_t FindInMemory(lldb::addr_t low, lldb::addr_t high,
2707+
const uint8_t *buf, size_t size);
27082708

27092709
AddressRanges FindRangesInMemory(const uint8_t *buf, uint64_t size,
27102710
const AddressRanges &ranges,
@@ -2835,6 +2835,34 @@ void PruneThreadPlans();
28352835
AddressRanges &matches, size_t alignment,
28362836
size_t max_matches);
28372837

2838+
template <typename IT>
2839+
lldb::addr_t FindInMemoryGeneric(IT &&iterator, lldb::addr_t low,
2840+
lldb::addr_t high, const uint8_t *buf,
2841+
size_t size) {
2842+
const size_t region_size = high - low;
2843+
2844+
if (region_size < size)
2845+
return LLDB_INVALID_ADDRESS;
2846+
2847+
std::vector<size_t> bad_char_heuristic(256, size);
2848+
2849+
for (size_t idx = 0; idx < size - 1; idx++) {
2850+
decltype(bad_char_heuristic)::size_type bcu_idx = buf[idx];
2851+
bad_char_heuristic[bcu_idx] = size - idx - 1;
2852+
}
2853+
for (size_t s = 0; s <= (region_size - size);) {
2854+
int64_t j = size - 1;
2855+
while (j >= 0 && buf[j] == iterator[s + j])
2856+
j--;
2857+
if (j < 0)
2858+
return low + s;
2859+
else
2860+
s += bad_char_heuristic[iterator[s + size - 1]];
2861+
}
2862+
2863+
return LLDB_INVALID_ADDRESS;
2864+
}
2865+
28382866
/// DoGetMemoryRegionInfo is called by GetMemoryRegionInfo after it has
28392867
/// removed non address bits from load_addr. Override this method in
28402868
/// subclasses of Process.

lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,3 +1095,8 @@ bool ProcessElfCore::GetProcessInfo(ProcessInstanceInfo &info) {
10951095
}
10961096
return true;
10971097
}
1098+
1099+
llvm::ArrayRef<uint8_t> ProcessElfCore::PeekMemory(lldb::addr_t low,
1100+
lldb::addr_t high) {
1101+
return DoPeekMemory(m_core_module_sp, m_core_aranges, low, high);
1102+
}

lldb/source/Plugins/Process/elf-core/ProcessElfCore.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
111111

112112
bool SupportsMemoryTagging() override { return !m_core_tag_ranges.IsEmpty(); }
113113

114+
llvm::ArrayRef<uint8_t> PeekMemory(lldb::addr_t low,
115+
lldb::addr_t high) override;
116+
114117
private:
115118
struct NT_FILE_Entry {
116119
lldb::addr_t start;
@@ -123,13 +126,6 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
123126
lldb_private::UUID uuid;
124127
};
125128

126-
// For ProcessElfCore only
127-
typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
128-
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange>
129-
VMRangeToFileOffset;
130-
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t>
131-
VMRangeToPermissions;
132-
133129
lldb::ModuleSP m_core_module_sp;
134130
std::string m_dyld_plugin_name;
135131

lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,3 +776,8 @@ addr_t ProcessMachCore::GetImageInfoAddress() {
776776
lldb_private::ObjectFile *ProcessMachCore::GetCoreObjectFile() {
777777
return m_core_module_sp->GetObjectFile();
778778
}
779+
780+
llvm::ArrayRef<uint8_t> ProcessMachCore::PeekMemory(lldb::addr_t low,
781+
lldb::addr_t high) {
782+
return DoPeekMemory(m_core_module_sp, m_core_aranges, low, high);
783+
}

lldb/source/Plugins/Process/mach-core/ProcessMachCore.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ class ProcessMachCore : public lldb_private::PostMortemProcess {
8484
DoGetMemoryRegionInfo(lldb::addr_t load_addr,
8585
lldb_private::MemoryRegionInfo &region_info) override;
8686

87+
llvm::ArrayRef<uint8_t> PeekMemory(lldb::addr_t low,
88+
lldb::addr_t high) override;
89+
8790
private:
8891
void CreateMemoryRegions();
8992

@@ -120,13 +123,6 @@ class ProcessMachCore : public lldb_private::PostMortemProcess {
120123
return eKernelCorefile;
121124
}
122125

123-
// For ProcessMachCore only
124-
typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
125-
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange>
126-
VMRangeToFileOffset;
127-
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t>
128-
VMRangeToPermissions;
129-
130126
VMRangeToFileOffset m_core_aranges;
131127
VMRangeToPermissions m_core_range_infos;
132128
lldb::ModuleSP m_core_module_sp;

lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,11 @@ JITLoaderList &ProcessMinidump::GetJITLoaders() {
564564
#define APPEND_OPT(VAR) \
565565
m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1)
566566

567+
llvm::ArrayRef<uint8_t> ProcessMinidump::PeekMemory(lldb::addr_t low,
568+
lldb::addr_t high) {
569+
return m_minidump_parser->GetMemory(low, high - low);
570+
}
571+
567572
class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
568573
private:
569574
OptionGroupOptions m_option_group;

lldb/source/Plugins/Process/minidump/ProcessMinidump.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ class ProcessMinidump : public PostMortemProcess {
106106

107107
JITLoaderList &GetJITLoaders() override;
108108

109+
llvm::ArrayRef<uint8_t> PeekMemory(lldb::addr_t low,
110+
lldb::addr_t high) override;
111+
109112
private:
110113
lldb::DataBufferSP m_core_data;
111114
llvm::ArrayRef<minidump::Thread> m_thread_list;

lldb/source/Symbol/ObjectFile.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,13 @@ size_t ObjectFile::CopyData(lldb::offset_t offset, size_t length,
482482
return m_data.CopyData(offset, length, dst);
483483
}
484484

485+
llvm::ArrayRef<uint8_t> ObjectFile::PeekData(lldb::addr_t offset,
486+
size_t length) const {
487+
const uint8_t *data = m_data.PeekData(offset, length);
488+
llvm::ArrayRef<uint8_t> array(data, length);
489+
return array;
490+
}
491+
485492
size_t ObjectFile::ReadSectionData(Section *section,
486493
lldb::offset_t section_offset, void *dst,
487494
size_t dst_len) {

lldb/source/Target/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ add_lldb_library(lldbTarget
2626
OperatingSystem.cpp
2727
PathMappingList.cpp
2828
Platform.cpp
29+
PostMortemProcess.cpp
2930
Process.cpp
3031
ProcessTrace.cpp
3132
Queue.cpp
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===-- PostMortemProcess.cpp -----------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "lldb/Target/PostMortemProcess.h"
10+
11+
#include "lldb/Core/Module.h"
12+
#include "lldb/Utility/LLDBLog.h"
13+
#include "lldb/lldb-forward.h"
14+
15+
using namespace lldb;
16+
using namespace lldb_private;
17+
18+
lldb::addr_t PostMortemProcess::FindInMemory(lldb::addr_t low,
19+
lldb::addr_t high,
20+
const uint8_t *buf, size_t size) {
21+
const size_t region_size = high - low;
22+
if (region_size < size)
23+
return LLDB_INVALID_ADDRESS;
24+
25+
llvm::ArrayRef<uint8_t> data = PeekMemory(low, high);
26+
if (data.empty()) {
27+
LLDB_LOG(GetLog(LLDBLog::Process),
28+
"Failed to get contiguous memory region for search. low: 0x{}, "
29+
"high: 0x{}. Failling back to Process::FindInMemory",
30+
low, high);
31+
// In an edge case when the search has to happen across non-contiguous
32+
// memory, we will have to fall back on the Process::FindInMemory.
33+
return Process::FindInMemory(low, high, buf, size);
34+
}
35+
36+
return Process::FindInMemoryGeneric(data, low, high, buf, size);
37+
}
38+
39+
llvm::ArrayRef<uint8_t> PostMortemProcess::PeekMemory(lldb::addr_t low,
40+
lldb::addr_t high) {
41+
return {};
42+
}
43+
44+
llvm::ArrayRef<uint8_t>
45+
PostMortemProcess::DoPeekMemory(lldb::ModuleSP &core_module_sp,
46+
VMRangeToFileOffset &core_aranges,
47+
lldb::addr_t low, lldb::addr_t high) {
48+
49+
ObjectFile *core_objfile = core_module_sp->GetObjectFile();
50+
51+
if (core_objfile == nullptr) {
52+
return {};
53+
}
54+
55+
const VMRangeToFileOffset::Entry *core_memory_entry =
56+
core_aranges.FindEntryThatContains(low);
57+
if (core_memory_entry == nullptr || core_memory_entry->GetRangeEnd() < low) {
58+
return {};
59+
}
60+
const lldb::addr_t offset = low - core_memory_entry->GetRangeBase();
61+
const lldb::addr_t file_start = core_memory_entry->data.GetRangeBase();
62+
const lldb::addr_t file_end = core_memory_entry->data.GetRangeEnd();
63+
64+
if (file_start == file_end) {
65+
return {};
66+
}
67+
size_t bytes_available = 0;
68+
if (file_end > file_start + offset)
69+
bytes_available = file_end - (file_start + offset);
70+
71+
size_t bytes_to_read = high - low;
72+
bytes_to_read = std::min(bytes_to_read, bytes_available);
73+
if (bytes_to_read == 0) {
74+
return {};
75+
}
76+
77+
return core_objfile->PeekData(core_memory_entry->data.GetRangeBase() + offset,
78+
bytes_to_read);
79+
}

lldb/source/Target/Process.cpp

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,9 +2126,8 @@ lldb::addr_t Process::FindInMemory(const uint8_t *buf, uint64_t size,
21262126
error.SetErrorString("range load address is invalid");
21272127
return LLDB_INVALID_ADDRESS;
21282128
}
2129-
const lldb::addr_t end_addr = start_addr + range.GetByteSize();
2130-
21312129
AddressRanges matches;
2130+
const lldb::addr_t end_addr = start_addr + range.GetByteSize();
21322131
DoFindInMemory(start_addr, end_addr, buf, size, matches, alignment, 1);
21332132
if (matches.empty())
21342133
return LLDB_INVALID_ADDRESS;
@@ -3362,29 +3361,8 @@ Status Process::Halt(bool clear_thread_plans, bool use_run_lock) {
33623361

33633362
lldb::addr_t Process::FindInMemory(lldb::addr_t low, lldb::addr_t high,
33643363
const uint8_t *buf, size_t size) {
3365-
const size_t region_size = high - low;
3366-
3367-
if (region_size < size)
3368-
return LLDB_INVALID_ADDRESS;
3369-
3370-
std::vector<size_t> bad_char_heuristic(256, size);
3371-
ProcessMemoryIterator iterator(*this, low);
3372-
3373-
for (size_t idx = 0; idx < size - 1; idx++) {
3374-
decltype(bad_char_heuristic)::size_type bcu_idx = buf[idx];
3375-
bad_char_heuristic[bcu_idx] = size - idx - 1;
3376-
}
3377-
for (size_t s = 0; s <= (region_size - size);) {
3378-
int64_t j = size - 1;
3379-
while (j >= 0 && buf[j] == iterator[s + j])
3380-
j--;
3381-
if (j < 0)
3382-
return low + s;
3383-
else
3384-
s += bad_char_heuristic[iterator[s + size - 1]];
3385-
}
3386-
3387-
return LLDB_INVALID_ADDRESS;
3364+
return FindInMemoryGeneric(ProcessMemoryIterator(*this, low), low, high, buf,
3365+
size);
33883366
}
33893367

33903368
Status Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) {

0 commit comments

Comments
 (0)