/ src / processor / minidump_processor_unittest.cc
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  }