Skip to content

Commit eeba06b

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 1248698 commit eeba06b

21 files changed

+711
-183
lines changed

lldb/include/lldb/Symbol/ObjectFile.h

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

672+
// Returns a pointer to the data at the specified offset. If the offset is
673+
// invalid, this function will return nullptr. The 'available_bytes' argument
674+
// will be set to the number of bytes available at the given offset, which
675+
// will be at most 'length' bytes.
676+
const uint8_t *PeekData(lldb::addr_t offset, size_t length,
677+
size_t &available_bytes) const;
678+
672679
// This function will transparently decompress section data if the section if
673680
// compressed.
674681
virtual size_t ReadSectionData(Section *section,

lldb/include/lldb/Target/PostMortemProcess.h

Lines changed: 18 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,23 @@ 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 const uint8_t *PeekMemory(lldb::addr_t low, lldb::addr_t high,
44+
size_t &size) = 0;
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+
const uint8_t *DoPeekMemory(lldb::ModuleSP &core_module_sp,
50+
VMRangeToFileOffset &core_aranges,
51+
lldb::addr_t low, lldb::addr_t high,
52+
size_t &available_bytes);
53+
3654
FileSpec m_core_file;
3755
};
3856

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/include/lldb/Target/ProcessTrace.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ class ProcessTrace : public PostMortemProcess {
7272
bool DoUpdateThreadList(ThreadList &old_thread_list,
7373
ThreadList &new_thread_list) override;
7474

75+
const uint8_t *PeekMemory(lldb::addr_t low, lldb::addr_t high,
76+
size_t &available_bytes) override;
77+
7578
private:
7679
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
7780
lldb::ListenerSP listener_sp,

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,3 +1095,9 @@ bool ProcessElfCore::GetProcessInfo(ProcessInstanceInfo &info) {
10951095
}
10961096
return true;
10971097
}
1098+
1099+
const uint8_t *ProcessElfCore::PeekMemory(lldb::addr_t low, lldb::addr_t high,
1100+
size_t &available_bytes) {
1101+
return DoPeekMemory(m_core_module_sp, m_core_aranges, low, high,
1102+
available_bytes);
1103+
}

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+
const uint8_t *PeekMemory(lldb::addr_t low, lldb::addr_t high,
115+
size_t &available_bytes) 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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,3 +776,9 @@ addr_t ProcessMachCore::GetImageInfoAddress() {
776776
lldb_private::ObjectFile *ProcessMachCore::GetCoreObjectFile() {
777777
return m_core_module_sp->GetObjectFile();
778778
}
779+
780+
const uint8_t *ProcessMachCore::PeekMemory(lldb::addr_t low, lldb::addr_t high,
781+
size_t &available_bytes) {
782+
return DoPeekMemory(m_core_module_sp, m_core_aranges, low, high,
783+
available_bytes);
784+
}

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+
const uint8_t *PeekMemory(lldb::addr_t low, lldb::addr_t high,
88+
size_t &available_bytes) 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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,17 @@ JITLoaderList &ProcessMinidump::GetJITLoaders() {
564564
#define APPEND_OPT(VAR) \
565565
m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1)
566566

567+
const uint8_t *ProcessMinidump::PeekMemory(lldb::addr_t low, lldb::addr_t high,
568+
size_t &available_bytes) {
569+
llvm::ArrayRef<uint8_t> mem = m_minidump_parser->GetMemory(low, high - low);
570+
if (mem.empty()) {
571+
available_bytes = 0;
572+
return nullptr;
573+
}
574+
available_bytes = mem.size();
575+
return mem.data();
576+
}
577+
567578
class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
568579
private:
569580
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+
const uint8_t *PeekMemory(lldb::addr_t low, lldb::addr_t high,
110+
size_t &available_bytes) 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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,18 @@ size_t ObjectFile::CopyData(lldb::offset_t offset, size_t length,
483483
return m_data.CopyData(offset, length, dst);
484484
}
485485

486+
const uint8_t *ObjectFile::PeekData(lldb::addr_t offset, size_t length,
487+
size_t &available_bytes) const {
488+
const uint8_t *data = m_data.PeekData(offset, length);
489+
if (data == nullptr) {
490+
available_bytes = 0;
491+
return nullptr;
492+
}
493+
494+
available_bytes = length;
495+
return data;
496+
}
497+
486498
size_t ObjectFile::ReadSectionData(Section *section,
487499
lldb::offset_t section_offset, void *dst,
488500
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: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
size_t mem_size = 0;
26+
const uint8_t *data = PeekMemory(low, high, mem_size);
27+
if (data == nullptr || mem_size != region_size) {
28+
LLDB_LOG(GetLog(LLDBLog::Process),
29+
"Failed to get contiguous memory region for search. low: 0x{}, "
30+
"high: 0x{}. Failling back to Process::FindInMemory",
31+
low, high);
32+
// In an edge case when the search has to happen across non-contiguous
33+
// memory, we will have to fall back on the Process::FindInMemory.
34+
return Process::FindInMemory(low, high, buf, size);
35+
}
36+
37+
return Process::FindInMemoryGeneric(data, low, high, buf, size);
38+
}
39+
40+
const uint8_t *PostMortemProcess::DoPeekMemory(
41+
lldb::ModuleSP &core_module_sp, VMRangeToFileOffset &core_aranges,
42+
lldb::addr_t low, lldb::addr_t high, size_t &available_bytes) {
43+
44+
ObjectFile *core_objfile = core_module_sp->GetObjectFile();
45+
46+
if (core_objfile == nullptr) {
47+
available_bytes = 0;
48+
return nullptr;
49+
}
50+
51+
const VMRangeToFileOffset::Entry *core_memory_entry =
52+
core_aranges.FindEntryThatContains(low);
53+
if (core_memory_entry == nullptr || core_memory_entry->GetRangeEnd() < low) {
54+
available_bytes = 0;
55+
return nullptr;
56+
}
57+
const lldb::addr_t offset = low - core_memory_entry->GetRangeBase();
58+
const lldb::addr_t file_start = core_memory_entry->data.GetRangeBase();
59+
const lldb::addr_t file_end = core_memory_entry->data.GetRangeEnd();
60+
61+
if (file_start == file_end) {
62+
available_bytes = 0;
63+
return nullptr;
64+
}
65+
size_t bytes_available = 0;
66+
if (file_end > file_start + offset)
67+
bytes_available = file_end - (file_start + offset);
68+
69+
size_t bytes_to_read = high - low;
70+
bytes_to_read = std::min(bytes_to_read, bytes_available);
71+
if (bytes_to_read == 0) {
72+
available_bytes = 0;
73+
return nullptr;
74+
}
75+
76+
const uint8_t *ret =
77+
core_objfile->PeekData(core_memory_entry->data.GetRangeBase() + offset,
78+
bytes_to_read, available_bytes);
79+
return ret;
80+
}

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) {

lldb/source/Target/ProcessTrace.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ size_t ProcessTrace::ReadMemory(addr_t addr, void *buf, size_t size,
9494

9595
void ProcessTrace::Clear() { m_thread_list.Clear(); }
9696

97+
const uint8_t *ProcessTrace::PeekMemory(lldb::addr_t low, lldb::addr_t high,
98+
size_t &available_bytes) {
99+
available_bytes = 0;
100+
return nullptr;
101+
}
102+
97103
void ProcessTrace::Initialize() {
98104
static llvm::once_flag g_once_flag;
99105

0 commit comments

Comments
 (0)