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( 380 testing::ElementsAre( 381 MemoryRegionInfo({0x0, 0x10000}, no, no, no, no, ConstString(), 382 unknown, 0, unknown, unknown), 383 MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, yes, 384 ConstString(), unknown, 0, unknown, unknown), 385 MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, yes, 386 ConstString(), unknown, 0, unknown, unknown), 387 MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, yes, 388 ConstString(), unknown, 0, unknown, unknown), 389 MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, yes, 390 ConstString(), unknown, 0, unknown, unknown)), 391 true)); 392 } 393 394 TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) { 395 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 396 --- !minidump 397 Streams: 398 - Type: MemoryList 399 Memory Ranges: 400 - Start of Memory Range: 0x0000000000001000 401 Content: '31313131313131313131313131313131' 402 - Start of Memory Range: 0x0000000000002000 403 Content: '3333333333333333333333333333333333333333333333333333333333333333' 404 ... 405 )"), 406 llvm::Succeeded()); 407 408 // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when 409 // we don't have a MemoryInfoListStream. 410 411 EXPECT_THAT( 412 parser->BuildMemoryRegions(), 413 testing::Pair( 414 testing::ElementsAre( 415 MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, yes, 416 ConstString(), unknown, 0, unknown, unknown), 417 MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes, 418 ConstString(), unknown, 0, unknown, unknown)), 419 false)); 420 } 421 422 TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) { 423 SetUpData("regions-memlist64.dmp"); 424 425 // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when 426 // we don't have a MemoryInfoListStream. 427 EXPECT_THAT( 428 parser->BuildMemoryRegions(), 429 testing::Pair( 430 testing::ElementsAre( 431 MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, yes, 432 ConstString(), unknown, 0, unknown, unknown), 433 MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes, 434 ConstString(), unknown, 0, unknown, unknown)), 435 false)); 436 } 437 438 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) { 439 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 440 --- !minidump 441 Streams: 442 - Type: LinuxMaps 443 Text: | 444 400d9000-400db000 r-xp 00000000 b3:04 227 /system/bin/app_process 445 400db000-400dc000 r--p 00001000 b3:04 227 /system/bin/app_process 446 400dc000-400dd000 rw-p 00000000 00:00 0 447 400ec000-400ed000 r--p 00000000 00:00 0 448 400ee000-400ef000 rw-p 00010000 b3:04 300 /system/bin/linker 449 400fc000-400fd000 rwxp 00001000 b3:04 1096 /system/lib/liblog.so 450 451 ... 452 )"), 453 llvm::Succeeded()); 454 // Test we can get memory regions from the linux /proc/<pid>/maps stream when 455 // we don't have a MemoryInfoListStream. 456 ConstString app_process("/system/bin/app_process"); 457 ConstString linker("/system/bin/linker"); 458 ConstString liblog("/system/lib/liblog.so"); 459 EXPECT_THAT( 460 parser->BuildMemoryRegions(), 461 testing::Pair( 462 testing::ElementsAre( 463 MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes, yes, 464 app_process, unknown, 0, unknown, unknown), 465 MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, yes, 466 app_process, unknown, 0, unknown, unknown), 467 MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, yes, 468 ConstString(), unknown, 0, unknown, unknown), 469 MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, yes, 470 ConstString(), unknown, 0, unknown, unknown), 471 MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, yes, linker, 472 unknown, 0, unknown, unknown), 473 MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, yes, liblog, 474 unknown, 0, unknown, unknown)), 475 true)); 476 } 477 478 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) { 479 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 480 --- !minidump 481 Streams: 482 - Type: LinuxMaps 483 Text: | 484 400d9000-400db000 r?xp 00000000 b3:04 227 485 400fc000-400fd000 rwxp 00001000 b3:04 1096 486 ... 487 )"), 488 llvm::Succeeded()); 489 // Test that when a /proc/maps region fails to parse 490 // we handle the error and continue with the rest. 491 EXPECT_THAT( 492 parser->BuildMemoryRegions(), 493 testing::Pair(testing::ElementsAre(MemoryRegionInfo( 494 {0x400fc000, 0x1000}, yes, yes, yes, yes, 495 ConstString(nullptr), unknown, 0, unknown, unknown)), 496 true)); 497 } 498 499 // Windows Minidump tests 500 TEST_F(MinidumpParserTest, GetArchitectureWindows) { 501 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 502 --- !minidump 503 Streams: 504 - Type: SystemInfo 505 Processor Arch: X86 506 Processor Level: 6 507 Processor Revision: 15876 508 Number of Processors: 32 509 Product type: 1 510 Major Version: 6 511 Minor Version: 1 512 Build Number: 7601 513 Platform ID: Win32NT 514 CSD Version: Service Pack 1 515 Suite Mask: 0x0100 516 CPU: 517 Vendor ID: GenuineIntel 518 Version Info: 0x000306E4 519 Feature Info: 0xBFEBFBFF 520 AMD Extended Features: 0x771EEC80 521 ... 522 )"), 523 llvm::Succeeded()); 524 ASSERT_EQ(llvm::Triple::ArchType::x86, 525 parser->GetArchitecture().GetMachine()); 526 ASSERT_EQ(llvm::Triple::OSType::Win32, 527 parser->GetArchitecture().GetTriple().getOS()); 528 } 529 530 TEST_F(MinidumpParserTest, GetLinuxProcStatus_no_stream) { 531 // Test that GetLinuxProcStatus returns nullptr when the minidump does not 532 // contain this stream. 533 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 534 --- !minidump 535 Streams: 536 ... 537 )"), 538 llvm::Succeeded()); 539 EXPECT_EQ(llvm::None, parser->GetLinuxProcStatus()); 540 } 541 542 TEST_F(MinidumpParserTest, GetMiscInfoWindows) { 543 SetUpData("fizzbuzz_no_heap.dmp"); 544 const MinidumpMiscInfo *misc_info = parser->GetMiscInfo(); 545 ASSERT_NE(nullptr, misc_info); 546 llvm::Optional<lldb::pid_t> pid = misc_info->GetPid(); 547 ASSERT_TRUE(pid.hasValue()); 548 ASSERT_EQ(4440UL, pid.getValue()); 549 } 550 551 TEST_F(MinidumpParserTest, GetPidWindows) { 552 SetUpData("fizzbuzz_no_heap.dmp"); 553 llvm::Optional<lldb::pid_t> pid = parser->GetPid(); 554 ASSERT_TRUE(pid.hasValue()); 555 ASSERT_EQ(4440UL, pid.getValue()); 556 } 557 558 // wow64 559 TEST_F(MinidumpParserTest, GetPidWow64) { 560 SetUpData("fizzbuzz_wow64.dmp"); 561 llvm::Optional<lldb::pid_t> pid = parser->GetPid(); 562 ASSERT_TRUE(pid.hasValue()); 563 ASSERT_EQ(7836UL, pid.getValue()); 564 } 565 566 // Register tests 567 #define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x)) 568 #define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x)) 569 570 TEST_F(MinidumpParserTest, GetThreadContext_x86_32) { 571 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 572 --- !minidump 573 Streams: 574 - Type: ThreadList 575 Threads: 576 - Thread Id: 0x00026804 577 Stack: 578 Start of Memory Range: 0x00000000FF9DD000 579 Content: 68D39DFF 580 Context: 0F0001000000000000000000000000000000000000000000000000007F03FFFF0000FFFFFFFFFFFF09DC62F72300000088E36CF72B00FFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063000000000000002B0000002B000000A88204085CD59DFF008077F7A3D49DFF01000000000000003CD59DFFA082040823000000820201002CD59DFF2B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 581 )"), 582 llvm::Succeeded()); 583 584 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads(); 585 const minidump::Thread &thread = thread_list[0]; 586 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread)); 587 const MinidumpContext_x86_32 *context; 588 EXPECT_TRUE(consumeObject(registers, context).Success()); 589 590 EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)), 591 MinidumpContext_x86_32_Flags::x86_32_Flag | 592 MinidumpContext_x86_32_Flags::Full | 593 MinidumpContext_x86_32_Flags::FloatingPoint); 594 595 EXPECT_EQ(0x00000000u, context->eax); 596 EXPECT_EQ(0xf7778000u, context->ebx); 597 EXPECT_EQ(0x00000001u, context->ecx); 598 EXPECT_EQ(0xff9dd4a3u, context->edx); 599 EXPECT_EQ(0x080482a8u, context->edi); 600 EXPECT_EQ(0xff9dd55cu, context->esi); 601 EXPECT_EQ(0xff9dd53cu, context->ebp); 602 EXPECT_EQ(0xff9dd52cu, context->esp); 603 EXPECT_EQ(0x080482a0u, context->eip); 604 EXPECT_EQ(0x00010282u, context->eflags); 605 EXPECT_EQ(0x0023u, context->cs); 606 EXPECT_EQ(0x0000u, context->fs); 607 EXPECT_EQ(0x0063u, context->gs); 608 EXPECT_EQ(0x002bu, context->ss); 609 EXPECT_EQ(0x002bu, context->ds); 610 EXPECT_EQ(0x002bu, context->es); 611 } 612 613 TEST_F(MinidumpParserTest, GetThreadContext_x86_64) { 614 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 615 --- !minidump 616 Streams: 617 - Type: ThreadList 618 Threads: 619 - Thread Id: 0x00003E81 620 Stack: 621 Start of Memory Range: 0x00007FFCEB34A000 622 Content: C84D04BCE97F00 623 Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0010000000000033000000000000000000000006020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010A234EBFC7F000010A234EBFC7F00000000000000000000F09C34EBFC7F0000C0A91ABCE97F00000000000000000000A0163FBCE97F00004602000000000000921C40000000000030A434EBFC7F000000000000000000000000000000000000C61D4000000000007F0300000000000000000000000000000000000000000000801F0000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF25252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 624 ... 625 )"), 626 llvm::Succeeded()); 627 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads(); 628 const minidump::Thread &thread = thread_list[0]; 629 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread)); 630 const MinidumpContext_x86_64 *context; 631 EXPECT_TRUE(consumeObject(registers, context).Success()); 632 633 EXPECT_EQ(MinidumpContext_x86_64_Flags(uint32_t(context->context_flags)), 634 MinidumpContext_x86_64_Flags::x86_64_Flag | 635 MinidumpContext_x86_64_Flags::Control | 636 MinidumpContext_x86_64_Flags::FloatingPoint | 637 MinidumpContext_x86_64_Flags::Integer); 638 EXPECT_EQ(0x0000000000000000u, context->rax); 639 EXPECT_EQ(0x0000000000000000u, context->rbx); 640 EXPECT_EQ(0x0000000000000010u, context->rcx); 641 EXPECT_EQ(0x0000000000000000u, context->rdx); 642 EXPECT_EQ(0x00007ffceb349cf0u, context->rdi); 643 EXPECT_EQ(0x0000000000000000u, context->rsi); 644 EXPECT_EQ(0x00007ffceb34a210u, context->rbp); 645 EXPECT_EQ(0x00007ffceb34a210u, context->rsp); 646 EXPECT_EQ(0x00007fe9bc1aa9c0u, context->r8); 647 EXPECT_EQ(0x0000000000000000u, context->r9); 648 EXPECT_EQ(0x00007fe9bc3f16a0u, context->r10); 649 EXPECT_EQ(0x0000000000000246u, context->r11); 650 EXPECT_EQ(0x0000000000401c92u, context->r12); 651 EXPECT_EQ(0x00007ffceb34a430u, context->r13); 652 EXPECT_EQ(0x0000000000000000u, context->r14); 653 EXPECT_EQ(0x0000000000000000u, context->r15); 654 EXPECT_EQ(0x0000000000401dc6u, context->rip); 655 EXPECT_EQ(0x00010206u, context->eflags); 656 EXPECT_EQ(0x0033u, context->cs); 657 EXPECT_EQ(0x0000u, context->ss); 658 } 659 660 TEST_F(MinidumpParserTest, GetThreadContext_x86_32_wow64) { 661 SetUpData("fizzbuzz_wow64.dmp"); 662 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads(); 663 const minidump::Thread &thread = thread_list[0]; 664 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContextWow64(thread)); 665 const MinidumpContext_x86_32 *context; 666 EXPECT_TRUE(consumeObject(registers, context).Success()); 667 668 EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)), 669 MinidumpContext_x86_32_Flags::x86_32_Flag | 670 MinidumpContext_x86_32_Flags::Full | 671 MinidumpContext_x86_32_Flags::FloatingPoint | 672 MinidumpContext_x86_32_Flags::ExtendedRegisters); 673 674 EXPECT_EQ(0x00000000u, context->eax); 675 EXPECT_EQ(0x0037f608u, context->ebx); 676 EXPECT_EQ(0x00e61578u, context->ecx); 677 EXPECT_EQ(0x00000008u, context->edx); 678 EXPECT_EQ(0x00000000u, context->edi); 679 EXPECT_EQ(0x00000002u, context->esi); 680 EXPECT_EQ(0x0037f654u, context->ebp); 681 EXPECT_EQ(0x0037f5b8u, context->esp); 682 EXPECT_EQ(0x77ce01fdu, context->eip); 683 EXPECT_EQ(0x00000246u, context->eflags); 684 EXPECT_EQ(0x0023u, context->cs); 685 EXPECT_EQ(0x0053u, context->fs); 686 EXPECT_EQ(0x002bu, context->gs); 687 EXPECT_EQ(0x002bu, context->ss); 688 EXPECT_EQ(0x002bu, context->ds); 689 EXPECT_EQ(0x002bu, context->es); 690 } 691 692 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) { 693 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 694 --- !minidump 695 Streams: 696 - Type: ModuleList 697 Modules: 698 - Base of Image: 0x0000000000002000 699 Size of Image: 0x00001000 700 Module Name: '/tmp/a' 701 CodeView Record: '' 702 - Base of Image: 0x0000000000001000 703 Size of Image: 0x00001000 704 Module Name: '/tmp/a' 705 CodeView Record: '' 706 ... 707 )"), 708 llvm::Succeeded()); 709 // If we have a module mentioned twice in the module list, the filtered 710 // module list should contain the instance with the lowest BaseOfImage. 711 std::vector<const minidump::Module *> filtered_modules = 712 parser->GetFilteredModuleList(); 713 ASSERT_EQ(1u, filtered_modules.size()); 714 EXPECT_EQ(0x0000000000001000u, filtered_modules[0]->BaseOfImage); 715 } 716 717 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedFirst) { 718 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 719 --- !minidump 720 Streams: 721 - Type: ModuleList 722 Modules: 723 - Base of Image: 0x400d0000 724 Size of Image: 0x00002000 725 Module Name: '/usr/lib/libc.so' 726 CodeView Record: '' 727 - Base of Image: 0x400d3000 728 Size of Image: 0x00001000 729 Module Name: '/usr/lib/libc.so' 730 CodeView Record: '' 731 - Type: LinuxMaps 732 Text: | 733 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so 734 400d2000-400d3000 rw-p 00000000 00:00 0 735 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so 736 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so 737 ... 738 )"), 739 llvm::Succeeded()); 740 // If we have a module mentioned twice in the module list, and we have full 741 // linux maps for all of the memory regions, make sure we pick the one that 742 // has a consecutive region with a matching path that has executable 743 // permissions. If clients open an object file with mmap, breakpad can create 744 // multiple mappings for a library errnoneously and the lowest address isn't 745 // always the right address. In this case we check the consective memory 746 // regions whose path matches starting at the base of image address and make 747 // sure one of the regions is executable and prefer that one. 748 // 749 // This test will make sure that if the executable is second in the module 750 // list, that it will become the selected module in the filtered list. 751 std::vector<const minidump::Module *> filtered_modules = 752 parser->GetFilteredModuleList(); 753 ASSERT_EQ(1u, filtered_modules.size()); 754 EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage); 755 } 756 757 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecond) { 758 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 759 --- !minidump 760 Streams: 761 - Type: ModuleList 762 Modules: 763 - Base of Image: 0x400d0000 764 Size of Image: 0x00002000 765 Module Name: '/usr/lib/libc.so' 766 CodeView Record: '' 767 - Base of Image: 0x400d3000 768 Size of Image: 0x00001000 769 Module Name: '/usr/lib/libc.so' 770 CodeView Record: '' 771 - Type: LinuxMaps 772 Text: | 773 400d0000-400d1000 r-xp 00010000 b3:04 227 /usr/lib/libc.so 774 400d1000-400d2000 rwxp 00001000 b3:04 227 /usr/lib/libc.so 775 400d2000-400d3000 rw-p 00000000 00:00 0 776 400d3000-400d5000 r--p 00000000 b3:04 227 /usr/lib/libc.so 777 ... 778 )"), 779 llvm::Succeeded()); 780 // If we have a module mentioned twice in the module list, and we have full 781 // linux maps for all of the memory regions, make sure we pick the one that 782 // has a consecutive region with a matching path that has executable 783 // permissions. If clients open an object file with mmap, breakpad can create 784 // multiple mappings for a library errnoneously and the lowest address isn't 785 // always the right address. In this case we check the consective memory 786 // regions whose path matches starting at the base of image address and make 787 // sure one of the regions is executable and prefer that one. 788 // 789 // This test will make sure that if the executable is first in the module 790 // list, that it will remain the correctly selected module in the filtered 791 // list. 792 std::vector<const minidump::Module *> filtered_modules = 793 parser->GetFilteredModuleList(); 794 ASSERT_EQ(1u, filtered_modules.size()); 795 EXPECT_EQ(0x400d0000u, filtered_modules[0]->BaseOfImage); 796 } 797 798 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecondHigh) { 799 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 800 --- !minidump 801 Streams: 802 - Type: ModuleList 803 Modules: 804 - Base of Image: 0x400d3000 805 Size of Image: 0x00002000 806 Module Name: '/usr/lib/libc.so' 807 CodeView Record: '' 808 - Base of Image: 0x400d0000 809 Size of Image: 0x00001000 810 Module Name: '/usr/lib/libc.so' 811 CodeView Record: '' 812 - Type: LinuxMaps 813 Text: | 814 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so 815 400d2000-400d3000 rw-p 00000000 00:00 0 816 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so 817 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so 818 ... 819 )"), 820 llvm::Succeeded()); 821 // If we have a module mentioned twice in the module list, and we have full 822 // linux maps for all of the memory regions, make sure we pick the one that 823 // has a consecutive region with a matching path that has executable 824 // permissions. If clients open an object file with mmap, breakpad can create 825 // multiple mappings for a library errnoneously and the lowest address isn't 826 // always the right address. In this case we check the consective memory 827 // regions whose path matches starting at the base of image address and make 828 // sure one of the regions is executable and prefer that one. 829 // 830 // This test will make sure that if the executable is first in the module 831 // list, that it will remain the correctly selected module in the filtered 832 // list, even if the non-executable module was loaded at a lower base address. 833 std::vector<const minidump::Module *> filtered_modules = 834 parser->GetFilteredModuleList(); 835 ASSERT_EQ(1u, filtered_modules.size()); 836 EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage); 837 } 838 839 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleSeparateCode) { 840 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 841 --- !minidump 842 Streams: 843 - Type: ModuleList 844 Modules: 845 - Base of Image: 0x400d0000 846 Size of Image: 0x00002000 847 Module Name: '/usr/lib/libc.so' 848 CodeView Record: '' 849 - Base of Image: 0x400d5000 850 Size of Image: 0x00001000 851 Module Name: '/usr/lib/libc.so' 852 CodeView Record: '' 853 - Type: LinuxMaps 854 Text: | 855 400d0000-400d3000 r--p 00000000 b3:04 227 /usr/lib/libc.so 856 400d3000-400d5000 rw-p 00000000 00:00 0 857 400d5000-400d6000 r--p 00000000 b3:04 227 /usr/lib/libc.so 858 400d6000-400d7000 r-xp 00010000 b3:04 227 /usr/lib/libc.so 859 400d7000-400d8000 rwxp 00001000 b3:04 227 /usr/lib/libc.so 860 ... 861 )"), 862 llvm::Succeeded()); 863 // If we have a module mentioned twice in the module list, and we have full 864 // linux maps for all of the memory regions, make sure we pick the one that 865 // has a consecutive region with a matching path that has executable 866 // permissions. If clients open an object file with mmap, breakpad can create 867 // multiple mappings for a library errnoneously and the lowest address isn't 868 // always the right address. In this case we check the consective memory 869 // regions whose path matches starting at the base of image address and make 870 // sure one of the regions is executable and prefer that one. 871 // 872 // This test will make sure if binaries are compiled with "-z separate-code", 873 // where the first region for a binary won't be marked as executable, that 874 // it gets selected by detecting the second consecutive mapping at 0x400d7000 875 // when asked about the a module mamed "/usr/lib/libc.so" at 0x400d5000. 876 std::vector<const minidump::Module *> filtered_modules = 877 parser->GetFilteredModuleList(); 878 ASSERT_EQ(1u, filtered_modules.size()); 879 EXPECT_EQ(0x400d5000u, filtered_modules[0]->BaseOfImage); 880 } 881 882 TEST_F(MinidumpParserTest, MinidumpModuleOrder) { 883 ASSERT_THAT_ERROR(SetUpFromYaml(R"( 884 --- !minidump 885 Streams: 886 - Type: ModuleList 887 Modules: 888 - Base of Image: 0x0000000000002000 889 Size of Image: 0x00001000 890 Module Name: '/tmp/a' 891 CodeView Record: '' 892 - Base of Image: 0x0000000000001000 893 Size of Image: 0x00001000 894 Module Name: '/tmp/b' 895 CodeView Record: '' 896 ... 897 )"), 898 llvm::Succeeded()); 899 // Test module filtering does not affect the overall module order. Previous 900 // versions of the MinidumpParser::GetFilteredModuleList() function would sort 901 // all images by address and modify the order of the modules. 902 std::vector<const minidump::Module *> filtered_modules = 903 parser->GetFilteredModuleList(); 904 ASSERT_EQ(2u, filtered_modules.size()); 905 EXPECT_EQ(0x0000000000002000u, filtered_modules[0]->BaseOfImage); 906 EXPECT_THAT_EXPECTED( 907 parser->GetMinidumpFile().getString(filtered_modules[0]->ModuleNameRVA), 908 llvm::HasValue("/tmp/a")); 909 EXPECT_EQ(0x0000000000001000u, filtered_modules[1]->BaseOfImage); 910 EXPECT_THAT_EXPECTED( 911 parser->GetMinidumpFile().getString(filtered_modules[1]->ModuleNameRVA), 912 llvm::HasValue("/tmp/b")); 913 } 914