summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/source/Plugins/Process/minidump/MinidumpParser.cpp200
-rw-r--r--lldb/source/Plugins/Process/minidump/MinidumpParser.h24
-rw-r--r--lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp57
-rw-r--r--lldb/source/Plugins/Process/minidump/MinidumpTypes.h77
-rw-r--r--lldb/unittests/Process/minidump/CMakeLists.txt4
-rw-r--r--lldb/unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmpbin0 -> 9280561 bytes
-rw-r--r--lldb/unittests/Process/minidump/Inputs/linux-x86_64_not_crashed.dmpbin0 -> 63744 bytes
-rw-r--r--lldb/unittests/Process/minidump/MinidumpParserTest.cpp104
8 files changed, 464 insertions, 2 deletions
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
index 2ccea6839cb..abb0810c813 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
+++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -11,8 +11,11 @@
#include "MinidumpParser.h"
// Other libraries and framework includes
+#include "lldb/Target/MemoryRegionInfo.h"
+
// C includes
// C++ includes
+#include <map>
using namespace lldb_private;
using namespace minidump;
@@ -100,6 +103,14 @@ llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() {
return MinidumpThread::ParseThreadList(data);
}
+llvm::ArrayRef<uint8_t>
+MinidumpParser::GetThreadContext(const MinidumpThread &td) {
+ if (td.thread_context.rva + td.thread_context.data_size > GetData().size())
+ return llvm::None;
+
+ return GetData().slice(td.thread_context.rva, td.thread_context.data_size);
+}
+
const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo);
@@ -216,6 +227,42 @@ llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() {
return MinidumpModule::ParseModuleList(data);
}
+std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() {
+ llvm::ArrayRef<MinidumpModule> modules = GetModuleList();
+ // mapping module_name to pair(load_address, pointer to module struct in
+ // memory)
+ llvm::StringMap<std::pair<uint64_t, const MinidumpModule *>> lowest_addr;
+
+ std::vector<const MinidumpModule *> filtered_modules;
+
+ llvm::Optional<std::string> name;
+ std::string module_name;
+
+ for (const auto &module : modules) {
+ name = GetMinidumpString(module.module_name_rva);
+
+ if (!name)
+ continue;
+
+ module_name = name.getValue();
+
+ auto iter = lowest_addr.end();
+ bool exists;
+ std::tie(iter, exists) = lowest_addr.try_emplace(
+ module_name, std::make_pair(module.base_of_image, &module));
+
+ if (exists && module.base_of_image < iter->second.first)
+ iter->second = std::make_pair(module.base_of_image, &module);
+ }
+
+ filtered_modules.reserve(lowest_addr.size());
+ for (const auto &module : lowest_addr) {
+ filtered_modules.push_back(module.second.second);
+ }
+
+ return filtered_modules;
+}
+
const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::Exception);
@@ -224,3 +271,156 @@ const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() {
return MinidumpExceptionStream::Parse(data);
}
+
+llvm::Optional<minidump::Range>
+MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
+ llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryList);
+ llvm::ArrayRef<uint8_t> data64 = GetStream(MinidumpStreamType::Memory64List);
+
+ if (data.empty() && data64.empty())
+ return llvm::None;
+
+ if (!data.empty()) {
+ llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list =
+ MinidumpMemoryDescriptor::ParseMemoryList(data);
+
+ if (memory_list.empty())
+ return llvm::None;
+
+ for (const auto &memory_desc : memory_list) {
+ const MinidumpLocationDescriptor &loc_desc = memory_desc.memory;
+ const lldb::addr_t range_start = memory_desc.start_of_memory_range;
+ const size_t range_size = loc_desc.data_size;
+
+ if (loc_desc.rva + loc_desc.data_size > GetData().size())
+ return llvm::None;
+
+ if (range_start <= addr && addr < range_start + range_size) {
+ return minidump::Range(range_start,
+ GetData().slice(loc_desc.rva, range_size));
+ }
+ }
+ }
+
+ // 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 different 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 llvm::None;
+
+ 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 llvm::None;
+
+ if (range_start <= addr && addr < range_start + range_size) {
+ return minidump::Range(range_start,
+ GetData().slice(base_rva, range_size));
+ }
+ base_rva += range_size;
+ }
+ }
+
+ return llvm::None;
+}
+
+llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
+ size_t size) {
+ // I don't have a sense of how frequently this is called or how many memory
+ // ranges a Minidump typically has, so I'm not sure if searching for the
+ // appropriate range linearly each time is stupid. Perhaps we should build
+ // an index for faster lookups.
+ llvm::Optional<minidump::Range> range = FindMemoryRange(addr);
+ if (!range)
+ return {};
+
+ // There's at least some overlap between the beginning of the desired range
+ // (addr) and the current range. Figure out where the overlap begins and
+ // how much overlap there is.
+
+ const size_t offset = addr - range->start;
+
+ if (addr < range->start || offset >= range->range_ref.size())
+ return {};
+
+ const size_t overlap = std::min(size, range->range_ref.size() - offset);
+ return range->range_ref.slice(offset, overlap);
+}
+
+llvm::Optional<MemoryRegionInfo>
+MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) {
+ MemoryRegionInfo info;
+ llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryInfoList);
+ if (data.empty())
+ return llvm::None;
+
+ std::vector<const MinidumpMemoryInfo *> mem_info_list =
+ MinidumpMemoryInfo::ParseMemoryInfoList(data);
+ if (mem_info_list.empty())
+ return llvm::None;
+
+ const auto yes = MemoryRegionInfo::eYes;
+ const auto no = MemoryRegionInfo::eNo;
+
+ const MinidumpMemoryInfo *next_entry = nullptr;
+ for (const auto &entry : mem_info_list) {
+ const auto head = entry->base_address;
+ const auto tail = head + entry->region_size;
+
+ if (head <= load_addr && load_addr < tail) {
+ info.GetRange().SetRangeBase(
+ (entry->state != uint32_t(MinidumpMemoryInfoState::MemFree))
+ ? head
+ : load_addr);
+ info.GetRange().SetRangeEnd(tail);
+
+ const uint32_t PageNoAccess =
+ static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageNoAccess);
+ info.SetReadable((entry->protect & PageNoAccess) == 0 ? yes : no);
+
+ const uint32_t PageWritable =
+ static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageWritable);
+ info.SetWritable((entry->protect & PageWritable) != 0 ? yes : no);
+
+ const uint32_t PageExecutable = static_cast<uint32_t>(
+ MinidumpMemoryProtectionContants::PageExecutable);
+ info.SetExecutable((entry->protect & PageExecutable) != 0 ? yes : no);
+
+ const uint32_t MemFree =
+ static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree);
+ info.SetMapped((entry->state != MemFree) ? yes : no);
+
+ return info;
+ } else if (head > load_addr &&
+ (next_entry == nullptr || head < next_entry->base_address)) {
+ // In case there is no region containing load_addr keep track of the
+ // nearest region after load_addr so we can return the distance to it.
+ next_entry = entry;
+ }
+ }
+
+ // No containing region found. Create an unmapped region that extends to the
+ // next region or LLDB_INVALID_ADDRESS
+ info.GetRange().SetRangeBase(load_addr);
+ info.GetRange().SetRangeEnd((next_entry != nullptr) ? next_entry->base_address
+ : LLDB_INVALID_ADDRESS);
+ info.SetReadable(no);
+ info.SetWritable(no);
+ info.SetExecutable(no);
+ info.SetMapped(no);
+
+ // Note that the memory info list doesn't seem to contain ranges in kernel
+ // space, so if you're walking a stack that has kernel frames, the stack may
+ // appear truncated.
+ return info;
+}
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/lldb/source/Plugins/Process/minidump/MinidumpParser.h
index 76a8ece00b2..202ef37d8cd 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpParser.h
+++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.h
@@ -34,6 +34,16 @@ namespace lldb_private {
namespace minidump {
+// Describes a range of memory captured in the Minidump
+struct Range {
+ lldb::addr_t start; // virtual address of the beginning of the range
+ // range_ref - absolute pointer to the first byte of the range and size
+ llvm::ArrayRef<uint8_t> range_ref;
+
+ Range(lldb::addr_t start, llvm::ArrayRef<uint8_t> range_ref)
+ : start(start), range_ref(range_ref) {}
+};
+
class MinidumpParser {
public:
static llvm::Optional<MinidumpParser>
@@ -47,6 +57,8 @@ public:
llvm::ArrayRef<MinidumpThread> GetThreads();
+ llvm::ArrayRef<uint8_t> GetThreadContext(const MinidumpThread &td);
+
const MinidumpSystemInfo *GetSystemInfo();
ArchSpec GetArchitecture();
@@ -59,8 +71,20 @@ public:
llvm::ArrayRef<MinidumpModule> GetModuleList();
+ // There are cases in which there is more than one record in the ModuleList
+ // for the same module name.(e.g. when the binary has non contiguous segments)
+ // So this function returns a filtered module list - if it finds records that
+ // have the same name, it keeps the copy with the lowest load address.
+ std::vector<const MinidumpModule *> GetFilteredModuleList();
+
const MinidumpExceptionStream *GetExceptionStream();
+ llvm::Optional<Range> FindMemoryRange(lldb::addr_t addr);
+
+ llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size);
+
+ llvm::Optional<MemoryRegionInfo> GetMemoryRegionInfo(lldb::addr_t);
+
private:
lldb::DataBufferSP m_data_sp;
const MinidumpHeader *m_header;
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp b/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
index 5f8aa59397f..863d124a7cc 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
+++ b/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
@@ -176,3 +176,60 @@ MinidumpExceptionStream::Parse(llvm::ArrayRef<uint8_t> &data) {
return exception_stream;
}
+
+llvm::ArrayRef<MinidumpMemoryDescriptor>
+MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef<uint8_t> &data) {
+ const llvm::support::ulittle32_t *mem_ranges_count;
+ Error error = consumeObject(data, mem_ranges_count);
+ if (error.Fail() ||
+ *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) > data.size())
+ return {};
+
+ return llvm::makeArrayRef(
+ reinterpret_cast<const MinidumpMemoryDescriptor *>(data.data()),
+ *mem_ranges_count);
+}
+
+std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
+MinidumpMemoryDescriptor64::ParseMemory64List(llvm::ArrayRef<uint8_t> &data) {
+ const llvm::support::ulittle64_t *mem_ranges_count;
+ Error 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::makeArrayRef(
+ reinterpret_cast<const MinidumpMemoryDescriptor64 *>(data.data()),
+ *mem_ranges_count),
+ *base_rva);
+}
+
+std::vector<const MinidumpMemoryInfo *>
+MinidumpMemoryInfo::ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data) {
+ const MinidumpMemoryInfoListHeader *header;
+ Error error = consumeObject(data, header);
+ if (error.Fail() ||
+ header->size_of_header < sizeof(MinidumpMemoryInfoListHeader) ||
+ header->size_of_entry < sizeof(MinidumpMemoryInfo))
+ return {};
+
+ data = data.drop_front(header->size_of_header -
+ sizeof(MinidumpMemoryInfoListHeader));
+
+ if (header->size_of_entry * header->num_of_entries > data.size())
+ return {};
+
+ std::vector<const MinidumpMemoryInfo *> result;
+ for (uint64_t i = 0; i < header->num_of_entries; ++i) {
+ result.push_back(reinterpret_cast<const MinidumpMemoryInfo *>(
+ data.data() + i * header->size_of_entry));
+ }
+
+ return result;
+}
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpTypes.h b/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
index bc3d846550a..1b903075010 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
+++ b/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
@@ -207,10 +207,23 @@ static_assert(sizeof(MinidumpLocationDescriptor) == 8,
struct MinidumpMemoryDescriptor {
llvm::support::ulittle64_t start_of_memory_range;
MinidumpLocationDescriptor memory;
+
+ static llvm::ArrayRef<MinidumpMemoryDescriptor>
+ ParseMemoryList(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpMemoryDescriptor) == 16,
"sizeof MinidumpMemoryDescriptor is not correct!");
+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!");
+
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680365.aspx
struct MinidumpDirectory {
@@ -221,6 +234,70 @@ static_assert(sizeof(MinidumpDirectory) == 12,
"sizeof MinidumpDirectory is not correct!");
// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680385(v=vs.85).aspx
+struct MinidumpMemoryInfoListHeader {
+ llvm::support::ulittle32_t size_of_header;
+ llvm::support::ulittle32_t size_of_entry;
+ llvm::support::ulittle64_t num_of_entries;
+};
+static_assert(sizeof(MinidumpMemoryInfoListHeader) == 16,
+ "sizeof MinidumpMemoryInfoListHeader is not correct!");
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680386(v=vs.85).aspx
+struct MinidumpMemoryInfo {
+ llvm::support::ulittle64_t base_address;
+ llvm::support::ulittle64_t allocation_base;
+ llvm::support::ulittle32_t allocation_protect;
+ llvm::support::ulittle32_t alignment1;
+ llvm::support::ulittle64_t region_size;
+ llvm::support::ulittle32_t state;
+ llvm::support::ulittle32_t protect;
+ llvm::support::ulittle32_t type;
+ llvm::support::ulittle32_t alignment2;
+
+ static std::vector<const MinidumpMemoryInfo *>
+ ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data);
+};
+static_assert(sizeof(MinidumpMemoryInfo) == 48,
+ "sizeof MinidumpMemoryInfo is not correct!");
+
+enum class MinidumpMemoryInfoState : uint32_t {
+ MemCommit = 0x1000,
+ MemFree = 0x10000,
+ MemReserve = 0x2000,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemFree)
+};
+
+enum class MinidumpMemoryInfoType : uint32_t {
+ MemImage = 0x1000000,
+ MemMapped = 0x40000,
+ MemPrivate = 0x20000,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemImage)
+};
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx
+enum class MinidumpMemoryProtectionContants : uint32_t {
+ PageExecute = 0x10,
+ PageExecuteRead = 0x20,
+ PageExecuteReadWrite = 0x40,
+ PageExecuteWriteCopy = 0x80,
+ PageNoAccess = 0x01,
+ PageReadOnly = 0x02,
+ PageReadWrite = 0x04,
+ PageWriteCopy = 0x08,
+ PageTargetsInvalid = 0x40000000,
+ PageTargetsNoUpdate = 0x40000000,
+
+ PageWritable = PageExecuteReadWrite | PageExecuteWriteCopy | PageReadWrite |
+ PageWriteCopy,
+ PageExecutable = PageExecute | PageExecuteRead | PageExecuteReadWrite |
+ PageExecuteWriteCopy,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ PageTargetsInvalid)
+};
+
+// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx
struct MinidumpThread {
llvm::support::ulittle32_t thread_id;
diff --git a/lldb/unittests/Process/minidump/CMakeLists.txt b/lldb/unittests/Process/minidump/CMakeLists.txt
index f96f4a47d98..c24ef475a6c 100644
--- a/lldb/unittests/Process/minidump/CMakeLists.txt
+++ b/lldb/unittests/Process/minidump/CMakeLists.txt
@@ -4,6 +4,8 @@ add_lldb_unittest(LLDBMinidumpTests
set(test_inputs
linux-x86_64.dmp
- fizzbuzz_no_heap.dmp)
+ linux-x86_64_not_crashed.dmp
+ fizzbuzz_no_heap.dmp
+ fizzbuzz_wow64.dmp)
add_unittest_inputs(LLDBMinidumpTests "${test_inputs}")
diff --git a/lldb/unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmp b/lldb/unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmp
new file mode 100644
index 00000000000..3d97186f2cd
--- /dev/null
+++ b/lldb/unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmp
Binary files differ
diff --git a/lldb/unittests/Process/minidump/Inputs/linux-x86_64_not_crashed.dmp b/lldb/unittests/Process/minidump/Inputs/linux-x86_64_not_crashed.dmp
new file mode 100644
index 00000000000..ad4b61a7bbb
--- /dev/null
+++ b/lldb/unittests/Process/minidump/Inputs/linux-x86_64_not_crashed.dmp
Binary files differ
diff --git a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
index 7597fab36c2..4600a81afef 100644
--- a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
+++ b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
@@ -19,6 +19,7 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Target/MemoryRegionInfo.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
@@ -68,7 +69,11 @@ TEST_F(MinidumpParserTest, GetThreads) {
ASSERT_EQ(1UL, thread_list.size());
const MinidumpThread thread = thread_list[0];
- ASSERT_EQ(16001UL, thread.thread_id);
+
+ EXPECT_EQ(16001UL, thread.thread_id);
+
+ llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(thread);
+ EXPECT_EQ(1232UL, context.size());
}
TEST_F(MinidumpParserTest, GetThreadsTruncatedFile) {
@@ -131,6 +136,28 @@ TEST_F(MinidumpParserTest, GetModuleList) {
}
}
+TEST_F(MinidumpParserTest, GetFilteredModuleList) {
+ SetUpData("linux-x86_64_not_crashed.dmp");
+ llvm::ArrayRef<MinidumpModule> modules = parser->GetModuleList();
+ std::vector<const MinidumpModule *> filtered_modules =
+ parser->GetFilteredModuleList();
+ EXPECT_EQ(10UL, modules.size());
+ EXPECT_EQ(9UL, filtered_modules.size());
+ // EXPECT_GT(modules.size(), filtered_modules.size());
+ bool found = false;
+ for (size_t i = 0; i < filtered_modules.size(); ++i) {
+ llvm::Optional<std::string> name =
+ parser->GetMinidumpString(filtered_modules[i]->module_name_rva);
+ ASSERT_TRUE(name.hasValue());
+ if (name.getValue() == "/tmp/test/linux-x86_64_not_crashed") {
+ ASSERT_FALSE(found) << "There should be only one module with this name "
+ "in the filtered module list";
+ found = true;
+ ASSERT_EQ(0x400000UL, filtered_modules[i]->base_of_image);
+ }
+ }
+}
+
TEST_F(MinidumpParserTest, GetExceptionStream) {
SetUpData("linux-x86_64.dmp");
const MinidumpExceptionStream *exception_stream =
@@ -139,6 +166,81 @@ TEST_F(MinidumpParserTest, GetExceptionStream) {
ASSERT_EQ(11UL, exception_stream->exception_record.exception_code);
}
+void check_mem_range_exists(std::unique_ptr<MinidumpParser> &parser,
+ const uint64_t range_start,
+ const uint64_t range_size) {
+ llvm::Optional<minidump::Range> range = parser->FindMemoryRange(range_start);
+ ASSERT_TRUE(range.hasValue()) << "There is no range containing this address";
+ EXPECT_EQ(range_start, range->start);
+ EXPECT_EQ(range_start + range_size, range->start + range->range_ref.size());
+}
+
+TEST_F(MinidumpParserTest, FindMemoryRange) {
+ SetUpData("linux-x86_64.dmp");
+ // There are two memory ranges in the file (size is in bytes, decimal):
+ // 1) 0x401d46 256
+ // 2) 0x7ffceb34a000 12288
+ EXPECT_FALSE(parser->FindMemoryRange(0x00).hasValue());
+ EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue());
+
+ check_mem_range_exists(parser, 0x401d46, 256);
+ EXPECT_FALSE(parser->FindMemoryRange(0x401d46 + 256).hasValue());
+
+ check_mem_range_exists(parser, 0x7ffceb34a000, 12288);
+ EXPECT_FALSE(parser->FindMemoryRange(0x7ffceb34a000 + 12288).hasValue());
+}
+
+TEST_F(MinidumpParserTest, GetMemory) {
+ SetUpData("linux-x86_64.dmp");
+
+ EXPECT_EQ(128UL, parser->GetMemory(0x401d46, 128).size());
+ EXPECT_EQ(256UL, parser->GetMemory(0x401d46, 512).size());
+
+ EXPECT_EQ(12288UL, parser->GetMemory(0x7ffceb34a000, 12288).size());
+ EXPECT_EQ(1024UL, parser->GetMemory(0x7ffceb34a000, 1024).size());
+
+ EXPECT_TRUE(parser->GetMemory(0x500000, 512).empty());
+}
+
+TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) {
+ SetUpData("fizzbuzz_wow64.dmp");
+
+ // There are a lot of ranges in the file, just testing with some of them
+ EXPECT_FALSE(parser->FindMemoryRange(0x00).hasValue());
+ EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue());
+ check_mem_range_exists(parser, 0x10000, 65536); // first range
+ check_mem_range_exists(parser, 0x40000, 4096);
+ EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).hasValue());
+ check_mem_range_exists(parser, 0x77c12000, 8192);
+ check_mem_range_exists(parser, 0x7ffe0000, 4096); // last range
+ EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).hasValue());
+}
+
+void check_region_info(std::unique_ptr<MinidumpParser> &parser,
+ const uint64_t addr, MemoryRegionInfo::OptionalBool read,
+ MemoryRegionInfo::OptionalBool write,
+ MemoryRegionInfo::OptionalBool exec) {
+ auto range_info = parser->GetMemoryRegionInfo(addr);
+ ASSERT_TRUE(range_info.hasValue());
+ EXPECT_EQ(read, range_info->GetReadable());
+ EXPECT_EQ(write, range_info->GetWritable());
+ EXPECT_EQ(exec, range_info->GetExecutable());
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {
+ SetUpData("fizzbuzz_wow64.dmp");
+
+ const auto yes = MemoryRegionInfo::eYes;
+ const auto no = MemoryRegionInfo::eNo;
+
+ check_region_info(parser, 0x00000, no, no, no);
+ check_region_info(parser, 0x10000, yes, yes, no);
+ check_region_info(parser, 0x20000, yes, yes, no);
+ check_region_info(parser, 0x30000, yes, yes, no);
+ check_region_info(parser, 0x31000, no, no, no);
+ check_region_info(parser, 0x40000, yes, no, no);
+}
+
// Windows Minidump tests
// fizzbuzz_no_heap.dmp is copied from the WinMiniDump tests
TEST_F(MinidumpParserTest, GetArchitectureWindows) {
OpenPOWER on IntegriCloud