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-exception 6 // 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/ADT/Optional.h" 23 #include "llvm/ObjectYAML/yaml2obj.h" 24 #include "llvm/Support/FileSystem.h" 25 #include "llvm/Support/MemoryBuffer.h" 26 #include "llvm/Support/Path.h" 27 #include "llvm/Support/YAMLTraits.h" 28 #include "llvm/Testing/Support/Error.h" 29 #include "gtest/gtest.h" 30 31 // C includes 32 33 // C++ includes 34 #include <memory> 35 36 using namespace lldb_private; 37 using namespace minidump; 38 39 class MinidumpParserTest : public testing::Test { 40 public: 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 os.flush(); 63 auto data_buffer_sp = 64 std::make_shared<DataBufferHeap>(data.data(), data.size()); 65 auto expected_parser = MinidumpParser::Create(std::move(data_buffer_sp)); 66 if (!expected_parser) 67 return expected_parser.takeError(); 68 parser = std::move(*expected_parser); 69 return llvm::Error::success(); 70 } 71 72 llvm::Optional<MinidumpParser> parser; 73 }; 74 75 TEST_F(MinidumpParserTest, InvalidMinidump) { 76 std::string duplicate_streams; 77 llvm::raw_string_ostream os(duplicate_streams); 78 llvm::yaml::Input YIn(R"( 79 --- !minidump 80 Streams: 81 - Type: LinuxAuxv 82 Content: DEADBEEFBAADF00D 83 - Type: LinuxAuxv 84 Content: DEADBEEFBAADF00D 85 )"); 86 87 ASSERT_TRUE(llvm::yaml::convertYAML(YIn, os, [](const llvm::Twine &Msg){})); 88 os.flush(); 89 auto data_buffer_sp = std::make_shared<DataBufferHeap>( 90 duplicate_streams.data(), duplicate_streams.size()); 91 ASSERT_THAT_EXPECTED(MinidumpParser::Create(data_buffer_sp), llvm::Failed()); 92 } 93 94 TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) { 95 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 96 --- !minidump 97 Streams: 98 - Type: ThreadList 99 Threads: 100 - Thread Id: 0x00003E81 101 Stack: 102 Start of Memory Range: 0x00007FFCEB34A000 103 Content: C84D04BCE97F00 104 Context: 00000000000000 105 ... 106 )"), 107 llvm::Succeeded()); 108 llvm::ArrayRef<minidump::Thread> thread_list; 109 110 thread_list = parser->GetThreads(); 111 ASSERT_EQ(1UL, thread_list.size()); 112 113 const minidump::Thread &thread = thread_list[0]; 114 115 EXPECT_EQ(0x3e81u, thread.ThreadId); 116 117 llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(thread); 118 EXPECT_EQ(7u, context.size()); 119 } 120 121 TEST_F(MinidumpParserTest, GetArchitecture) { 122 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 123 --- !minidump 124 Streams: 125 - Type: SystemInfo 126 Processor Arch: AMD64 127 Processor Level: 6 128 Processor Revision: 16130 129 Number of Processors: 1 130 Platform ID: Linux 131 CPU: 132 Vendor ID: GenuineIntel 133 Version Info: 0x00000000 134 Feature Info: 0x00000000 135 ... 136 )"), 137 llvm::Succeeded()); 138 ASSERT_EQ(llvm::Triple::ArchType::x86_64, 139 parser->GetArchitecture().GetMachine()); 140 ASSERT_EQ(llvm::Triple::OSType::Linux, 141 parser->GetArchitecture().GetTriple().getOS()); 142 } 143 144 TEST_F(MinidumpParserTest, GetMiscInfo_no_stream) { 145 // Test that GetMiscInfo returns nullptr when the minidump does not contain 146 // this stream. 147 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 148 --- !minidump 149 Streams: 150 ... 151 )"), 152 llvm::Succeeded()); 153 EXPECT_EQ(nullptr, parser->GetMiscInfo()); 154 } 155 156 TEST_F(MinidumpParserTest, GetLinuxProcStatus) { 157 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 158 --- !minidump 159 Streams: 160 - Type: SystemInfo 161 Processor Arch: AMD64 162 Processor Level: 6 163 Processor Revision: 16130 164 Number of Processors: 1 165 Platform ID: Linux 166 CSD Version: 'Linux 3.13.0-91-generic' 167 CPU: 168 Vendor ID: GenuineIntel 169 Version Info: 0x00000000 170 Feature Info: 0x00000000 171 - Type: LinuxProcStatus 172 Text: | 173 Name: a.out 174 State: t (tracing stop) 175 Tgid: 16001 176 Ngid: 0 177 Pid: 16001 178 PPid: 13243 179 TracerPid: 16002 180 Uid: 404696 404696 404696 404696 181 Gid: 5762 5762 5762 5762 182 ... 183 )"), 184 llvm::Succeeded()); 185 llvm::Optional<LinuxProcStatus> proc_status = parser->GetLinuxProcStatus(); 186 ASSERT_TRUE(proc_status.hasValue()); 187 lldb::pid_t pid = proc_status->GetPid(); 188 ASSERT_EQ(16001UL, pid); 189 } 190 191 TEST_F(MinidumpParserTest, GetPid) { 192 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 193 --- !minidump 194 Streams: 195 - Type: SystemInfo 196 Processor Arch: AMD64 197 Processor Level: 6 198 Processor Revision: 16130 199 Number of Processors: 1 200 Platform ID: Linux 201 CSD Version: 'Linux 3.13.0-91-generic' 202 CPU: 203 Vendor ID: GenuineIntel 204 Version Info: 0x00000000 205 Feature Info: 0x00000000 206 - Type: LinuxProcStatus 207 Text: | 208 Name: a.out 209 State: t (tracing stop) 210 Tgid: 16001 211 Ngid: 0 212 Pid: 16001 213 PPid: 13243 214 TracerPid: 16002 215 Uid: 404696 404696 404696 404696 216 Gid: 5762 5762 5762 5762 217 ... 218 )"), 219 llvm::Succeeded()); 220 llvm::Optional<lldb::pid_t> pid = parser->GetPid(); 221 ASSERT_TRUE(pid.hasValue()); 222 ASSERT_EQ(16001UL, pid.getValue()); 223 } 224 225 TEST_F(MinidumpParserTest, GetFilteredModuleList) { 226 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 227 --- !minidump 228 Streams: 229 - Type: ModuleList 230 Modules: 231 - Base of Image: 0x0000000000400000 232 Size of Image: 0x00001000 233 Module Name: '/tmp/test/linux-x86_64_not_crashed' 234 CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611 235 - Base of Image: 0x0000000000600000 236 Size of Image: 0x00002000 237 Module Name: '/tmp/test/linux-x86_64_not_crashed' 238 CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611 239 ... 240 )"), 241 llvm::Succeeded()); 242 llvm::ArrayRef<minidump::Module> modules = parser->GetModuleList(); 243 std::vector<const minidump::Module *> filtered_modules = 244 parser->GetFilteredModuleList(); 245 EXPECT_EQ(2u, modules.size()); 246 ASSERT_EQ(1u, filtered_modules.size()); 247 const minidump::Module &M = *filtered_modules[0]; 248 EXPECT_THAT_EXPECTED(parser->GetMinidumpFile().getString(M.ModuleNameRVA), 249 llvm::HasValue("/tmp/test/linux-x86_64_not_crashed")); 250 } 251 252 TEST_F(MinidumpParserTest, GetExceptionStream) { 253 SetUpData("linux-x86_64.dmp"); 254 const llvm::minidump::ExceptionStream *exception_stream = 255 parser->GetExceptionStream(); 256 ASSERT_NE(nullptr, exception_stream); 257 ASSERT_EQ(11UL, exception_stream->ExceptionRecord.ExceptionCode); 258 } 259 260 void check_mem_range_exists(MinidumpParser &parser, const uint64_t range_start, 261 const uint64_t range_size) { 262 llvm::Optional<minidump::Range> range = parser.FindMemoryRange(range_start); 263 ASSERT_TRUE(range.hasValue()) << "There is no range containing this address"; 264 EXPECT_EQ(range_start, range->start); 265 EXPECT_EQ(range_start + range_size, range->start + range->range_ref.size()); 266 } 267 268 TEST_F(MinidumpParserTest, FindMemoryRange) { 269 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 270 --- !minidump 271 Streams: 272 - Type: MemoryList 273 Memory Ranges: 274 - Start of Memory Range: 0x00007FFCEB34A000 275 Content: C84D04BCE9 276 - Start of Memory Range: 0x0000000000401D46 277 Content: 5421 278 ... 279 )"), 280 llvm::Succeeded()); 281 EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x00)); 282 EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x2a)); 283 EXPECT_EQ((minidump::Range{0x401d46, llvm::ArrayRef<uint8_t>{0x54, 0x21}}), 284 parser->FindMemoryRange(0x401d46)); 285 EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x401d46 + 2)); 286 287 EXPECT_EQ( 288 (minidump::Range{0x7ffceb34a000, 289 llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}}), 290 parser->FindMemoryRange(0x7ffceb34a000 + 2)); 291 EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x7ffceb34a000 + 5)); 292 } 293 294 TEST_F(MinidumpParserTest, GetMemory) { 295 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 296 --- !minidump 297 Streams: 298 - Type: MemoryList 299 Memory Ranges: 300 - Start of Memory Range: 0x00007FFCEB34A000 301 Content: C84D04BCE9 302 - Start of Memory Range: 0x0000000000401D46 303 Content: 5421 304 ... 305 )"), 306 llvm::Succeeded()); 307 308 EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54}), parser->GetMemory(0x401d46, 1)); 309 EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54, 0x21}), 310 parser->GetMemory(0x401d46, 4)); 311 312 EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}), 313 parser->GetMemory(0x7ffceb34a000, 5)); 314 EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04}), 315 parser->GetMemory(0x7ffceb34a000, 3)); 316 317 EXPECT_EQ(llvm::ArrayRef<uint8_t>(), parser->GetMemory(0x500000, 512)); 318 } 319 320 TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) { 321 SetUpData("fizzbuzz_wow64.dmp"); 322 323 // There are a lot of ranges in the file, just testing with some of them 324 EXPECT_FALSE(parser->FindMemoryRange(0x00).hasValue()); 325 EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue()); 326 check_mem_range_exists(*parser, 0x10000, 65536); // first range 327 check_mem_range_exists(*parser, 0x40000, 4096); 328 EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).hasValue()); 329 check_mem_range_exists(*parser, 0x77c12000, 8192); 330 check_mem_range_exists(*parser, 0x7ffe0000, 4096); // last range 331 EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).hasValue()); 332 } 333 334 constexpr auto yes = MemoryRegionInfo::eYes; 335 constexpr auto no = MemoryRegionInfo::eNo; 336 constexpr auto unknown = MemoryRegionInfo::eDontKnow; 337 338 TEST_F(MinidumpParserTest, GetMemoryRegionInfo) { 339 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 340 --- !minidump 341 Streams: 342 - Type: MemoryInfoList 343 Memory Ranges: 344 - Base Address: 0x0000000000000000 345 Allocation Protect: [ ] 346 Region Size: 0x0000000000010000 347 State: [ MEM_FREE ] 348 Protect: [ PAGE_NO_ACCESS ] 349 Type: [ ] 350 - Base Address: 0x0000000000010000 351 Allocation Protect: [ PAGE_READ_WRITE ] 352 Region Size: 0x0000000000021000 353 State: [ MEM_COMMIT ] 354 Type: [ MEM_MAPPED ] 355 - Base Address: 0x0000000000040000 356 Allocation Protect: [ PAGE_EXECUTE_WRITE_COPY ] 357 Region Size: 0x0000000000001000 358 State: [ MEM_COMMIT ] 359 Protect: [ PAGE_READ_ONLY ] 360 Type: [ MEM_IMAGE ] 361 - Base Address: 0x000000007FFE0000 362 Allocation Protect: [ PAGE_READ_ONLY ] 363 Region Size: 0x0000000000001000 364 State: [ MEM_COMMIT ] 365 Type: [ MEM_PRIVATE ] 366 - Base Address: 0x000000007FFE1000 367 Allocation Base: 0x000000007FFE0000 368 Allocation Protect: [ PAGE_READ_ONLY ] 369 Region Size: 0x000000000000F000 370 State: [ MEM_RESERVE ] 371 Protect: [ PAGE_NO_ACCESS ] 372 Type: [ MEM_PRIVATE ] 373 ... 374 )"), 375 llvm::Succeeded()); 376 377 EXPECT_THAT( 378 parser->BuildMemoryRegions(), 379 testing::Pair(testing::ElementsAre( 380 MemoryRegionInfo({0x0, 0x10000}, no, no, no, no, 381 ConstString(), unknown, 0, unknown), 382 MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, yes, 383 ConstString(), unknown, 0, unknown), 384 MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, yes, 385 ConstString(), unknown, 0, unknown), 386 MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, yes, 387 ConstString(), unknown, 0, unknown), 388 MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, yes, 389 ConstString(), unknown, 0, unknown)), 390 true)); 391 } 392 393 TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) { 394 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 395 --- !minidump 396 Streams: 397 - Type: MemoryList 398 Memory Ranges: 399 - Start of Memory Range: 0x0000000000001000 400 Content: '31313131313131313131313131313131' 401 - Start of Memory Range: 0x0000000000002000 402 Content: '3333333333333333333333333333333333333333333333333333333333333333' 403 ... 404 )"), 405 llvm::Succeeded()); 406 407 // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when 408 // we don't have a MemoryInfoListStream. 409 410 EXPECT_THAT( 411 parser->BuildMemoryRegions(), 412 testing::Pair( 413 testing::ElementsAre( 414 MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, yes, 415 ConstString(), unknown, 0, unknown), 416 MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes, 417 ConstString(), unknown, 0, unknown)), 418 false)); 419 } 420 421 TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) { 422 SetUpData("regions-memlist64.dmp"); 423 424 // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when 425 // we don't have a MemoryInfoListStream. 426 EXPECT_THAT( 427 parser->BuildMemoryRegions(), 428 testing::Pair( 429 testing::ElementsAre( 430 MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, yes, 431 ConstString(), unknown, 0, unknown), 432 MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes, 433 ConstString(), unknown, 0, unknown)), 434 false)); 435 } 436 437 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) { 438 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 439 --- !minidump 440 Streams: 441 - Type: LinuxMaps 442 Text: | 443 400d9000-400db000 r-xp 00000000 b3:04 227 /system/bin/app_process 444 400db000-400dc000 r--p 00001000 b3:04 227 /system/bin/app_process 445 400dc000-400dd000 rw-p 00000000 00:00 0 446 400ec000-400ed000 r--p 00000000 00:00 0 447 400ee000-400ef000 rw-p 00010000 b3:04 300 /system/bin/linker 448 400fc000-400fd000 rwxp 00001000 b3:04 1096 /system/lib/liblog.so 449 450 ... 451 )"), 452 llvm::Succeeded()); 453 // Test we can get memory regions from the linux /proc/<pid>/maps stream when 454 // we don't have a MemoryInfoListStream. 455 ConstString app_process("/system/bin/app_process"); 456 ConstString linker("/system/bin/linker"); 457 ConstString liblog("/system/lib/liblog.so"); 458 EXPECT_THAT(parser->BuildMemoryRegions(), 459 testing::Pair( 460 testing::ElementsAre( 461 MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes, yes, 462 app_process, unknown, 0, unknown), 463 MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, yes, 464 app_process, unknown, 0, unknown), 465 MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, yes, 466 ConstString(), unknown, 0, unknown), 467 MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, yes, 468 ConstString(), unknown, 0, unknown), 469 MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, yes, 470 linker, unknown, 0, unknown), 471 MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, yes, 472 liblog, unknown, 0, unknown)), 473 true)); 474 } 475 476 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) { 477 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 478 --- !minidump 479 Streams: 480 - Type: LinuxMaps 481 Text: | 482 400d9000-400db000 r?xp 00000000 b3:04 227 483 400fc000-400fd000 rwxp 00001000 b3:04 1096 484 ... 485 )"), 486 llvm::Succeeded()); 487 // Test that when a /proc/maps region fails to parse 488 // we handle the error and continue with the rest. 489 EXPECT_THAT(parser->BuildMemoryRegions(), 490 testing::Pair(testing::ElementsAre(MemoryRegionInfo( 491 {0x400fc000, 0x1000}, yes, yes, yes, yes, 492 ConstString(nullptr), unknown, 0, unknown)), 493 true)); 494 } 495 496 // Windows Minidump tests 497 TEST_F(MinidumpParserTest, GetArchitectureWindows) { 498 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 499 --- !minidump 500 Streams: 501 - Type: SystemInfo 502 Processor Arch: X86 503 Processor Level: 6 504 Processor Revision: 15876 505 Number of Processors: 32 506 Product type: 1 507 Major Version: 6 508 Minor Version: 1 509 Build Number: 7601 510 Platform ID: Win32NT 511 CSD Version: Service Pack 1 512 Suite Mask: 0x0100 513 CPU: 514 Vendor ID: GenuineIntel 515 Version Info: 0x000306E4 516 Feature Info: 0xBFEBFBFF 517 AMD Extended Features: 0x771EEC80 518 ... 519 )"), 520 llvm::Succeeded()); 521 ASSERT_EQ(llvm::Triple::ArchType::x86, 522 parser->GetArchitecture().GetMachine()); 523 ASSERT_EQ(llvm::Triple::OSType::Win32, 524 parser->GetArchitecture().GetTriple().getOS()); 525 } 526 527 TEST_F(MinidumpParserTest, GetLinuxProcStatus_no_stream) { 528 // Test that GetLinuxProcStatus returns nullptr when the minidump does not 529 // contain this stream. 530 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 531 --- !minidump 532 Streams: 533 ... 534 )"), 535 llvm::Succeeded()); 536 EXPECT_EQ(llvm::None, parser->GetLinuxProcStatus()); 537 } 538 539 TEST_F(MinidumpParserTest, GetMiscInfoWindows) { 540 SetUpData("fizzbuzz_no_heap.dmp"); 541 const MinidumpMiscInfo *misc_info = parser->GetMiscInfo(); 542 ASSERT_NE(nullptr, misc_info); 543 llvm::Optional<lldb::pid_t> pid = misc_info->GetPid(); 544 ASSERT_TRUE(pid.hasValue()); 545 ASSERT_EQ(4440UL, pid.getValue()); 546 } 547 548 TEST_F(MinidumpParserTest, GetPidWindows) { 549 SetUpData("fizzbuzz_no_heap.dmp"); 550 llvm::Optional<lldb::pid_t> pid = parser->GetPid(); 551 ASSERT_TRUE(pid.hasValue()); 552 ASSERT_EQ(4440UL, pid.getValue()); 553 } 554 555 // wow64 556 TEST_F(MinidumpParserTest, GetPidWow64) { 557 SetUpData("fizzbuzz_wow64.dmp"); 558 llvm::Optional<lldb::pid_t> pid = parser->GetPid(); 559 ASSERT_TRUE(pid.hasValue()); 560 ASSERT_EQ(7836UL, pid.getValue()); 561 } 562 563 // Register tests 564 #define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x)) 565 #define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x)) 566 567 TEST_F(MinidumpParserTest, GetThreadContext_x86_32) { 568 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 569 --- !minidump 570 Streams: 571 - Type: ThreadList 572 Threads: 573 - Thread Id: 0x00026804 574 Stack: 575 Start of Memory Range: 0x00000000FF9DD000 576 Content: 68D39DFF 577 Context: 0F0001000000000000000000000000000000000000000000000000007F03FFFF0000FFFFFFFFFFFF09DC62F72300000088E36CF72B00FFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063000000000000002B0000002B000000A88204085CD59DFF008077F7A3D49DFF01000000000000003CD59DFFA082040823000000820201002CD59DFF2B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 578 )"), 579 llvm::Succeeded()); 580 581 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads(); 582 const minidump::Thread &thread = thread_list[0]; 583 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread)); 584 const MinidumpContext_x86_32 *context; 585 EXPECT_TRUE(consumeObject(registers, context).Success()); 586 587 EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)), 588 MinidumpContext_x86_32_Flags::x86_32_Flag | 589 MinidumpContext_x86_32_Flags::Full | 590 MinidumpContext_x86_32_Flags::FloatingPoint); 591 592 EXPECT_EQ(0x00000000u, context->eax); 593 EXPECT_EQ(0xf7778000u, context->ebx); 594 EXPECT_EQ(0x00000001u, context->ecx); 595 EXPECT_EQ(0xff9dd4a3u, context->edx); 596 EXPECT_EQ(0x080482a8u, context->edi); 597 EXPECT_EQ(0xff9dd55cu, context->esi); 598 EXPECT_EQ(0xff9dd53cu, context->ebp); 599 EXPECT_EQ(0xff9dd52cu, context->esp); 600 EXPECT_EQ(0x080482a0u, context->eip); 601 EXPECT_EQ(0x00010282u, context->eflags); 602 EXPECT_EQ(0x0023u, context->cs); 603 EXPECT_EQ(0x0000u, context->fs); 604 EXPECT_EQ(0x0063u, context->gs); 605 EXPECT_EQ(0x002bu, context->ss); 606 EXPECT_EQ(0x002bu, context->ds); 607 EXPECT_EQ(0x002bu, context->es); 608 } 609 610 TEST_F(MinidumpParserTest, GetThreadContext_x86_64) { 611 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 612 --- !minidump 613 Streams: 614 - Type: ThreadList 615 Threads: 616 - Thread Id: 0x00003E81 617 Stack: 618 Start of Memory Range: 0x00007FFCEB34A000 619 Content: C84D04BCE97F00 620 Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0010000000000033000000000000000000000006020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010A234EBFC7F000010A234EBFC7F00000000000000000000F09C34EBFC7F0000C0A91ABCE97F00000000000000000000A0163FBCE97F00004602000000000000921C40000000000030A434EBFC7F000000000000000000000000000000000000C61D4000000000007F0300000000000000000000000000000000000000000000801F0000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF25252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 621 ... 622 )"), 623 llvm::Succeeded()); 624 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads(); 625 const minidump::Thread &thread = thread_list[0]; 626 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread)); 627 const MinidumpContext_x86_64 *context; 628 EXPECT_TRUE(consumeObject(registers, context).Success()); 629 630 EXPECT_EQ(MinidumpContext_x86_64_Flags(uint32_t(context->context_flags)), 631 MinidumpContext_x86_64_Flags::x86_64_Flag | 632 MinidumpContext_x86_64_Flags::Control | 633 MinidumpContext_x86_64_Flags::FloatingPoint | 634 MinidumpContext_x86_64_Flags::Integer); 635 EXPECT_EQ(0x0000000000000000u, context->rax); 636 EXPECT_EQ(0x0000000000000000u, context->rbx); 637 EXPECT_EQ(0x0000000000000010u, context->rcx); 638 EXPECT_EQ(0x0000000000000000u, context->rdx); 639 EXPECT_EQ(0x00007ffceb349cf0u, context->rdi); 640 EXPECT_EQ(0x0000000000000000u, context->rsi); 641 EXPECT_EQ(0x00007ffceb34a210u, context->rbp); 642 EXPECT_EQ(0x00007ffceb34a210u, context->rsp); 643 EXPECT_EQ(0x00007fe9bc1aa9c0u, context->r8); 644 EXPECT_EQ(0x0000000000000000u, context->r9); 645 EXPECT_EQ(0x00007fe9bc3f16a0u, context->r10); 646 EXPECT_EQ(0x0000000000000246u, context->r11); 647 EXPECT_EQ(0x0000000000401c92u, context->r12); 648 EXPECT_EQ(0x00007ffceb34a430u, context->r13); 649 EXPECT_EQ(0x0000000000000000u, context->r14); 650 EXPECT_EQ(0x0000000000000000u, context->r15); 651 EXPECT_EQ(0x0000000000401dc6u, context->rip); 652 EXPECT_EQ(0x00010206u, context->eflags); 653 EXPECT_EQ(0x0033u, context->cs); 654 EXPECT_EQ(0x0000u, context->ss); 655 } 656 657 TEST_F(MinidumpParserTest, GetThreadContext_x86_32_wow64) { 658 SetUpData("fizzbuzz_wow64.dmp"); 659 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads(); 660 const minidump::Thread &thread = thread_list[0]; 661 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContextWow64(thread)); 662 const MinidumpContext_x86_32 *context; 663 EXPECT_TRUE(consumeObject(registers, context).Success()); 664 665 EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)), 666 MinidumpContext_x86_32_Flags::x86_32_Flag | 667 MinidumpContext_x86_32_Flags::Full | 668 MinidumpContext_x86_32_Flags::FloatingPoint | 669 MinidumpContext_x86_32_Flags::ExtendedRegisters); 670 671 EXPECT_EQ(0x00000000u, context->eax); 672 EXPECT_EQ(0x0037f608u, context->ebx); 673 EXPECT_EQ(0x00e61578u, context->ecx); 674 EXPECT_EQ(0x00000008u, context->edx); 675 EXPECT_EQ(0x00000000u, context->edi); 676 EXPECT_EQ(0x00000002u, context->esi); 677 EXPECT_EQ(0x0037f654u, context->ebp); 678 EXPECT_EQ(0x0037f5b8u, context->esp); 679 EXPECT_EQ(0x77ce01fdu, context->eip); 680 EXPECT_EQ(0x00000246u, context->eflags); 681 EXPECT_EQ(0x0023u, context->cs); 682 EXPECT_EQ(0x0053u, context->fs); 683 EXPECT_EQ(0x002bu, context->gs); 684 EXPECT_EQ(0x002bu, context->ss); 685 EXPECT_EQ(0x002bu, context->ds); 686 EXPECT_EQ(0x002bu, context->es); 687 } 688 689 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) { 690 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 691 --- !minidump 692 Streams: 693 - Type: ModuleList 694 Modules: 695 - Base of Image: 0x0000000000002000 696 Size of Image: 0x00001000 697 Module Name: '/tmp/a' 698 CodeView Record: '' 699 - Base of Image: 0x0000000000001000 700 Size of Image: 0x00001000 701 Module Name: '/tmp/a' 702 CodeView Record: '' 703 ... 704 )"), 705 llvm::Succeeded()); 706 // If we have a module mentioned twice in the module list, the filtered 707 // module list should contain the instance with the lowest BaseOfImage. 708 std::vector<const minidump::Module *> filtered_modules = 709 parser->GetFilteredModuleList(); 710 ASSERT_EQ(1u, filtered_modules.size()); 711 EXPECT_EQ(0x0000000000001000u, filtered_modules[0]->BaseOfImage); 712 } 713 714 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedFirst) { 715 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 716 --- !minidump 717 Streams: 718 - Type: ModuleList 719 Modules: 720 - Base of Image: 0x400d0000 721 Size of Image: 0x00002000 722 Module Name: '/usr/lib/libc.so' 723 CodeView Record: '' 724 - Base of Image: 0x400d3000 725 Size of Image: 0x00001000 726 Module Name: '/usr/lib/libc.so' 727 CodeView Record: '' 728 - Type: LinuxMaps 729 Text: | 730 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so 731 400d2000-400d3000 rw-p 00000000 00:00 0 732 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so 733 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so 734 ... 735 )"), 736 llvm::Succeeded()); 737 // If we have a module mentioned twice in the module list, and we have full 738 // linux maps for all of the memory regions, make sure we pick the one that 739 // has a consecutive region with a matching path that has executable 740 // permissions. If clients open an object file with mmap, breakpad can create 741 // multiple mappings for a library errnoneously and the lowest address isn't 742 // always the right address. In this case we check the consective memory 743 // regions whose path matches starting at the base of image address and make 744 // sure one of the regions is executable and prefer that one. 745 // 746 // This test will make sure that if the executable is second in the module 747 // list, that it will become the selected module in the filtered list. 748 std::vector<const minidump::Module *> filtered_modules = 749 parser->GetFilteredModuleList(); 750 ASSERT_EQ(1u, filtered_modules.size()); 751 EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage); 752 } 753 754 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecond) { 755 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 756 --- !minidump 757 Streams: 758 - Type: ModuleList 759 Modules: 760 - Base of Image: 0x400d0000 761 Size of Image: 0x00002000 762 Module Name: '/usr/lib/libc.so' 763 CodeView Record: '' 764 - Base of Image: 0x400d3000 765 Size of Image: 0x00001000 766 Module Name: '/usr/lib/libc.so' 767 CodeView Record: '' 768 - Type: LinuxMaps 769 Text: | 770 400d0000-400d1000 r-xp 00010000 b3:04 227 /usr/lib/libc.so 771 400d1000-400d2000 rwxp 00001000 b3:04 227 /usr/lib/libc.so 772 400d2000-400d3000 rw-p 00000000 00:00 0 773 400d3000-400d5000 r--p 00000000 b3:04 227 /usr/lib/libc.so 774 ... 775 )"), 776 llvm::Succeeded()); 777 // If we have a module mentioned twice in the module list, and we have full 778 // linux maps for all of the memory regions, make sure we pick the one that 779 // has a consecutive region with a matching path that has executable 780 // permissions. If clients open an object file with mmap, breakpad can create 781 // multiple mappings for a library errnoneously and the lowest address isn't 782 // always the right address. In this case we check the consective memory 783 // regions whose path matches starting at the base of image address and make 784 // sure one of the regions is executable and prefer that one. 785 // 786 // This test will make sure that if the executable is first in the module 787 // list, that it will remain the correctly selected module in the filtered 788 // list. 789 std::vector<const minidump::Module *> filtered_modules = 790 parser->GetFilteredModuleList(); 791 ASSERT_EQ(1u, filtered_modules.size()); 792 EXPECT_EQ(0x400d0000u, filtered_modules[0]->BaseOfImage); 793 } 794 795 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecondHigh) { 796 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 797 --- !minidump 798 Streams: 799 - Type: ModuleList 800 Modules: 801 - Base of Image: 0x400d3000 802 Size of Image: 0x00002000 803 Module Name: '/usr/lib/libc.so' 804 CodeView Record: '' 805 - Base of Image: 0x400d0000 806 Size of Image: 0x00001000 807 Module Name: '/usr/lib/libc.so' 808 CodeView Record: '' 809 - Type: LinuxMaps 810 Text: | 811 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so 812 400d2000-400d3000 rw-p 00000000 00:00 0 813 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so 814 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so 815 ... 816 )"), 817 llvm::Succeeded()); 818 // If we have a module mentioned twice in the module list, and we have full 819 // linux maps for all of the memory regions, make sure we pick the one that 820 // has a consecutive region with a matching path that has executable 821 // permissions. If clients open an object file with mmap, breakpad can create 822 // multiple mappings for a library errnoneously and the lowest address isn't 823 // always the right address. In this case we check the consective memory 824 // regions whose path matches starting at the base of image address and make 825 // sure one of the regions is executable and prefer that one. 826 // 827 // This test will make sure that if the executable is first in the module 828 // list, that it will remain the correctly selected module in the filtered 829 // list, even if the non-executable module was loaded at a lower base address. 830 std::vector<const minidump::Module *> filtered_modules = 831 parser->GetFilteredModuleList(); 832 ASSERT_EQ(1u, filtered_modules.size()); 833 EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage); 834 } 835 836 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleSeparateCode) { 837 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 838 --- !minidump 839 Streams: 840 - Type: ModuleList 841 Modules: 842 - Base of Image: 0x400d0000 843 Size of Image: 0x00002000 844 Module Name: '/usr/lib/libc.so' 845 CodeView Record: '' 846 - Base of Image: 0x400d5000 847 Size of Image: 0x00001000 848 Module Name: '/usr/lib/libc.so' 849 CodeView Record: '' 850 - Type: LinuxMaps 851 Text: | 852 400d0000-400d3000 r--p 00000000 b3:04 227 /usr/lib/libc.so 853 400d3000-400d5000 rw-p 00000000 00:00 0 854 400d5000-400d6000 r--p 00000000 b3:04 227 /usr/lib/libc.so 855 400d6000-400d7000 r-xp 00010000 b3:04 227 /usr/lib/libc.so 856 400d7000-400d8000 rwxp 00001000 b3:04 227 /usr/lib/libc.so 857 ... 858 )"), 859 llvm::Succeeded()); 860 // If we have a module mentioned twice in the module list, and we have full 861 // linux maps for all of the memory regions, make sure we pick the one that 862 // has a consecutive region with a matching path that has executable 863 // permissions. If clients open an object file with mmap, breakpad can create 864 // multiple mappings for a library errnoneously and the lowest address isn't 865 // always the right address. In this case we check the consective memory 866 // regions whose path matches starting at the base of image address and make 867 // sure one of the regions is executable and prefer that one. 868 // 869 // This test will make sure if binaries are compiled with "-z separate-code", 870 // where the first region for a binary won't be marked as executable, that 871 // it gets selected by detecting the second consecutive mapping at 0x400d7000 872 // when asked about the a module mamed "/usr/lib/libc.so" at 0x400d5000. 873 std::vector<const minidump::Module *> filtered_modules = 874 parser->GetFilteredModuleList(); 875 ASSERT_EQ(1u, filtered_modules.size()); 876 EXPECT_EQ(0x400d5000u, filtered_modules[0]->BaseOfImage); 877 } 878 879 TEST_F(MinidumpParserTest, MinidumpModuleOrder) { 880 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 881 --- !minidump 882 Streams: 883 - Type: ModuleList 884 Modules: 885 - Base of Image: 0x0000000000002000 886 Size of Image: 0x00001000 887 Module Name: '/tmp/a' 888 CodeView Record: '' 889 - Base of Image: 0x0000000000001000 890 Size of Image: 0x00001000 891 Module Name: '/tmp/b' 892 CodeView Record: '' 893 ... 894 )"), 895 llvm::Succeeded()); 896 // Test module filtering does not affect the overall module order. Previous 897 // versions of the MinidumpParser::GetFilteredModuleList() function would sort 898 // all images by address and modify the order of the modules. 899 std::vector<const minidump::Module *> filtered_modules = 900 parser->GetFilteredModuleList(); 901 ASSERT_EQ(2u, filtered_modules.size()); 902 EXPECT_EQ(0x0000000000002000u, filtered_modules[0]->BaseOfImage); 903 EXPECT_THAT_EXPECTED( 904 parser->GetMinidumpFile().getString(filtered_modules[0]->ModuleNameRVA), 905 llvm::HasValue("/tmp/a")); 906 EXPECT_EQ(0x0000000000001000u, filtered_modules[1]->BaseOfImage); 907 EXPECT_THAT_EXPECTED( 908 parser->GetMinidumpFile().getString(filtered_modules[1]->ModuleNameRVA), 909 llvm::HasValue("/tmp/b")); 910 } 911