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:
MockMinidump()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:
MockMinidumpThreadList()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:
MockMinidumpMemoryList()87   MockMinidumpMemoryList() : MinidumpMemoryList(NULL) {}
88 
89   MOCK_METHOD1(GetMemoryRegionForAddress, MinidumpMemoryRegion*(uint64_t));
90 };
91 
92 class MockMinidumpThread : public MinidumpThread {
93  public:
MockMinidumpThread()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:
MockMinidumpMemoryRegion(uint64_t base,const string & contents)106   MockMinidumpMemoryRegion(uint64_t base, const string& contents) :
107       MinidumpMemoryRegion(NULL) {
108     region_.Init(base, contents);
109   }
110 
GetBase() const111   uint64_t GetBase() const { return region_.GetBase(); }
GetSize() const112   uint32_t GetSize() const { return region_.GetSize(); }
113 
GetMemoryAtAddress(uint64_t address,uint8_t * value) const114   bool GetMemoryAtAddress(uint64_t address, uint8_t  *value) const {
115     return region_.GetMemoryAtAddress(address, value);
116   }
GetMemoryAtAddress(uint64_t address,uint16_t * value) const117   bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
118     return region_.GetMemoryAtAddress(address, value);
119   }
GetMemoryAtAddress(uint64_t address,uint32_t * value) const120   bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
121     return region_.GetMemoryAtAddress(address, value);
122   }
GetMemoryAtAddress(uint64_t address,uint64_t * value) const123   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:
TestMinidumpMiscInfo(const MDRawMiscInfo & misc_info)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:
TestSymbolSupplier()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
set_interrupt(bool interrupt)210   void set_interrupt(bool interrupt) { interrupt_ = interrupt; }
211 
212  private:
213   bool interrupt_;
214   map<string, char *> memory_buffers_;
215 };
216 
GetSymbolFile(const CodeModule * module,const SystemInfo * system_info,string * symbol_file)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 
GetSymbolFile(const CodeModule * module,const SystemInfo * system_info,string * symbol_file,string * symbol_data)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 
GetCStringSymbolData(const CodeModule * module,const SystemInfo * system_info,string * symbol_file,char ** symbol_data,size_t * symbol_data_size)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 
FreeSymbolData(const CodeModule * module)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:
TestMinidumpSystemInfo(MDRawSystemInfo info)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:
TestMinidumpContext(const MDRawContextX86 & context)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 
TEST_F(MinidumpProcessorTest,TestCorruptMinidumps)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.
TEST_F(MinidumpProcessorTest,TestSymbolSupplierLookupCounts)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 
TEST_F(MinidumpProcessorTest,TestBasicProcessing)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 
TEST_F(MinidumpProcessorTest,TestThreadMissingMemory)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 
TEST_F(MinidumpProcessorTest,GetProcessCreateTime)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 
TEST_F(MinidumpProcessorTest,TestThreadMissingContext)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 
main(int argc,char * argv[])641 int main(int argc, char *argv[]) {
642   ::testing::InitGoogleTest(&argc, argv);
643   return RUN_ALL_TESTS();
644 }
645