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