• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(GetUnloadedModuleList, MinidumpUnloadedModuleList*());
75   MOCK_METHOD0(GetMemoryList, MinidumpMemoryList*());
76 };
77 
78 class MockMinidumpUnloadedModule : public MinidumpUnloadedModule {
79  public:
MockMinidumpUnloadedModule()80   MockMinidumpUnloadedModule() : MinidumpUnloadedModule(NULL) {}
81 };
82 
83 class MockMinidumpUnloadedModuleList : public MinidumpUnloadedModuleList {
84  public:
MockMinidumpUnloadedModuleList()85   MockMinidumpUnloadedModuleList() : MinidumpUnloadedModuleList(NULL) {}
86 
~MockMinidumpUnloadedModuleList()87   ~MockMinidumpUnloadedModuleList() {}
88   MOCK_CONST_METHOD0(Copy, CodeModules*());
89   MOCK_CONST_METHOD1(GetModuleForAddress,
90                      const MinidumpUnloadedModule*(uint64_t));
91 };
92 
93 class MockMinidumpThreadList : public MinidumpThreadList {
94  public:
MockMinidumpThreadList()95   MockMinidumpThreadList() : MinidumpThreadList(NULL) {}
96 
97   MOCK_CONST_METHOD0(thread_count, unsigned int());
98   MOCK_CONST_METHOD1(GetThreadAtIndex, MinidumpThread*(unsigned int));
99 };
100 
101 class MockMinidumpMemoryList : public MinidumpMemoryList {
102  public:
MockMinidumpMemoryList()103   MockMinidumpMemoryList() : MinidumpMemoryList(NULL) {}
104 
105   MOCK_METHOD1(GetMemoryRegionForAddress, MinidumpMemoryRegion*(uint64_t));
106 };
107 
108 class MockMinidumpThread : public MinidumpThread {
109  public:
MockMinidumpThread()110   MockMinidumpThread() : MinidumpThread(NULL) {}
111 
112   MOCK_CONST_METHOD1(GetThreadID, bool(uint32_t*));
113   MOCK_METHOD0(GetContext, MinidumpContext*());
114   MOCK_METHOD0(GetMemory, MinidumpMemoryRegion*());
115   MOCK_CONST_METHOD0(GetStartOfStackMemoryRange, uint64_t());
116 };
117 
118 // This is crappy, but MinidumpProcessor really does want a
119 // MinidumpMemoryRegion.
120 class MockMinidumpMemoryRegion : public MinidumpMemoryRegion {
121  public:
MockMinidumpMemoryRegion(uint64_t base,const string & contents)122   MockMinidumpMemoryRegion(uint64_t base, const string& contents) :
123       MinidumpMemoryRegion(NULL) {
124     region_.Init(base, contents);
125   }
126 
GetBase() const127   uint64_t GetBase() const { return region_.GetBase(); }
GetSize() const128   uint32_t GetSize() const { return region_.GetSize(); }
129 
GetMemoryAtAddress(uint64_t address,uint8_t * value) const130   bool GetMemoryAtAddress(uint64_t address, uint8_t  *value) const {
131     return region_.GetMemoryAtAddress(address, value);
132   }
GetMemoryAtAddress(uint64_t address,uint16_t * value) const133   bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
134     return region_.GetMemoryAtAddress(address, value);
135   }
GetMemoryAtAddress(uint64_t address,uint32_t * value) const136   bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
137     return region_.GetMemoryAtAddress(address, value);
138   }
GetMemoryAtAddress(uint64_t address,uint64_t * value) const139   bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
140     return region_.GetMemoryAtAddress(address, value);
141   }
142 
143   MockMemoryRegion region_;
144 };
145 
146 // A test miscelaneous info stream, just returns values from the
147 // MDRawMiscInfo fed to it.
148 class TestMinidumpMiscInfo : public MinidumpMiscInfo {
149  public:
TestMinidumpMiscInfo(const MDRawMiscInfo & misc_info)150   explicit TestMinidumpMiscInfo(const MDRawMiscInfo& misc_info) :
151       MinidumpMiscInfo(NULL) {
152     valid_ = true;
153     misc_info_ = misc_info;
154   }
155 };
156 
157 }  // namespace google_breakpad
158 
159 namespace {
160 
161 using google_breakpad::BasicSourceLineResolver;
162 using google_breakpad::CallStack;
163 using google_breakpad::CodeModule;
164 using google_breakpad::MinidumpContext;
165 using google_breakpad::MinidumpMemoryRegion;
166 using google_breakpad::MinidumpMiscInfo;
167 using google_breakpad::MinidumpProcessor;
168 using google_breakpad::MinidumpSystemInfo;
169 using google_breakpad::MinidumpThreadList;
170 using google_breakpad::MinidumpThread;
171 using google_breakpad::MockMinidump;
172 using google_breakpad::MockMinidumpMemoryList;
173 using google_breakpad::MockMinidumpMemoryRegion;
174 using google_breakpad::MockMinidumpThread;
175 using google_breakpad::MockMinidumpThreadList;
176 using google_breakpad::MockMinidumpUnloadedModule;
177 using google_breakpad::MockMinidumpUnloadedModuleList;
178 using google_breakpad::ProcessState;
179 using google_breakpad::scoped_ptr;
180 using google_breakpad::SymbolSupplier;
181 using google_breakpad::SystemInfo;
182 using ::testing::_;
183 using ::testing::AnyNumber;
184 using ::testing::DoAll;
185 using ::testing::Mock;
186 using ::testing::Ne;
187 using ::testing::Property;
188 using ::testing::Return;
189 using ::testing::SetArgumentPointee;
190 
191 static const char *kSystemInfoOS = "Windows NT";
192 static const char *kSystemInfoOSShort = "windows";
193 static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2";
194 static const char *kSystemInfoCPU = "x86";
195 static const char *kSystemInfoCPUInfo =
196     "GenuineIntel family 6 model 13 stepping 8";
197 
198 #define ASSERT_TRUE_ABORT(cond) \
199   if (!(cond)) {                                                        \
200     fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \
201     abort(); \
202   }
203 
204 #define ASSERT_EQ_ABORT(e1, e2) ASSERT_TRUE_ABORT((e1) == (e2))
205 
GetTestDataPath()206 static string GetTestDataPath() {
207   char *srcdir = getenv("srcdir");
208 
209   return string(srcdir ? srcdir : ".") + "/src/processor/testdata/";
210 }
211 
212 class TestSymbolSupplier : public SymbolSupplier {
213  public:
TestSymbolSupplier()214   TestSymbolSupplier() : interrupt_(false) {}
215 
216   virtual SymbolResult GetSymbolFile(const CodeModule *module,
217                                      const SystemInfo *system_info,
218                                      string *symbol_file);
219 
220   virtual SymbolResult GetSymbolFile(const CodeModule *module,
221                                      const SystemInfo *system_info,
222                                      string *symbol_file,
223                                      string *symbol_data);
224 
225   virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
226                                             const SystemInfo *system_info,
227                                             string *symbol_file,
228                                             char **symbol_data,
229                                             size_t *symbol_data_size);
230 
231   virtual void FreeSymbolData(const CodeModule *module);
232 
233   // When set to true, causes the SymbolSupplier to return INTERRUPT
set_interrupt(bool interrupt)234   void set_interrupt(bool interrupt) { interrupt_ = interrupt; }
235 
236  private:
237   bool interrupt_;
238   map<string, char *> memory_buffers_;
239 };
240 
GetSymbolFile(const CodeModule * module,const SystemInfo * system_info,string * symbol_file)241 SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
242     const CodeModule *module,
243     const SystemInfo *system_info,
244     string *symbol_file) {
245   ASSERT_TRUE_ABORT(module);
246   ASSERT_TRUE_ABORT(system_info);
247   ASSERT_EQ_ABORT(system_info->cpu, kSystemInfoCPU);
248   ASSERT_EQ_ABORT(system_info->cpu_info, kSystemInfoCPUInfo);
249   ASSERT_EQ_ABORT(system_info->os, kSystemInfoOS);
250   ASSERT_EQ_ABORT(system_info->os_short, kSystemInfoOSShort);
251   ASSERT_EQ_ABORT(system_info->os_version, kSystemInfoOSVersion);
252 
253   if (interrupt_) {
254     return INTERRUPT;
255   }
256 
257   if (module && module->code_file() == "c:\\test_app.exe") {
258       *symbol_file = GetTestDataPath() + "symbols/test_app.pdb/" +
259                      module->debug_identifier() + "/test_app.sym";
260     return FOUND;
261   }
262 
263   return NOT_FOUND;
264 }
265 
GetSymbolFile(const CodeModule * module,const SystemInfo * system_info,string * symbol_file,string * symbol_data)266 SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
267     const CodeModule *module,
268     const SystemInfo *system_info,
269     string *symbol_file,
270     string *symbol_data) {
271   SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info,
272                                                  symbol_file);
273   if (s == FOUND) {
274     std::ifstream in(symbol_file->c_str());
275     std::getline(in, *symbol_data, string::traits_type::to_char_type(
276                      string::traits_type::eof()));
277     in.close();
278   }
279 
280   return s;
281 }
282 
GetCStringSymbolData(const CodeModule * module,const SystemInfo * system_info,string * symbol_file,char ** symbol_data,size_t * symbol_data_size)283 SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData(
284     const CodeModule *module,
285     const SystemInfo *system_info,
286     string *symbol_file,
287     char **symbol_data,
288     size_t *symbol_data_size) {
289   string symbol_data_string;
290   SymbolSupplier::SymbolResult s = GetSymbolFile(module,
291                                                  system_info,
292                                                  symbol_file,
293                                                  &symbol_data_string);
294   if (s == FOUND) {
295     *symbol_data_size = symbol_data_string.size() + 1;
296     *symbol_data = new char[*symbol_data_size];
297     if (*symbol_data == NULL) {
298       BPLOG(ERROR) << "Memory allocation failed for module: "
299                    << module->code_file() << " size: " << *symbol_data_size;
300       return INTERRUPT;
301     }
302     memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size());
303     (*symbol_data)[symbol_data_string.size()] = '\0';
304     memory_buffers_.insert(make_pair(module->code_file(), *symbol_data));
305   }
306 
307   return s;
308 }
309 
FreeSymbolData(const CodeModule * module)310 void TestSymbolSupplier::FreeSymbolData(const CodeModule *module) {
311   map<string, char *>::iterator it = memory_buffers_.find(module->code_file());
312   if (it != memory_buffers_.end()) {
313     delete [] it->second;
314     memory_buffers_.erase(it);
315   }
316 }
317 
318 // A test system info stream, just returns values from the
319 // MDRawSystemInfo fed to it.
320 class TestMinidumpSystemInfo : public MinidumpSystemInfo {
321  public:
TestMinidumpSystemInfo(MDRawSystemInfo info)322   explicit TestMinidumpSystemInfo(MDRawSystemInfo info) :
323       MinidumpSystemInfo(NULL) {
324     valid_ = true;
325     system_info_ = info;
326     csd_version_ = new string("");
327   }
328 };
329 
330 // A test minidump context, just returns the MDRawContextX86
331 // fed to it.
332 class TestMinidumpContext : public MinidumpContext {
333  public:
TestMinidumpContext(const MDRawContextX86 & context)334   explicit TestMinidumpContext(const MDRawContextX86& context) :
335       MinidumpContext(NULL) {
336     valid_ = true;
337     SetContextX86(new MDRawContextX86(context));
338     SetContextFlags(MD_CONTEXT_X86);
339   }
340 };
341 
342 class MinidumpProcessorTest : public ::testing::Test {
343 };
344 
TEST_F(MinidumpProcessorTest,TestUnloadedModules)345 TEST_F(MinidumpProcessorTest, TestUnloadedModules) {
346   MockMinidump dump;
347 
348   EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
349   EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
350 
351   MDRawHeader fake_header;
352   fake_header.time_date_stamp = 0;
353   EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
354 
355   MDRawSystemInfo raw_system_info;
356   memset(&raw_system_info, 0, sizeof(raw_system_info));
357   raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86;
358   raw_system_info.platform_id = MD_OS_WIN32_NT;
359   TestMinidumpSystemInfo dump_system_info(raw_system_info);
360 
361   EXPECT_CALL(dump, GetSystemInfo()).
362       WillRepeatedly(Return(&dump_system_info));
363 
364   // No loaded modules
365 
366   MockMinidumpUnloadedModuleList unloaded_module_list;
367   EXPECT_CALL(dump, GetUnloadedModuleList()).
368       WillOnce(Return(&unloaded_module_list));
369 
370   MockMinidumpMemoryList memory_list;
371   EXPECT_CALL(dump, GetMemoryList()).
372       WillOnce(Return(&memory_list));
373 
374   MockMinidumpThreadList thread_list;
375   EXPECT_CALL(dump, GetThreadList()).
376       WillOnce(Return(&thread_list));
377 
378   EXPECT_CALL(thread_list, thread_count()).
379     WillRepeatedly(Return(1));
380 
381   MockMinidumpThread thread;
382   EXPECT_CALL(thread_list, GetThreadAtIndex(0)).
383     WillOnce(Return(&thread));
384 
385   EXPECT_CALL(thread, GetThreadID(_)).
386     WillRepeatedly(DoAll(SetArgumentPointee<0>(1),
387                          Return(true)));
388 
389   MDRawContextX86 thread_raw_context;
390   memset(&thread_raw_context, 0,
391          sizeof(thread_raw_context));
392   thread_raw_context.context_flags = MD_CONTEXT_X86_FULL;
393   const uint32_t kExpectedEIP = 0xabcd1234;
394   thread_raw_context.eip = kExpectedEIP;
395   TestMinidumpContext thread_context(thread_raw_context);
396   EXPECT_CALL(thread, GetContext()).
397     WillRepeatedly(Return(&thread_context));
398 
399   // The memory contents don't really matter here, since it won't be used.
400   MockMinidumpMemoryRegion thread_memory(0x1234, "xxx");
401   EXPECT_CALL(thread, GetMemory()).
402     WillRepeatedly(Return(&thread_memory));
403   EXPECT_CALL(thread, GetStartOfStackMemoryRange()).
404     Times(0);
405   EXPECT_CALL(memory_list, GetMemoryRegionForAddress(_)).
406     Times(0);
407 
408   MockMinidumpUnloadedModuleList* unloaded_module_list_copy =
409       new MockMinidumpUnloadedModuleList();
410   EXPECT_CALL(unloaded_module_list, Copy()).
411       WillOnce(Return(unloaded_module_list_copy));
412 
413   MockMinidumpUnloadedModule unloaded_module;
414   EXPECT_CALL(*unloaded_module_list_copy, GetModuleForAddress(kExpectedEIP)).
415       WillOnce(Return(&unloaded_module));
416 
417   MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
418   ProcessState state;
419   EXPECT_EQ(processor.Process(&dump, &state),
420             google_breakpad::PROCESS_OK);
421 
422   // The single frame should be populated with the unloaded module.
423   ASSERT_EQ(1U, state.threads()->size());
424   ASSERT_EQ(1U, state.threads()->at(0)->frames()->size());
425   ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction);
426   ASSERT_EQ(&unloaded_module, state.threads()->at(0)->frames()->at(0)->module);
427 }
428 
TEST_F(MinidumpProcessorTest,TestCorruptMinidumps)429 TEST_F(MinidumpProcessorTest, TestCorruptMinidumps) {
430   MockMinidump dump;
431   TestSymbolSupplier supplier;
432   BasicSourceLineResolver resolver;
433   MinidumpProcessor processor(&supplier, &resolver);
434   ProcessState state;
435 
436   EXPECT_EQ(processor.Process("nonexistent minidump", &state),
437             google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND);
438 
439   EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
440   EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
441 
442   MDRawHeader fakeHeader;
443   fakeHeader.time_date_stamp = 0;
444   EXPECT_CALL(dump, header()).
445       WillOnce(Return(reinterpret_cast<MDRawHeader*>(NULL))).
446       WillRepeatedly(Return(&fakeHeader));
447 
448   EXPECT_EQ(processor.Process(&dump, &state),
449             google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER);
450 
451   EXPECT_CALL(dump, GetThreadList()).
452       WillOnce(Return(reinterpret_cast<MinidumpThreadList*>(NULL)));
453   EXPECT_CALL(dump, GetSystemInfo()).
454       WillRepeatedly(Return(reinterpret_cast<MinidumpSystemInfo*>(NULL)));
455 
456   EXPECT_EQ(processor.Process(&dump, &state),
457             google_breakpad::PROCESS_ERROR_NO_THREAD_LIST);
458 }
459 
460 // This test case verifies that the symbol supplier is only consulted
461 // once per minidump per module.
TEST_F(MinidumpProcessorTest,TestSymbolSupplierLookupCounts)462 TEST_F(MinidumpProcessorTest, TestSymbolSupplierLookupCounts) {
463   MockSymbolSupplier supplier;
464   BasicSourceLineResolver resolver;
465   MinidumpProcessor processor(&supplier, &resolver);
466 
467   string minidump_file = GetTestDataPath() + "minidump2.dmp";
468   ProcessState state;
469   EXPECT_CALL(supplier, GetCStringSymbolData(
470       Property(&google_breakpad::CodeModule::code_file,
471                "c:\\test_app.exe"),
472       _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
473   EXPECT_CALL(supplier, GetCStringSymbolData(
474       Property(&google_breakpad::CodeModule::code_file,
475                Ne("c:\\test_app.exe")),
476       _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
477   // Avoid GMOCK WARNING "Uninteresting mock function call - returning
478   // directly" for FreeSymbolData().
479   EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber());
480   ASSERT_EQ(processor.Process(minidump_file, &state),
481             google_breakpad::PROCESS_OK);
482 
483   ASSERT_TRUE(Mock::VerifyAndClearExpectations(&supplier));
484 
485   // We need to verify that across minidumps, the processor will refetch
486   // symbol files, even with the same symbol supplier.
487   EXPECT_CALL(supplier, GetCStringSymbolData(
488       Property(&google_breakpad::CodeModule::code_file,
489                "c:\\test_app.exe"),
490       _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
491   EXPECT_CALL(supplier, GetCStringSymbolData(
492       Property(&google_breakpad::CodeModule::code_file,
493                Ne("c:\\test_app.exe")),
494       _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
495   // Avoid GMOCK WARNING "Uninteresting mock function call - returning
496   // directly" for FreeSymbolData().
497   EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber());
498   ASSERT_EQ(processor.Process(minidump_file, &state),
499             google_breakpad::PROCESS_OK);
500 }
501 
TEST_F(MinidumpProcessorTest,TestBasicProcessing)502 TEST_F(MinidumpProcessorTest, TestBasicProcessing) {
503   TestSymbolSupplier supplier;
504   BasicSourceLineResolver resolver;
505   MinidumpProcessor processor(&supplier, &resolver);
506 
507   string minidump_file = GetTestDataPath() + "minidump2.dmp";
508 
509   ProcessState state;
510   ASSERT_EQ(processor.Process(minidump_file, &state),
511             google_breakpad::PROCESS_OK);
512   ASSERT_EQ(state.system_info()->os, kSystemInfoOS);
513   ASSERT_EQ(state.system_info()->os_short, kSystemInfoOSShort);
514   ASSERT_EQ(state.system_info()->os_version, kSystemInfoOSVersion);
515   ASSERT_EQ(state.system_info()->cpu, kSystemInfoCPU);
516   ASSERT_EQ(state.system_info()->cpu_info, kSystemInfoCPUInfo);
517   ASSERT_TRUE(state.crashed());
518   ASSERT_EQ(state.crash_reason(), "EXCEPTION_ACCESS_VIOLATION_WRITE");
519   ASSERT_EQ(state.crash_address(), 0x45U);
520   ASSERT_EQ(state.threads()->size(), size_t(1));
521   EXPECT_EQ((*state.threads())[0]->tid(), 3060U);
522   ASSERT_EQ(state.requesting_thread(), 0);
523   EXPECT_EQ(1171480435U, state.time_date_stamp());
524   EXPECT_EQ(1171480435U, state.process_create_time());
525 
526   CallStack *stack = state.threads()->at(0);
527   ASSERT_TRUE(stack);
528   ASSERT_EQ(stack->frames()->size(), 4U);
529 
530   ASSERT_TRUE(stack->frames()->at(0)->module);
531   ASSERT_EQ(stack->frames()->at(0)->module->base_address(), 0x400000U);
532   ASSERT_EQ(stack->frames()->at(0)->module->code_file(), "c:\\test_app.exe");
533   ASSERT_EQ(stack->frames()->at(0)->function_name,
534             "`anonymous namespace'::CrashFunction");
535   ASSERT_EQ(stack->frames()->at(0)->source_file_name, "c:\\test_app.cc");
536   ASSERT_EQ(stack->frames()->at(0)->source_line, 58);
537 
538   ASSERT_TRUE(stack->frames()->at(1)->module);
539   ASSERT_EQ(stack->frames()->at(1)->module->base_address(), 0x400000U);
540   ASSERT_EQ(stack->frames()->at(1)->module->code_file(), "c:\\test_app.exe");
541   ASSERT_EQ(stack->frames()->at(1)->function_name, "main");
542   ASSERT_EQ(stack->frames()->at(1)->source_file_name, "c:\\test_app.cc");
543   ASSERT_EQ(stack->frames()->at(1)->source_line, 65);
544 
545   // This comes from the CRT
546   ASSERT_TRUE(stack->frames()->at(2)->module);
547   ASSERT_EQ(stack->frames()->at(2)->module->base_address(), 0x400000U);
548   ASSERT_EQ(stack->frames()->at(2)->module->code_file(), "c:\\test_app.exe");
549   ASSERT_EQ(stack->frames()->at(2)->function_name, "__tmainCRTStartup");
550   ASSERT_EQ(stack->frames()->at(2)->source_file_name,
551             "f:\\sp\\vctools\\crt_bld\\self_x86\\crt\\src\\crt0.c");
552   ASSERT_EQ(stack->frames()->at(2)->source_line, 327);
553 
554   // No debug info available for kernel32.dll
555   ASSERT_TRUE(stack->frames()->at(3)->module);
556   ASSERT_EQ(stack->frames()->at(3)->module->base_address(), 0x7c800000U);
557   ASSERT_EQ(stack->frames()->at(3)->module->code_file(),
558             "C:\\WINDOWS\\system32\\kernel32.dll");
559   ASSERT_TRUE(stack->frames()->at(3)->function_name.empty());
560   ASSERT_TRUE(stack->frames()->at(3)->source_file_name.empty());
561   ASSERT_EQ(stack->frames()->at(3)->source_line, 0);
562 
563   ASSERT_EQ(state.modules()->module_count(), 13U);
564   ASSERT_TRUE(state.modules()->GetMainModule());
565   ASSERT_EQ(state.modules()->GetMainModule()->code_file(), "c:\\test_app.exe");
566   ASSERT_FALSE(state.modules()->GetModuleForAddress(0));
567   ASSERT_EQ(state.modules()->GetMainModule(),
568             state.modules()->GetModuleForAddress(0x400000));
569   ASSERT_EQ(state.modules()->GetModuleForAddress(0x7c801234)->debug_file(),
570             "kernel32.pdb");
571   ASSERT_EQ(state.modules()->GetModuleForAddress(0x77d43210)->version(),
572             "5.1.2600.2622");
573 
574   // Test that disabled exploitability engine defaults to
575   // EXPLOITABILITY_NOT_ANALYZED.
576   ASSERT_EQ(google_breakpad::EXPLOITABILITY_NOT_ANALYZED,
577             state.exploitability());
578 
579   // Test that the symbol supplier can interrupt processing
580   state.Clear();
581   supplier.set_interrupt(true);
582   ASSERT_EQ(processor.Process(minidump_file, &state),
583             google_breakpad::PROCESS_SYMBOL_SUPPLIER_INTERRUPTED);
584 }
585 
TEST_F(MinidumpProcessorTest,TestThreadMissingMemory)586 TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) {
587   MockMinidump dump;
588   EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
589   EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
590 
591   MDRawHeader fake_header;
592   fake_header.time_date_stamp = 0;
593   EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
594 
595   MDRawSystemInfo raw_system_info;
596   memset(&raw_system_info, 0, sizeof(raw_system_info));
597   raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86;
598   raw_system_info.platform_id = MD_OS_WIN32_NT;
599   TestMinidumpSystemInfo dump_system_info(raw_system_info);
600 
601   EXPECT_CALL(dump, GetSystemInfo()).
602       WillRepeatedly(Return(&dump_system_info));
603 
604   MockMinidumpThreadList thread_list;
605   EXPECT_CALL(dump, GetThreadList()).
606       WillOnce(Return(&thread_list));
607 
608   MockMinidumpMemoryList memory_list;
609   EXPECT_CALL(dump, GetMemoryList()).
610       WillOnce(Return(&memory_list));
611 
612   // Return a thread missing stack memory.
613   MockMinidumpThread no_memory_thread;
614   EXPECT_CALL(no_memory_thread, GetThreadID(_)).
615     WillRepeatedly(DoAll(SetArgumentPointee<0>(1),
616                          Return(true)));
617   EXPECT_CALL(no_memory_thread, GetMemory()).
618     WillRepeatedly(Return(reinterpret_cast<MinidumpMemoryRegion*>(NULL)));
619 
620   const uint64_t kTestStartOfMemoryRange = 0x1234;
621   EXPECT_CALL(no_memory_thread, GetStartOfStackMemoryRange()).
622     WillRepeatedly(Return(kTestStartOfMemoryRange));
623   EXPECT_CALL(memory_list, GetMemoryRegionForAddress(kTestStartOfMemoryRange)).
624     WillRepeatedly(Return(reinterpret_cast<MinidumpMemoryRegion*>(NULL)));
625 
626   MDRawContextX86 no_memory_thread_raw_context;
627   memset(&no_memory_thread_raw_context, 0,
628          sizeof(no_memory_thread_raw_context));
629   no_memory_thread_raw_context.context_flags = MD_CONTEXT_X86_FULL;
630   const uint32_t kExpectedEIP = 0xabcd1234;
631   no_memory_thread_raw_context.eip = kExpectedEIP;
632   TestMinidumpContext no_memory_thread_context(no_memory_thread_raw_context);
633   EXPECT_CALL(no_memory_thread, GetContext()).
634     WillRepeatedly(Return(&no_memory_thread_context));
635 
636   EXPECT_CALL(thread_list, thread_count()).
637     WillRepeatedly(Return(1));
638   EXPECT_CALL(thread_list, GetThreadAtIndex(0)).
639     WillOnce(Return(&no_memory_thread));
640 
641   MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
642   ProcessState state;
643   EXPECT_EQ(processor.Process(&dump, &state),
644             google_breakpad::PROCESS_OK);
645 
646   // Should have a single thread with a single frame in it.
647   ASSERT_EQ(1U, state.threads()->size());
648   ASSERT_EQ(1U, state.threads()->at(0)->frames()->size());
649   ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction);
650 }
651 
TEST_F(MinidumpProcessorTest,GetProcessCreateTime)652 TEST_F(MinidumpProcessorTest, GetProcessCreateTime) {
653   const uint32_t kProcessCreateTime = 2000;
654   const uint32_t kTimeDateStamp = 5000;
655   MockMinidump dump;
656   EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
657   EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
658 
659   // Set time of crash.
660   MDRawHeader fake_header;
661   fake_header.time_date_stamp = kTimeDateStamp;
662   EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
663 
664   // Set process create time.
665   MDRawMiscInfo raw_misc_info;
666   memset(&raw_misc_info, 0, sizeof(raw_misc_info));
667   raw_misc_info.process_create_time = kProcessCreateTime;
668   raw_misc_info.flags1 |= MD_MISCINFO_FLAGS1_PROCESS_TIMES;
669   google_breakpad::TestMinidumpMiscInfo dump_misc_info(raw_misc_info);
670   EXPECT_CALL(dump, GetMiscInfo()).WillRepeatedly(Return(&dump_misc_info));
671 
672   // No threads
673   MockMinidumpThreadList thread_list;
674   EXPECT_CALL(dump, GetThreadList()).WillOnce(Return(&thread_list));
675   EXPECT_CALL(thread_list, thread_count()).WillRepeatedly(Return(0));
676 
677   MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
678   ProcessState state;
679   EXPECT_EQ(google_breakpad::PROCESS_OK, processor.Process(&dump, &state));
680 
681   // Verify the time stamps.
682   ASSERT_EQ(kTimeDateStamp, state.time_date_stamp());
683   ASSERT_EQ(kProcessCreateTime, state.process_create_time());
684 }
685 
TEST_F(MinidumpProcessorTest,TestThreadMissingContext)686 TEST_F(MinidumpProcessorTest, TestThreadMissingContext) {
687   MockMinidump dump;
688   EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
689   EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
690 
691   MDRawHeader fake_header;
692   fake_header.time_date_stamp = 0;
693   EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
694 
695   MDRawSystemInfo raw_system_info;
696   memset(&raw_system_info, 0, sizeof(raw_system_info));
697   raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86;
698   raw_system_info.platform_id = MD_OS_WIN32_NT;
699   TestMinidumpSystemInfo dump_system_info(raw_system_info);
700 
701   EXPECT_CALL(dump, GetSystemInfo()).
702       WillRepeatedly(Return(&dump_system_info));
703 
704   MockMinidumpThreadList thread_list;
705   EXPECT_CALL(dump, GetThreadList()).
706       WillOnce(Return(&thread_list));
707 
708   MockMinidumpMemoryList memory_list;
709   EXPECT_CALL(dump, GetMemoryList()).
710       WillOnce(Return(&memory_list));
711 
712   // Return a thread missing a thread context.
713   MockMinidumpThread no_context_thread;
714   EXPECT_CALL(no_context_thread, GetThreadID(_)).
715     WillRepeatedly(DoAll(SetArgumentPointee<0>(1),
716                          Return(true)));
717   EXPECT_CALL(no_context_thread, GetContext()).
718     WillRepeatedly(Return(reinterpret_cast<MinidumpContext*>(NULL)));
719 
720   // The memory contents don't really matter here, since it won't be used.
721   MockMinidumpMemoryRegion no_context_thread_memory(0x1234, "xxx");
722   EXPECT_CALL(no_context_thread, GetMemory()).
723     WillRepeatedly(Return(&no_context_thread_memory));
724   EXPECT_CALL(no_context_thread, GetStartOfStackMemoryRange()).
725     Times(0);
726   EXPECT_CALL(memory_list, GetMemoryRegionForAddress(_)).
727     Times(0);
728 
729   EXPECT_CALL(thread_list, thread_count()).
730     WillRepeatedly(Return(1));
731   EXPECT_CALL(thread_list, GetThreadAtIndex(0)).
732     WillOnce(Return(&no_context_thread));
733 
734   MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
735   ProcessState state;
736   EXPECT_EQ(processor.Process(&dump, &state),
737             google_breakpad::PROCESS_OK);
738 
739   // Should have a single thread with zero frames.
740   ASSERT_EQ(1U, state.threads()->size());
741   ASSERT_EQ(0U, state.threads()->at(0)->frames()->size());
742 }
743 
TEST_F(MinidumpProcessorTest,Test32BitCrashingAddress)744 TEST_F(MinidumpProcessorTest, Test32BitCrashingAddress) {
745   TestSymbolSupplier supplier;
746   BasicSourceLineResolver resolver;
747   MinidumpProcessor processor(&supplier, &resolver);
748 
749   string minidump_file = GetTestDataPath() + "minidump_32bit_crash_addr.dmp";
750 
751   ProcessState state;
752   ASSERT_EQ(processor.Process(minidump_file, &state),
753             google_breakpad::PROCESS_OK);
754   ASSERT_EQ(state.system_info()->os, kSystemInfoOS);
755   ASSERT_EQ(state.system_info()->os_short, kSystemInfoOSShort);
756   ASSERT_EQ(state.system_info()->os_version, kSystemInfoOSVersion);
757   ASSERT_EQ(state.system_info()->cpu, kSystemInfoCPU);
758   ASSERT_EQ(state.system_info()->cpu_info, kSystemInfoCPUInfo);
759   ASSERT_TRUE(state.crashed());
760   ASSERT_EQ(state.crash_reason(), "EXCEPTION_ACCESS_VIOLATION_WRITE");
761   ASSERT_EQ(state.crash_address(), 0x45U);
762 }
763 
764 }  // namespace
765 
main(int argc,char * argv[])766 int main(int argc, char *argv[]) {
767   ::testing::InitGoogleTest(&argc, argv);
768   return RUN_ALL_TESTS();
769 }
770