xref: /aosp_15_r20/external/google-breakpad/src/processor/minidump_processor_unittest.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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:
MockMinidump()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:
MockMinidumpUnloadedModule()83   MockMinidumpUnloadedModule() : MinidumpUnloadedModule(NULL) {}
84 };
85 
86 class MockMinidumpUnloadedModuleList : public MinidumpUnloadedModuleList {
87  public:
MockMinidumpUnloadedModuleList()88   MockMinidumpUnloadedModuleList() : MinidumpUnloadedModuleList(NULL) {}
89 
~MockMinidumpUnloadedModuleList()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:
MockMinidumpThreadList()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:
MockMinidumpMemoryList()106   MockMinidumpMemoryList() : MinidumpMemoryList(NULL) {}
107 
108   MOCK_METHOD1(GetMemoryRegionForAddress, MinidumpMemoryRegion*(uint64_t));
109 };
110 
111 class MockMinidumpThread : public MinidumpThread {
112  public:
MockMinidumpThread()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:
MockMinidumpMemoryRegion(uint64_t base,const string & contents)125   MockMinidumpMemoryRegion(uint64_t base, const string& contents) :
126       MinidumpMemoryRegion(NULL) {
127     region_.Init(base, contents);
128   }
129 
GetBase() const130   uint64_t GetBase() const { return region_.GetBase(); }
GetSize() const131   uint32_t GetSize() const { return region_.GetSize(); }
132 
GetMemoryAtAddress(uint64_t address,uint8_t * value) const133   bool GetMemoryAtAddress(uint64_t address, uint8_t*  value) const {
134     return region_.GetMemoryAtAddress(address, value);
135   }
GetMemoryAtAddress(uint64_t address,uint16_t * value) const136   bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const {
137     return region_.GetMemoryAtAddress(address, value);
138   }
GetMemoryAtAddress(uint64_t address,uint32_t * value) const139   bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const {
140     return region_.GetMemoryAtAddress(address, value);
141   }
GetMemoryAtAddress(uint64_t address,uint64_t * value) const142   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:
TestMinidumpMiscInfo(const MDRawMiscInfo & misc_info)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 
GetTestDataPath()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:
TestSymbolSupplier()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
set_interrupt(bool interrupt)237   void set_interrupt(bool interrupt) { interrupt_ = interrupt; }
238 
239  private:
240   bool interrupt_;
241   map<string, char*> memory_buffers_;
242 };
243 
GetSymbolFile(const CodeModule * module,const SystemInfo * system_info,string * symbol_file)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 
GetSymbolFile(const CodeModule * module,const SystemInfo * system_info,string * symbol_file,string * symbol_data)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 
GetCStringSymbolData(const CodeModule * module,const SystemInfo * system_info,string * symbol_file,char ** symbol_data,size_t * symbol_data_size)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 
FreeSymbolData(const CodeModule * module)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:
TestMinidumpSystemInfo(MDRawSystemInfo info)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:
TestMinidumpContext(const MDRawContextX86 & context)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 
TEST_F(MinidumpProcessorTest,TestUnloadedModules)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 
TEST_F(MinidumpProcessorTest,TestCorruptMinidumps)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.
TEST_F(MinidumpProcessorTest,TestSymbolSupplierLookupCounts)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 
TEST_F(MinidumpProcessorTest,TestBasicProcessing)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 
TEST_F(MinidumpProcessorTest,TestThreadMissingMemory)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 
TEST_F(MinidumpProcessorTest,GetProcessCreateTime)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 
TEST_F(MinidumpProcessorTest,TestThreadMissingContext)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 
TEST_F(MinidumpProcessorTest,Test32BitCrashingAddress)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 
TEST_F(MinidumpProcessorTest,TestXStateAmd64ContextMinidump)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 
TEST_F(MinidumpProcessorTest,TestFastFailException)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__
TEST_F(MinidumpProcessorTest,TestNonCanonicalAddress)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 
main(int argc,char * argv[])827 int main(int argc, char* argv[]) {
828   ::testing::InitGoogleTest(&argc, argv);
829   return RUN_ALL_TESTS();
830 }
831