Skip to content

Commit

Permalink
[LLDB] Reapply SBSaveCore Add Memory List (#107937)
Browse files Browse the repository at this point in the history
Recently in #107731 this change was revereted due to excess memory size
in `TestSkinnyCore`. This was due to a bug where a range's end was being
passed as size. Creating massive memory ranges.

Additionally, and requiring additional review, I added more unit tests
and more verbose logic to the merging of save core memory regions.

@jasonmolenda as an FYI.
  • Loading branch information
Jlalond authored Sep 11, 2024
1 parent b7b28e7 commit 96b7c64
Show file tree
Hide file tree
Showing 25 changed files with 635 additions and 67 deletions.
2 changes: 1 addition & 1 deletion lldb/include/lldb/API/SBMemoryRegionInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class LLDB_API SBMemoryRegionInfo {
private:
friend class SBProcess;
friend class SBMemoryRegionInfoList;

friend class SBSaveCoreOptions;
friend class lldb_private::ScriptInterpreter;

lldb_private::MemoryRegionInfo &ref();
Expand Down
11 changes: 11 additions & 0 deletions lldb/include/lldb/API/SBSaveCoreOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,17 @@ class LLDB_API SBSaveCoreOptions {
/// \return True if the thread was removed, false if it was not in the list.
bool RemoveThread(lldb::SBThread thread);

/// Add a memory region to save in the core file.
///
/// \param region The memory region to save.
/// \returns An empty SBError upon success, or an error if the region is
/// invalid.
/// \note Ranges that overlapped will be unioned into a single region, this
/// also supercedes stack minification. Specifying full regions and a
/// non-custom core style will include the specified regions and union them
/// with all style specific regions.
SBError AddMemoryRegionToSave(const SBMemoryRegionInfo &region);

/// Reset all options.
void Clear();

Expand Down
11 changes: 9 additions & 2 deletions lldb/include/lldb/Symbol/SaveCoreOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
#define LLDB_SOURCE_PLUGINS_OBJECTFILE_SaveCoreOPTIONS_H

#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-types.h"
#include "lldb/Utility/RangeMap.h"

#include <optional>
#include <set>
#include <string>
#include <unordered_set>

using MemoryRanges = lldb_private::RangeVector<lldb::addr_t, lldb::addr_t>;

namespace lldb_private {

class SaveCoreOptions {
Expand All @@ -38,8 +40,12 @@ class SaveCoreOptions {
Status AddThread(lldb::ThreadSP thread_sp);
bool RemoveThread(lldb::ThreadSP thread_sp);
bool ShouldThreadBeSaved(lldb::tid_t tid) const;
bool HasSpecifiedThreads() const;

Status EnsureValidConfiguration(lldb::ProcessSP process_sp) const;
const MemoryRanges &GetCoreFileMemoryRanges() const;

void AddMemoryRegionToSave(const lldb_private::MemoryRegionInfo &region);

void Clear();

Expand All @@ -51,6 +57,7 @@ class SaveCoreOptions {
std::optional<lldb::SaveCoreStyle> m_style;
lldb::ProcessSP m_process_sp;
std::unordered_set<lldb::tid_t> m_threads_to_save;
MemoryRanges m_regions_to_save;
};
} // namespace lldb_private

Expand Down
50 changes: 50 additions & 0 deletions lldb/include/lldb/Target/CoreFileMemoryRanges.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//===-- CoreFileMemoryRanges.h ----------------------------------*- 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/Utility/RangeMap.h"
#include "lldb/Utility/Status.h"

#include "llvm/ADT/AddressRanges.h"

#ifndef LLDB_TARGET_COREFILEMEMORYRANGES_H
#define LLDB_TARGET_COREFILEMEMORYRANGES_H

namespace lldb_private {

struct CoreFileMemoryRange {
llvm::AddressRange range; /// The address range to save into the core file.
uint32_t lldb_permissions; /// A bit set of lldb::Permissions bits.

bool operator==(const CoreFileMemoryRange &rhs) const {
return range == rhs.range && lldb_permissions == rhs.lldb_permissions;
}

bool operator!=(const CoreFileMemoryRange &rhs) const {
return !(*this == rhs);
}

bool operator<(const CoreFileMemoryRange &rhs) const {
if (range < rhs.range)
return true;
if (range == rhs.range)
return lldb_permissions < rhs.lldb_permissions;
return false;
}
};

class CoreFileMemoryRanges
: public lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t,
CoreFileMemoryRange> {
public:
/// Finalize and merge all overlapping ranges in this collection. Ranges
/// will be seperated based on permissions.
Status FinalizeCoreFileSaveRanges();
};
} // namespace lldb_private

#endif // LLDB_TARGET_COREFILEMEMORYRANGES_H
25 changes: 2 additions & 23 deletions lldb/include/lldb/Target/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include "lldb/Host/ProcessLaunchInfo.h"
#include "lldb/Host/ProcessRunLock.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SaveCoreOptions.h"
#include "lldb/Target/CoreFileMemoryRanges.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/InstrumentationRuntime.h"
#include "lldb/Target/Memory.h"
Expand Down Expand Up @@ -710,29 +712,6 @@ class Process : public std::enable_shared_from_this<Process>,
/// is not supported by the plugin, error otherwise.
virtual llvm::Expected<bool> SaveCore(llvm::StringRef outfile);

struct CoreFileMemoryRange {
llvm::AddressRange range; /// The address range to save into the core file.
uint32_t lldb_permissions; /// A bit set of lldb::Permissions bits.

bool operator==(const CoreFileMemoryRange &rhs) const {
return range == rhs.range && lldb_permissions == rhs.lldb_permissions;
}

bool operator!=(const CoreFileMemoryRange &rhs) const {
return !(*this == rhs);
}

bool operator<(const CoreFileMemoryRange &rhs) const {
if (range < rhs.range)
return true;
if (range == rhs.range)
return lldb_permissions < rhs.lldb_permissions;
return false;
}
};

using CoreFileMemoryRanges = std::vector<CoreFileMemoryRange>;

/// Helper function for Process::SaveCore(...) that calculates the address
/// ranges that should be saved. This allows all core file plug-ins to save
/// consistent memory ranges given a \a core_style.
Expand Down
6 changes: 6 additions & 0 deletions lldb/include/lldb/Utility/RangeMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,12 @@ class RangeDataVector {

void Append(const Entry &entry) { m_entries.emplace_back(entry); }

/// Append a range with data to the vector
/// \param B The base of the memory range
/// \param S The size of the memory range
/// \param T The data associated with the memory range
void Append(B &&b, S &&s, T &&t) { m_entries.emplace_back(Entry(b, s, t)); }

bool Erase(uint32_t start, uint32_t end) {
if (start >= end || end > m_entries.size())
return false;
Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/lldb-enumerations.h
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,7 @@ enum SaveCoreStyle {
eSaveCoreFull = 1,
eSaveCoreDirtyOnly = 2,
eSaveCoreStackOnly = 3,
eSaveCoreCustomOnly = 4,
};

/// Events that might happen during a trace session.
Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/lldb-forward.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ class StackFrameRecognizer;
class StackFrameRecognizerManager;
class StackID;
class Status;
class SaveCoreOptions;
class StopInfo;
class Stoppoint;
class StoppointCallbackContext;
Expand Down
1 change: 0 additions & 1 deletion lldb/include/lldb/lldb-private-interfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#ifndef LLDB_LLDB_PRIVATE_INTERFACES_H
#define LLDB_LLDB_PRIVATE_INTERFACES_H

#include "lldb/Symbol/SaveCoreOptions.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private-enumerations.h"
Expand Down
11 changes: 11 additions & 0 deletions lldb/source/API/SBSaveCoreOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "lldb/API/SBSaveCoreOptions.h"
#include "lldb/API/SBMemoryRegionInfo.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Symbol/SaveCoreOptions.h"
#include "lldb/Utility/Instrumentation.h"
Expand Down Expand Up @@ -89,6 +90,16 @@ bool SBSaveCoreOptions::RemoveThread(lldb::SBThread thread) {
return m_opaque_up->RemoveThread(thread.GetSP());
}

lldb::SBError
SBSaveCoreOptions::AddMemoryRegionToSave(const SBMemoryRegionInfo &region) {
LLDB_INSTRUMENT_VA(this, region);
// Currently add memory region can't fail, so we always return a success
// SBerror, but because these API's live forever, this is the most future
// proof thing to do.
m_opaque_up->AddMemoryRegionToSave(region.ref());
return SBError();
}

void SBSaveCoreOptions::Clear() {
LLDB_INSTRUMENT_VA(this);
m_opaque_up->Clear();
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Commands/CommandObjectProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
#include "lldb/Interpreter/Options.h"
#include "lldb/Symbol/SaveCoreOptions.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StopInfo.h"
Expand Down
6 changes: 4 additions & 2 deletions lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6562,13 +6562,15 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
}

if (make_core) {
Process::CoreFileMemoryRanges core_ranges;
CoreFileMemoryRanges core_ranges;
error = process_sp->CalculateCoreFileSaveRanges(options, core_ranges);
if (error.Success()) {
const uint32_t addr_byte_size = target_arch.GetAddressByteSize();
const ByteOrder byte_order = target_arch.GetByteOrder();
std::vector<llvm::MachO::segment_command_64> segment_load_commands;
for (const auto &core_range : core_ranges) {
for (const auto &core_range_info : core_ranges) {
// TODO: Refactor RangeDataVector to have a data iterator.
const auto &core_range = core_range_info.data;
uint32_t cmd_type = LC_SEGMENT_64;
uint32_t segment_size = sizeof(llvm::MachO::segment_command_64);
if (addr_byte_size == 4) {
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "lldb/Core/Address.h"
#include "lldb/Host/SafeMachO.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SaveCoreOptions.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/FileSpecList.h"
#include "lldb/Utility/RangeMap.h"
Expand Down
35 changes: 21 additions & 14 deletions lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -831,25 +831,32 @@ Status MinidumpFileBuilder::AddMemoryList() {
// bytes of the core file. Thread structures in minidump files can only use
// 32 bit memory descriptiors, so we emit them first to ensure the memory is
// in accessible with a 32 bit offset.
Process::CoreFileMemoryRanges ranges_32;
Process::CoreFileMemoryRanges ranges_64;
Process::CoreFileMemoryRanges all_core_memory_ranges;
std::vector<CoreFileMemoryRange> ranges_32;
std::vector<CoreFileMemoryRange> ranges_64;
CoreFileMemoryRanges all_core_memory_ranges;
error = m_process_sp->CalculateCoreFileSaveRanges(m_save_core_options,
all_core_memory_ranges);

std::vector<CoreFileMemoryRange> all_core_memory_vec;
// Extract all the data into just a vector of data. So we can mutate this in
// place.
for (const auto &core_range : all_core_memory_ranges)
all_core_memory_vec.push_back(core_range.data);

if (error.Fail())
return error;

// Start by saving all of the stacks and ensuring they fit under the 32b
// limit.
uint64_t total_size = GetCurrentDataEndOffset();
auto iterator = all_core_memory_ranges.begin();
while (iterator != all_core_memory_ranges.end()) {
auto iterator = all_core_memory_vec.begin();
while (iterator != all_core_memory_vec.end()) {
if (m_saved_stack_ranges.count(iterator->range.start()) > 0) {
// We don't save stacks twice.
ranges_32.push_back(*iterator);
total_size +=
iterator->range.size() + sizeof(llvm::minidump::MemoryDescriptor);
iterator = all_core_memory_ranges.erase(iterator);
iterator = all_core_memory_vec.erase(iterator);
} else {
iterator++;
}
Expand All @@ -869,11 +876,11 @@ Status MinidumpFileBuilder::AddMemoryList() {
// Then anything overflow extends into 64b addressable space.
// All core memeroy ranges will either container nothing on stacks only
// or all the memory ranges including stacks
if (!all_core_memory_ranges.empty())
total_size += 256 + (all_core_memory_ranges.size() *
if (!all_core_memory_vec.empty())
total_size += 256 + (all_core_memory_vec.size() *
sizeof(llvm::minidump::MemoryDescriptor_64));

for (const auto &core_range : all_core_memory_ranges) {
for (const auto &core_range : all_core_memory_vec) {
const addr_t range_size = core_range.range.size();
// We don't need to check for stacks here because we already removed them
// from all_core_memory_ranges.
Expand Down Expand Up @@ -958,15 +965,15 @@ Status MinidumpFileBuilder::DumpDirectories() const {
}

static uint64_t
GetLargestRangeSize(const Process::CoreFileMemoryRanges &ranges) {
GetLargestRangeSize(const std::vector<CoreFileMemoryRange> &ranges) {
uint64_t max_size = 0;
for (const auto &core_range : ranges)
max_size = std::max(max_size, core_range.range.size());
return max_size;
}

Status
MinidumpFileBuilder::AddMemoryList_32(Process::CoreFileMemoryRanges &ranges) {
Status MinidumpFileBuilder::AddMemoryList_32(
std::vector<CoreFileMemoryRange> &ranges) {
std::vector<MemoryDescriptor> descriptors;
Status error;
if (ranges.size() == 0)
Expand Down Expand Up @@ -1042,8 +1049,8 @@ MinidumpFileBuilder::AddMemoryList_32(Process::CoreFileMemoryRanges &ranges) {
return error;
}

Status
MinidumpFileBuilder::AddMemoryList_64(Process::CoreFileMemoryRanges &ranges) {
Status MinidumpFileBuilder::AddMemoryList_64(
std::vector<CoreFileMemoryRange> &ranges) {
Status error;
if (ranges.empty())
return error;
Expand Down
5 changes: 3 additions & 2 deletions lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <utility>
#include <variant>

#include "lldb/Symbol/SaveCoreOptions.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
Expand Down Expand Up @@ -120,9 +121,9 @@ class MinidumpFileBuilder {
lldb_private::Status AddData(const void *data, uint64_t size);
// Add MemoryList stream, containing dumps of important memory segments
lldb_private::Status
AddMemoryList_64(lldb_private::Process::CoreFileMemoryRanges &ranges);
AddMemoryList_64(std::vector<lldb_private::CoreFileMemoryRange> &ranges);
lldb_private::Status
AddMemoryList_32(lldb_private::Process::CoreFileMemoryRanges &ranges);
AddMemoryList_32(std::vector<lldb_private::CoreFileMemoryRange> &ranges);
// Update the thread list on disk with the newly emitted stack RVAs.
lldb_private::Status FixThreadStacks();
lldb_private::Status FlushBufferToDisk();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_OBJECTFILEMINIDUMP_H

#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SaveCoreOptions.h"
#include "lldb/Utility/ArchSpec.h"

class ObjectFileMinidump : public lldb_private::PluginInterface {
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "lldb/Interpreter/OptionValueDictionary.h"
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SaveCoreOptions.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <vector>

#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SaveCoreOptions.h"
#include "llvm/Object/COFF.h"

class ObjectFilePECOFF : public lldb_private::ObjectFile {
Expand Down
Loading

0 comments on commit 96b7c64

Please sign in to comment.