930 lines · cpp
1//===-- MinidumpTypesTest.cpp ---------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Plugins/Process/minidump/MinidumpParser.h"10#include "Plugins/Process/minidump/MinidumpTypes.h"11#include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h"12#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"13#include "TestingSupport/SubsystemRAII.h"14#include "TestingSupport/TestUtilities.h"15#include "lldb/Host/FileSystem.h"16#include "lldb/Target/MemoryRegionInfo.h"17#include "lldb/Utility/ArchSpec.h"18#include "lldb/Utility/DataBufferHeap.h"19#include "lldb/Utility/DataExtractor.h"20#include "lldb/Utility/FileSpec.h"21#include "llvm/ADT/ArrayRef.h"22#include "llvm/ObjectYAML/yaml2obj.h"23#include "llvm/Support/FileSystem.h"24#include "llvm/Support/MemoryBuffer.h"25#include "llvm/Support/Path.h"26#include "llvm/Support/YAMLTraits.h"27#include "llvm/Testing/Support/Error.h"28#include "gtest/gtest.h"29 30// C includes31 32// C++ includes33#include <memory>34#include <optional>35 36using namespace lldb_private;37using namespace minidump;38 39class MinidumpParserTest : public testing::Test {40public:41 SubsystemRAII<FileSystem> subsystems;42 43 void SetUpData(const char *minidump_filename) {44 std::string filename = GetInputFilePath(minidump_filename);45 auto BufferPtr = FileSystem::Instance().CreateDataBuffer(filename, -1, 0);46 ASSERT_NE(BufferPtr, nullptr);47 llvm::Expected<MinidumpParser> expected_parser =48 MinidumpParser::Create(BufferPtr);49 ASSERT_THAT_EXPECTED(expected_parser, llvm::Succeeded());50 parser = std::move(*expected_parser);51 ASSERT_GT(parser->GetData().size(), 0UL);52 }53 54 llvm::Error SetUpFromYaml(llvm::StringRef yaml) {55 std::string data;56 llvm::raw_string_ostream os(data);57 llvm::yaml::Input YIn(yaml);58 if (!llvm::yaml::convertYAML(YIn, os, [](const llvm::Twine &Msg) {}))59 return llvm::createStringError(llvm::inconvertibleErrorCode(),60 "convertYAML() failed");61 62 auto data_buffer_sp =63 std::make_shared<DataBufferHeap>(data.data(), data.size());64 auto expected_parser = MinidumpParser::Create(std::move(data_buffer_sp));65 if (!expected_parser)66 return expected_parser.takeError();67 parser = std::move(*expected_parser);68 return llvm::Error::success();69 }70 71 std::optional<MinidumpParser> parser;72};73 74TEST_F(MinidumpParserTest, InvalidMinidump) {75 std::string duplicate_streams;76 llvm::raw_string_ostream os(duplicate_streams);77 llvm::yaml::Input YIn(R"(78--- !minidump79Streams:80 - Type: LinuxAuxv81 Content: DEADBEEFBAADF00D82 - Type: LinuxAuxv83 Content: DEADBEEFBAADF00D84 )");85 86 ASSERT_TRUE(llvm::yaml::convertYAML(YIn, os, [](const llvm::Twine &Msg){}));87 auto data_buffer_sp = std::make_shared<DataBufferHeap>(88 duplicate_streams.data(), duplicate_streams.size());89 ASSERT_THAT_EXPECTED(MinidumpParser::Create(data_buffer_sp), llvm::Failed());90}91 92TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) {93 ASSERT_THAT_ERROR(SetUpFromYaml(R"(94--- !minidump95Streams:96 - Type: ThreadList97 Threads:98 - Thread Id: 0x00003E8199 Stack:100 Start of Memory Range: 0x00007FFCEB34A000101 Content: C84D04BCE97F00102 Context: 00000000000000103...104)"),105 llvm::Succeeded());106 llvm::ArrayRef<minidump::Thread> thread_list;107 108 thread_list = parser->GetThreads();109 ASSERT_EQ(1UL, thread_list.size());110 111 const minidump::Thread &thread = thread_list[0];112 113 EXPECT_EQ(0x3e81u, thread.ThreadId);114 115 llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(thread);116 EXPECT_EQ(7u, context.size());117}118 119TEST_F(MinidumpParserTest, GetArchitecture) {120 ASSERT_THAT_ERROR(SetUpFromYaml(R"(121--- !minidump122Streams:123 - Type: SystemInfo124 Processor Arch: AMD64125 Processor Level: 6126 Processor Revision: 16130127 Number of Processors: 1128 Platform ID: Linux129 CPU:130 Vendor ID: GenuineIntel131 Version Info: 0x00000000132 Feature Info: 0x00000000133...134)"),135 llvm::Succeeded());136 ASSERT_EQ(llvm::Triple::ArchType::x86_64,137 parser->GetArchitecture().GetMachine());138 ASSERT_EQ(llvm::Triple::OSType::Linux,139 parser->GetArchitecture().GetTriple().getOS());140}141 142TEST_F(MinidumpParserTest, GetMiscInfo_no_stream) {143 // Test that GetMiscInfo returns nullptr when the minidump does not contain144 // this stream.145 ASSERT_THAT_ERROR(SetUpFromYaml(R"(146--- !minidump147Streams:148...149)"),150 llvm::Succeeded());151 EXPECT_EQ(nullptr, parser->GetMiscInfo());152}153 154TEST_F(MinidumpParserTest, GetLinuxProcStatus) {155 ASSERT_THAT_ERROR(SetUpFromYaml(R"(156--- !minidump157Streams:158 - Type: SystemInfo159 Processor Arch: AMD64160 Processor Level: 6161 Processor Revision: 16130162 Number of Processors: 1163 Platform ID: Linux164 CSD Version: 'Linux 3.13.0-91-generic'165 CPU:166 Vendor ID: GenuineIntel167 Version Info: 0x00000000168 Feature Info: 0x00000000169 - Type: LinuxProcStatus170 Text: |171 Name: a.out172 State: t (tracing stop)173 Tgid: 16001174 Ngid: 0175 Pid: 16001176 PPid: 13243177 TracerPid: 16002178 Uid: 404696 404696 404696 404696179 Gid: 5762 5762 5762 5762180...181)"),182 llvm::Succeeded());183 std::optional<LinuxProcStatus> proc_status = parser->GetLinuxProcStatus();184 ASSERT_TRUE(proc_status.has_value());185 lldb::pid_t pid = proc_status->GetPid();186 ASSERT_EQ(16001UL, pid);187}188 189TEST_F(MinidumpParserTest, GetPid) {190 ASSERT_THAT_ERROR(SetUpFromYaml(R"(191--- !minidump192Streams:193 - Type: SystemInfo194 Processor Arch: AMD64195 Processor Level: 6196 Processor Revision: 16130197 Number of Processors: 1198 Platform ID: Linux199 CSD Version: 'Linux 3.13.0-91-generic'200 CPU:201 Vendor ID: GenuineIntel202 Version Info: 0x00000000203 Feature Info: 0x00000000204 - Type: LinuxProcStatus205 Text: |206 Name: a.out207 State: t (tracing stop)208 Tgid: 16001209 Ngid: 0210 Pid: 16001211 PPid: 13243212 TracerPid: 16002213 Uid: 404696 404696 404696 404696214 Gid: 5762 5762 5762 5762215...216)"),217 llvm::Succeeded());218 std::optional<lldb::pid_t> pid = parser->GetPid();219 ASSERT_TRUE(pid.has_value());220 ASSERT_EQ(16001UL, *pid);221}222 223TEST_F(MinidumpParserTest, GetFilteredModuleList) {224 ASSERT_THAT_ERROR(SetUpFromYaml(R"(225--- !minidump226Streams:227 - Type: ModuleList228 Modules:229 - Base of Image: 0x0000000000400000230 Size of Image: 0x00001000231 Module Name: '/tmp/test/linux-x86_64_not_crashed'232 CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611233 - Base of Image: 0x0000000000600000234 Size of Image: 0x00002000235 Module Name: '/tmp/test/linux-x86_64_not_crashed'236 CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611237...238)"),239 llvm::Succeeded());240 llvm::ArrayRef<minidump::Module> modules = parser->GetModuleList();241 std::vector<const minidump::Module *> filtered_modules =242 parser->GetFilteredModuleList();243 EXPECT_EQ(2u, modules.size());244 ASSERT_EQ(1u, filtered_modules.size());245 const minidump::Module &M = *filtered_modules[0];246 EXPECT_THAT_EXPECTED(parser->GetMinidumpFile().getString(M.ModuleNameRVA),247 llvm::HasValue("/tmp/test/linux-x86_64_not_crashed"));248}249 250TEST_F(MinidumpParserTest, GetExceptionStream) {251 SetUpData("linux-x86_64.dmp");252 auto exception_streams = parser->GetExceptionStreams();253 size_t count = 0;254 for (auto exception_stream : exception_streams) {255 ASSERT_THAT_EXPECTED(exception_stream, llvm::Succeeded());256 ASSERT_EQ(16001UL, exception_stream->ThreadId);257 count++;258 }259 260 ASSERT_THAT(1UL, count);261}262 263void check_mem_range_exists(MinidumpParser &parser, const uint64_t range_start,264 const uint64_t range_size) {265 std::optional<minidump::Range> range = parser.FindMemoryRange(range_start);266 ASSERT_TRUE(range.has_value()) << "There is no range containing this address";267 EXPECT_EQ(range_start, range->start);268 EXPECT_EQ(range_start + range_size, range->start + range->range_ref.size());269}270 271TEST_F(MinidumpParserTest, FindMemoryRange) {272 ASSERT_THAT_ERROR(SetUpFromYaml(R"(273--- !minidump274Streams:275 - Type: MemoryList276 Memory Ranges:277 - Start of Memory Range: 0x00007FFCEB34A000278 Content: C84D04BCE9279 - Start of Memory Range: 0x0000000000401D46280 Content: 5421281...282)"),283 llvm::Succeeded());284 EXPECT_EQ(std::nullopt, parser->FindMemoryRange(0x00));285 EXPECT_EQ(std::nullopt, parser->FindMemoryRange(0x2a));286 EXPECT_EQ((minidump::Range{0x401d46, llvm::ArrayRef<uint8_t>{0x54, 0x21}}),287 parser->FindMemoryRange(0x401d46));288 EXPECT_EQ(std::nullopt, parser->FindMemoryRange(0x401d46 + 2));289 290 EXPECT_EQ(291 (minidump::Range{0x7ffceb34a000,292 llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}}),293 parser->FindMemoryRange(0x7ffceb34a000 + 2));294 EXPECT_EQ(std::nullopt, parser->FindMemoryRange(0x7ffceb34a000 + 5));295}296 297TEST_F(MinidumpParserTest, GetMemory) {298 ASSERT_THAT_ERROR(SetUpFromYaml(R"(299--- !minidump300Streams:301 - Type: MemoryList302 Memory Ranges:303 - Start of Memory Range: 0x00007FFCEB34A000304 Content: C84D04BCE9305 - Start of Memory Range: 0x0000000000401D46306 Content: 5421307...308)"),309 llvm::Succeeded());310 311 EXPECT_THAT_EXPECTED(parser->GetMemory(0x401d46, 1),312 llvm::HasValue(llvm::ArrayRef<uint8_t>{0x54}));313 EXPECT_THAT_EXPECTED(parser->GetMemory(0x401d46, 4),314 llvm::HasValue(llvm::ArrayRef<uint8_t>{0x54, 0x21}));315 EXPECT_THAT_EXPECTED(316 parser->GetMemory(0x7ffceb34a000, 5),317 llvm::HasValue(llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}));318 EXPECT_THAT_EXPECTED(319 parser->GetMemory(0x7ffceb34a000, 3),320 llvm::HasValue(llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04}));321 EXPECT_THAT_EXPECTED(322 parser->GetMemory(0x500000, 512),323 llvm::FailedWithMessage("No memory range found for address (0x500000)"));324}325 326TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) {327 SetUpData("fizzbuzz_wow64.dmp");328 329 // There are a lot of ranges in the file, just testing with some of them330 EXPECT_FALSE(parser->FindMemoryRange(0x00).has_value());331 EXPECT_FALSE(parser->FindMemoryRange(0x2a).has_value());332 check_mem_range_exists(*parser, 0x10000, 65536); // first range333 check_mem_range_exists(*parser, 0x40000, 4096);334 EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).has_value());335 check_mem_range_exists(*parser, 0x77c12000, 8192);336 check_mem_range_exists(*parser, 0x7ffe0000, 4096); // last range337 EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).has_value());338}339 340constexpr auto yes = MemoryRegionInfo::eYes;341constexpr auto no = MemoryRegionInfo::eNo;342constexpr auto unknown = MemoryRegionInfo::eDontKnow;343 344TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {345 ASSERT_THAT_ERROR(SetUpFromYaml(R"(346--- !minidump347Streams:348 - Type: MemoryInfoList349 Memory Ranges:350 - Base Address: 0x0000000000000000351 Allocation Protect: [ ]352 Region Size: 0x0000000000010000353 State: [ MEM_FREE ]354 Protect: [ PAGE_NO_ACCESS ]355 Type: [ ]356 - Base Address: 0x0000000000010000357 Allocation Protect: [ PAGE_READ_WRITE ]358 Region Size: 0x0000000000021000359 State: [ MEM_COMMIT ]360 Type: [ MEM_MAPPED ]361 - Base Address: 0x0000000000040000362 Allocation Protect: [ PAGE_EXECUTE_WRITE_COPY ]363 Region Size: 0x0000000000001000364 State: [ MEM_COMMIT ]365 Protect: [ PAGE_READ_ONLY ]366 Type: [ MEM_IMAGE ]367 - Base Address: 0x000000007FFE0000368 Allocation Protect: [ PAGE_READ_ONLY ]369 Region Size: 0x0000000000001000370 State: [ MEM_COMMIT ]371 Type: [ MEM_PRIVATE ]372 - Base Address: 0x000000007FFE1000373 Allocation Base: 0x000000007FFE0000374 Allocation Protect: [ PAGE_READ_ONLY ]375 Region Size: 0x000000000000F000376 State: [ MEM_RESERVE ]377 Protect: [ PAGE_NO_ACCESS ]378 Type: [ MEM_PRIVATE ]379...380)"),381 llvm::Succeeded());382 383 EXPECT_THAT(384 parser->BuildMemoryRegions(),385 testing::Pair(testing::ElementsAre(386 MemoryRegionInfo({0x0, 0x10000}, no, no, no, unknown,387 no, ConstString(), unknown, 0, unknown,388 unknown, unknown),389 MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no,390 unknown, yes, ConstString(), unknown,391 0, unknown, unknown, unknown),392 MemoryRegionInfo({0x40000, 0x1000}, yes, no, no,393 unknown, yes, ConstString(), unknown,394 0, unknown, unknown, unknown),395 MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no,396 unknown, yes, ConstString(), unknown,397 0, unknown, unknown, unknown),398 MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no,399 unknown, yes, ConstString(), unknown,400 0, unknown, unknown, unknown)),401 true));402}403 404TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) {405 ASSERT_THAT_ERROR(SetUpFromYaml(R"(406--- !minidump407Streams:408 - Type: MemoryList409 Memory Ranges:410 - Start of Memory Range: 0x0000000000001000411 Content: '31313131313131313131313131313131'412 - Start of Memory Range: 0x0000000000002000413 Content: '3333333333333333333333333333333333333333333333333333333333333333'414...415)"),416 llvm::Succeeded());417 418 // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when419 // we don't have a MemoryInfoListStream.420 421 EXPECT_THAT(422 parser->BuildMemoryRegions(),423 testing::Pair(testing::ElementsAre(424 MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown,425 unknown, yes, ConstString(), unknown,426 0, unknown, unknown, unknown),427 MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown,428 unknown, yes, ConstString(), unknown,429 0, unknown, unknown, unknown)),430 false));431}432 433TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) {434 SetUpData("regions-memlist64.dmp");435 436 // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when437 // we don't have a MemoryInfoListStream.438 EXPECT_THAT(439 parser->BuildMemoryRegions(),440 testing::Pair(testing::ElementsAre(441 MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown,442 unknown, yes, ConstString(), unknown,443 0, unknown, unknown, unknown),444 MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown,445 unknown, yes, ConstString(), unknown,446 0, unknown, unknown, unknown)),447 false));448}449 450TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {451 ASSERT_THAT_ERROR(SetUpFromYaml(R"(452--- !minidump453Streams:454 - Type: LinuxMaps455 Text: |456 400d9000-400db000 r-xp 00000000 b3:04 227 /system/bin/app_process457 400db000-400dc000 r--p 00001000 b3:04 227 /system/bin/app_process458 400dc000-400dd000 rw-p 00000000 00:00 0459 400ec000-400ed000 r--p 00000000 00:00 0460 400ee000-400ef000 rw-p 00010000 b3:04 300 /system/bin/linker461 400fc000-400fd000 rwxp 00001000 b3:04 1096 /system/lib/liblog.so462 463...464)"),465 llvm::Succeeded());466 // Test we can get memory regions from the linux /proc/<pid>/maps stream when467 // we don't have a MemoryInfoListStream.468 ConstString app_process("/system/bin/app_process");469 ConstString linker("/system/bin/linker");470 ConstString liblog("/system/lib/liblog.so");471 EXPECT_THAT(472 parser->BuildMemoryRegions(),473 testing::Pair(474 testing::ElementsAre(475 MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes, no, yes,476 app_process, unknown, 0, unknown, unknown,477 unknown),478 MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, no, yes,479 app_process, unknown, 0, unknown, unknown,480 unknown),481 MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, no, yes,482 ConstString(), unknown, 0, unknown, unknown,483 unknown),484 MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, no, yes,485 ConstString(), unknown, 0, unknown, unknown,486 unknown),487 MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, no, yes,488 linker, unknown, 0, unknown, unknown, unknown),489 MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, no, yes,490 liblog, unknown, 0, unknown, unknown, unknown)),491 true));492}493 494TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) {495 ASSERT_THAT_ERROR(SetUpFromYaml(R"(496--- !minidump497Streams:498 - Type: LinuxMaps499 Text: |500 400d9000-400db000 r?xp 00000000 b3:04 227501 400fc000-400fd000 rwxp 00001000 b3:04 1096502...503)"),504 llvm::Succeeded());505 // Test that when a /proc/maps region fails to parse506 // we handle the error and continue with the rest.507 EXPECT_THAT(parser->BuildMemoryRegions(),508 testing::Pair(testing::ElementsAre(MemoryRegionInfo(509 {0x400fc000, 0x1000}, yes, yes, yes, no, yes,510 ConstString(nullptr), unknown, 0, unknown,511 unknown, unknown)),512 true));513}514 515// Windows Minidump tests516TEST_F(MinidumpParserTest, GetArchitectureWindows) {517 ASSERT_THAT_ERROR(SetUpFromYaml(R"(518--- !minidump519Streams:520 - Type: SystemInfo521 Processor Arch: X86522 Processor Level: 6523 Processor Revision: 15876524 Number of Processors: 32525 Product type: 1526 Major Version: 6527 Minor Version: 1528 Build Number: 7601529 Platform ID: Win32NT530 CSD Version: Service Pack 1531 Suite Mask: 0x0100532 CPU:533 Vendor ID: GenuineIntel534 Version Info: 0x000306E4535 Feature Info: 0xBFEBFBFF536 AMD Extended Features: 0x771EEC80537...538)"),539 llvm::Succeeded());540 ASSERT_EQ(llvm::Triple::ArchType::x86,541 parser->GetArchitecture().GetMachine());542 ASSERT_EQ(llvm::Triple::OSType::Win32,543 parser->GetArchitecture().GetTriple().getOS());544}545 546TEST_F(MinidumpParserTest, GetLinuxProcStatus_no_stream) {547 // Test that GetLinuxProcStatus returns nullptr when the minidump does not548 // contain this stream.549 ASSERT_THAT_ERROR(SetUpFromYaml(R"(550--- !minidump551Streams:552...553)"),554 llvm::Succeeded());555 EXPECT_EQ(std::nullopt, parser->GetLinuxProcStatus());556}557 558TEST_F(MinidumpParserTest, GetMiscInfoWindows) {559 SetUpData("fizzbuzz_no_heap.dmp");560 const MinidumpMiscInfo *misc_info = parser->GetMiscInfo();561 ASSERT_NE(nullptr, misc_info);562 std::optional<lldb::pid_t> pid = misc_info->GetPid();563 ASSERT_TRUE(pid.has_value());564 ASSERT_EQ(4440UL, *pid);565}566 567TEST_F(MinidumpParserTest, GetPidWindows) {568 SetUpData("fizzbuzz_no_heap.dmp");569 std::optional<lldb::pid_t> pid = parser->GetPid();570 ASSERT_TRUE(pid.has_value());571 ASSERT_EQ(4440UL, *pid);572}573 574// wow64575TEST_F(MinidumpParserTest, GetPidWow64) {576 SetUpData("fizzbuzz_wow64.dmp");577 std::optional<lldb::pid_t> pid = parser->GetPid();578 ASSERT_TRUE(pid.has_value());579 ASSERT_EQ(7836UL, *pid);580}581 582// Register tests583#define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x))584#define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x))585 586TEST_F(MinidumpParserTest, GetThreadContext_x86_32) {587 ASSERT_THAT_ERROR(SetUpFromYaml(R"(588--- !minidump589Streams:590 - Type: ThreadList591 Threads:592 - Thread Id: 0x00026804593 Stack:594 Start of Memory Range: 0x00000000FF9DD000595 Content: 68D39DFF596 Context: 0F0001000000000000000000000000000000000000000000000000007F03FFFF0000FFFFFFFFFFFF09DC62F72300000088E36CF72B00FFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063000000000000002B0000002B000000A88204085CD59DFF008077F7A3D49DFF01000000000000003CD59DFFA082040823000000820201002CD59DFF2B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000597)"),598 llvm::Succeeded());599 600 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();601 const minidump::Thread &thread = thread_list[0];602 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));603 const MinidumpContext_x86_32 *context;604 EXPECT_TRUE(consumeObject(registers, context).Success());605 606 EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),607 MinidumpContext_x86_32_Flags::x86_32_Flag |608 MinidumpContext_x86_32_Flags::Full |609 MinidumpContext_x86_32_Flags::FloatingPoint);610 611 EXPECT_EQ(0x00000000u, context->eax);612 EXPECT_EQ(0xf7778000u, context->ebx);613 EXPECT_EQ(0x00000001u, context->ecx);614 EXPECT_EQ(0xff9dd4a3u, context->edx);615 EXPECT_EQ(0x080482a8u, context->edi);616 EXPECT_EQ(0xff9dd55cu, context->esi);617 EXPECT_EQ(0xff9dd53cu, context->ebp);618 EXPECT_EQ(0xff9dd52cu, context->esp);619 EXPECT_EQ(0x080482a0u, context->eip);620 EXPECT_EQ(0x00010282u, context->eflags);621 EXPECT_EQ(0x0023u, context->cs);622 EXPECT_EQ(0x0000u, context->fs);623 EXPECT_EQ(0x0063u, context->gs);624 EXPECT_EQ(0x002bu, context->ss);625 EXPECT_EQ(0x002bu, context->ds);626 EXPECT_EQ(0x002bu, context->es);627}628 629TEST_F(MinidumpParserTest, GetThreadContext_x86_64) {630 ASSERT_THAT_ERROR(SetUpFromYaml(R"(631--- !minidump632Streams:633 - Type: ThreadList634 Threads:635 - Thread Id: 0x00003E81636 Stack:637 Start of Memory Range: 0x00007FFCEB34A000638 Content: C84D04BCE97F00639 Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0010000000000033000000000000000000000006020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010A234EBFC7F000010A234EBFC7F00000000000000000000F09C34EBFC7F0000C0A91ABCE97F00000000000000000000A0163FBCE97F00004602000000000000921C40000000000030A434EBFC7F000000000000000000000000000000000000C61D4000000000007F0300000000000000000000000000000000000000000000801F0000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF25252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000640...641)"),642 llvm::Succeeded());643 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();644 const minidump::Thread &thread = thread_list[0];645 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));646 const MinidumpContext_x86_64 *context;647 EXPECT_TRUE(consumeObject(registers, context).Success());648 649 EXPECT_EQ(MinidumpContext_x86_64_Flags(uint32_t(context->context_flags)),650 MinidumpContext_x86_64_Flags::x86_64_Flag |651 MinidumpContext_x86_64_Flags::Control |652 MinidumpContext_x86_64_Flags::FloatingPoint |653 MinidumpContext_x86_64_Flags::Integer);654 EXPECT_EQ(0x0000000000000000u, context->rax);655 EXPECT_EQ(0x0000000000000000u, context->rbx);656 EXPECT_EQ(0x0000000000000010u, context->rcx);657 EXPECT_EQ(0x0000000000000000u, context->rdx);658 EXPECT_EQ(0x00007ffceb349cf0u, context->rdi);659 EXPECT_EQ(0x0000000000000000u, context->rsi);660 EXPECT_EQ(0x00007ffceb34a210u, context->rbp);661 EXPECT_EQ(0x00007ffceb34a210u, context->rsp);662 EXPECT_EQ(0x00007fe9bc1aa9c0u, context->r8);663 EXPECT_EQ(0x0000000000000000u, context->r9);664 EXPECT_EQ(0x00007fe9bc3f16a0u, context->r10);665 EXPECT_EQ(0x0000000000000246u, context->r11);666 EXPECT_EQ(0x0000000000401c92u, context->r12);667 EXPECT_EQ(0x00007ffceb34a430u, context->r13);668 EXPECT_EQ(0x0000000000000000u, context->r14);669 EXPECT_EQ(0x0000000000000000u, context->r15);670 EXPECT_EQ(0x0000000000401dc6u, context->rip);671 EXPECT_EQ(0x00010206u, context->eflags);672 EXPECT_EQ(0x0033u, context->cs);673 EXPECT_EQ(0x0000u, context->ss);674}675 676TEST_F(MinidumpParserTest, GetThreadContext_x86_32_wow64) {677 SetUpData("fizzbuzz_wow64.dmp");678 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();679 const minidump::Thread &thread = thread_list[0];680 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContextWow64(thread));681 const MinidumpContext_x86_32 *context;682 EXPECT_TRUE(consumeObject(registers, context).Success());683 684 EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),685 MinidumpContext_x86_32_Flags::x86_32_Flag |686 MinidumpContext_x86_32_Flags::Full |687 MinidumpContext_x86_32_Flags::FloatingPoint |688 MinidumpContext_x86_32_Flags::ExtendedRegisters);689 690 EXPECT_EQ(0x00000000u, context->eax);691 EXPECT_EQ(0x0037f608u, context->ebx);692 EXPECT_EQ(0x00e61578u, context->ecx);693 EXPECT_EQ(0x00000008u, context->edx);694 EXPECT_EQ(0x00000000u, context->edi);695 EXPECT_EQ(0x00000002u, context->esi);696 EXPECT_EQ(0x0037f654u, context->ebp);697 EXPECT_EQ(0x0037f5b8u, context->esp);698 EXPECT_EQ(0x77ce01fdu, context->eip);699 EXPECT_EQ(0x00000246u, context->eflags);700 EXPECT_EQ(0x0023u, context->cs);701 EXPECT_EQ(0x0053u, context->fs);702 EXPECT_EQ(0x002bu, context->gs);703 EXPECT_EQ(0x002bu, context->ss);704 EXPECT_EQ(0x002bu, context->ds);705 EXPECT_EQ(0x002bu, context->es);706}707 708TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) {709 ASSERT_THAT_ERROR(SetUpFromYaml(R"(710--- !minidump711Streams:712 - Type: ModuleList713 Modules:714 - Base of Image: 0x0000000000002000715 Size of Image: 0x00001000716 Module Name: '/tmp/a'717 CodeView Record: ''718 - Base of Image: 0x0000000000001000719 Size of Image: 0x00001000720 Module Name: '/tmp/a'721 CodeView Record: ''722...723)"),724 llvm::Succeeded());725 // If we have a module mentioned twice in the module list, the filtered726 // module list should contain the instance with the lowest BaseOfImage.727 std::vector<const minidump::Module *> filtered_modules =728 parser->GetFilteredModuleList();729 ASSERT_EQ(1u, filtered_modules.size());730 EXPECT_EQ(0x0000000000001000u, filtered_modules[0]->BaseOfImage);731}732 733TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedFirst) {734 ASSERT_THAT_ERROR(SetUpFromYaml(R"(735--- !minidump736Streams:737 - Type: ModuleList738 Modules:739 - Base of Image: 0x400d0000740 Size of Image: 0x00002000741 Module Name: '/usr/lib/libc.so'742 CodeView Record: ''743 - Base of Image: 0x400d3000744 Size of Image: 0x00001000745 Module Name: '/usr/lib/libc.so'746 CodeView Record: ''747 - Type: LinuxMaps748 Text: |749 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so750 400d2000-400d3000 rw-p 00000000 00:00 0751 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so752 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so753...754)"),755 llvm::Succeeded());756 // If we have a module mentioned twice in the module list, and we have full757 // linux maps for all of the memory regions, make sure we pick the one that758 // has a consecutive region with a matching path that has executable759 // permissions. If clients open an object file with mmap, breakpad can create760 // multiple mappings for a library errnoneously and the lowest address isn't761 // always the right address. In this case we check the consective memory762 // regions whose path matches starting at the base of image address and make763 // sure one of the regions is executable and prefer that one.764 //765 // This test will make sure that if the executable is second in the module766 // list, that it will become the selected module in the filtered list.767 std::vector<const minidump::Module *> filtered_modules =768 parser->GetFilteredModuleList();769 ASSERT_EQ(1u, filtered_modules.size());770 EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage);771}772 773TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecond) {774 ASSERT_THAT_ERROR(SetUpFromYaml(R"(775--- !minidump776Streams:777 - Type: ModuleList778 Modules:779 - Base of Image: 0x400d0000780 Size of Image: 0x00002000781 Module Name: '/usr/lib/libc.so'782 CodeView Record: ''783 - Base of Image: 0x400d3000784 Size of Image: 0x00001000785 Module Name: '/usr/lib/libc.so'786 CodeView Record: ''787 - Type: LinuxMaps788 Text: |789 400d0000-400d1000 r-xp 00010000 b3:04 227 /usr/lib/libc.so790 400d1000-400d2000 rwxp 00001000 b3:04 227 /usr/lib/libc.so791 400d2000-400d3000 rw-p 00000000 00:00 0792 400d3000-400d5000 r--p 00000000 b3:04 227 /usr/lib/libc.so793...794)"),795 llvm::Succeeded());796 // If we have a module mentioned twice in the module list, and we have full797 // linux maps for all of the memory regions, make sure we pick the one that798 // has a consecutive region with a matching path that has executable799 // permissions. If clients open an object file with mmap, breakpad can create800 // multiple mappings for a library errnoneously and the lowest address isn't801 // always the right address. In this case we check the consective memory802 // regions whose path matches starting at the base of image address and make803 // sure one of the regions is executable and prefer that one.804 //805 // This test will make sure that if the executable is first in the module806 // list, that it will remain the correctly selected module in the filtered807 // list.808 std::vector<const minidump::Module *> filtered_modules =809 parser->GetFilteredModuleList();810 ASSERT_EQ(1u, filtered_modules.size());811 EXPECT_EQ(0x400d0000u, filtered_modules[0]->BaseOfImage);812}813 814TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecondHigh) {815 ASSERT_THAT_ERROR(SetUpFromYaml(R"(816--- !minidump817Streams:818 - Type: ModuleList819 Modules:820 - Base of Image: 0x400d3000821 Size of Image: 0x00002000822 Module Name: '/usr/lib/libc.so'823 CodeView Record: ''824 - Base of Image: 0x400d0000825 Size of Image: 0x00001000826 Module Name: '/usr/lib/libc.so'827 CodeView Record: ''828 - Type: LinuxMaps829 Text: |830 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so831 400d2000-400d3000 rw-p 00000000 00:00 0832 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so833 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so834...835)"),836 llvm::Succeeded());837 // If we have a module mentioned twice in the module list, and we have full838 // linux maps for all of the memory regions, make sure we pick the one that839 // has a consecutive region with a matching path that has executable840 // permissions. If clients open an object file with mmap, breakpad can create841 // multiple mappings for a library errnoneously and the lowest address isn't842 // always the right address. In this case we check the consective memory843 // regions whose path matches starting at the base of image address and make844 // sure one of the regions is executable and prefer that one.845 //846 // This test will make sure that if the executable is first in the module847 // list, that it will remain the correctly selected module in the filtered848 // list, even if the non-executable module was loaded at a lower base address.849 std::vector<const minidump::Module *> filtered_modules =850 parser->GetFilteredModuleList();851 ASSERT_EQ(1u, filtered_modules.size());852 EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage);853}854 855TEST_F(MinidumpParserTest, MinidumpDuplicateModuleSeparateCode) {856 ASSERT_THAT_ERROR(SetUpFromYaml(R"(857--- !minidump858Streams:859 - Type: ModuleList860 Modules:861 - Base of Image: 0x400d0000862 Size of Image: 0x00002000863 Module Name: '/usr/lib/libc.so'864 CodeView Record: ''865 - Base of Image: 0x400d5000866 Size of Image: 0x00001000867 Module Name: '/usr/lib/libc.so'868 CodeView Record: ''869 - Type: LinuxMaps870 Text: |871 400d0000-400d3000 r--p 00000000 b3:04 227 /usr/lib/libc.so872 400d3000-400d5000 rw-p 00000000 00:00 0873 400d5000-400d6000 r--p 00000000 b3:04 227 /usr/lib/libc.so874 400d6000-400d7000 r-xp 00010000 b3:04 227 /usr/lib/libc.so875 400d7000-400d8000 rwxp 00001000 b3:04 227 /usr/lib/libc.so876...877)"),878 llvm::Succeeded());879 // If we have a module mentioned twice in the module list, and we have full880 // linux maps for all of the memory regions, make sure we pick the one that881 // has a consecutive region with a matching path that has executable882 // permissions. If clients open an object file with mmap, breakpad can create883 // multiple mappings for a library errnoneously and the lowest address isn't884 // always the right address. In this case we check the consective memory885 // regions whose path matches starting at the base of image address and make886 // sure one of the regions is executable and prefer that one.887 //888 // This test will make sure if binaries are compiled with "-z separate-code",889 // where the first region for a binary won't be marked as executable, that890 // it gets selected by detecting the second consecutive mapping at 0x400d7000891 // when asked about the a module mamed "/usr/lib/libc.so" at 0x400d5000.892 std::vector<const minidump::Module *> filtered_modules =893 parser->GetFilteredModuleList();894 ASSERT_EQ(1u, filtered_modules.size());895 EXPECT_EQ(0x400d5000u, filtered_modules[0]->BaseOfImage);896}897 898TEST_F(MinidumpParserTest, MinidumpModuleOrder) {899 ASSERT_THAT_ERROR(SetUpFromYaml(R"(900--- !minidump901Streams:902 - Type: ModuleList903 Modules:904 - Base of Image: 0x0000000000002000905 Size of Image: 0x00001000906 Module Name: '/tmp/a'907 CodeView Record: ''908 - Base of Image: 0x0000000000001000909 Size of Image: 0x00001000910 Module Name: '/tmp/b'911 CodeView Record: ''912...913)"),914 llvm::Succeeded());915 // Test module filtering does not affect the overall module order. Previous916 // versions of the MinidumpParser::GetFilteredModuleList() function would sort917 // all images by address and modify the order of the modules.918 std::vector<const minidump::Module *> filtered_modules =919 parser->GetFilteredModuleList();920 ASSERT_EQ(2u, filtered_modules.size());921 EXPECT_EQ(0x0000000000002000u, filtered_modules[0]->BaseOfImage);922 EXPECT_THAT_EXPECTED(923 parser->GetMinidumpFile().getString(filtered_modules[0]->ModuleNameRVA),924 llvm::HasValue("/tmp/a"));925 EXPECT_EQ(0x0000000000001000u, filtered_modules[1]->BaseOfImage);926 EXPECT_THAT_EXPECTED(927 parser->GetMinidumpFile().getString(filtered_modules[1]->ModuleNameRVA),928 llvm::HasValue("/tmp/b"));929}930