minidump_processor_unittest.cc
1 // Copyright 2006 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 // Unit test for MinidumpProcessor. Uses a pre-generated minidump and 30 // corresponding symbol file, and checks the stack frames for correctness. 31 32 #ifdef HAVE_CONFIG_H 33 #include <config.h> // Must come first 34 #endif 35 36 #include <stdlib.h> 37 38 #include <string> 39 #include <iostream> 40 #include <fstream> 41 #include <map> 42 #include <utility> 43 44 #include "breakpad_googletest_includes.h" 45 #include "common/scoped_ptr.h" 46 #include "common/using_std_string.h" 47 #include "google_breakpad/processor/basic_source_line_resolver.h" 48 #include "google_breakpad/processor/call_stack.h" 49 #include "google_breakpad/processor/code_module.h" 50 #include "google_breakpad/processor/code_modules.h" 51 #include "google_breakpad/processor/minidump.h" 52 #include "google_breakpad/processor/minidump_processor.h" 53 #include "google_breakpad/processor/process_state.h" 54 #include "google_breakpad/processor/stack_frame.h" 55 #include "google_breakpad/processor/symbol_supplier.h" 56 #include "processor/logging.h" 57 #include "processor/stackwalker_unittest_utils.h" 58 59 using std::map; 60 61 namespace google_breakpad { 62 class MockMinidump : public Minidump { 63 public: 64 MockMinidump() : Minidump("") { 65 } 66 67 MOCK_METHOD0(Read, bool()); 68 MOCK_CONST_METHOD0(path, string()); 69 MOCK_CONST_METHOD0(header, const MDRawHeader*()); 70 MOCK_METHOD0(GetThreadList, MinidumpThreadList*()); 71 MOCK_METHOD0(GetSystemInfo, MinidumpSystemInfo*()); 72 MOCK_METHOD0(GetMiscInfo, MinidumpMiscInfo*()); 73 MOCK_METHOD0(GetBreakpadInfo, MinidumpBreakpadInfo*()); 74 MOCK_METHOD0(GetException, MinidumpException*()); 75 MOCK_METHOD0(GetAssertion, MinidumpAssertion*()); 76 MOCK_METHOD0(GetModuleList, MinidumpModuleList*()); 77 MOCK_METHOD0(GetUnloadedModuleList, MinidumpUnloadedModuleList*()); 78 MOCK_METHOD0(GetMemoryList, MinidumpMemoryList*()); 79 }; 80 81 class MockMinidumpUnloadedModule : public MinidumpUnloadedModule { 82 public: 83 MockMinidumpUnloadedModule() : MinidumpUnloadedModule(NULL) {} 84 }; 85 86 class MockMinidumpUnloadedModuleList : public MinidumpUnloadedModuleList { 87 public: 88 MockMinidumpUnloadedModuleList() : MinidumpUnloadedModuleList(NULL) {} 89 90 ~MockMinidumpUnloadedModuleList() {} 91 MOCK_CONST_METHOD0(Copy, CodeModules*()); 92 MOCK_CONST_METHOD1(GetModuleForAddress, 93 const MinidumpUnloadedModule*(uint64_t)); 94 }; 95 96 class MockMinidumpThreadList : public MinidumpThreadList { 97 public: 98 MockMinidumpThreadList() : MinidumpThreadList(NULL) {} 99 100 MOCK_CONST_METHOD0(thread_count, unsigned int()); 101 MOCK_CONST_METHOD1(GetThreadAtIndex, MinidumpThread*(unsigned int)); 102 }; 103 104 class MockMinidumpMemoryList : public MinidumpMemoryList { 105 public: 106 MockMinidumpMemoryList() : MinidumpMemoryList(NULL) {} 107 108 MOCK_METHOD1(GetMemoryRegionForAddress, MinidumpMemoryRegion*(uint64_t)); 109 }; 110 111 class MockMinidumpThread : public MinidumpThread { 112 public: 113 MockMinidumpThread() : MinidumpThread(NULL) {} 114 115 MOCK_CONST_METHOD1(GetThreadID, bool(uint32_t*)); 116 MOCK_METHOD0(GetContext, MinidumpContext*()); 117 MOCK_METHOD0(GetMemory, MinidumpMemoryRegion*()); 118 MOCK_CONST_METHOD0(GetStartOfStackMemoryRange, uint64_t()); 119 }; 120 121 // This is crappy, but MinidumpProcessor really does want a 122 // MinidumpMemoryRegion. 123 class MockMinidumpMemoryRegion : public MinidumpMemoryRegion { 124 public: 125 MockMinidumpMemoryRegion(uint64_t base, const string& contents) : 126 MinidumpMemoryRegion(NULL) { 127 region_.Init(base, contents); 128 } 129 130 uint64_t GetBase() const { return region_.GetBase(); } 131 uint32_t GetSize() const { return region_.GetSize(); } 132 133 bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const { 134 return region_.GetMemoryAtAddress(address, value); 135 } 136 bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const { 137 return region_.GetMemoryAtAddress(address, value); 138 } 139 bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const { 140 return region_.GetMemoryAtAddress(address, value); 141 } 142 bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const { 143 return region_.GetMemoryAtAddress(address, value); 144 } 145 146 MockMemoryRegion region_; 147 }; 148 149 // A test miscelaneous info stream, just returns values from the 150 // MDRawMiscInfo fed to it. 151 class TestMinidumpMiscInfo : public MinidumpMiscInfo { 152 public: 153 explicit TestMinidumpMiscInfo(const MDRawMiscInfo& misc_info) : 154 MinidumpMiscInfo(NULL) { 155 valid_ = true; 156 misc_info_ = misc_info; 157 } 158 }; 159 160 } // namespace google_breakpad 161 162 namespace { 163 164 using google_breakpad::BasicSourceLineResolver; 165 using google_breakpad::CallStack; 166 using google_breakpad::CodeModule; 167 using google_breakpad::MinidumpContext; 168 using google_breakpad::MinidumpMemoryRegion; 169 using google_breakpad::MinidumpMiscInfo; 170 using google_breakpad::MinidumpProcessor; 171 using google_breakpad::MinidumpSystemInfo; 172 using google_breakpad::MinidumpThreadList; 173 using google_breakpad::MinidumpThread; 174 using google_breakpad::MockMinidump; 175 using google_breakpad::MockMinidumpMemoryList; 176 using google_breakpad::MockMinidumpMemoryRegion; 177 using google_breakpad::MockMinidumpThread; 178 using google_breakpad::MockMinidumpThreadList; 179 using google_breakpad::MockMinidumpUnloadedModule; 180 using google_breakpad::MockMinidumpUnloadedModuleList; 181 using google_breakpad::ProcessState; 182 using google_breakpad::scoped_ptr; 183 using google_breakpad::SymbolSupplier; 184 using google_breakpad::SystemInfo; 185 using ::testing::_; 186 using ::testing::AnyNumber; 187 using ::testing::DoAll; 188 using ::testing::Mock; 189 using ::testing::Ne; 190 using ::testing::Property; 191 using ::testing::Return; 192 using ::testing::SetArgumentPointee; 193 194 static const char* kSystemInfoOS = "Windows NT"; 195 static const char* kSystemInfoOSShort = "windows"; 196 static const char* kSystemInfoOSVersion = "5.1.2600 Service Pack 2"; 197 static const char* kSystemInfoCPU = "x86"; 198 static const char* kSystemInfoCPUInfo = 199 "GenuineIntel family 6 model 13 stepping 8"; 200 201 #define ASSERT_TRUE_ABORT(cond) \ 202 if (!(cond)) { \ 203 fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \ 204 abort(); \ 205 } 206 207 #define ASSERT_EQ_ABORT(e1, e2) ASSERT_TRUE_ABORT((e1) == (e2)) 208 209 static string GetTestDataPath() { 210 char* srcdir = getenv("srcdir"); 211 212 return string(srcdir ? srcdir : ".") + "/src/processor/testdata/"; 213 } 214 215 class TestSymbolSupplier : public SymbolSupplier { 216 public: 217 TestSymbolSupplier() : interrupt_(false) {} 218 219 virtual SymbolResult GetSymbolFile(const CodeModule* module, 220 const SystemInfo* system_info, 221 string* symbol_file); 222 223 virtual SymbolResult GetSymbolFile(const CodeModule* module, 224 const SystemInfo* system_info, 225 string* symbol_file, 226 string* symbol_data); 227 228 virtual SymbolResult GetCStringSymbolData(const CodeModule* module, 229 const SystemInfo* system_info, 230 string* symbol_file, 231 char** symbol_data, 232 size_t* symbol_data_size); 233 234 virtual void FreeSymbolData(const CodeModule* module); 235 236 // When set to true, causes the SymbolSupplier to return INTERRUPT 237 void set_interrupt(bool interrupt) { interrupt_ = interrupt; } 238 239 private: 240 bool interrupt_; 241 map<string, char*> memory_buffers_; 242 }; 243 244 SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile( 245 const CodeModule* module, 246 const SystemInfo* system_info, 247 string* symbol_file) { 248 ASSERT_TRUE_ABORT(module); 249 ASSERT_TRUE_ABORT(system_info); 250 ASSERT_EQ_ABORT(system_info->cpu, kSystemInfoCPU); 251 ASSERT_EQ_ABORT(system_info->cpu_info, kSystemInfoCPUInfo); 252 ASSERT_EQ_ABORT(system_info->os, kSystemInfoOS); 253 ASSERT_EQ_ABORT(system_info->os_short, kSystemInfoOSShort); 254 ASSERT_EQ_ABORT(system_info->os_version, kSystemInfoOSVersion); 255 256 if (interrupt_) { 257 return INTERRUPT; 258 } 259 260 if (module && module->code_file() == "c:\\test_app.exe") { 261 *symbol_file = GetTestDataPath() + "symbols/test_app.pdb/" + 262 module->debug_identifier() + "/test_app.sym"; 263 return FOUND; 264 } 265 266 return NOT_FOUND; 267 } 268 269 SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile( 270 const CodeModule* module, 271 const SystemInfo* system_info, 272 string* symbol_file, 273 string* symbol_data) { 274 SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info, 275 symbol_file); 276 if (s == FOUND) { 277 std::ifstream in(symbol_file->c_str()); 278 std::getline(in, *symbol_data, string::traits_type::to_char_type( 279 string::traits_type::eof())); 280 in.close(); 281 } 282 283 return s; 284 } 285 286 SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData( 287 const CodeModule* module, 288 const SystemInfo* system_info, 289 string* symbol_file, 290 char** symbol_data, 291 size_t* symbol_data_size) { 292 string symbol_data_string; 293 SymbolSupplier::SymbolResult s = GetSymbolFile(module, 294 system_info, 295 symbol_file, 296 &symbol_data_string); 297 if (s == FOUND) { 298 *symbol_data_size = symbol_data_string.size() + 1; 299 *symbol_data = new char[*symbol_data_size]; 300 if (*symbol_data == NULL) { 301 BPLOG(ERROR) << "Memory allocation failed for module: " 302 << module->code_file() << " size: " << *symbol_data_size; 303 return INTERRUPT; 304 } 305 memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size()); 306 (*symbol_data)[symbol_data_string.size()] = '\0'; 307 memory_buffers_.insert(make_pair(module->code_file(), *symbol_data)); 308 } 309 310 return s; 311 } 312 313 void TestSymbolSupplier::FreeSymbolData(const CodeModule* module) { 314 map<string, char*>::iterator it = memory_buffers_.find(module->code_file()); 315 if (it != memory_buffers_.end()) { 316 delete [] it->second; 317 memory_buffers_.erase(it); 318 } 319 } 320 321 // A test system info stream, just returns values from the 322 // MDRawSystemInfo fed to it. 323 class TestMinidumpSystemInfo : public MinidumpSystemInfo { 324 public: 325 explicit TestMinidumpSystemInfo(MDRawSystemInfo info) : 326 MinidumpSystemInfo(NULL) { 327 valid_ = true; 328 system_info_ = info; 329 csd_version_ = new string(""); 330 } 331 }; 332 333 // A test minidump context, just returns the MDRawContextX86 334 // fed to it. 335 class TestMinidumpContext : public MinidumpContext { 336 public: 337 explicit TestMinidumpContext(const MDRawContextX86& context) : 338 MinidumpContext(NULL) { 339 valid_ = true; 340 SetContextX86(new MDRawContextX86(context)); 341 SetContextFlags(MD_CONTEXT_X86); 342 } 343 }; 344 345 class MinidumpProcessorTest : public ::testing::Test { 346 }; 347 348 TEST_F(MinidumpProcessorTest, TestUnloadedModules) { 349 MockMinidump dump; 350 351 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); 352 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); 353 354 MDRawHeader fake_header; 355 fake_header.time_date_stamp = 0; 356 EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); 357 358 MDRawSystemInfo raw_system_info; 359 memset(&raw_system_info, 0, sizeof(raw_system_info)); 360 raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86; 361 raw_system_info.platform_id = MD_OS_WIN32_NT; 362 TestMinidumpSystemInfo dump_system_info(raw_system_info); 363 364 EXPECT_CALL(dump, GetSystemInfo()). 365 WillRepeatedly(Return(&dump_system_info)); 366 367 // No loaded modules 368 369 MockMinidumpUnloadedModuleList unloaded_module_list; 370 EXPECT_CALL(dump, GetUnloadedModuleList()). 371 WillOnce(Return(&unloaded_module_list)); 372 373 MockMinidumpMemoryList memory_list; 374 EXPECT_CALL(dump, GetMemoryList()). 375 WillOnce(Return(&memory_list)); 376 377 MockMinidumpThreadList thread_list; 378 EXPECT_CALL(dump, GetThreadList()). 379 WillOnce(Return(&thread_list)); 380 381 EXPECT_CALL(thread_list, thread_count()). 382 WillRepeatedly(Return(1)); 383 384 MockMinidumpThread thread; 385 EXPECT_CALL(thread_list, GetThreadAtIndex(0)). 386 WillOnce(Return(&thread)); 387 388 EXPECT_CALL(thread, GetThreadID(_)). 389 WillRepeatedly(DoAll(SetArgumentPointee<0>(1), 390 Return(true))); 391 392 MDRawContextX86 thread_raw_context; 393 memset(&thread_raw_context, 0, 394 sizeof(thread_raw_context)); 395 thread_raw_context.context_flags = MD_CONTEXT_X86_FULL; 396 const uint32_t kExpectedEIP = 0xabcd1234; 397 thread_raw_context.eip = kExpectedEIP; 398 TestMinidumpContext thread_context(thread_raw_context); 399 EXPECT_CALL(thread, GetContext()). 400 WillRepeatedly(Return(&thread_context)); 401 402 // The memory contents don't really matter here, since it won't be used. 403 MockMinidumpMemoryRegion thread_memory(0x1234, "xxx"); 404 EXPECT_CALL(thread, GetMemory()). 405 WillRepeatedly(Return(&thread_memory)); 406 EXPECT_CALL(thread, GetStartOfStackMemoryRange()). 407 Times(0); 408 EXPECT_CALL(memory_list, GetMemoryRegionForAddress(_)). 409 Times(0); 410 411 MockMinidumpUnloadedModuleList* unloaded_module_list_copy = 412 new MockMinidumpUnloadedModuleList(); 413 EXPECT_CALL(unloaded_module_list, Copy()). 414 WillOnce(Return(unloaded_module_list_copy)); 415 416 MockMinidumpUnloadedModule unloaded_module; 417 EXPECT_CALL(*unloaded_module_list_copy, GetModuleForAddress(kExpectedEIP)). 418 WillOnce(Return(&unloaded_module)); 419 420 MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL); 421 ProcessState state; 422 EXPECT_EQ(processor.Process(&dump, &state), 423 google_breakpad::PROCESS_OK); 424 425 // The single frame should be populated with the unloaded module. 426 ASSERT_EQ(1U, state.threads()->size()); 427 ASSERT_EQ(1U, state.threads()->at(0)->frames()->size()); 428 ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction); 429 ASSERT_EQ(&unloaded_module, state.threads()->at(0)->frames()->at(0)->module); 430 } 431 432 TEST_F(MinidumpProcessorTest, TestCorruptMinidumps) { 433 MockMinidump dump; 434 TestSymbolSupplier supplier; 435 BasicSourceLineResolver resolver; 436 MinidumpProcessor processor(&supplier, &resolver); 437 ProcessState state; 438 439 EXPECT_EQ(processor.Process("nonexistent minidump", &state), 440 google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND); 441 442 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); 443 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); 444 445 MDRawHeader fakeHeader; 446 fakeHeader.time_date_stamp = 0; 447 EXPECT_CALL(dump, header()). 448 WillOnce(Return(reinterpret_cast<MDRawHeader*>(NULL))). 449 WillRepeatedly(Return(&fakeHeader)); 450 451 EXPECT_EQ(processor.Process(&dump, &state), 452 google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER); 453 454 EXPECT_CALL(dump, GetThreadList()). 455 WillOnce(Return(reinterpret_cast<MinidumpThreadList*>(NULL))); 456 EXPECT_CALL(dump, GetSystemInfo()). 457 WillRepeatedly(Return(reinterpret_cast<MinidumpSystemInfo*>(NULL))); 458 459 EXPECT_EQ(processor.Process(&dump, &state), 460 google_breakpad::PROCESS_ERROR_NO_THREAD_LIST); 461 } 462 463 // This test case verifies that the symbol supplier is only consulted 464 // once per minidump per module. 465 TEST_F(MinidumpProcessorTest, TestSymbolSupplierLookupCounts) { 466 MockSymbolSupplier supplier; 467 BasicSourceLineResolver resolver; 468 MinidumpProcessor processor(&supplier, &resolver); 469 470 string minidump_file = GetTestDataPath() + "minidump2.dmp"; 471 ProcessState state; 472 EXPECT_CALL(supplier, GetCStringSymbolData( 473 Property(&google_breakpad::CodeModule::code_file, 474 "c:\\test_app.exe"), 475 _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND)); 476 EXPECT_CALL(supplier, GetCStringSymbolData( 477 Property(&google_breakpad::CodeModule::code_file, 478 Ne("c:\\test_app.exe")), 479 _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND)); 480 // Avoid GMOCK WARNING "Uninteresting mock function call - returning 481 // directly" for FreeSymbolData(). 482 EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); 483 ASSERT_EQ(processor.Process(minidump_file, &state), 484 google_breakpad::PROCESS_OK); 485 486 ASSERT_TRUE(Mock::VerifyAndClearExpectations(&supplier)); 487 488 // We need to verify that across minidumps, the processor will refetch 489 // symbol files, even with the same symbol supplier. 490 EXPECT_CALL(supplier, GetCStringSymbolData( 491 Property(&google_breakpad::CodeModule::code_file, 492 "c:\\test_app.exe"), 493 _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND)); 494 EXPECT_CALL(supplier, GetCStringSymbolData( 495 Property(&google_breakpad::CodeModule::code_file, 496 Ne("c:\\test_app.exe")), 497 _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND)); 498 // Avoid GMOCK WARNING "Uninteresting mock function call - returning 499 // directly" for FreeSymbolData(). 500 EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); 501 ASSERT_EQ(processor.Process(minidump_file, &state), 502 google_breakpad::PROCESS_OK); 503 } 504 505 TEST_F(MinidumpProcessorTest, TestBasicProcessing) { 506 TestSymbolSupplier supplier; 507 BasicSourceLineResolver resolver; 508 MinidumpProcessor processor(&supplier, &resolver); 509 510 string minidump_file = GetTestDataPath() + "minidump2.dmp"; 511 512 ProcessState state; 513 ASSERT_EQ(processor.Process(minidump_file, &state), 514 google_breakpad::PROCESS_OK); 515 ASSERT_EQ(state.system_info()->os, kSystemInfoOS); 516 ASSERT_EQ(state.system_info()->os_short, kSystemInfoOSShort); 517 ASSERT_EQ(state.system_info()->os_version, kSystemInfoOSVersion); 518 ASSERT_EQ(state.system_info()->cpu, kSystemInfoCPU); 519 ASSERT_EQ(state.system_info()->cpu_info, kSystemInfoCPUInfo); 520 ASSERT_TRUE(state.crashed()); 521 ASSERT_EQ(state.crash_reason(), "EXCEPTION_ACCESS_VIOLATION_WRITE"); 522 ASSERT_EQ(state.crash_address(), 0x45U); 523 ASSERT_EQ(state.threads()->size(), size_t(1)); 524 EXPECT_EQ((*state.threads())[0]->tid(), 3060U); 525 ASSERT_EQ(state.requesting_thread(), 0); 526 EXPECT_EQ(1171480435U, state.time_date_stamp()); 527 EXPECT_EQ(1171480435U, state.process_create_time()); 528 529 CallStack* stack = state.threads()->at(0); 530 ASSERT_TRUE(stack); 531 ASSERT_EQ(stack->frames()->size(), 4U); 532 533 ASSERT_TRUE(stack->frames()->at(0)->module); 534 ASSERT_EQ(stack->frames()->at(0)->module->base_address(), 0x400000U); 535 ASSERT_EQ(stack->frames()->at(0)->module->code_file(), "c:\\test_app.exe"); 536 ASSERT_EQ(stack->frames()->at(0)->function_name, 537 "`anonymous namespace'::CrashFunction"); 538 ASSERT_EQ(stack->frames()->at(0)->source_file_name, "c:\\test_app.cc"); 539 ASSERT_EQ(stack->frames()->at(0)->source_line, 58); 540 541 ASSERT_TRUE(stack->frames()->at(1)->module); 542 ASSERT_EQ(stack->frames()->at(1)->module->base_address(), 0x400000U); 543 ASSERT_EQ(stack->frames()->at(1)->module->code_file(), "c:\\test_app.exe"); 544 ASSERT_EQ(stack->frames()->at(1)->function_name, "main"); 545 ASSERT_EQ(stack->frames()->at(1)->source_file_name, "c:\\test_app.cc"); 546 ASSERT_EQ(stack->frames()->at(1)->source_line, 65); 547 548 // This comes from the CRT 549 ASSERT_TRUE(stack->frames()->at(2)->module); 550 ASSERT_EQ(stack->frames()->at(2)->module->base_address(), 0x400000U); 551 ASSERT_EQ(stack->frames()->at(2)->module->code_file(), "c:\\test_app.exe"); 552 ASSERT_EQ(stack->frames()->at(2)->function_name, "__tmainCRTStartup"); 553 ASSERT_EQ(stack->frames()->at(2)->source_file_name, 554 "f:\\sp\\vctools\\crt_bld\\self_x86\\crt\\src\\crt0.c"); 555 ASSERT_EQ(stack->frames()->at(2)->source_line, 327); 556 557 // No debug info available for kernel32.dll 558 ASSERT_TRUE(stack->frames()->at(3)->module); 559 ASSERT_EQ(stack->frames()->at(3)->module->base_address(), 0x7c800000U); 560 ASSERT_EQ(stack->frames()->at(3)->module->code_file(), 561 "C:\\WINDOWS\\system32\\kernel32.dll"); 562 ASSERT_TRUE(stack->frames()->at(3)->function_name.empty()); 563 ASSERT_TRUE(stack->frames()->at(3)->source_file_name.empty()); 564 ASSERT_EQ(stack->frames()->at(3)->source_line, 0); 565 566 ASSERT_EQ(state.modules()->module_count(), 13U); 567 ASSERT_TRUE(state.modules()->GetMainModule()); 568 ASSERT_EQ(state.modules()->GetMainModule()->code_file(), "c:\\test_app.exe"); 569 ASSERT_FALSE(state.modules()->GetModuleForAddress(0)); 570 ASSERT_EQ(state.modules()->GetMainModule(), 571 state.modules()->GetModuleForAddress(0x400000)); 572 ASSERT_EQ(state.modules()->GetModuleForAddress(0x7c801234)->debug_file(), 573 "kernel32.pdb"); 574 ASSERT_EQ(state.modules()->GetModuleForAddress(0x77d43210)->version(), 575 "5.1.2600.2622"); 576 577 // Test that disabled exploitability engine defaults to 578 // EXPLOITABILITY_NOT_ANALYZED. 579 ASSERT_EQ(google_breakpad::EXPLOITABILITY_NOT_ANALYZED, 580 state.exploitability()); 581 582 // Test that the symbol supplier can interrupt processing 583 state.Clear(); 584 supplier.set_interrupt(true); 585 ASSERT_EQ(processor.Process(minidump_file, &state), 586 google_breakpad::PROCESS_SYMBOL_SUPPLIER_INTERRUPTED); 587 } 588 589 TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) { 590 MockMinidump dump; 591 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); 592 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); 593 594 MDRawHeader fake_header; 595 fake_header.time_date_stamp = 0; 596 EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); 597 598 MDRawSystemInfo raw_system_info; 599 memset(&raw_system_info, 0, sizeof(raw_system_info)); 600 raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86; 601 raw_system_info.platform_id = MD_OS_WIN32_NT; 602 TestMinidumpSystemInfo dump_system_info(raw_system_info); 603 604 EXPECT_CALL(dump, GetSystemInfo()). 605 WillRepeatedly(Return(&dump_system_info)); 606 607 MockMinidumpThreadList thread_list; 608 EXPECT_CALL(dump, GetThreadList()). 609 WillOnce(Return(&thread_list)); 610 611 MockMinidumpMemoryList memory_list; 612 EXPECT_CALL(dump, GetMemoryList()). 613 WillOnce(Return(&memory_list)); 614 615 // Return a thread missing stack memory. 616 MockMinidumpThread no_memory_thread; 617 EXPECT_CALL(no_memory_thread, GetThreadID(_)). 618 WillRepeatedly(DoAll(SetArgumentPointee<0>(1), 619 Return(true))); 620 EXPECT_CALL(no_memory_thread, GetMemory()). 621 WillRepeatedly(Return(reinterpret_cast<MinidumpMemoryRegion*>(NULL))); 622 623 const uint64_t kTestStartOfMemoryRange = 0x1234; 624 EXPECT_CALL(no_memory_thread, GetStartOfStackMemoryRange()). 625 WillRepeatedly(Return(kTestStartOfMemoryRange)); 626 EXPECT_CALL(memory_list, GetMemoryRegionForAddress(kTestStartOfMemoryRange)). 627 WillRepeatedly(Return(reinterpret_cast<MinidumpMemoryRegion*>(NULL))); 628 629 MDRawContextX86 no_memory_thread_raw_context; 630 memset(&no_memory_thread_raw_context, 0, 631 sizeof(no_memory_thread_raw_context)); 632 no_memory_thread_raw_context.context_flags = MD_CONTEXT_X86_FULL; 633 const uint32_t kExpectedEIP = 0xabcd1234; 634 no_memory_thread_raw_context.eip = kExpectedEIP; 635 TestMinidumpContext no_memory_thread_context(no_memory_thread_raw_context); 636 EXPECT_CALL(no_memory_thread, GetContext()). 637 WillRepeatedly(Return(&no_memory_thread_context)); 638 639 EXPECT_CALL(thread_list, thread_count()). 640 WillRepeatedly(Return(1)); 641 EXPECT_CALL(thread_list, GetThreadAtIndex(0)). 642 WillOnce(Return(&no_memory_thread)); 643 644 MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL); 645 ProcessState state; 646 EXPECT_EQ(processor.Process(&dump, &state), 647 google_breakpad::PROCESS_OK); 648 649 // Should have a single thread with a single frame in it. 650 ASSERT_EQ(1U, state.threads()->size()); 651 ASSERT_EQ(1U, state.threads()->at(0)->frames()->size()); 652 ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction); 653 } 654 655 TEST_F(MinidumpProcessorTest, GetProcessCreateTime) { 656 const uint32_t kProcessCreateTime = 2000; 657 const uint32_t kTimeDateStamp = 5000; 658 MockMinidump dump; 659 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); 660 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); 661 662 // Set time of crash. 663 MDRawHeader fake_header; 664 fake_header.time_date_stamp = kTimeDateStamp; 665 EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); 666 667 // Set process create time. 668 MDRawMiscInfo raw_misc_info; 669 memset(&raw_misc_info, 0, sizeof(raw_misc_info)); 670 raw_misc_info.process_create_time = kProcessCreateTime; 671 raw_misc_info.flags1 |= MD_MISCINFO_FLAGS1_PROCESS_TIMES; 672 google_breakpad::TestMinidumpMiscInfo dump_misc_info(raw_misc_info); 673 EXPECT_CALL(dump, GetMiscInfo()).WillRepeatedly(Return(&dump_misc_info)); 674 675 // No threads 676 MockMinidumpThreadList thread_list; 677 EXPECT_CALL(dump, GetThreadList()).WillOnce(Return(&thread_list)); 678 EXPECT_CALL(thread_list, thread_count()).WillRepeatedly(Return(0)); 679 680 MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL); 681 ProcessState state; 682 EXPECT_EQ(google_breakpad::PROCESS_OK, processor.Process(&dump, &state)); 683 684 // Verify the time stamps. 685 ASSERT_EQ(kTimeDateStamp, state.time_date_stamp()); 686 ASSERT_EQ(kProcessCreateTime, state.process_create_time()); 687 } 688 689 TEST_F(MinidumpProcessorTest, TestThreadMissingContext) { 690 MockMinidump dump; 691 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); 692 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); 693 694 MDRawHeader fake_header; 695 fake_header.time_date_stamp = 0; 696 EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); 697 698 MDRawSystemInfo raw_system_info; 699 memset(&raw_system_info, 0, sizeof(raw_system_info)); 700 raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86; 701 raw_system_info.platform_id = MD_OS_WIN32_NT; 702 TestMinidumpSystemInfo dump_system_info(raw_system_info); 703 704 EXPECT_CALL(dump, GetSystemInfo()). 705 WillRepeatedly(Return(&dump_system_info)); 706 707 MockMinidumpThreadList thread_list; 708 EXPECT_CALL(dump, GetThreadList()). 709 WillOnce(Return(&thread_list)); 710 711 MockMinidumpMemoryList memory_list; 712 EXPECT_CALL(dump, GetMemoryList()). 713 WillOnce(Return(&memory_list)); 714 715 // Return a thread missing a thread context. 716 MockMinidumpThread no_context_thread; 717 EXPECT_CALL(no_context_thread, GetThreadID(_)). 718 WillRepeatedly(DoAll(SetArgumentPointee<0>(1), 719 Return(true))); 720 EXPECT_CALL(no_context_thread, GetContext()). 721 WillRepeatedly(Return(reinterpret_cast<MinidumpContext*>(NULL))); 722 723 // The memory contents don't really matter here, since it won't be used. 724 MockMinidumpMemoryRegion no_context_thread_memory(0x1234, "xxx"); 725 EXPECT_CALL(no_context_thread, GetMemory()). 726 WillRepeatedly(Return(&no_context_thread_memory)); 727 EXPECT_CALL(no_context_thread, GetStartOfStackMemoryRange()). 728 Times(0); 729 EXPECT_CALL(memory_list, GetMemoryRegionForAddress(_)). 730 Times(0); 731 732 EXPECT_CALL(thread_list, thread_count()). 733 WillRepeatedly(Return(1)); 734 EXPECT_CALL(thread_list, GetThreadAtIndex(0)). 735 WillOnce(Return(&no_context_thread)); 736 737 MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL); 738 ProcessState state; 739 EXPECT_EQ(processor.Process(&dump, &state), 740 google_breakpad::PROCESS_OK); 741 742 // Should have a single thread with zero frames. 743 ASSERT_EQ(1U, state.threads()->size()); 744 ASSERT_EQ(0U, state.threads()->at(0)->frames()->size()); 745 } 746 747 TEST_F(MinidumpProcessorTest, Test32BitCrashingAddress) { 748 TestSymbolSupplier supplier; 749 BasicSourceLineResolver resolver; 750 MinidumpProcessor processor(&supplier, &resolver); 751 752 string minidump_file = GetTestDataPath() + "minidump_32bit_crash_addr.dmp"; 753 754 ProcessState state; 755 ASSERT_EQ(processor.Process(minidump_file, &state), 756 google_breakpad::PROCESS_OK); 757 ASSERT_EQ(state.system_info()->os, kSystemInfoOS); 758 ASSERT_EQ(state.system_info()->os_short, kSystemInfoOSShort); 759 ASSERT_EQ(state.system_info()->os_version, kSystemInfoOSVersion); 760 ASSERT_EQ(state.system_info()->cpu, kSystemInfoCPU); 761 ASSERT_EQ(state.system_info()->cpu_info, kSystemInfoCPUInfo); 762 ASSERT_TRUE(state.crashed()); 763 ASSERT_EQ(state.crash_reason(), "EXCEPTION_ACCESS_VIOLATION_WRITE"); 764 ASSERT_EQ(state.crash_address(), 0x45U); 765 } 766 767 TEST_F(MinidumpProcessorTest, TestXStateAmd64ContextMinidump) { 768 // This tests if we can passively process a minidump with cet registers in its 769 // context. Dump is captured from a toy executable and is readable by windbg. 770 MinidumpProcessor processor(nullptr, nullptr /*&supplier, &resolver*/); 771 772 string minidump_file = GetTestDataPath() 773 + "tiny-exe-with-cet-xsave.dmp"; 774 775 ProcessState state; 776 ASSERT_EQ(processor.Process(minidump_file, &state), 777 google_breakpad::PROCESS_OK); 778 ASSERT_EQ(state.system_info()->os, "Windows NT"); 779 ASSERT_EQ(state.system_info()->os_version, "10.0.22000 282"); 780 ASSERT_EQ(state.system_info()->cpu, "amd64"); 781 ASSERT_EQ(state.system_info()->cpu_info, 782 "family 6 model 140 stepping 1"); 783 ASSERT_FALSE(state.crashed()); 784 ASSERT_EQ(state.threads()->size(), size_t(1)); 785 786 // TODO: verify cetumsr and cetussp once these are supported by 787 // breakpad. 788 } 789 790 TEST_F(MinidumpProcessorTest, TestFastFailException) { 791 // This tests if we can understand fastfail exception subcodes. 792 // Dump is captured from a toy executable and is readable by windbg. 793 MinidumpProcessor processor(nullptr, nullptr /*&supplier, &resolver*/); 794 795 string minidump_file = GetTestDataPath() 796 + "tiny-exe-fastfail.dmp"; 797 798 ProcessState state; 799 ASSERT_EQ(processor.Process(minidump_file, &state), 800 google_breakpad::PROCESS_OK); 801 ASSERT_TRUE(state.crashed()); 802 ASSERT_EQ(state.threads()->size(), size_t(4)); 803 ASSERT_EQ(state.crash_reason(), "FAST_FAIL_FATAL_APP_EXIT"); 804 } 805 806 #ifdef __linux__ 807 TEST_F(MinidumpProcessorTest, TestNonCanonicalAddress) { 808 // This tests if we can correctly fixup non-canonical address GPF fault 809 // addresses. 810 // Dump is captured from a toy executable and is readable by windbg. 811 MinidumpProcessor processor(nullptr, nullptr /*&supplier, &resolver*/); 812 processor.set_enable_objdump(true); 813 814 string minidump_file = GetTestDataPath() 815 + "write_av_non_canonical.dmp"; 816 817 ProcessState state; 818 ASSERT_EQ(processor.Process(minidump_file, &state), 819 google_breakpad::PROCESS_OK); 820 ASSERT_TRUE(state.crashed()); 821 ASSERT_EQ(state.crash_address(), 0xfefefefefefefefeU); 822 } 823 #endif // __linux__ 824 825 } // namespace 826 827 int main(int argc, char* argv[]) { 828 ::testing::InitGoogleTest(&argc, argv); 829 return RUN_ALL_TESTS(); 830 }