1 //===-- MinidumpTypesTest.cpp -----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "Plugins/Process/Utility/RegisterContextLinux_i386.h" 11 #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" 12 #include "Plugins/Process/minidump/MinidumpParser.h" 13 #include "Plugins/Process/minidump/MinidumpTypes.h" 14 #include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h" 15 #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h" 16 17 #include "TestingSupport/TestUtilities.h" 18 #include "lldb/Host/FileSystem.h" 19 #include "lldb/Target/MemoryRegionInfo.h" 20 #include "lldb/Utility/ArchSpec.h" 21 #include "lldb/Utility/DataExtractor.h" 22 #include "lldb/Utility/FileSpec.h" 23 #include "llvm/ADT/ArrayRef.h" 24 #include "llvm/ADT/Optional.h" 25 #include "llvm/Support/FileSystem.h" 26 #include "llvm/Support/MemoryBuffer.h" 27 #include "llvm/Support/Path.h" 28 #include "gtest/gtest.h" 29 30 // C includes 31 32 // C++ includes 33 #include <memory> 34 35 using namespace lldb_private; 36 using namespace minidump; 37 38 class MinidumpParserTest : public testing::Test { 39 public: 40 void SetUp() override { FileSystem::Initialize(); } 41 42 void TearDown() override { FileSystem::Terminate(); } 43 44 void SetUpData(const char *minidump_filename) { 45 std::string filename = GetInputFilePath(minidump_filename); 46 auto BufferPtr = FileSystem::Instance().CreateDataBuffer(filename, -1, 0); 47 ASSERT_NE(BufferPtr, nullptr); 48 llvm::Optional<MinidumpParser> optional_parser = 49 MinidumpParser::Create(BufferPtr); 50 ASSERT_TRUE(optional_parser.hasValue()); 51 parser.reset(new MinidumpParser(optional_parser.getValue())); 52 ASSERT_GT(parser->GetData().size(), 0UL); 53 auto result = parser->Initialize(); 54 ASSERT_TRUE(result.Success()) << result.AsCString(); 55 } 56 57 void InvalidMinidump(const char *minidump_filename, uint64_t load_size) { 58 std::string filename = GetInputFilePath(minidump_filename); 59 auto BufferPtr = 60 FileSystem::Instance().CreateDataBuffer(filename, load_size, 0); 61 ASSERT_NE(BufferPtr, nullptr); 62 63 llvm::Optional<MinidumpParser> optional_parser = 64 MinidumpParser::Create(BufferPtr); 65 ASSERT_TRUE(optional_parser.hasValue()); 66 parser.reset(new MinidumpParser(optional_parser.getValue())); 67 ASSERT_GT(parser->GetData().size(), 0UL); 68 auto result = parser->Initialize(); 69 ASSERT_TRUE(result.Fail()); 70 } 71 72 std::unique_ptr<MinidumpParser> parser; 73 }; 74 75 TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) { 76 SetUpData("linux-x86_64.dmp"); 77 llvm::ArrayRef<MinidumpThread> thread_list; 78 79 thread_list = parser->GetThreads(); 80 ASSERT_EQ(1UL, thread_list.size()); 81 82 const MinidumpThread thread = thread_list[0]; 83 84 EXPECT_EQ(16001UL, thread.thread_id); 85 86 llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(thread); 87 EXPECT_EQ(1232UL, context.size()); 88 } 89 90 TEST_F(MinidumpParserTest, GetThreadListNotPadded) { 91 // Verify that we can load a thread list that doesn't have 4 bytes of padding 92 // after the thread count. 93 SetUpData("thread-list-not-padded.dmp"); 94 llvm::ArrayRef<MinidumpThread> thread_list; 95 96 thread_list = parser->GetThreads(); 97 ASSERT_EQ(2UL, thread_list.size()); 98 EXPECT_EQ(0x11223344UL, thread_list[0].thread_id); 99 EXPECT_EQ(0x55667788UL, thread_list[1].thread_id); 100 } 101 102 TEST_F(MinidumpParserTest, GetThreadListPadded) { 103 // Verify that we can load a thread list that has 4 bytes of padding 104 // after the thread count as found in breakpad minidump files. 105 SetUpData("thread-list-padded.dmp"); 106 auto thread_list = parser->GetThreads(); 107 ASSERT_EQ(2UL, thread_list.size()); 108 EXPECT_EQ(0x11223344UL, thread_list[0].thread_id); 109 EXPECT_EQ(0x55667788UL, thread_list[1].thread_id); 110 } 111 112 TEST_F(MinidumpParserTest, GetModuleListNotPadded) { 113 // Verify that we can load a module list that doesn't have 4 bytes of padding 114 // after the module count. 115 SetUpData("module-list-not-padded.dmp"); 116 auto module_list = parser->GetModuleList(); 117 ASSERT_EQ(2UL, module_list.size()); 118 EXPECT_EQ(0x1000UL, module_list[0].base_of_image); 119 EXPECT_EQ(0x2000UL, module_list[0].size_of_image); 120 EXPECT_EQ(0x5000UL, module_list[1].base_of_image); 121 EXPECT_EQ(0x3000UL, module_list[1].size_of_image); 122 } 123 124 TEST_F(MinidumpParserTest, GetModuleListPadded) { 125 // Verify that we can load a module list that has 4 bytes of padding 126 // after the module count as found in breakpad minidump files. 127 SetUpData("module-list-padded.dmp"); 128 auto module_list = parser->GetModuleList(); 129 ASSERT_EQ(2UL, module_list.size()); 130 EXPECT_EQ(0x1000UL, module_list[0].base_of_image); 131 EXPECT_EQ(0x2000UL, module_list[0].size_of_image); 132 EXPECT_EQ(0x5000UL, module_list[1].base_of_image); 133 EXPECT_EQ(0x3000UL, module_list[1].size_of_image); 134 } 135 136 TEST_F(MinidumpParserTest, GetMemoryListNotPadded) { 137 // Verify that we can load a memory list that doesn't have 4 bytes of padding 138 // after the memory range count. 139 SetUpData("memory-list-not-padded.dmp"); 140 auto mem = parser->FindMemoryRange(0x8000); 141 ASSERT_TRUE(mem.hasValue()); 142 EXPECT_EQ((lldb::addr_t)0x8000, mem->start); 143 mem = parser->FindMemoryRange(0x8010); 144 ASSERT_TRUE(mem.hasValue()); 145 EXPECT_EQ((lldb::addr_t)0x8010, mem->start); 146 } 147 148 TEST_F(MinidumpParserTest, GetMemoryListPadded) { 149 // Verify that we can load a memory list that has 4 bytes of padding 150 // after the memory range count as found in breakpad minidump files. 151 SetUpData("memory-list-padded.dmp"); 152 auto mem = parser->FindMemoryRange(0x8000); 153 ASSERT_TRUE(mem.hasValue()); 154 EXPECT_EQ((lldb::addr_t)0x8000, mem->start); 155 mem = parser->FindMemoryRange(0x8010); 156 ASSERT_TRUE(mem.hasValue()); 157 EXPECT_EQ((lldb::addr_t)0x8010, mem->start); 158 } 159 160 TEST_F(MinidumpParserTest, TruncatedMinidumps) { 161 InvalidMinidump("linux-x86_64.dmp", 32); 162 InvalidMinidump("linux-x86_64.dmp", 100); 163 InvalidMinidump("linux-x86_64.dmp", 20 * 1024); 164 } 165 166 TEST_F(MinidumpParserTest, IllFormedMinidumps) { 167 InvalidMinidump("bad_duplicate_streams.dmp", -1); 168 InvalidMinidump("bad_overlapping_streams.dmp", -1); 169 } 170 171 TEST_F(MinidumpParserTest, GetArchitecture) { 172 SetUpData("linux-x86_64.dmp"); 173 ASSERT_EQ(llvm::Triple::ArchType::x86_64, 174 parser->GetArchitecture().GetMachine()); 175 ASSERT_EQ(llvm::Triple::OSType::Linux, 176 parser->GetArchitecture().GetTriple().getOS()); 177 } 178 179 TEST_F(MinidumpParserTest, GetMiscInfo) { 180 SetUpData("linux-x86_64.dmp"); 181 const MinidumpMiscInfo *misc_info = parser->GetMiscInfo(); 182 ASSERT_EQ(nullptr, misc_info); 183 } 184 185 TEST_F(MinidumpParserTest, GetLinuxProcStatus) { 186 SetUpData("linux-x86_64.dmp"); 187 llvm::Optional<LinuxProcStatus> proc_status = parser->GetLinuxProcStatus(); 188 ASSERT_TRUE(proc_status.hasValue()); 189 lldb::pid_t pid = proc_status->GetPid(); 190 ASSERT_EQ(16001UL, pid); 191 } 192 193 TEST_F(MinidumpParserTest, GetPid) { 194 SetUpData("linux-x86_64.dmp"); 195 llvm::Optional<lldb::pid_t> pid = parser->GetPid(); 196 ASSERT_TRUE(pid.hasValue()); 197 ASSERT_EQ(16001UL, pid.getValue()); 198 } 199 200 TEST_F(MinidumpParserTest, GetModuleList) { 201 SetUpData("linux-x86_64.dmp"); 202 llvm::ArrayRef<MinidumpModule> modules = parser->GetModuleList(); 203 ASSERT_EQ(8UL, modules.size()); 204 std::string module_names[8] = { 205 "/usr/local/google/home/dvlahovski/projects/test_breakpad/a.out", 206 "/lib/x86_64-linux-gnu/libm-2.19.so", 207 "/lib/x86_64-linux-gnu/libc-2.19.so", 208 "/lib/x86_64-linux-gnu/libgcc_s.so.1", 209 "/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19", 210 "/lib/x86_64-linux-gnu/libpthread-2.19.so", 211 "/lib/x86_64-linux-gnu/ld-2.19.so", 212 "linux-gate.so", 213 }; 214 215 for (int i = 0; i < 8; ++i) { 216 llvm::Optional<std::string> name = 217 parser->GetMinidumpString(modules[i].module_name_rva); 218 ASSERT_TRUE(name.hasValue()); 219 EXPECT_EQ(module_names[i], name.getValue()); 220 } 221 } 222 223 TEST_F(MinidumpParserTest, GetFilteredModuleList) { 224 SetUpData("linux-x86_64_not_crashed.dmp"); 225 llvm::ArrayRef<MinidumpModule> modules = parser->GetModuleList(); 226 std::vector<const MinidumpModule *> filtered_modules = 227 parser->GetFilteredModuleList(); 228 EXPECT_EQ(10UL, modules.size()); 229 EXPECT_EQ(9UL, filtered_modules.size()); 230 // EXPECT_GT(modules.size(), filtered_modules.size()); 231 bool found = false; 232 for (size_t i = 0; i < filtered_modules.size(); ++i) { 233 llvm::Optional<std::string> name = 234 parser->GetMinidumpString(filtered_modules[i]->module_name_rva); 235 ASSERT_TRUE(name.hasValue()); 236 if (name.getValue() == "/tmp/test/linux-x86_64_not_crashed") { 237 ASSERT_FALSE(found) << "There should be only one module with this name " 238 "in the filtered module list"; 239 found = true; 240 ASSERT_EQ(0x400000UL, filtered_modules[i]->base_of_image); 241 } 242 } 243 } 244 245 TEST_F(MinidumpParserTest, GetExceptionStream) { 246 SetUpData("linux-x86_64.dmp"); 247 const MinidumpExceptionStream *exception_stream = 248 parser->GetExceptionStream(); 249 ASSERT_NE(nullptr, exception_stream); 250 ASSERT_EQ(11UL, exception_stream->exception_record.exception_code); 251 } 252 253 void check_mem_range_exists(std::unique_ptr<MinidumpParser> &parser, 254 const uint64_t range_start, 255 const uint64_t range_size) { 256 llvm::Optional<minidump::Range> range = parser->FindMemoryRange(range_start); 257 ASSERT_TRUE(range.hasValue()) << "There is no range containing this address"; 258 EXPECT_EQ(range_start, range->start); 259 EXPECT_EQ(range_start + range_size, range->start + range->range_ref.size()); 260 } 261 262 TEST_F(MinidumpParserTest, FindMemoryRange) { 263 SetUpData("linux-x86_64.dmp"); 264 // There are two memory ranges in the file (size is in bytes, decimal): 265 // 1) 0x401d46 256 266 // 2) 0x7ffceb34a000 12288 267 EXPECT_FALSE(parser->FindMemoryRange(0x00).hasValue()); 268 EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue()); 269 270 check_mem_range_exists(parser, 0x401d46, 256); 271 EXPECT_FALSE(parser->FindMemoryRange(0x401d46 + 256).hasValue()); 272 273 check_mem_range_exists(parser, 0x7ffceb34a000, 12288); 274 EXPECT_FALSE(parser->FindMemoryRange(0x7ffceb34a000 + 12288).hasValue()); 275 } 276 277 TEST_F(MinidumpParserTest, GetMemory) { 278 SetUpData("linux-x86_64.dmp"); 279 280 EXPECT_EQ(128UL, parser->GetMemory(0x401d46, 128).size()); 281 EXPECT_EQ(256UL, parser->GetMemory(0x401d46, 512).size()); 282 283 EXPECT_EQ(12288UL, parser->GetMemory(0x7ffceb34a000, 12288).size()); 284 EXPECT_EQ(1024UL, parser->GetMemory(0x7ffceb34a000, 1024).size()); 285 286 EXPECT_TRUE(parser->GetMemory(0x500000, 512).empty()); 287 } 288 289 TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) { 290 SetUpData("fizzbuzz_wow64.dmp"); 291 292 // There are a lot of ranges in the file, just testing with some of them 293 EXPECT_FALSE(parser->FindMemoryRange(0x00).hasValue()); 294 EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue()); 295 check_mem_range_exists(parser, 0x10000, 65536); // first range 296 check_mem_range_exists(parser, 0x40000, 4096); 297 EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).hasValue()); 298 check_mem_range_exists(parser, 0x77c12000, 8192); 299 check_mem_range_exists(parser, 0x7ffe0000, 4096); // last range 300 EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).hasValue()); 301 } 302 303 void check_region(std::unique_ptr<MinidumpParser> &parser, 304 lldb::addr_t addr, lldb::addr_t start, lldb::addr_t end, 305 MemoryRegionInfo::OptionalBool read, 306 MemoryRegionInfo::OptionalBool write, 307 MemoryRegionInfo::OptionalBool exec, 308 MemoryRegionInfo::OptionalBool mapped, 309 ConstString name = ConstString()) { 310 auto range_info = parser->GetMemoryRegionInfo(addr); 311 EXPECT_EQ(start, range_info.GetRange().GetRangeBase()); 312 EXPECT_EQ(end, range_info.GetRange().GetRangeEnd()); 313 EXPECT_EQ(read, range_info.GetReadable()); 314 EXPECT_EQ(write, range_info.GetWritable()); 315 EXPECT_EQ(exec, range_info.GetExecutable()); 316 EXPECT_EQ(mapped, range_info.GetMapped()); 317 EXPECT_EQ(name, range_info.GetName()); 318 } 319 320 // Same as above function where addr == start 321 void check_region(std::unique_ptr<MinidumpParser> &parser, 322 lldb::addr_t start, lldb::addr_t end, 323 MemoryRegionInfo::OptionalBool read, 324 MemoryRegionInfo::OptionalBool write, 325 MemoryRegionInfo::OptionalBool exec, 326 MemoryRegionInfo::OptionalBool mapped, 327 ConstString name = ConstString()) { 328 check_region(parser, start, start, end, read, write, exec, mapped, name); 329 } 330 331 332 constexpr auto yes = MemoryRegionInfo::eYes; 333 constexpr auto no = MemoryRegionInfo::eNo; 334 constexpr auto unknown = MemoryRegionInfo::eDontKnow; 335 336 TEST_F(MinidumpParserTest, GetMemoryRegionInfo) { 337 SetUpData("fizzbuzz_wow64.dmp"); 338 339 check_region(parser, 0x00000000, 0x00010000, no, no, no, no); 340 check_region(parser, 0x00010000, 0x00020000, yes, yes, no, yes); 341 check_region(parser, 0x00020000, 0x00030000, yes, yes, no, yes); 342 check_region(parser, 0x00030000, 0x00031000, yes, yes, no, yes); 343 check_region(parser, 0x00031000, 0x00040000, no, no, no, no); 344 check_region(parser, 0x00040000, 0x00041000, yes, no, no, yes); 345 346 // Check addresses contained inside ranges 347 check_region(parser, 0x00000001, 0x00000000, 0x00010000, no, no, no, no); 348 check_region(parser, 0x0000ffff, 0x00000000, 0x00010000, no, no, no, no); 349 check_region(parser, 0x00010001, 0x00010000, 0x00020000, yes, yes, no, yes); 350 check_region(parser, 0x0001ffff, 0x00010000, 0x00020000, yes, yes, no, yes); 351 352 // Test that an address after the last entry maps to rest of the memory space 353 check_region(parser, 0x7fff0000, 0x7fff0000, UINT64_MAX, no, no, no, no); 354 } 355 356 TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) { 357 SetUpData("regions-memlist.dmp"); 358 // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when 359 // we don't have a MemoryInfoListStream. 360 361 // Test addres before the first entry comes back with nothing mapped up 362 // to first valid region info 363 check_region(parser, 0x00000000, 0x00001000, no, no, no, no); 364 check_region(parser, 0x00001000, 0x00001010, yes, unknown, unknown, yes); 365 check_region(parser, 0x00001010, 0x00002000, no, no, no, no); 366 check_region(parser, 0x00002000, 0x00002020, yes, unknown, unknown, yes); 367 check_region(parser, 0x00002020, UINT64_MAX, no, no, no, no); 368 } 369 370 TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) { 371 SetUpData("regions-memlist64.dmp"); 372 // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when 373 // we don't have a MemoryInfoListStream. 374 375 // Test addres before the first entry comes back with nothing mapped up 376 // to first valid region info 377 check_region(parser, 0x00000000, 0x00001000, no, no, no, no); 378 check_region(parser, 0x00001000, 0x00001010, yes, unknown, unknown, yes); 379 check_region(parser, 0x00001010, 0x00002000, no, no, no, no); 380 check_region(parser, 0x00002000, 0x00002020, yes, unknown, unknown, yes); 381 check_region(parser, 0x00002020, UINT64_MAX, no, no, no, no); 382 } 383 384 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) { 385 SetUpData("regions-linux-map.dmp"); 386 // Test we can get memory regions from the linux /proc/<pid>/maps stream when 387 // we don't have a MemoryInfoListStream. 388 389 // Test addres before the first entry comes back with nothing mapped up 390 // to first valid region info 391 ConstString a("/system/bin/app_process"); 392 ConstString b("/system/bin/linker"); 393 ConstString c("/system/lib/liblog.so"); 394 ConstString d("/system/lib/libc.so"); 395 ConstString n; 396 check_region(parser, 0x00000000, 0x400d9000, no , no , no , no , n); 397 check_region(parser, 0x400d9000, 0x400db000, yes, no , yes, yes, a); 398 check_region(parser, 0x400db000, 0x400dc000, yes, no , no , yes, a); 399 check_region(parser, 0x400dc000, 0x400dd000, yes, yes, no , yes, n); 400 check_region(parser, 0x400dd000, 0x400ec000, yes, no , yes, yes, b); 401 check_region(parser, 0x400ec000, 0x400ed000, yes, no , no , yes, n); 402 check_region(parser, 0x400ed000, 0x400ee000, yes, no , no , yes, b); 403 check_region(parser, 0x400ee000, 0x400ef000, yes, yes, no , yes, b); 404 check_region(parser, 0x400ef000, 0x400fb000, yes, yes, no , yes, n); 405 check_region(parser, 0x400fb000, 0x400fc000, yes, no , yes, yes, c); 406 check_region(parser, 0x400fc000, 0x400fd000, yes, yes, yes, yes, c); 407 check_region(parser, 0x400fd000, 0x400ff000, yes, no , yes, yes, c); 408 check_region(parser, 0x400ff000, 0x40100000, yes, no , no , yes, c); 409 check_region(parser, 0x40100000, 0x40101000, yes, yes, no , yes, c); 410 check_region(parser, 0x40101000, 0x40122000, yes, no , yes, yes, d); 411 check_region(parser, 0x40122000, 0x40123000, yes, yes, yes, yes, d); 412 check_region(parser, 0x40123000, 0x40167000, yes, no , yes, yes, d); 413 check_region(parser, 0x40167000, 0x40169000, yes, no , no , yes, d); 414 check_region(parser, 0x40169000, 0x4016b000, yes, yes, no , yes, d); 415 check_region(parser, 0x4016b000, 0x40176000, yes, yes, no , yes, n); 416 check_region(parser, 0x40176000, UINT64_MAX, no , no , no , no , n); 417 } 418 419 // Windows Minidump tests 420 // fizzbuzz_no_heap.dmp is copied from the WinMiniDump tests 421 TEST_F(MinidumpParserTest, GetArchitectureWindows) { 422 SetUpData("fizzbuzz_no_heap.dmp"); 423 ASSERT_EQ(llvm::Triple::ArchType::x86, 424 parser->GetArchitecture().GetMachine()); 425 ASSERT_EQ(llvm::Triple::OSType::Win32, 426 parser->GetArchitecture().GetTriple().getOS()); 427 } 428 429 TEST_F(MinidumpParserTest, GetLinuxProcStatusWindows) { 430 SetUpData("fizzbuzz_no_heap.dmp"); 431 llvm::Optional<LinuxProcStatus> proc_status = parser->GetLinuxProcStatus(); 432 ASSERT_FALSE(proc_status.hasValue()); 433 } 434 435 TEST_F(MinidumpParserTest, GetMiscInfoWindows) { 436 SetUpData("fizzbuzz_no_heap.dmp"); 437 const MinidumpMiscInfo *misc_info = parser->GetMiscInfo(); 438 ASSERT_NE(nullptr, misc_info); 439 llvm::Optional<lldb::pid_t> pid = misc_info->GetPid(); 440 ASSERT_TRUE(pid.hasValue()); 441 ASSERT_EQ(4440UL, pid.getValue()); 442 } 443 444 TEST_F(MinidumpParserTest, GetPidWindows) { 445 SetUpData("fizzbuzz_no_heap.dmp"); 446 llvm::Optional<lldb::pid_t> pid = parser->GetPid(); 447 ASSERT_TRUE(pid.hasValue()); 448 ASSERT_EQ(4440UL, pid.getValue()); 449 } 450 451 // wow64 452 TEST_F(MinidumpParserTest, GetPidWow64) { 453 SetUpData("fizzbuzz_wow64.dmp"); 454 llvm::Optional<lldb::pid_t> pid = parser->GetPid(); 455 ASSERT_TRUE(pid.hasValue()); 456 ASSERT_EQ(7836UL, pid.getValue()); 457 } 458 459 TEST_F(MinidumpParserTest, GetModuleListWow64) { 460 SetUpData("fizzbuzz_wow64.dmp"); 461 llvm::ArrayRef<MinidumpModule> modules = parser->GetModuleList(); 462 ASSERT_EQ(16UL, modules.size()); 463 std::string module_names[16] = { 464 R"(D:\src\llvm\llvm\tools\lldb\packages\Python\lldbsuite\test\functionalities\postmortem\wow64_minidump\fizzbuzz.exe)", 465 R"(C:\Windows\System32\ntdll.dll)", 466 R"(C:\Windows\System32\wow64.dll)", 467 R"(C:\Windows\System32\wow64win.dll)", 468 R"(C:\Windows\System32\wow64cpu.dll)", 469 R"(D:\src\llvm\llvm\tools\lldb\packages\Python\lldbsuite\test\functionalities\postmortem\wow64_minidump\fizzbuzz.exe)", 470 R"(C:\Windows\SysWOW64\ntdll.dll)", 471 R"(C:\Windows\SysWOW64\kernel32.dll)", 472 R"(C:\Windows\SysWOW64\KERNELBASE.dll)", 473 R"(C:\Windows\SysWOW64\advapi32.dll)", 474 R"(C:\Windows\SysWOW64\msvcrt.dll)", 475 R"(C:\Windows\SysWOW64\sechost.dll)", 476 R"(C:\Windows\SysWOW64\rpcrt4.dll)", 477 R"(C:\Windows\SysWOW64\sspicli.dll)", 478 R"(C:\Windows\SysWOW64\CRYPTBASE.dll)", 479 R"(C:\Windows\System32\api-ms-win-core-synch-l1-2-0.DLL)", 480 }; 481 482 for (int i = 0; i < 16; ++i) { 483 llvm::Optional<std::string> name = 484 parser->GetMinidumpString(modules[i].module_name_rva); 485 ASSERT_TRUE(name.hasValue()); 486 EXPECT_EQ(module_names[i], name.getValue()); 487 } 488 } 489 490 // Register tests 491 #define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x)) 492 #define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x)) 493 494 TEST_F(MinidumpParserTest, ConvertMinidumpContext_x86_32) { 495 SetUpData("linux-i386.dmp"); 496 llvm::ArrayRef<MinidumpThread> thread_list = parser->GetThreads(); 497 const MinidumpThread thread = thread_list[0]; 498 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread)); 499 500 ArchSpec arch = parser->GetArchitecture(); 501 auto reg_interface = llvm::make_unique<RegisterContextLinux_i386>(arch); 502 lldb::DataBufferSP buf = 503 ConvertMinidumpContext_x86_32(registers, reg_interface.get()); 504 ASSERT_EQ(reg_interface->GetGPRSize(), buf->GetByteSize()); 505 506 const RegisterInfo *reg_info = reg_interface->GetRegisterInfo(); 507 508 std::map<uint64_t, uint32_t> reg_values; 509 510 reg_values[lldb_eax_i386] = 0x00000000; 511 reg_values[lldb_ebx_i386] = 0xf7778000; 512 reg_values[lldb_ecx_i386] = 0x00000001; 513 reg_values[lldb_edx_i386] = 0xff9dd4a3; 514 reg_values[lldb_edi_i386] = 0x080482a8; 515 reg_values[lldb_esi_i386] = 0xff9dd55c; 516 reg_values[lldb_ebp_i386] = 0xff9dd53c; 517 reg_values[lldb_esp_i386] = 0xff9dd52c; 518 reg_values[lldb_eip_i386] = 0x080482a0; 519 reg_values[lldb_eflags_i386] = 0x00010282; 520 reg_values[lldb_cs_i386] = 0x00000023; 521 reg_values[lldb_fs_i386] = 0x00000000; 522 reg_values[lldb_gs_i386] = 0x00000063; 523 reg_values[lldb_ss_i386] = 0x0000002b; 524 reg_values[lldb_ds_i386] = 0x0000002b; 525 reg_values[lldb_es_i386] = 0x0000002b; 526 527 for (uint32_t reg_index = 0; reg_index < reg_interface->GetRegisterCount(); 528 ++reg_index) { 529 if (reg_values.find(reg_index) != reg_values.end()) { 530 EXPECT_EQ(reg_values[reg_index], 531 REG_VAL32(buf->GetBytes() + reg_info[reg_index].byte_offset)); 532 } 533 } 534 } 535 536 TEST_F(MinidumpParserTest, ConvertMinidumpContext_x86_64) { 537 SetUpData("linux-x86_64.dmp"); 538 llvm::ArrayRef<MinidumpThread> thread_list = parser->GetThreads(); 539 const MinidumpThread thread = thread_list[0]; 540 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread)); 541 542 ArchSpec arch = parser->GetArchitecture(); 543 auto reg_interface = llvm::make_unique<RegisterContextLinux_x86_64>(arch); 544 lldb::DataBufferSP buf = 545 ConvertMinidumpContext_x86_64(registers, reg_interface.get()); 546 ASSERT_EQ(reg_interface->GetGPRSize(), buf->GetByteSize()); 547 548 const RegisterInfo *reg_info = reg_interface->GetRegisterInfo(); 549 550 std::map<uint64_t, uint64_t> reg_values; 551 552 reg_values[lldb_rax_x86_64] = 0x0000000000000000; 553 reg_values[lldb_rbx_x86_64] = 0x0000000000000000; 554 reg_values[lldb_rcx_x86_64] = 0x0000000000000010; 555 reg_values[lldb_rdx_x86_64] = 0x0000000000000000; 556 reg_values[lldb_rdi_x86_64] = 0x00007ffceb349cf0; 557 reg_values[lldb_rsi_x86_64] = 0x0000000000000000; 558 reg_values[lldb_rbp_x86_64] = 0x00007ffceb34a210; 559 reg_values[lldb_rsp_x86_64] = 0x00007ffceb34a210; 560 reg_values[lldb_r8_x86_64] = 0x00007fe9bc1aa9c0; 561 reg_values[lldb_r9_x86_64] = 0x0000000000000000; 562 reg_values[lldb_r10_x86_64] = 0x00007fe9bc3f16a0; 563 reg_values[lldb_r11_x86_64] = 0x0000000000000246; 564 reg_values[lldb_r12_x86_64] = 0x0000000000401c92; 565 reg_values[lldb_r13_x86_64] = 0x00007ffceb34a430; 566 reg_values[lldb_r14_x86_64] = 0x0000000000000000; 567 reg_values[lldb_r15_x86_64] = 0x0000000000000000; 568 reg_values[lldb_rip_x86_64] = 0x0000000000401dc6; 569 reg_values[lldb_rflags_x86_64] = 0x0000000000010206; 570 reg_values[lldb_cs_x86_64] = 0x0000000000000033; 571 reg_values[lldb_fs_x86_64] = 0x0000000000000000; 572 reg_values[lldb_gs_x86_64] = 0x0000000000000000; 573 reg_values[lldb_ss_x86_64] = 0x0000000000000000; 574 reg_values[lldb_ds_x86_64] = 0x0000000000000000; 575 reg_values[lldb_es_x86_64] = 0x0000000000000000; 576 577 for (uint32_t reg_index = 0; reg_index < reg_interface->GetRegisterCount(); 578 ++reg_index) { 579 if (reg_values.find(reg_index) != reg_values.end()) { 580 EXPECT_EQ(reg_values[reg_index], 581 REG_VAL64(buf->GetBytes() + reg_info[reg_index].byte_offset)); 582 } 583 } 584 } 585 586 TEST_F(MinidumpParserTest, ConvertMinidumpContext_x86_32_wow64) { 587 SetUpData("fizzbuzz_wow64.dmp"); 588 llvm::ArrayRef<MinidumpThread> thread_list = parser->GetThreads(); 589 const MinidumpThread thread = thread_list[0]; 590 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContextWow64(thread)); 591 592 ArchSpec arch = parser->GetArchitecture(); 593 auto reg_interface = llvm::make_unique<RegisterContextLinux_i386>(arch); 594 lldb::DataBufferSP buf = 595 ConvertMinidumpContext_x86_32(registers, reg_interface.get()); 596 ASSERT_EQ(reg_interface->GetGPRSize(), buf->GetByteSize()); 597 598 const RegisterInfo *reg_info = reg_interface->GetRegisterInfo(); 599 600 std::map<uint64_t, uint32_t> reg_values; 601 602 reg_values[lldb_eax_i386] = 0x00000000; 603 reg_values[lldb_ebx_i386] = 0x0037f608; 604 reg_values[lldb_ecx_i386] = 0x00e61578; 605 reg_values[lldb_edx_i386] = 0x00000008; 606 reg_values[lldb_edi_i386] = 0x00000000; 607 reg_values[lldb_esi_i386] = 0x00000002; 608 reg_values[lldb_ebp_i386] = 0x0037f654; 609 reg_values[lldb_esp_i386] = 0x0037f5b8; 610 reg_values[lldb_eip_i386] = 0x77ce01fd; 611 reg_values[lldb_eflags_i386] = 0x00000246; 612 reg_values[lldb_cs_i386] = 0x00000023; 613 reg_values[lldb_fs_i386] = 0x00000053; 614 reg_values[lldb_gs_i386] = 0x0000002b; 615 reg_values[lldb_ss_i386] = 0x0000002b; 616 reg_values[lldb_ds_i386] = 0x0000002b; 617 reg_values[lldb_es_i386] = 0x0000002b; 618 619 for (uint32_t reg_index = 0; reg_index < reg_interface->GetRegisterCount(); 620 ++reg_index) { 621 if (reg_values.find(reg_index) != reg_values.end()) { 622 EXPECT_EQ(reg_values[reg_index], 623 REG_VAL32(buf->GetBytes() + reg_info[reg_index].byte_offset)); 624 } 625 } 626 } 627 628 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) { 629 SetUpData("modules-dup-min-addr.dmp"); 630 // Test that if we have two modules in the module list: 631 // /tmp/a with range [0x2000-0x3000) 632 // /tmp/a with range [0x1000-0x2000) 633 // That we end up with one module in the filtered list with the 634 // range [0x1000-0x2000). MinidumpParser::GetFilteredModuleList() is 635 // trying to ensure that if we have the same module mentioned more than 636 // one time, we pick the one with the lowest base_of_image. 637 std::vector<const MinidumpModule *> filtered_modules = 638 parser->GetFilteredModuleList(); 639 EXPECT_EQ(1u, filtered_modules.size()); 640 EXPECT_EQ(0x0000000000001000u, filtered_modules[0]->base_of_image); 641 } 642 643 TEST_F(MinidumpParserTest, MinidumpModuleOrder) { 644 SetUpData("modules-order.dmp"); 645 // Test that if we have two modules in the module list: 646 // /tmp/a with range [0x2000-0x3000) 647 // /tmp/b with range [0x1000-0x2000) 648 // That we end up with two modules in the filtered list with the same ranges 649 // and in the same order. Previous versions of the 650 // MinidumpParser::GetFilteredModuleList() function would sort all images 651 // by address and modify the order of the modules. 652 std::vector<const MinidumpModule *> filtered_modules = 653 parser->GetFilteredModuleList(); 654 llvm::Optional<std::string> name; 655 EXPECT_EQ(2u, filtered_modules.size()); 656 EXPECT_EQ(0x0000000000002000u, filtered_modules[0]->base_of_image); 657 name = parser->GetMinidumpString(filtered_modules[0]->module_name_rva); 658 ASSERT_TRUE((bool)name); 659 EXPECT_EQ(std::string("/tmp/a"), *name); 660 EXPECT_EQ(0x0000000000001000u, filtered_modules[1]->base_of_image); 661 name = parser->GetMinidumpString(filtered_modules[1]->module_name_rva); 662 ASSERT_TRUE((bool)name); 663 EXPECT_EQ(std::string("/tmp/b"), *name); 664 } 665 666