Skip to content

Commit 215bacb

Browse files
authored
Centralize the code that figures out which memory ranges to save into core files (#71772)
Prior to this patch, each core file plugin (ObjectFileMachO.cpp and ObjectFileMinindump.cpp) would calculate the address ranges to save in different ways. This patch adds a new function to Process.h/.cpp: ``` Status Process::CalculateCoreFileSaveRanges(lldb::SaveCoreStyle core_style, CoreFileMemoryRanges &ranges); ``` The patch updates the ObjectFileMachO::SaveCore(...) and ObjectFileMinindump::SaveCore(...) to use same code. This will allow core files to be consistent with the lldb::SaveCoreStyle across different core file creators and will allow us to add new core file saving features that do more complex things in future patches.
1 parent e70d2a4 commit 215bacb

File tree

9 files changed

+361
-212
lines changed

9 files changed

+361
-212
lines changed

lldb/include/lldb/Target/MemoryRegionInfo.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ class MemoryRegionInfo {
8181
// lldb::Permissions
8282
uint32_t GetLLDBPermissions() const {
8383
uint32_t permissions = 0;
84-
if (m_read)
84+
if (m_read == eYes)
8585
permissions |= lldb::ePermissionsReadable;
86-
if (m_write)
86+
if (m_write == eYes)
8787
permissions |= lldb::ePermissionsWritable;
88-
if (m_execute)
88+
if (m_execute == eYes)
8989
permissions |= lldb::ePermissionsExecutable;
9090
return permissions;
9191
}
@@ -151,7 +151,7 @@ class MemoryRegionInfo {
151151
int m_pagesize = 0;
152152
std::optional<std::vector<lldb::addr_t>> m_dirty_pages;
153153
};
154-
154+
155155
inline bool operator<(const MemoryRegionInfo &lhs,
156156
const MemoryRegionInfo &rhs) {
157157
return lhs.GetRange() < rhs.GetRange();

lldb/include/lldb/Target/Process.h

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include "lldb/Utility/UserIDResolver.h"
5555
#include "lldb/lldb-private.h"
5656

57+
#include "llvm/ADT/AddressRanges.h"
5758
#include "llvm/ADT/ArrayRef.h"
5859
#include "llvm/Support/Threading.h"
5960
#include "llvm/Support/VersionTuple.h"
@@ -354,12 +355,10 @@ class Process : public std::enable_shared_from_this<Process>,
354355
};
355356
// This is all the event bits the public process broadcaster broadcasts.
356357
// The process shadow listener signs up for all these bits...
357-
static constexpr int g_all_event_bits = eBroadcastBitStateChanged
358-
| eBroadcastBitInterrupt
359-
| eBroadcastBitSTDOUT
360-
| eBroadcastBitSTDERR
361-
| eBroadcastBitProfileData
362-
| eBroadcastBitStructuredData;
358+
static constexpr int g_all_event_bits =
359+
eBroadcastBitStateChanged | eBroadcastBitInterrupt | eBroadcastBitSTDOUT |
360+
eBroadcastBitSTDERR | eBroadcastBitProfileData |
361+
eBroadcastBitStructuredData;
363362

364363
enum {
365364
eBroadcastInternalStateControlStop = (1 << 0),
@@ -390,7 +389,7 @@ class Process : public std::enable_shared_from_this<Process>,
390389
ConstString &GetBroadcasterClass() const override {
391390
return GetStaticBroadcasterClass();
392391
}
393-
392+
394393
/// A notification structure that can be used by clients to listen
395394
/// for changes in a process's lifetime.
396395
///
@@ -579,7 +578,7 @@ class Process : public std::enable_shared_from_this<Process>,
579578
/// of CommandObject like CommandObjectRaw, CommandObjectParsed,
580579
/// or CommandObjectMultiword.
581580
virtual CommandObject *GetPluginCommandObject() { return nullptr; }
582-
581+
583582
/// The underlying plugin might store the low-level communication history for
584583
/// this session. Dump it into the provided stream.
585584
virtual void DumpPluginHistory(Stream &s) { return; }
@@ -614,7 +613,7 @@ class Process : public std::enable_shared_from_this<Process>,
614613
return error;
615614
}
616615

617-
/// The "ShadowListener" for a process is just an ordinary Listener that
616+
/// The "ShadowListener" for a process is just an ordinary Listener that
618617
/// listens for all the Process event bits. It's convenient because you can
619618
/// specify it in the LaunchInfo or AttachInfo, so it will get events from
620619
/// the very start of the process.
@@ -704,6 +703,35 @@ class Process : public std::enable_shared_from_this<Process>,
704703
/// is not supported by the plugin, error otherwise.
705704
virtual llvm::Expected<bool> SaveCore(llvm::StringRef outfile);
706705

706+
struct CoreFileMemoryRange {
707+
llvm::AddressRange range; /// The address range to save into the core file.
708+
uint32_t lldb_permissions; /// A bit set of lldb::Permissions bits.
709+
710+
bool operator==(const CoreFileMemoryRange &rhs) const {
711+
return range == rhs.range && lldb_permissions == rhs.lldb_permissions;
712+
}
713+
714+
bool operator!=(const CoreFileMemoryRange &rhs) const {
715+
return !(*this == rhs);
716+
}
717+
718+
bool operator<(const CoreFileMemoryRange &rhs) const {
719+
if (range < rhs.range)
720+
return true;
721+
if (range == rhs.range)
722+
return lldb_permissions < rhs.lldb_permissions;
723+
return false;
724+
}
725+
};
726+
727+
using CoreFileMemoryRanges = std::vector<CoreFileMemoryRange>;
728+
729+
/// Helper function for Process::SaveCore(...) that calculates the address
730+
/// ranges that should be saved. This allows all core file plug-ins to save
731+
/// consistent memory ranges given a \a core_style.
732+
Status CalculateCoreFileSaveRanges(lldb::SaveCoreStyle core_style,
733+
CoreFileMemoryRanges &ranges);
734+
707735
protected:
708736
virtual JITLoaderList &GetJITLoaders();
709737

lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp

Lines changed: 28 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -6476,9 +6476,8 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
64766476
return false;
64776477

64786478
// Default on macOS is to create a dirty-memory-only corefile.
6479-
if (core_style == SaveCoreStyle::eSaveCoreUnspecified) {
6479+
if (core_style == SaveCoreStyle::eSaveCoreUnspecified)
64806480
core_style = SaveCoreStyle::eSaveCoreDirtyOnly;
6481-
}
64826481

64836482
Target &target = process_sp->GetTarget();
64846483
const ArchSpec target_arch = target.GetArchitecture();
@@ -6507,115 +6506,42 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
65076506
}
65086507

65096508
if (make_core) {
6510-
std::vector<llvm::MachO::segment_command_64> segment_load_commands;
6511-
// uint32_t range_info_idx = 0;
6512-
MemoryRegionInfo range_info;
6513-
Status range_error = process_sp->GetMemoryRegionInfo(0, range_info);
6514-
const uint32_t addr_byte_size = target_arch.GetAddressByteSize();
6515-
const ByteOrder byte_order = target_arch.GetByteOrder();
6516-
std::vector<page_object> pages_to_copy;
6517-
6518-
if (range_error.Success()) {
6519-
while (range_info.GetRange().GetRangeBase() != LLDB_INVALID_ADDRESS) {
6520-
// Calculate correct protections
6521-
uint32_t prot = 0;
6522-
if (range_info.GetReadable() == MemoryRegionInfo::eYes)
6523-
prot |= VM_PROT_READ;
6524-
if (range_info.GetWritable() == MemoryRegionInfo::eYes)
6525-
prot |= VM_PROT_WRITE;
6526-
if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
6527-
prot |= VM_PROT_EXECUTE;
6528-
6529-
const addr_t addr = range_info.GetRange().GetRangeBase();
6530-
const addr_t size = range_info.GetRange().GetByteSize();
6531-
6532-
if (size == 0)
6533-
break;
6534-
6535-
bool include_this_region = true;
6536-
bool dirty_pages_only = false;
6537-
if (core_style == SaveCoreStyle::eSaveCoreStackOnly) {
6538-
dirty_pages_only = true;
6539-
if (range_info.IsStackMemory() != MemoryRegionInfo::eYes) {
6540-
include_this_region = false;
6541-
}
6542-
}
6543-
if (core_style == SaveCoreStyle::eSaveCoreDirtyOnly) {
6544-
dirty_pages_only = true;
6545-
}
6546-
6547-
if (prot != 0 && include_this_region) {
6548-
addr_t pagesize = range_info.GetPageSize();
6549-
const std::optional<std::vector<addr_t>> &dirty_page_list =
6550-
range_info.GetDirtyPageList();
6551-
if (dirty_pages_only && dirty_page_list) {
6552-
for (addr_t dirtypage : *dirty_page_list) {
6553-
page_object obj;
6554-
obj.addr = dirtypage;
6555-
obj.size = pagesize;
6556-
obj.prot = prot;
6557-
pages_to_copy.push_back(obj);
6558-
}
6559-
} else {
6560-
page_object obj;
6561-
obj.addr = addr;
6562-
obj.size = size;
6563-
obj.prot = prot;
6564-
pages_to_copy.push_back(obj);
6565-
}
6566-
}
6567-
6568-
range_error = process_sp->GetMemoryRegionInfo(
6569-
range_info.GetRange().GetRangeEnd(), range_info);
6570-
if (range_error.Fail())
6571-
break;
6572-
}
6573-
6574-
// Combine contiguous entries that have the same
6575-
// protections so we don't have an excess of
6576-
// load commands.
6577-
std::vector<page_object> combined_page_objects;
6578-
page_object last_obj;
6579-
last_obj.addr = LLDB_INVALID_ADDRESS;
6580-
last_obj.size = 0;
6581-
for (page_object obj : pages_to_copy) {
6582-
if (last_obj.addr == LLDB_INVALID_ADDRESS) {
6583-
last_obj = obj;
6584-
continue;
6585-
}
6586-
if (last_obj.addr + last_obj.size == obj.addr &&
6587-
last_obj.prot == obj.prot) {
6588-
last_obj.size += obj.size;
6589-
continue;
6590-
}
6591-
combined_page_objects.push_back(last_obj);
6592-
last_obj = obj;
6593-
}
6594-
// Add the last entry we were looking to combine
6595-
// on to the array.
6596-
if (last_obj.addr != LLDB_INVALID_ADDRESS && last_obj.size != 0)
6597-
combined_page_objects.push_back(last_obj);
6598-
6599-
for (page_object obj : combined_page_objects) {
6509+
Process::CoreFileMemoryRanges core_ranges;
6510+
error = process_sp->CalculateCoreFileSaveRanges(core_style, core_ranges);
6511+
if (error.Success()) {
6512+
const uint32_t addr_byte_size = target_arch.GetAddressByteSize();
6513+
const ByteOrder byte_order = target_arch.GetByteOrder();
6514+
std::vector<llvm::MachO::segment_command_64> segment_load_commands;
6515+
for (const auto &core_range : core_ranges) {
66006516
uint32_t cmd_type = LC_SEGMENT_64;
66016517
uint32_t segment_size = sizeof(llvm::MachO::segment_command_64);
66026518
if (addr_byte_size == 4) {
66036519
cmd_type = LC_SEGMENT;
66046520
segment_size = sizeof(llvm::MachO::segment_command);
66056521
}
6522+
// Skip any ranges with no read/write/execute permissions and empty
6523+
// ranges.
6524+
if (core_range.lldb_permissions == 0 || core_range.range.size() == 0)
6525+
continue;
6526+
uint32_t vm_prot = 0;
6527+
if (core_range.lldb_permissions & ePermissionsReadable)
6528+
vm_prot |= VM_PROT_READ;
6529+
if (core_range.lldb_permissions & ePermissionsWritable)
6530+
vm_prot |= VM_PROT_WRITE;
6531+
if (core_range.lldb_permissions & ePermissionsExecutable)
6532+
vm_prot |= VM_PROT_EXECUTE;
6533+
const addr_t vm_addr = core_range.range.start();
6534+
const addr_t vm_size = core_range.range.size();
66066535
llvm::MachO::segment_command_64 segment = {
66076536
cmd_type, // uint32_t cmd;
66086537
segment_size, // uint32_t cmdsize;
66096538
{0}, // char segname[16];
6610-
obj.addr, // uint64_t vmaddr; // uint32_t for 32-bit
6611-
// Mach-O
6612-
obj.size, // uint64_t vmsize; // uint32_t for 32-bit
6613-
// Mach-O
6614-
0, // uint64_t fileoff; // uint32_t for 32-bit Mach-O
6615-
obj.size, // uint64_t filesize; // uint32_t for 32-bit
6616-
// Mach-O
6617-
obj.prot, // uint32_t maxprot;
6618-
obj.prot, // uint32_t initprot;
6539+
vm_addr, // uint64_t vmaddr; // uint32_t for 32-bit Mach-O
6540+
vm_size, // uint64_t vmsize; // uint32_t for 32-bit Mach-O
6541+
0, // uint64_t fileoff; // uint32_t for 32-bit Mach-O
6542+
vm_size, // uint64_t filesize; // uint32_t for 32-bit Mach-O
6543+
vm_prot, // uint32_t maxprot;
6544+
vm_prot, // uint32_t initprot;
66196545
0, // uint32_t nsects;
66206546
0}; // uint32_t flags;
66216547
segment_load_commands.push_back(segment);
@@ -6624,11 +6550,7 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
66246550
StreamString buffer(Stream::eBinary, addr_byte_size, byte_order);
66256551

66266552
llvm::MachO::mach_header_64 mach_header;
6627-
if (addr_byte_size == 8) {
6628-
mach_header.magic = MH_MAGIC_64;
6629-
} else {
6630-
mach_header.magic = MH_MAGIC;
6631-
}
6553+
mach_header.magic = addr_byte_size == 8 ? MH_MAGIC_64 : MH_MAGIC;
66326554
mach_header.cputype = target_arch.GetMachOCPUType();
66336555
mach_header.cpusubtype = target_arch.GetMachOCPUSubType();
66346556
mach_header.filetype = MH_CORE;
@@ -6913,9 +6835,6 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
69136835
}
69146836
}
69156837
}
6916-
} else {
6917-
error.SetErrorString(
6918-
"process doesn't support getting memory region info");
69196838
}
69206839
}
69216840
return true; // This is the right plug to handle saving core files for

lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -557,43 +557,24 @@ Status MinidumpFileBuilder::AddException(const lldb::ProcessSP &process_sp) {
557557
}
558558

559559
lldb_private::Status
560-
MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp) {
560+
MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp,
561+
lldb::SaveCoreStyle core_style) {
561562
Status error;
562-
563+
Process::CoreFileMemoryRanges core_ranges;
564+
error = process_sp->CalculateCoreFileSaveRanges(core_style, core_ranges);
563565
if (error.Fail()) {
564566
error.SetErrorString("Process doesn't support getting memory region info.");
565567
return error;
566568
}
567569

568-
// Get interesting addresses
569-
std::vector<size_t> interesting_addresses;
570-
auto thread_list = process_sp->GetThreadList();
571-
for (size_t i = 0; i < thread_list.GetSize(); ++i) {
572-
ThreadSP thread_sp(thread_list.GetThreadAtIndex(i));
573-
RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
574-
RegisterContext *reg_ctx = reg_ctx_sp.get();
575-
576-
interesting_addresses.push_back(read_register_u64(reg_ctx, "rsp"));
577-
interesting_addresses.push_back(read_register_u64(reg_ctx, "rip"));
578-
}
579-
580570
DataBufferHeap helper_data;
581571
std::vector<MemoryDescriptor> mem_descriptors;
582-
583-
std::set<addr_t> visited_region_base_addresses;
584-
for (size_t interesting_address : interesting_addresses) {
585-
MemoryRegionInfo range_info;
586-
error = process_sp->GetMemoryRegionInfo(interesting_address, range_info);
587-
// Skip failed memory region requests or any regions with no permissions.
588-
if (error.Fail() || range_info.GetLLDBPermissions() == 0)
589-
continue;
590-
const addr_t addr = range_info.GetRange().GetRangeBase();
591-
// Skip any regions we have already saved out.
592-
if (visited_region_base_addresses.insert(addr).second == false)
593-
continue;
594-
const addr_t size = range_info.GetRange().GetByteSize();
595-
if (size == 0)
572+
for (const auto &core_range : core_ranges) {
573+
// Skip empty memory regions or any regions with no permissions.
574+
if (core_range.range.empty() || core_range.lldb_permissions == 0)
596575
continue;
576+
const addr_t addr = core_range.range.start();
577+
const addr_t size = core_range.range.size();
597578
auto data_up = std::make_unique<DataBufferHeap>(size, 0);
598579
const size_t bytes_read =
599580
process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);

lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ class MinidumpFileBuilder {
6464
// failed status.
6565
lldb_private::Status AddException(const lldb::ProcessSP &process_sp);
6666
// Add MemoryList stream, containing dumps of important memory segments
67-
lldb_private::Status AddMemoryList(const lldb::ProcessSP &process_sp);
67+
lldb_private::Status AddMemoryList(const lldb::ProcessSP &process_sp,
68+
lldb::SaveCoreStyle core_style);
6869
// Add MiscInfo stream, mainly providing ProcessId
6970
void AddMiscInfo(const lldb::ProcessSP &process_sp);
7071
// Add informative files about a Linux process

lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,9 @@ bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp,
5757
const lldb_private::FileSpec &outfile,
5858
lldb::SaveCoreStyle &core_style,
5959
lldb_private::Status &error) {
60-
if (core_style != SaveCoreStyle::eSaveCoreStackOnly) {
61-
error.SetErrorString("Only stack minidumps supported yet.");
62-
return false;
63-
}
60+
// Set default core style if it isn't set.
61+
if (core_style == SaveCoreStyle::eSaveCoreUnspecified)
62+
core_style = SaveCoreStyle::eSaveCoreStackOnly;
6463

6564
if (!process_sp)
6665
return false;
@@ -88,7 +87,7 @@ bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp,
8887
if (error.Fail())
8988
return false;
9089

91-
error = builder.AddMemoryList(process_sp);
90+
error = builder.AddMemoryList(process_sp, core_style);
9291
if (error.Fail())
9392
return false;
9493
}

0 commit comments

Comments
 (0)