Skip to content

Commit f1bd931

Browse files
committed
Centralize the code that figures out which memory ranges to save into core files.
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 f1bd931

File tree

8 files changed

+267
-169
lines changed

8 files changed

+267
-169
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)