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