From 2dd7e5e22251e938dda62533a267cb435b6857f6 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Mon, 23 Jul 2018 14:16:08 +0000 Subject: [PATCH] Add support for parsing Breakpad minidump files that can have extra padding in the module, thread and memory lists. Differential Revision: https://reviews.llvm.org/D49579 llvm-svn: 337694 --- .../Plugins/Process/minidump/MinidumpTypes.cpp | 21 ++++++- lldb/unittests/Process/minidump/CMakeLists.txt | 8 ++- .../minidump/Inputs/memory-list-not-padded.dmp | Bin 0 -> 107 bytes .../Process/minidump/Inputs/memory-list-padded.dmp | Bin 0 -> 111 bytes .../minidump/Inputs/module-list-not-padded.dmp | Bin 0 -> 296 bytes .../Process/minidump/Inputs/module-list-padded.dmp | Bin 0 -> 300 bytes .../minidump/Inputs/thread-list-not-padded.dmp | Bin 0 -> 144 bytes .../Process/minidump/Inputs/thread-list-padded.dmp | Bin 0 -> 148 bytes .../Process/minidump/MinidumpParserTest.cpp | 70 +++++++++++++++++++++ 9 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 lldb/unittests/Process/minidump/Inputs/memory-list-not-padded.dmp create mode 100644 lldb/unittests/Process/minidump/Inputs/memory-list-padded.dmp create mode 100644 lldb/unittests/Process/minidump/Inputs/module-list-not-padded.dmp create mode 100644 lldb/unittests/Process/minidump/Inputs/module-list-padded.dmp create mode 100644 lldb/unittests/Process/minidump/Inputs/thread-list-not-padded.dmp create mode 100644 lldb/unittests/Process/minidump/Inputs/thread-list-padded.dmp diff --git a/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp b/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp index b095aeb..049704b 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp +++ b/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp @@ -81,11 +81,17 @@ const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef &data) { llvm::ArrayRef MinidumpThread::ParseThreadList(llvm::ArrayRef &data) { + const auto orig_size = data.size(); const llvm::support::ulittle32_t *thread_count; Status error = consumeObject(data, thread_count); if (error.Fail() || *thread_count * sizeof(MinidumpThread) > data.size()) return {}; + // Compilers might end up padding an extra 4 bytes depending on how the + // structure is padded by the compiler and the #pragma pack settings. + if (4 + *thread_count * sizeof(MinidumpThread) < orig_size) + data = data.drop_front(4); + return llvm::ArrayRef( reinterpret_cast(data.data()), *thread_count); } @@ -157,12 +163,17 @@ const MinidumpModule *MinidumpModule::Parse(llvm::ArrayRef &data) { llvm::ArrayRef MinidumpModule::ParseModuleList(llvm::ArrayRef &data) { - + const auto orig_size = data.size(); const llvm::support::ulittle32_t *modules_count; Status error = consumeObject(data, modules_count); if (error.Fail() || *modules_count * sizeof(MinidumpModule) > data.size()) return {}; - + + // Compilers might end up padding an extra 4 bytes depending on how the + // structure is padded by the compiler and the #pragma pack settings. + if (4 + *modules_count * sizeof(MinidumpModule) < orig_size) + data = data.drop_front(4); + return llvm::ArrayRef( reinterpret_cast(data.data()), *modules_count); } @@ -180,11 +191,17 @@ MinidumpExceptionStream::Parse(llvm::ArrayRef &data) { llvm::ArrayRef MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef &data) { + const auto orig_size = data.size(); const llvm::support::ulittle32_t *mem_ranges_count; Status error = consumeObject(data, mem_ranges_count); if (error.Fail() || *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) > data.size()) return {}; + + // Compilers might end up padding an extra 4 bytes depending on how the + // structure is padded by the compiler and the #pragma pack settings. + if (4 + *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) < orig_size) + data = data.drop_front(4); return llvm::makeArrayRef( reinterpret_cast(data.data()), diff --git a/lldb/unittests/Process/minidump/CMakeLists.txt b/lldb/unittests/Process/minidump/CMakeLists.txt index 308b77a..a4ebb07 100644 --- a/lldb/unittests/Process/minidump/CMakeLists.txt +++ b/lldb/unittests/Process/minidump/CMakeLists.txt @@ -19,6 +19,12 @@ set(test_inputs fizzbuzz_no_heap.dmp fizzbuzz_wow64.dmp bad_duplicate_streams.dmp - bad_overlapping_streams.dmp) + bad_overlapping_streams.dmp + thread-list-padded.dmp + thread-list-not-padded.dmp + module-list-padded.dmp + module-list-not-padded.dmp + memory-list-padded.dmp + memory-list-not-padded.dmp) add_unittest_inputs(LLDBMinidumpTests "${test_inputs}") diff --git a/lldb/unittests/Process/minidump/Inputs/memory-list-not-padded.dmp b/lldb/unittests/Process/minidump/Inputs/memory-list-not-padded.dmp new file mode 100644 index 0000000000000000000000000000000000000000..cb7b5fb7ee83220e664c0887ad4bffe87e651e64 GIT binary patch literal 107 zcmeZu@eP=~oPmLnfq_8*h|vKnP(THUb%2-&B-sEW7#MhfH~@$R8h`{4@B?uS5PPKN dNAofVj$;nqJ Z&o9bJQFPDGPf4mwRmjcH&(qV>0{{v@4ov_6 literal 0 HcmV?d00001 diff --git a/lldb/unittests/Process/minidump/Inputs/module-list-not-padded.dmp b/lldb/unittests/Process/minidump/Inputs/module-list-not-padded.dmp new file mode 100644 index 0000000000000000000000000000000000000000..b37e251ce21d5d8f08941b45be844d0a1198ac21 GIT binary patch literal 296 zcmeZu@eP=~oPmLnfq_8*h|vKHP~Z*_>i{tmNKybq0D%IS1QQ$}&9ndkP(uw6hD*@M XE*_v2`V1uuxeNtBI*|dDpTqzFy*~(} literal 0 HcmV?d00001 diff --git a/lldb/unittests/Process/minidump/Inputs/module-list-padded.dmp b/lldb/unittests/Process/minidump/Inputs/module-list-padded.dmp new file mode 100644 index 0000000000000000000000000000000000000000..431c7c025b230466bc2ba2ee27a3884298022805 GIT binary patch literal 300 zcmeZu@eP=~oPmLnfq_8*h|vKHP~ZU&>i{tm5QBjLlvaS!K#B)s04+cO)KCM2;W9L` Xiw9_hK0^sZE<*v3PGmskCoup3)h`II literal 0 HcmV?d00001 diff --git a/lldb/unittests/Process/minidump/Inputs/thread-list-not-padded.dmp b/lldb/unittests/Process/minidump/Inputs/thread-list-not-padded.dmp new file mode 100644 index 0000000000000000000000000000000000000000..34ba5cc34c8eadabf543d16d6dc33ac01fd198b1 GIT binary patch literal 144 xcmeZu@eP=~oPmLnfq_8*h|vKvP#^_}b%2-&h+T}81c4OMprbr3lxW33g#a?O1%m(p literal 0 HcmV?d00001 diff --git a/lldb/unittests/Process/minidump/Inputs/thread-list-padded.dmp b/lldb/unittests/Process/minidump/Inputs/thread-list-padded.dmp new file mode 100644 index 0000000000000000000000000000000000000000..838a4dfb51fe67656736053fbd4c21a3256092d3 GIT binary patch literal 148 ycmeZu@eP=~oPmLnfq_8*h|vKvP#^<{b%2-&D(PaZBnV{^MRk;?g%YI@st5o;@dbwf literal 0 HcmV?d00001 diff --git a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp index 9a99f6b..cf4873f 100644 --- a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp +++ b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp @@ -84,6 +84,76 @@ TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) { EXPECT_EQ(1232UL, context.size()); } +TEST_F(MinidumpParserTest, GetThreadListNotPadded) { + // Verify that we can load a thread list that doesn't have 4 bytes of padding + // after the thread count. + SetUpData("thread-list-not-padded.dmp"); + llvm::ArrayRef thread_list; + + thread_list = parser->GetThreads(); + ASSERT_EQ(2UL, thread_list.size()); + EXPECT_EQ(0x11223344UL, thread_list[0].thread_id); + EXPECT_EQ(0x55667788UL, thread_list[1].thread_id); +} + +TEST_F(MinidumpParserTest, GetThreadListPadded) { + // Verify that we can load a thread list that has 4 bytes of padding + // after the thread count as found in breakpad minidump files. + SetUpData("thread-list-padded.dmp"); + auto thread_list = parser->GetThreads(); + ASSERT_EQ(2UL, thread_list.size()); + EXPECT_EQ(0x11223344UL, thread_list[0].thread_id); + EXPECT_EQ(0x55667788UL, thread_list[1].thread_id); +} + +TEST_F(MinidumpParserTest, GetModuleListNotPadded) { + // Verify that we can load a module list that doesn't have 4 bytes of padding + // after the module count. + SetUpData("module-list-not-padded.dmp"); + auto module_list = parser->GetModuleList(); + ASSERT_EQ(2UL, module_list.size()); + EXPECT_EQ(0x1000UL, module_list[0].base_of_image); + EXPECT_EQ(0x2000UL, module_list[0].size_of_image); + EXPECT_EQ(0x5000UL, module_list[1].base_of_image); + EXPECT_EQ(0x3000UL, module_list[1].size_of_image); +} + +TEST_F(MinidumpParserTest, GetModuleListPadded) { + // Verify that we can load a module list that has 4 bytes of padding + // after the module count as found in breakpad minidump files. + SetUpData("module-list-padded.dmp"); + auto module_list = parser->GetModuleList(); + ASSERT_EQ(2UL, module_list.size()); + EXPECT_EQ(0x1000UL, module_list[0].base_of_image); + EXPECT_EQ(0x2000UL, module_list[0].size_of_image); + EXPECT_EQ(0x5000UL, module_list[1].base_of_image); + EXPECT_EQ(0x3000UL, module_list[1].size_of_image); +} + +TEST_F(MinidumpParserTest, GetMemoryListNotPadded) { + // Verify that we can load a memory list that doesn't have 4 bytes of padding + // after the memory range count. + SetUpData("memory-list-not-padded.dmp"); + auto mem = parser->FindMemoryRange(0x8000); + ASSERT_TRUE(mem.hasValue()); + EXPECT_EQ((lldb::addr_t)0x8000, mem->start); + mem = parser->FindMemoryRange(0x8010); + ASSERT_TRUE(mem.hasValue()); + EXPECT_EQ((lldb::addr_t)0x8010, mem->start); +} + +TEST_F(MinidumpParserTest, GetMemoryListPadded) { + // Verify that we can load a memory list that has 4 bytes of padding + // after the memory range count as found in breakpad minidump files. + SetUpData("memory-list-padded.dmp"); + auto mem = parser->FindMemoryRange(0x8000); + ASSERT_TRUE(mem.hasValue()); + EXPECT_EQ((lldb::addr_t)0x8000, mem->start); + mem = parser->FindMemoryRange(0x8010); + ASSERT_TRUE(mem.hasValue()); + EXPECT_EQ((lldb::addr_t)0x8010, mem->start); +} + TEST_F(MinidumpParserTest, TruncatedMinidumps) { InvalidMinidump("linux-x86_64.dmp", 32); InvalidMinidump("linux-x86_64.dmp", 100); -- 2.7.4