summaryrefslogtreecommitdiff
path: root/unittests/Process/minidump/MinidumpParserTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/Process/minidump/MinidumpParserTest.cpp')
-rw-r--r--unittests/Process/minidump/MinidumpParserTest.cpp175
1 files changed, 154 insertions, 21 deletions
diff --git a/unittests/Process/minidump/MinidumpParserTest.cpp b/unittests/Process/minidump/MinidumpParserTest.cpp
index cf4873fbc4fc..92ea20f72860 100644
--- a/unittests/Process/minidump/MinidumpParserTest.cpp
+++ b/unittests/Process/minidump/MinidumpParserTest.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-// Project includes
#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
#include "Plugins/Process/minidump/MinidumpParser.h"
@@ -16,9 +15,9 @@
#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
#include "TestingSupport/TestUtilities.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/DataBufferLLVM.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/FileSpec.h"
#include "llvm/ADT/ArrayRef.h"
@@ -38,9 +37,13 @@ using namespace minidump;
class MinidumpParserTest : public testing::Test {
public:
+ void SetUp() override { FileSystem::Initialize(); }
+
+ void TearDown() override { FileSystem::Terminate(); }
+
void SetUpData(const char *minidump_filename) {
std::string filename = GetInputFilePath(minidump_filename);
- auto BufferPtr = DataBufferLLVM::CreateSliceFromPath(filename, -1, 0);
+ auto BufferPtr = FileSystem::Instance().CreateDataBuffer(filename, -1, 0);
ASSERT_NE(BufferPtr, nullptr);
llvm::Optional<MinidumpParser> optional_parser =
MinidumpParser::Create(BufferPtr);
@@ -54,7 +57,7 @@ public:
void InvalidMinidump(const char *minidump_filename, uint64_t load_size) {
std::string filename = GetInputFilePath(minidump_filename);
auto BufferPtr =
- DataBufferLLVM::CreateSliceFromPath(filename, load_size, 0);
+ FileSystem::Instance().CreateDataBuffer(filename, load_size, 0);
ASSERT_NE(BufferPtr, nullptr);
llvm::Optional<MinidumpParser> optional_parser =
@@ -89,7 +92,7 @@ TEST_F(MinidumpParserTest, GetThreadListNotPadded) {
// after the thread count.
SetUpData("thread-list-not-padded.dmp");
llvm::ArrayRef<MinidumpThread> thread_list;
-
+
thread_list = parser->GetThreads();
ASSERT_EQ(2UL, thread_list.size());
EXPECT_EQ(0x11223344UL, thread_list[0].thread_id);
@@ -297,29 +300,120 @@ TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) {
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) {
+void check_region(std::unique_ptr<MinidumpParser> &parser,
+ lldb::addr_t addr, lldb::addr_t start, lldb::addr_t end,
+ MemoryRegionInfo::OptionalBool read,
+ MemoryRegionInfo::OptionalBool write,
+ MemoryRegionInfo::OptionalBool exec,
+ MemoryRegionInfo::OptionalBool mapped,
+ ConstString name = ConstString()) {
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());
+ EXPECT_EQ(start, range_info.GetRange().GetRangeBase());
+ EXPECT_EQ(end, range_info.GetRange().GetRangeEnd());
+ EXPECT_EQ(read, range_info.GetReadable());
+ EXPECT_EQ(write, range_info.GetWritable());
+ EXPECT_EQ(exec, range_info.GetExecutable());
+ EXPECT_EQ(mapped, range_info.GetMapped());
+ EXPECT_EQ(name, range_info.GetName());
}
+// Same as above function where addr == start
+void check_region(std::unique_ptr<MinidumpParser> &parser,
+ lldb::addr_t start, lldb::addr_t end,
+ MemoryRegionInfo::OptionalBool read,
+ MemoryRegionInfo::OptionalBool write,
+ MemoryRegionInfo::OptionalBool exec,
+ MemoryRegionInfo::OptionalBool mapped,
+ ConstString name = ConstString()) {
+ check_region(parser, start, start, end, read, write, exec, mapped, name);
+}
+
+
+constexpr auto yes = MemoryRegionInfo::eYes;
+constexpr auto no = MemoryRegionInfo::eNo;
+constexpr auto unknown = MemoryRegionInfo::eDontKnow;
+
TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {
SetUpData("fizzbuzz_wow64.dmp");
- const auto yes = MemoryRegionInfo::eYes;
- const auto no = MemoryRegionInfo::eNo;
+ check_region(parser, 0x00000000, 0x00010000, no, no, no, no);
+ check_region(parser, 0x00010000, 0x00020000, yes, yes, no, yes);
+ check_region(parser, 0x00020000, 0x00030000, yes, yes, no, yes);
+ check_region(parser, 0x00030000, 0x00031000, yes, yes, no, yes);
+ check_region(parser, 0x00031000, 0x00040000, no, no, no, no);
+ check_region(parser, 0x00040000, 0x00041000, yes, no, no, yes);
+
+ // Check addresses contained inside ranges
+ check_region(parser, 0x00000001, 0x00000000, 0x00010000, no, no, no, no);
+ check_region(parser, 0x0000ffff, 0x00000000, 0x00010000, no, no, no, no);
+ check_region(parser, 0x00010001, 0x00010000, 0x00020000, yes, yes, no, yes);
+ check_region(parser, 0x0001ffff, 0x00010000, 0x00020000, yes, yes, no, yes);
+
+ // Test that an address after the last entry maps to rest of the memory space
+ check_region(parser, 0x7fff0000, 0x7fff0000, UINT64_MAX, no, no, no, no);
+}
- 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);
+TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) {
+ SetUpData("regions-memlist.dmp");
+ // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when
+ // we don't have a MemoryInfoListStream.
+
+ // Test addres before the first entry comes back with nothing mapped up
+ // to first valid region info
+ check_region(parser, 0x00000000, 0x00001000, no, no, no, no);
+ check_region(parser, 0x00001000, 0x00001010, yes, unknown, unknown, yes);
+ check_region(parser, 0x00001010, 0x00002000, no, no, no, no);
+ check_region(parser, 0x00002000, 0x00002020, yes, unknown, unknown, yes);
+ check_region(parser, 0x00002020, UINT64_MAX, no, no, no, no);
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) {
+ SetUpData("regions-memlist64.dmp");
+ // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when
+ // we don't have a MemoryInfoListStream.
+
+ // Test addres before the first entry comes back with nothing mapped up
+ // to first valid region info
+ check_region(parser, 0x00000000, 0x00001000, no, no, no, no);
+ check_region(parser, 0x00001000, 0x00001010, yes, unknown, unknown, yes);
+ check_region(parser, 0x00001010, 0x00002000, no, no, no, no);
+ check_region(parser, 0x00002000, 0x00002020, yes, unknown, unknown, yes);
+ check_region(parser, 0x00002020, UINT64_MAX, no, no, no, no);
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {
+ SetUpData("regions-linux-map.dmp");
+ // Test we can get memory regions from the linux /proc/<pid>/maps stream when
+ // we don't have a MemoryInfoListStream.
+
+ // Test addres before the first entry comes back with nothing mapped up
+ // to first valid region info
+ ConstString a("/system/bin/app_process");
+ ConstString b("/system/bin/linker");
+ ConstString c("/system/lib/liblog.so");
+ ConstString d("/system/lib/libc.so");
+ ConstString n;
+ check_region(parser, 0x00000000, 0x400d9000, no , no , no , no , n);
+ check_region(parser, 0x400d9000, 0x400db000, yes, no , yes, yes, a);
+ check_region(parser, 0x400db000, 0x400dc000, yes, no , no , yes, a);
+ check_region(parser, 0x400dc000, 0x400dd000, yes, yes, no , yes, n);
+ check_region(parser, 0x400dd000, 0x400ec000, yes, no , yes, yes, b);
+ check_region(parser, 0x400ec000, 0x400ed000, yes, no , no , yes, n);
+ check_region(parser, 0x400ed000, 0x400ee000, yes, no , no , yes, b);
+ check_region(parser, 0x400ee000, 0x400ef000, yes, yes, no , yes, b);
+ check_region(parser, 0x400ef000, 0x400fb000, yes, yes, no , yes, n);
+ check_region(parser, 0x400fb000, 0x400fc000, yes, no , yes, yes, c);
+ check_region(parser, 0x400fc000, 0x400fd000, yes, yes, yes, yes, c);
+ check_region(parser, 0x400fd000, 0x400ff000, yes, no , yes, yes, c);
+ check_region(parser, 0x400ff000, 0x40100000, yes, no , no , yes, c);
+ check_region(parser, 0x40100000, 0x40101000, yes, yes, no , yes, c);
+ check_region(parser, 0x40101000, 0x40122000, yes, no , yes, yes, d);
+ check_region(parser, 0x40122000, 0x40123000, yes, yes, yes, yes, d);
+ check_region(parser, 0x40123000, 0x40167000, yes, no , yes, yes, d);
+ check_region(parser, 0x40167000, 0x40169000, yes, no , no , yes, d);
+ check_region(parser, 0x40169000, 0x4016b000, yes, yes, no , yes, d);
+ check_region(parser, 0x4016b000, 0x40176000, yes, yes, no , yes, n);
+ check_region(parser, 0x40176000, UINT64_MAX, no , no , no , no , n);
}
// Windows Minidump tests
@@ -530,3 +624,42 @@ TEST_F(MinidumpParserTest, ConvertMinidumpContext_x86_32_wow64) {
}
}
}
+
+TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) {
+ SetUpData("modules-dup-min-addr.dmp");
+ // Test that if we have two modules in the module list:
+ // /tmp/a with range [0x2000-0x3000)
+ // /tmp/a with range [0x1000-0x2000)
+ // That we end up with one module in the filtered list with the
+ // range [0x1000-0x2000). MinidumpParser::GetFilteredModuleList() is
+ // trying to ensure that if we have the same module mentioned more than
+ // one time, we pick the one with the lowest base_of_image.
+ std::vector<const MinidumpModule *> filtered_modules =
+ parser->GetFilteredModuleList();
+ EXPECT_EQ(1u, filtered_modules.size());
+ EXPECT_EQ(0x0000000000001000u, filtered_modules[0]->base_of_image);
+}
+
+TEST_F(MinidumpParserTest, MinidumpModuleOrder) {
+ SetUpData("modules-order.dmp");
+ // Test that if we have two modules in the module list:
+ // /tmp/a with range [0x2000-0x3000)
+ // /tmp/b with range [0x1000-0x2000)
+ // That we end up with two modules in the filtered list with the same ranges
+ // and in the same order. Previous versions of the
+ // MinidumpParser::GetFilteredModuleList() function would sort all images
+ // by address and modify the order of the modules.
+ std::vector<const MinidumpModule *> filtered_modules =
+ parser->GetFilteredModuleList();
+ llvm::Optional<std::string> name;
+ EXPECT_EQ(2u, filtered_modules.size());
+ EXPECT_EQ(0x0000000000002000u, filtered_modules[0]->base_of_image);
+ name = parser->GetMinidumpString(filtered_modules[0]->module_name_rva);
+ ASSERT_TRUE((bool)name);
+ EXPECT_EQ(std::string("/tmp/a"), *name);
+ EXPECT_EQ(0x0000000000001000u, filtered_modules[1]->base_of_image);
+ name = parser->GetMinidumpString(filtered_modules[1]->module_name_rva);
+ ASSERT_TRUE((bool)name);
+ EXPECT_EQ(std::string("/tmp/b"), *name);
+}
+