Skip to content

[lldb] Add 'FindInMemory()' overload for PostMortemProcess. #102536

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions lldb/include/lldb/Target/PostMortemProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLDB_TARGET_POSTMORTEMPROCESS_H

#include "lldb/Target/Process.h"
#include "lldb/Utility/RangeMap.h"

namespace lldb_private {

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

protected:
typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange>
VMRangeToFileOffset;
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t>
VMRangeToPermissions;

virtual llvm::ArrayRef<uint8_t> PeekMemory(lldb::addr_t low,
lldb::addr_t high);

lldb::addr_t FindInMemory(lldb::addr_t low, lldb::addr_t high,
const uint8_t *buf, size_t size) override;

llvm::ArrayRef<uint8_t> DoPeekMemory(lldb::ModuleSP &core_module_sp,
VMRangeToFileOffset &core_aranges,
lldb::addr_t low, lldb::addr_t high);

FileSpec m_core_file;
};

Expand Down
34 changes: 32 additions & 2 deletions lldb/include/lldb/Target/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -2703,8 +2703,8 @@ void PruneThreadPlans();
///
/// \return The address where the pattern was found or LLDB_INVALID_ADDRESS if
/// not found.
lldb::addr_t FindInMemory(lldb::addr_t low, lldb::addr_t high,
const uint8_t *buf, size_t size);
virtual 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,
Expand Down Expand Up @@ -2835,6 +2835,36 @@ void PruneThreadPlans();
AddressRanges &matches, size_t alignment,
size_t max_matches);

template <typename IT>
lldb::addr_t FindInMemoryGeneric(IT &&iterator, lldb::addr_t low,
lldb::addr_t high, const uint8_t *buf,
size_t size) {
// This function implements the Boyer-Moore-Horspool algorithm for efficient
// string searching.
const size_t region_size = high - low;

if (region_size < size)
return LLDB_INVALID_ADDRESS;

std::vector<size_t> bad_char_heuristic(256, size);

for (size_t idx = 0; idx < size - 1; idx++) {
decltype(bad_char_heuristic)::size_type bcu_idx = buf[idx];
bad_char_heuristic[bcu_idx] = size - idx - 1;
}
for (size_t s = 0; s <= (region_size - size);) {
int64_t j = size - 1;
while (j >= 0 && buf[j] == iterator[s + j])
j--;
if (j < 0)
return low + s;
else
s += bad_char_heuristic[iterator[s + size - 1]];
}

return LLDB_INVALID_ADDRESS;
}

/// DoGetMemoryRegionInfo is called by GetMemoryRegionInfo after it has
/// removed non address bits from load_addr. Override this method in
/// subclasses of Process.
Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1095,3 +1095,8 @@ bool ProcessElfCore::GetProcessInfo(ProcessInstanceInfo &info) {
}
return true;
}

llvm::ArrayRef<uint8_t> ProcessElfCore::PeekMemory(lldb::addr_t low,
lldb::addr_t high) {
return DoPeekMemory(m_core_module_sp, m_core_aranges, low, high);
}
10 changes: 3 additions & 7 deletions lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {

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

llvm::ArrayRef<uint8_t> PeekMemory(lldb::addr_t low,
lldb::addr_t high) override;

private:
struct NT_FILE_Entry {
lldb::addr_t start;
Expand All @@ -123,13 +126,6 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
lldb_private::UUID uuid;
};

// For ProcessElfCore only
typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange>
VMRangeToFileOffset;
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t>
VMRangeToPermissions;

lldb::ModuleSP m_core_module_sp;
std::string m_dyld_plugin_name;

Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,3 +776,8 @@ addr_t ProcessMachCore::GetImageInfoAddress() {
lldb_private::ObjectFile *ProcessMachCore::GetCoreObjectFile() {
return m_core_module_sp->GetObjectFile();
}

llvm::ArrayRef<uint8_t> ProcessMachCore::PeekMemory(lldb::addr_t low,
lldb::addr_t high) {
return DoPeekMemory(m_core_module_sp, m_core_aranges, low, high);
}
10 changes: 3 additions & 7 deletions lldb/source/Plugins/Process/mach-core/ProcessMachCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class ProcessMachCore : public lldb_private::PostMortemProcess {
DoGetMemoryRegionInfo(lldb::addr_t load_addr,
lldb_private::MemoryRegionInfo &region_info) override;

llvm::ArrayRef<uint8_t> PeekMemory(lldb::addr_t low,
lldb::addr_t high) override;

private:
void CreateMemoryRegions();

Expand Down Expand Up @@ -120,13 +123,6 @@ class ProcessMachCore : public lldb_private::PostMortemProcess {
return eKernelCorefile;
}

// For ProcessMachCore only
typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange>
VMRangeToFileOffset;
typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t>
VMRangeToPermissions;

VMRangeToFileOffset m_core_aranges;
VMRangeToPermissions m_core_range_infos;
lldb::ModuleSP m_core_module_sp;
Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,11 @@ JITLoaderList &ProcessMinidump::GetJITLoaders() {
#define APPEND_OPT(VAR) \
m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1)

llvm::ArrayRef<uint8_t> ProcessMinidump::PeekMemory(lldb::addr_t low,
lldb::addr_t high) {
return m_minidump_parser->GetMemory(low, high - low);
}

class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
private:
OptionGroupOptions m_option_group;
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Plugins/Process/minidump/ProcessMinidump.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ class ProcessMinidump : public PostMortemProcess {

JITLoaderList &GetJITLoaders() override;

llvm::ArrayRef<uint8_t> PeekMemory(lldb::addr_t low,
lldb::addr_t high) override;

private:
lldb::DataBufferSP m_core_data;
llvm::ArrayRef<minidump::Thread> m_thread_list;
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Target/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ add_lldb_library(lldbTarget
OperatingSystem.cpp
PathMappingList.cpp
Platform.cpp
PostMortemProcess.cpp
Process.cpp
ProcessTrace.cpp
Queue.cpp
Expand Down
83 changes: 83 additions & 0 deletions lldb/source/Target/PostMortemProcess.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//===-- PostMortemProcess.cpp -----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "lldb/Target/PostMortemProcess.h"

#include "lldb/Core/Module.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/lldb-forward.h"

using namespace lldb;
using namespace lldb_private;

lldb::addr_t PostMortemProcess::FindInMemory(lldb::addr_t low,
lldb::addr_t high,
const uint8_t *buf, size_t size) {
const size_t region_size = high - low;
if (region_size < size)
return LLDB_INVALID_ADDRESS;

llvm::ArrayRef<uint8_t> data = PeekMemory(low, high);
if (data.empty()) {
LLDB_LOG(GetLog(LLDBLog::Process),
"Failed to get contiguous memory region for search. low: 0x{}, "
"high: 0x{}. Failling back to Process::FindInMemory",
low, high);
// In an edge case when the search has to happen across non-contiguous
// memory, we will have to fall back on the Process::FindInMemory.
return Process::FindInMemory(low, high, buf, size);
}

return Process::FindInMemoryGeneric(data, low, high, buf, size);
}

llvm::ArrayRef<uint8_t> PostMortemProcess::PeekMemory(lldb::addr_t low,
lldb::addr_t high) {
return llvm::ArrayRef<uint8_t>();
}

llvm::ArrayRef<uint8_t>
PostMortemProcess::DoPeekMemory(lldb::ModuleSP &core_module_sp,
VMRangeToFileOffset &core_aranges,
lldb::addr_t low, lldb::addr_t high) {

ObjectFile *core_objfile = core_module_sp->GetObjectFile();

if (core_objfile == nullptr) {
return llvm::ArrayRef<uint8_t>();
}

const VMRangeToFileOffset::Entry *core_memory_entry =
core_aranges.FindEntryThatContains(low);
if (core_memory_entry == nullptr || core_memory_entry->GetRangeEnd() < low) {
return llvm::ArrayRef<uint8_t>();
}
const lldb::addr_t offset = low - core_memory_entry->GetRangeBase();
const lldb::addr_t file_start = core_memory_entry->data.GetRangeBase();
const lldb::addr_t file_end = core_memory_entry->data.GetRangeEnd();

if (file_start == file_end) {
return llvm::ArrayRef<uint8_t>();
}
size_t bytes_available = 0;
if (file_end > file_start + offset)
bytes_available = file_end - (file_start + offset);

size_t bytes_to_read = high - low;
bytes_to_read = std::min(bytes_to_read, bytes_available);
if (bytes_to_read == 0) {
return llvm::ArrayRef<uint8_t>();
}
DataExtractor extractor;
core_objfile->GetData(core_memory_entry->data.GetRangeBase() + offset,
bytes_to_read, extractor);
if (extractor.GetByteSize() != bytes_to_read) {
return llvm::ArrayRef<uint8_t>();
}
return extractor.GetData();
}
28 changes: 3 additions & 25 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2126,9 +2126,8 @@ lldb::addr_t Process::FindInMemory(const uint8_t *buf, uint64_t size,
error.SetErrorString("range load address is invalid");
return LLDB_INVALID_ADDRESS;
}
const lldb::addr_t end_addr = start_addr + range.GetByteSize();

AddressRanges matches;
const lldb::addr_t end_addr = start_addr + range.GetByteSize();
DoFindInMemory(start_addr, end_addr, buf, size, matches, alignment, 1);
if (matches.empty())
return LLDB_INVALID_ADDRESS;
Expand Down Expand Up @@ -3362,29 +3361,8 @@ Status Process::Halt(bool clear_thread_plans, bool use_run_lock) {

lldb::addr_t Process::FindInMemory(lldb::addr_t low, lldb::addr_t high,
const uint8_t *buf, size_t size) {
const size_t region_size = high - low;

if (region_size < size)
return LLDB_INVALID_ADDRESS;

std::vector<size_t> bad_char_heuristic(256, size);
ProcessMemoryIterator iterator(*this, low);

for (size_t idx = 0; idx < size - 1; idx++) {
decltype(bad_char_heuristic)::size_type bcu_idx = buf[idx];
bad_char_heuristic[bcu_idx] = size - idx - 1;
}
for (size_t s = 0; s <= (region_size - size);) {
int64_t j = size - 1;
while (j >= 0 && buf[j] == iterator[s + j])
j--;
if (j < 0)
return low + s;
else
s += bad_char_heuristic[iterator[s + size - 1]];
}

return LLDB_INVALID_ADDRESS;
return FindInMemoryGeneric(ProcessMemoryIterator(*this, low), low, high, buf,
size);
}

Status Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) {
Expand Down
Loading
Loading