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