[Lldb-commits] [lldb] 6cb1459 - [LLDB][Minidump] Fix ProcessMinidump::GetMemoryRegions to include 64b regions when /proc/pid maps are missing. (#101086)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Aug 21 10:25:26 PDT 2024
Author: Jacob Lalonde
Date: 2024-08-21T10:25:23-07:00
New Revision: 6cb14599ade843be3171fa7e4dd5f3601a3bb0de
URL: https://github.com/llvm/llvm-project/commit/6cb14599ade843be3171fa7e4dd5f3601a3bb0de
DIFF: https://github.com/llvm/llvm-project/commit/6cb14599ade843be3171fa7e4dd5f3601a3bb0de.diff
LOG: [LLDB][Minidump] Fix ProcessMinidump::GetMemoryRegions to include 64b regions when /proc/pid maps are missing. (#101086)
This PR is in response to a bug my coworker @mbucko discovered where on
MacOS Minidumps were being created where the 64b memory regions were
readable, but were not being listed in
`SBProcess.GetMemoryRegionList()`. This went unnoticed in #95312 due to
all the linux testing including /proc/pid maps. On MacOS generated dumps
(or any dump without access to /proc/pid) we would fail to properly map
Memory Regions due to there being two independent methods for 32b and
64b mapping.
In this PR I addressed this minor bug and merged the methods, but in
order to add test coverage required additions to `obj2yaml` and
`yaml2obj` which make up the bulk of this patch.
Lastly, there are some non-required changes such as the addition of the
`Memory64ListHeader` type, to make writing/reading the header section of
the Memory64List easier.
Added:
lldb/test/API/functionalities/postmortem/minidump-new/linux-x86_64_mem64.yaml
Modified:
lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
lldb/source/Plugins/Process/minidump/MinidumpParser.h
lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
lldb/source/Plugins/Process/minidump/MinidumpTypes.h
lldb/test/API/functionalities/postmortem/minidump-new/TestMiniDumpNew.py
Removed:
################################################################################
diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
index c0cc3af638a777..4b862d8d8e99b8 100644
--- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
+++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
@@ -1014,15 +1014,17 @@ MinidumpFileBuilder::AddMemoryList_32(Process::CoreFileMemoryRanges &ranges) {
// With a size of the number of ranges as a 32 bit num
// And then the size of all the ranges
error = AddDirectory(StreamType::MemoryList,
- sizeof(llvm::support::ulittle32_t) +
+ sizeof(llvm::minidump::MemoryListHeader) +
descriptors.size() *
sizeof(llvm::minidump::MemoryDescriptor));
if (error.Fail())
return error;
+ llvm::minidump::MemoryListHeader list_header;
llvm::support::ulittle32_t memory_ranges_num =
static_cast<llvm::support::ulittle32_t>(descriptors.size());
- m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
+ list_header.NumberOfMemoryRanges = memory_ranges_num;
+ m_data.AppendData(&list_header, sizeof(llvm::minidump::MemoryListHeader));
// For 32b we can get away with writing off the descriptors after the data.
// This means no cleanup loop needed.
m_data.AppendData(descriptors.data(),
@@ -1044,9 +1046,10 @@ MinidumpFileBuilder::AddMemoryList_64(Process::CoreFileMemoryRanges &ranges) {
if (error.Fail())
return error;
+ llvm::minidump::Memory64ListHeader list_header;
llvm::support::ulittle64_t memory_ranges_num =
static_cast<llvm::support::ulittle64_t>(ranges.size());
- m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle64_t));
+ list_header.NumberOfMemoryRanges = memory_ranges_num;
// Capture the starting offset for all the descriptors so we can clean them up
// if needed.
offset_t starting_offset =
@@ -1058,8 +1061,8 @@ MinidumpFileBuilder::AddMemoryList_64(Process::CoreFileMemoryRanges &ranges) {
(ranges.size() * sizeof(llvm::minidump::MemoryDescriptor_64));
llvm::support::ulittle64_t memory_ranges_base_rva =
static_cast<llvm::support::ulittle64_t>(base_rva);
- m_data.AppendData(&memory_ranges_base_rva,
- sizeof(llvm::support::ulittle64_t));
+ list_header.BaseRVA = memory_ranges_base_rva;
+ m_data.AppendData(&list_header, sizeof(llvm::minidump::Memory64ListHeader));
bool cleanup_required = false;
std::vector<MemoryDescriptor_64> descriptors;
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
index be9fae938e2276..c099c28a620ecf 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
+++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -429,7 +429,6 @@ const minidump::ExceptionStream *MinidumpParser::GetExceptionStream() {
std::optional<minidump::Range>
MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
- llvm::ArrayRef<uint8_t> data64 = GetStream(StreamType::Memory64List);
Log *log = GetLog(LLDBLog::Modules);
auto ExpectedMemory = GetMinidumpFile().getMemoryList();
@@ -457,33 +456,17 @@ MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
}
}
- // Some Minidumps have a Memory64ListStream that captures all the heap memory
- // (full-memory Minidumps). We can't exactly use the same loop as above,
- // because the Minidump uses slightly
diff erent data structures to describe
- // those
-
- if (!data64.empty()) {
- llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
- uint64_t base_rva;
- std::tie(memory64_list, base_rva) =
- MinidumpMemoryDescriptor64::ParseMemory64List(data64);
-
- if (memory64_list.empty())
- return std::nullopt;
-
- for (const auto &memory_desc64 : memory64_list) {
- const lldb::addr_t range_start = memory_desc64.start_of_memory_range;
- const size_t range_size = memory_desc64.data_size;
-
- if (base_rva + range_size > GetData().size())
- return std::nullopt;
-
- if (range_start <= addr && addr < range_start + range_size) {
- return minidump::Range(range_start,
- GetData().slice(base_rva, range_size));
+ if (!GetStream(StreamType::Memory64List).empty()) {
+ llvm::Error err = llvm::Error::success();
+ for (const auto &memory_desc : GetMinidumpFile().getMemory64List(err)) {
+ if (memory_desc.first.StartOfMemoryRange <= addr
+ && addr < memory_desc.first.StartOfMemoryRange + memory_desc.first.DataSize) {
+ return minidump::Range(memory_desc.first.StartOfMemoryRange, memory_desc.second);
}
- base_rva += range_size;
}
+
+ if (err)
+ LLDB_LOG_ERROR(log, std::move(err), "Failed to read memory64 list: {0}");
}
return std::nullopt;
@@ -512,6 +495,11 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
return range->range_ref.slice(offset, overlap);
}
+llvm::iterator_range<FallibleMemory64Iterator> MinidumpParser::GetMemory64Iterator(llvm::Error &err) {
+ llvm::ErrorAsOutParameter ErrAsOutParam(&err);
+ return m_file->getMemory64List(err);
+}
+
static bool
CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,
std::vector<MemoryRegionInfo> ®ions) {
@@ -553,53 +541,44 @@ static bool
CreateRegionsCacheFromMemoryList(MinidumpParser &parser,
std::vector<MemoryRegionInfo> ®ions) {
Log *log = GetLog(LLDBLog::Modules);
+ // Cache the expected memory32 into an optional
+ // because it is possible to just have a memory64 list
auto ExpectedMemory = parser.GetMinidumpFile().getMemoryList();
if (!ExpectedMemory) {
LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),
"Failed to read memory list: {0}");
- return false;
- }
- regions.reserve(ExpectedMemory->size());
- for (const MemoryDescriptor &memory_desc : *ExpectedMemory) {
- if (memory_desc.Memory.DataSize == 0)
- continue;
- MemoryRegionInfo region;
- region.GetRange().SetRangeBase(memory_desc.StartOfMemoryRange);
- region.GetRange().SetByteSize(memory_desc.Memory.DataSize);
- region.SetReadable(MemoryRegionInfo::eYes);
- region.SetMapped(MemoryRegionInfo::eYes);
- regions.push_back(region);
+ } else {
+ for (const MemoryDescriptor &memory_desc : *ExpectedMemory) {
+ if (memory_desc.Memory.DataSize == 0)
+ continue;
+ MemoryRegionInfo region;
+ region.GetRange().SetRangeBase(memory_desc.StartOfMemoryRange);
+ region.GetRange().SetByteSize(memory_desc.Memory.DataSize);
+ region.SetReadable(MemoryRegionInfo::eYes);
+ region.SetMapped(MemoryRegionInfo::eYes);
+ regions.push_back(region);
+ }
}
- regions.shrink_to_fit();
- return !regions.empty();
-}
-
-static bool
-CreateRegionsCacheFromMemory64List(MinidumpParser &parser,
- std::vector<MemoryRegionInfo> ®ions) {
- llvm::ArrayRef<uint8_t> data =
- parser.GetStream(StreamType::Memory64List);
- if (data.empty())
- return false;
- llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
- uint64_t base_rva;
- std::tie(memory64_list, base_rva) =
- MinidumpMemoryDescriptor64::ParseMemory64List(data);
- if (memory64_list.empty())
- return false;
+ if (!parser.GetStream(StreamType::Memory64List).empty()) {
+ llvm::Error err = llvm::Error::success();
+ for (const auto &memory_desc : parser.GetMemory64Iterator(err)) {
+ if (memory_desc.first.DataSize == 0)
+ continue;
+ MemoryRegionInfo region;
+ region.GetRange().SetRangeBase(memory_desc.first.StartOfMemoryRange);
+ region.GetRange().SetByteSize(memory_desc.first.DataSize);
+ region.SetReadable(MemoryRegionInfo::eYes);
+ region.SetMapped(MemoryRegionInfo::eYes);
+ regions.push_back(region);
+ }
- regions.reserve(memory64_list.size());
- for (const auto &memory_desc : memory64_list) {
- if (memory_desc.data_size == 0)
- continue;
- MemoryRegionInfo region;
- region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);
- region.GetRange().SetByteSize(memory_desc.data_size);
- region.SetReadable(MemoryRegionInfo::eYes);
- region.SetMapped(MemoryRegionInfo::eYes);
- regions.push_back(region);
+ if (err) {
+ LLDB_LOG_ERROR(log, std::move(err), "Failed to read memory64 list: {0}");
+ return false;
+ }
}
+
regions.shrink_to_fit();
return !regions.empty();
}
@@ -620,9 +599,7 @@ std::pair<MemoryRegionInfos, bool> MinidumpParser::BuildMemoryRegions() {
return return_sorted(true);
if (CreateRegionsCacheFromMemoryInfoList(*this, result))
return return_sorted(true);
- if (CreateRegionsCacheFromMemoryList(*this, result))
- return return_sorted(false);
- CreateRegionsCacheFromMemory64List(*this, result);
+ CreateRegionsCacheFromMemoryList(*this, result);
return return_sorted(false);
}
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/lldb/source/Plugins/Process/minidump/MinidumpParser.h
index 050ba086f46f54..222c0ef47fb853 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpParser.h
+++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.h
@@ -47,6 +47,8 @@ struct Range {
}
};
+using FallibleMemory64Iterator = llvm::object::MinidumpFile::FallibleMemory64Iterator;
+
class MinidumpParser {
public:
static llvm::Expected<MinidumpParser>
@@ -92,6 +94,8 @@ class MinidumpParser {
/// complete (includes all regions mapped into the process memory).
std::pair<MemoryRegionInfos, bool> BuildMemoryRegions();
+ llvm::iterator_range<FallibleMemory64Iterator> GetMemory64Iterator(llvm::Error &err);
+
static llvm::StringRef GetStreamTypeAsString(StreamType stream_type);
llvm::object::MinidumpFile &GetMinidumpFile() { return *m_file; }
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp b/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
index 5b919828428fae..45dd2272aef041 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
+++ b/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
@@ -57,23 +57,3 @@ LinuxProcStatus::Parse(llvm::ArrayRef<uint8_t> &data) {
}
lldb::pid_t LinuxProcStatus::GetPid() const { return pid; }
-
-std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
-MinidumpMemoryDescriptor64::ParseMemory64List(llvm::ArrayRef<uint8_t> &data) {
- const llvm::support::ulittle64_t *mem_ranges_count;
- Status error = consumeObject(data, mem_ranges_count);
- if (error.Fail() ||
- *mem_ranges_count * sizeof(MinidumpMemoryDescriptor64) > data.size())
- return {};
-
- const llvm::support::ulittle64_t *base_rva;
- error = consumeObject(data, base_rva);
- if (error.Fail())
- return {};
-
- return std::make_pair(
- llvm::ArrayRef(
- reinterpret_cast<const MinidumpMemoryDescriptor64 *>(data.data()),
- *mem_ranges_count),
- *base_rva);
-}
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpTypes.h b/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
index fe99abf9e24ed9..9a9f1cc1578336 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
+++ b/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
@@ -62,9 +62,6 @@ Status consumeObject(llvm::ArrayRef<uint8_t> &Buffer, const T *&Object) {
struct MinidumpMemoryDescriptor64 {
llvm::support::ulittle64_t start_of_memory_range;
llvm::support::ulittle64_t data_size;
-
- static std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
- ParseMemory64List(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpMemoryDescriptor64) == 16,
"sizeof MinidumpMemoryDescriptor64 is not correct!");
diff --git a/lldb/test/API/functionalities/postmortem/minidump-new/TestMiniDumpNew.py b/lldb/test/API/functionalities/postmortem/minidump-new/TestMiniDumpNew.py
index 91fd2439492b54..2de3e36b507341 100644
--- a/lldb/test/API/functionalities/postmortem/minidump-new/TestMiniDumpNew.py
+++ b/lldb/test/API/functionalities/postmortem/minidump-new/TestMiniDumpNew.py
@@ -491,3 +491,22 @@ def test_minidump_sysroot(self):
spec_dir_norm = os.path.normcase(module.GetFileSpec().GetDirectory())
exe_dir_norm = os.path.normcase(exe_dir)
self.assertEqual(spec_dir_norm, exe_dir_norm)
+
+ def test_minidump_memory64list(self):
+ """Test that lldb can read from the memory64list in a minidump."""
+ self.process_from_yaml("linux-x86_64_mem64.yaml")
+
+ region_count = 3
+ region_info_list = self.process.GetMemoryRegions()
+ self.assertEqual(region_info_list.GetSize(), region_count)
+
+ region = lldb.SBMemoryRegionInfo()
+ self.assertTrue(region_info_list.GetMemoryRegionAtIndex(0, region))
+ self.assertEqual(region.GetRegionBase(), 0x7FFF12A84030)
+ self.assertTrue(region.GetRegionEnd(), 0x7FFF12A84030 + 0x2FD0)
+ self.assertTrue(region_info_list.GetMemoryRegionAtIndex(1, region))
+ self.assertEqual(region.GetRegionBase(), 0x00007fff12a87000)
+ self.assertTrue(region.GetRegionEnd(), 0x00007fff12a87000 + 0x00000018)
+ self.assertTrue(region_info_list.GetMemoryRegionAtIndex(2, region))
+ self.assertEqual(region.GetRegionBase(), 0x00007fff12a87018)
+ self.assertTrue(region.GetRegionEnd(), 0x00007fff12a87018 + 0x00000400)
diff --git a/lldb/test/API/functionalities/postmortem/minidump-new/linux-x86_64_mem64.yaml b/lldb/test/API/functionalities/postmortem/minidump-new/linux-x86_64_mem64.yaml
new file mode 100644
index 00000000000000..df3c6477ae50a0
--- /dev/null
+++ b/lldb/test/API/functionalities/postmortem/minidump-new/linux-x86_64_mem64.yaml
@@ -0,0 +1,43 @@
+--- !minidump
+Streams:
+ - Type: SystemInfo
+ Processor Arch: AMD64
+ Processor Level: 6
+ Processor Revision: 15876
+ Number of Processors: 40
+ Platform ID: Linux
+ CSD Version: 'Linux 3.13.0-91-generic'
+ CPU:
+ Vendor ID: GenuineIntel
+ Version Info: 0x00000000
+ Feature Info: 0x00000000
+ - Type: LinuxProcStatus
+ Text: |
+ Name: linux-x86_64
+ State: t (tracing stop)
+ Tgid: 29917
+ Ngid: 0
+ Pid: 29917
+ PPid: 29370
+ TracerPid: 29918
+ Uid: 1001 1001 1001 1001
+ Gid: 1001 1001 1001 1001
+ - Type: ThreadList
+ Threads:
+ - Thread Id: 0x2896BB
+ Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000700100000000000FFFFFFFF0000FFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B040A812FF7F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050D0A75BBA7F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ Stack:
+ Start of Memory Range: 0x0
+ Content: ''
+ - Type: Memory64List
+ Memory Ranges:
+ - Start of Memory Range: 0x7FFF12A84030
+ Data Size: 0x2FD0
+ Content : ''
+ - Start of Memory Range: 0x00007fff12a87000
+ Data Size: 0x00000018
+ Content : ''
+ - Start of Memory Range: 0x00007fff12a87018
+ Data Size: 0x00000400
+ Content : ''
+...
More information about the lldb-commits
mailing list