Home | History | Annotate | Download | only in processor
      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 
     56 using std::map;
     57 
     58 namespace google_breakpad {
     59 class 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 
     77 class 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 
     85 class MockMinidumpMemoryList : public MinidumpMemoryList {
     86  public:
     87   MockMinidumpMemoryList() : MinidumpMemoryList(NULL) {}
     88 
     89   MOCK_METHOD1(GetMemoryRegionForAddress, MinidumpMemoryRegion*(uint64_t));
     90 };
     91 
     92 class 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.
    104 class 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.
    132 class 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 
    143 namespace {
    144 
    145 using google_breakpad::BasicSourceLineResolver;
    146 using google_breakpad::CallStack;
    147 using google_breakpad::CodeModule;
    148 using google_breakpad::MinidumpContext;
    149 using google_breakpad::MinidumpMemoryRegion;
    150 using google_breakpad::MinidumpMiscInfo;
    151 using google_breakpad::MinidumpProcessor;
    152 using google_breakpad::MinidumpSystemInfo;
    153 using google_breakpad::MinidumpThreadList;
    154 using google_breakpad::MinidumpThread;
    155 using google_breakpad::MockMinidump;
    156 using google_breakpad::MockMinidumpMemoryList;
    157 using google_breakpad::MockMinidumpMemoryRegion;
    158 using google_breakpad::MockMinidumpThread;
    159 using google_breakpad::MockMinidumpThreadList;
    160 using google_breakpad::ProcessState;
    161 using google_breakpad::scoped_ptr;
    162 using google_breakpad::SymbolSupplier;
    163 using google_breakpad::SystemInfo;
    164 using ::testing::_;
    165 using ::testing::AnyNumber;
    166 using ::testing::DoAll;
    167 using ::testing::Mock;
    168 using ::testing::Ne;
    169 using ::testing::Property;
    170 using ::testing::Return;
    171 using ::testing::SetArgumentPointee;
    172 
    173 static const char *kSystemInfoOS = "Windows NT";
    174 static const char *kSystemInfoOSShort = "windows";
    175 static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2";
    176 static const char *kSystemInfoCPU = "x86";
    177 static 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 
    188 class 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 
    217 SymbolSupplier::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 
    244 SymbolSupplier::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 
    261 SymbolSupplier::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 
    288 void 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.
    298 class 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.
    310 class 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 
    320 class MinidumpProcessorTest : public ::testing::Test {
    321 };
    322 
    323 TEST_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.
    356 TEST_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 
    397 TEST_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 
    481 TEST_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 
    547 TEST_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 
    581 TEST_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 
    641 int main(int argc, char *argv[]) {
    642   ::testing::InitGoogleTest(&argc, argv);
    643   return RUN_ALL_TESTS();
    644 }
    645