1 // Copyright (c) 2006, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 // Unit test for MinidumpProcessor. Uses a pre-generated minidump and
31 // corresponding symbol file, and checks the stack frames for correctness.
32
33 #include <stdlib.h>
34
35 #include <string>
36 #include <iostream>
37 #include <fstream>
38 #include <map>
39 #include <utility>
40
41 #include "breakpad_googletest_includes.h"
42 #include "common/scoped_ptr.h"
43 #include "common/using_std_string.h"
44 #include "google_breakpad/processor/basic_source_line_resolver.h"
45 #include "google_breakpad/processor/call_stack.h"
46 #include "google_breakpad/processor/code_module.h"
47 #include "google_breakpad/processor/code_modules.h"
48 #include "google_breakpad/processor/minidump.h"
49 #include "google_breakpad/processor/minidump_processor.h"
50 #include "google_breakpad/processor/process_state.h"
51 #include "google_breakpad/processor/stack_frame.h"
52 #include "google_breakpad/processor/symbol_supplier.h"
53 #include "processor/logging.h"
54 #include "processor/stackwalker_unittest_utils.h"
55
56 using std::map;
57
58 namespace google_breakpad {
59 class MockMinidump : public Minidump {
60 public:
MockMinidump()61 MockMinidump() : Minidump("") {
62 }
63
64 MOCK_METHOD0(Read, bool());
65 MOCK_CONST_METHOD0(path, string());
66 MOCK_CONST_METHOD0(header, const MDRawHeader*());
67 MOCK_METHOD0(GetThreadList, MinidumpThreadList*());
68 MOCK_METHOD0(GetSystemInfo, MinidumpSystemInfo*());
69 MOCK_METHOD0(GetMiscInfo, MinidumpMiscInfo*());
70 MOCK_METHOD0(GetBreakpadInfo, MinidumpBreakpadInfo*());
71 MOCK_METHOD0(GetException, MinidumpException*());
72 MOCK_METHOD0(GetAssertion, MinidumpAssertion*());
73 MOCK_METHOD0(GetModuleList, MinidumpModuleList*());
74 MOCK_METHOD0(GetMemoryList, MinidumpMemoryList*());
75 };
76
77 class MockMinidumpThreadList : public MinidumpThreadList {
78 public:
MockMinidumpThreadList()79 MockMinidumpThreadList() : MinidumpThreadList(NULL) {}
80
81 MOCK_CONST_METHOD0(thread_count, unsigned int());
82 MOCK_CONST_METHOD1(GetThreadAtIndex, MinidumpThread*(unsigned int));
83 };
84
85 class MockMinidumpMemoryList : public MinidumpMemoryList {
86 public:
MockMinidumpMemoryList()87 MockMinidumpMemoryList() : MinidumpMemoryList(NULL) {}
88
89 MOCK_METHOD1(GetMemoryRegionForAddress, MinidumpMemoryRegion*(uint64_t));
90 };
91
92 class MockMinidumpThread : public MinidumpThread {
93 public:
MockMinidumpThread()94 MockMinidumpThread() : MinidumpThread(NULL) {}
95
96 MOCK_CONST_METHOD1(GetThreadID, bool(uint32_t*));
97 MOCK_METHOD0(GetContext, MinidumpContext*());
98 MOCK_METHOD0(GetMemory, MinidumpMemoryRegion*());
99 MOCK_CONST_METHOD0(GetStartOfStackMemoryRange, uint64_t());
100 };
101
102 // This is crappy, but MinidumpProcessor really does want a
103 // MinidumpMemoryRegion.
104 class MockMinidumpMemoryRegion : public MinidumpMemoryRegion {
105 public:
MockMinidumpMemoryRegion(uint64_t base,const string & contents)106 MockMinidumpMemoryRegion(uint64_t base, const string& contents) :
107 MinidumpMemoryRegion(NULL) {
108 region_.Init(base, contents);
109 }
110
GetBase() const111 uint64_t GetBase() const { return region_.GetBase(); }
GetSize() const112 uint32_t GetSize() const { return region_.GetSize(); }
113
GetMemoryAtAddress(uint64_t address,uint8_t * value) const114 bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const {
115 return region_.GetMemoryAtAddress(address, value);
116 }
GetMemoryAtAddress(uint64_t address,uint16_t * value) const117 bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
118 return region_.GetMemoryAtAddress(address, value);
119 }
GetMemoryAtAddress(uint64_t address,uint32_t * value) const120 bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
121 return region_.GetMemoryAtAddress(address, value);
122 }
GetMemoryAtAddress(uint64_t address,uint64_t * value) const123 bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
124 return region_.GetMemoryAtAddress(address, value);
125 }
126
127 MockMemoryRegion region_;
128 };
129
130 // A test miscelaneous info stream, just returns values from the
131 // MDRawMiscInfo fed to it.
132 class TestMinidumpMiscInfo : public MinidumpMiscInfo {
133 public:
TestMinidumpMiscInfo(const MDRawMiscInfo & misc_info)134 explicit TestMinidumpMiscInfo(const MDRawMiscInfo& misc_info) :
135 MinidumpMiscInfo(NULL) {
136 valid_ = true;
137 misc_info_ = misc_info;
138 }
139 };
140
141 } // namespace google_breakpad
142
143 namespace {
144
145 using google_breakpad::BasicSourceLineResolver;
146 using google_breakpad::CallStack;
147 using google_breakpad::CodeModule;
148 using google_breakpad::MinidumpContext;
149 using google_breakpad::MinidumpMemoryRegion;
150 using google_breakpad::MinidumpMiscInfo;
151 using google_breakpad::MinidumpProcessor;
152 using google_breakpad::MinidumpSystemInfo;
153 using google_breakpad::MinidumpThreadList;
154 using google_breakpad::MinidumpThread;
155 using google_breakpad::MockMinidump;
156 using google_breakpad::MockMinidumpMemoryList;
157 using google_breakpad::MockMinidumpMemoryRegion;
158 using google_breakpad::MockMinidumpThread;
159 using google_breakpad::MockMinidumpThreadList;
160 using google_breakpad::ProcessState;
161 using google_breakpad::scoped_ptr;
162 using google_breakpad::SymbolSupplier;
163 using google_breakpad::SystemInfo;
164 using ::testing::_;
165 using ::testing::AnyNumber;
166 using ::testing::DoAll;
167 using ::testing::Mock;
168 using ::testing::Ne;
169 using ::testing::Property;
170 using ::testing::Return;
171 using ::testing::SetArgumentPointee;
172
173 static const char *kSystemInfoOS = "Windows NT";
174 static const char *kSystemInfoOSShort = "windows";
175 static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2";
176 static const char *kSystemInfoCPU = "x86";
177 static const char *kSystemInfoCPUInfo =
178 "GenuineIntel family 6 model 13 stepping 8";
179
180 #define ASSERT_TRUE_ABORT(cond) \
181 if (!(cond)) { \
182 fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \
183 abort(); \
184 }
185
186 #define ASSERT_EQ_ABORT(e1, e2) ASSERT_TRUE_ABORT((e1) == (e2))
187
188 class TestSymbolSupplier : public SymbolSupplier {
189 public:
TestSymbolSupplier()190 TestSymbolSupplier() : interrupt_(false) {}
191
192 virtual SymbolResult GetSymbolFile(const CodeModule *module,
193 const SystemInfo *system_info,
194 string *symbol_file);
195
196 virtual SymbolResult GetSymbolFile(const CodeModule *module,
197 const SystemInfo *system_info,
198 string *symbol_file,
199 string *symbol_data);
200
201 virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
202 const SystemInfo *system_info,
203 string *symbol_file,
204 char **symbol_data,
205 size_t *symbol_data_size);
206
207 virtual void FreeSymbolData(const CodeModule *module);
208
209 // When set to true, causes the SymbolSupplier to return INTERRUPT
set_interrupt(bool interrupt)210 void set_interrupt(bool interrupt) { interrupt_ = interrupt; }
211
212 private:
213 bool interrupt_;
214 map<string, char *> memory_buffers_;
215 };
216
GetSymbolFile(const CodeModule * module,const SystemInfo * system_info,string * symbol_file)217 SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
218 const CodeModule *module,
219 const SystemInfo *system_info,
220 string *symbol_file) {
221 ASSERT_TRUE_ABORT(module);
222 ASSERT_TRUE_ABORT(system_info);
223 ASSERT_EQ_ABORT(system_info->cpu, kSystemInfoCPU);
224 ASSERT_EQ_ABORT(system_info->cpu_info, kSystemInfoCPUInfo);
225 ASSERT_EQ_ABORT(system_info->os, kSystemInfoOS);
226 ASSERT_EQ_ABORT(system_info->os_short, kSystemInfoOSShort);
227 ASSERT_EQ_ABORT(system_info->os_version, kSystemInfoOSVersion);
228
229 if (interrupt_) {
230 return INTERRUPT;
231 }
232
233 if (module && module->code_file() == "c:\\test_app.exe") {
234 *symbol_file = string(getenv("srcdir") ? getenv("srcdir") : ".") +
235 "/src/processor/testdata/symbols/test_app.pdb/" +
236 module->debug_identifier() +
237 "/test_app.sym";
238 return FOUND;
239 }
240
241 return NOT_FOUND;
242 }
243
GetSymbolFile(const CodeModule * module,const SystemInfo * system_info,string * symbol_file,string * symbol_data)244 SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
245 const CodeModule *module,
246 const SystemInfo *system_info,
247 string *symbol_file,
248 string *symbol_data) {
249 SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info,
250 symbol_file);
251 if (s == FOUND) {
252 std::ifstream in(symbol_file->c_str());
253 std::getline(in, *symbol_data, string::traits_type::to_char_type(
254 string::traits_type::eof()));
255 in.close();
256 }
257
258 return s;
259 }
260
GetCStringSymbolData(const CodeModule * module,const SystemInfo * system_info,string * symbol_file,char ** symbol_data,size_t * symbol_data_size)261 SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData(
262 const CodeModule *module,
263 const SystemInfo *system_info,
264 string *symbol_file,
265 char **symbol_data,
266 size_t *symbol_data_size) {
267 string symbol_data_string;
268 SymbolSupplier::SymbolResult s = GetSymbolFile(module,
269 system_info,
270 symbol_file,
271 &symbol_data_string);
272 if (s == FOUND) {
273 *symbol_data_size = symbol_data_string.size() + 1;
274 *symbol_data = new char[*symbol_data_size];
275 if (*symbol_data == NULL) {
276 BPLOG(ERROR) << "Memory allocation failed for module: "
277 << module->code_file() << " size: " << *symbol_data_size;
278 return INTERRUPT;
279 }
280 memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size());
281 (*symbol_data)[symbol_data_string.size()] = '\0';
282 memory_buffers_.insert(make_pair(module->code_file(), *symbol_data));
283 }
284
285 return s;
286 }
287
FreeSymbolData(const CodeModule * module)288 void TestSymbolSupplier::FreeSymbolData(const CodeModule *module) {
289 map<string, char *>::iterator it = memory_buffers_.find(module->code_file());
290 if (it != memory_buffers_.end()) {
291 delete [] it->second;
292 memory_buffers_.erase(it);
293 }
294 }
295
296 // A test system info stream, just returns values from the
297 // MDRawSystemInfo fed to it.
298 class TestMinidumpSystemInfo : public MinidumpSystemInfo {
299 public:
TestMinidumpSystemInfo(MDRawSystemInfo info)300 explicit TestMinidumpSystemInfo(MDRawSystemInfo info) :
301 MinidumpSystemInfo(NULL) {
302 valid_ = true;
303 system_info_ = info;
304 csd_version_ = new string("");
305 }
306 };
307
308 // A test minidump context, just returns the MDRawContextX86
309 // fed to it.
310 class TestMinidumpContext : public MinidumpContext {
311 public:
TestMinidumpContext(const MDRawContextX86 & context)312 explicit TestMinidumpContext(const MDRawContextX86& context) :
313 MinidumpContext(NULL) {
314 valid_ = true;
315 SetContextX86(new MDRawContextX86(context));
316 SetContextFlags(MD_CONTEXT_X86);
317 }
318 };
319
320 class MinidumpProcessorTest : public ::testing::Test {
321 };
322
TEST_F(MinidumpProcessorTest,TestCorruptMinidumps)323 TEST_F(MinidumpProcessorTest, TestCorruptMinidumps) {
324 MockMinidump dump;
325 TestSymbolSupplier supplier;
326 BasicSourceLineResolver resolver;
327 MinidumpProcessor processor(&supplier, &resolver);
328 ProcessState state;
329
330 EXPECT_EQ(processor.Process("nonexistent minidump", &state),
331 google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND);
332
333 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
334 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
335
336 MDRawHeader fakeHeader;
337 fakeHeader.time_date_stamp = 0;
338 EXPECT_CALL(dump, header()).
339 WillOnce(Return(reinterpret_cast<MDRawHeader*>(NULL))).
340 WillRepeatedly(Return(&fakeHeader));
341
342 EXPECT_EQ(processor.Process(&dump, &state),
343 google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER);
344
345 EXPECT_CALL(dump, GetThreadList()).
346 WillOnce(Return(reinterpret_cast<MinidumpThreadList*>(NULL)));
347 EXPECT_CALL(dump, GetSystemInfo()).
348 WillRepeatedly(Return(reinterpret_cast<MinidumpSystemInfo*>(NULL)));
349
350 EXPECT_EQ(processor.Process(&dump, &state),
351 google_breakpad::PROCESS_ERROR_NO_THREAD_LIST);
352 }
353
354 // This test case verifies that the symbol supplier is only consulted
355 // once per minidump per module.
TEST_F(MinidumpProcessorTest,TestSymbolSupplierLookupCounts)356 TEST_F(MinidumpProcessorTest, TestSymbolSupplierLookupCounts) {
357 MockSymbolSupplier supplier;
358 BasicSourceLineResolver resolver;
359 MinidumpProcessor processor(&supplier, &resolver);
360
361 string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") +
362 "/src/processor/testdata/minidump2.dmp";
363 ProcessState state;
364 EXPECT_CALL(supplier, GetCStringSymbolData(
365 Property(&google_breakpad::CodeModule::code_file,
366 "c:\\test_app.exe"),
367 _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
368 EXPECT_CALL(supplier, GetCStringSymbolData(
369 Property(&google_breakpad::CodeModule::code_file,
370 Ne("c:\\test_app.exe")),
371 _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
372 // Avoid GMOCK WARNING "Uninteresting mock function call - returning
373 // directly" for FreeSymbolData().
374 EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber());
375 ASSERT_EQ(processor.Process(minidump_file, &state),
376 google_breakpad::PROCESS_OK);
377
378 ASSERT_TRUE(Mock::VerifyAndClearExpectations(&supplier));
379
380 // We need to verify that across minidumps, the processor will refetch
381 // symbol files, even with the same symbol supplier.
382 EXPECT_CALL(supplier, GetCStringSymbolData(
383 Property(&google_breakpad::CodeModule::code_file,
384 "c:\\test_app.exe"),
385 _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
386 EXPECT_CALL(supplier, GetCStringSymbolData(
387 Property(&google_breakpad::CodeModule::code_file,
388 Ne("c:\\test_app.exe")),
389 _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
390 // Avoid GMOCK WARNING "Uninteresting mock function call - returning
391 // directly" for FreeSymbolData().
392 EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber());
393 ASSERT_EQ(processor.Process(minidump_file, &state),
394 google_breakpad::PROCESS_OK);
395 }
396
TEST_F(MinidumpProcessorTest,TestBasicProcessing)397 TEST_F(MinidumpProcessorTest, TestBasicProcessing) {
398 TestSymbolSupplier supplier;
399 BasicSourceLineResolver resolver;
400 MinidumpProcessor processor(&supplier, &resolver);
401
402 string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") +
403 "/src/processor/testdata/minidump2.dmp";
404
405 ProcessState state;
406 ASSERT_EQ(processor.Process(minidump_file, &state),
407 google_breakpad::PROCESS_OK);
408 ASSERT_EQ(state.system_info()->os, kSystemInfoOS);
409 ASSERT_EQ(state.system_info()->os_short, kSystemInfoOSShort);
410 ASSERT_EQ(state.system_info()->os_version, kSystemInfoOSVersion);
411 ASSERT_EQ(state.system_info()->cpu, kSystemInfoCPU);
412 ASSERT_EQ(state.system_info()->cpu_info, kSystemInfoCPUInfo);
413 ASSERT_TRUE(state.crashed());
414 ASSERT_EQ(state.crash_reason(), "EXCEPTION_ACCESS_VIOLATION_WRITE");
415 ASSERT_EQ(state.crash_address(), 0x45U);
416 ASSERT_EQ(state.threads()->size(), size_t(1));
417 ASSERT_EQ(state.requesting_thread(), 0);
418 EXPECT_EQ(1171480435U, state.time_date_stamp());
419 EXPECT_EQ(1171480435U, state.process_create_time());
420
421 CallStack *stack = state.threads()->at(0);
422 ASSERT_TRUE(stack);
423 ASSERT_EQ(stack->frames()->size(), 4U);
424
425 ASSERT_TRUE(stack->frames()->at(0)->module);
426 ASSERT_EQ(stack->frames()->at(0)->module->base_address(), 0x400000U);
427 ASSERT_EQ(stack->frames()->at(0)->module->code_file(), "c:\\test_app.exe");
428 ASSERT_EQ(stack->frames()->at(0)->function_name,
429 "`anonymous namespace'::CrashFunction");
430 ASSERT_EQ(stack->frames()->at(0)->source_file_name, "c:\\test_app.cc");
431 ASSERT_EQ(stack->frames()->at(0)->source_line, 58);
432
433 ASSERT_TRUE(stack->frames()->at(1)->module);
434 ASSERT_EQ(stack->frames()->at(1)->module->base_address(), 0x400000U);
435 ASSERT_EQ(stack->frames()->at(1)->module->code_file(), "c:\\test_app.exe");
436 ASSERT_EQ(stack->frames()->at(1)->function_name, "main");
437 ASSERT_EQ(stack->frames()->at(1)->source_file_name, "c:\\test_app.cc");
438 ASSERT_EQ(stack->frames()->at(1)->source_line, 65);
439
440 // This comes from the CRT
441 ASSERT_TRUE(stack->frames()->at(2)->module);
442 ASSERT_EQ(stack->frames()->at(2)->module->base_address(), 0x400000U);
443 ASSERT_EQ(stack->frames()->at(2)->module->code_file(), "c:\\test_app.exe");
444 ASSERT_EQ(stack->frames()->at(2)->function_name, "__tmainCRTStartup");
445 ASSERT_EQ(stack->frames()->at(2)->source_file_name,
446 "f:\\sp\\vctools\\crt_bld\\self_x86\\crt\\src\\crt0.c");
447 ASSERT_EQ(stack->frames()->at(2)->source_line, 327);
448
449 // No debug info available for kernel32.dll
450 ASSERT_TRUE(stack->frames()->at(3)->module);
451 ASSERT_EQ(stack->frames()->at(3)->module->base_address(), 0x7c800000U);
452 ASSERT_EQ(stack->frames()->at(3)->module->code_file(),
453 "C:\\WINDOWS\\system32\\kernel32.dll");
454 ASSERT_TRUE(stack->frames()->at(3)->function_name.empty());
455 ASSERT_TRUE(stack->frames()->at(3)->source_file_name.empty());
456 ASSERT_EQ(stack->frames()->at(3)->source_line, 0);
457
458 ASSERT_EQ(state.modules()->module_count(), 13U);
459 ASSERT_TRUE(state.modules()->GetMainModule());
460 ASSERT_EQ(state.modules()->GetMainModule()->code_file(), "c:\\test_app.exe");
461 ASSERT_FALSE(state.modules()->GetModuleForAddress(0));
462 ASSERT_EQ(state.modules()->GetMainModule(),
463 state.modules()->GetModuleForAddress(0x400000));
464 ASSERT_EQ(state.modules()->GetModuleForAddress(0x7c801234)->debug_file(),
465 "kernel32.pdb");
466 ASSERT_EQ(state.modules()->GetModuleForAddress(0x77d43210)->version(),
467 "5.1.2600.2622");
468
469 // Test that disabled exploitability engine defaults to
470 // EXPLOITABILITY_NOT_ANALYZED.
471 ASSERT_EQ(google_breakpad::EXPLOITABILITY_NOT_ANALYZED,
472 state.exploitability());
473
474 // Test that the symbol supplier can interrupt processing
475 state.Clear();
476 supplier.set_interrupt(true);
477 ASSERT_EQ(processor.Process(minidump_file, &state),
478 google_breakpad::PROCESS_SYMBOL_SUPPLIER_INTERRUPTED);
479 }
480
TEST_F(MinidumpProcessorTest,TestThreadMissingMemory)481 TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) {
482 MockMinidump dump;
483 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
484 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
485
486 MDRawHeader fake_header;
487 fake_header.time_date_stamp = 0;
488 EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
489
490 MDRawSystemInfo raw_system_info;
491 memset(&raw_system_info, 0, sizeof(raw_system_info));
492 raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86;
493 raw_system_info.platform_id = MD_OS_WIN32_NT;
494 TestMinidumpSystemInfo dump_system_info(raw_system_info);
495
496 EXPECT_CALL(dump, GetSystemInfo()).
497 WillRepeatedly(Return(&dump_system_info));
498
499 MockMinidumpThreadList thread_list;
500 EXPECT_CALL(dump, GetThreadList()).
501 WillOnce(Return(&thread_list));
502
503 MockMinidumpMemoryList memory_list;
504 EXPECT_CALL(dump, GetMemoryList()).
505 WillOnce(Return(&memory_list));
506
507 // Return a thread missing stack memory.
508 MockMinidumpThread no_memory_thread;
509 EXPECT_CALL(no_memory_thread, GetThreadID(_)).
510 WillRepeatedly(DoAll(SetArgumentPointee<0>(1),
511 Return(true)));
512 EXPECT_CALL(no_memory_thread, GetMemory()).
513 WillRepeatedly(Return(reinterpret_cast<MinidumpMemoryRegion*>(NULL)));
514
515 const uint64_t kTestStartOfMemoryRange = 0x1234;
516 EXPECT_CALL(no_memory_thread, GetStartOfStackMemoryRange()).
517 WillRepeatedly(Return(kTestStartOfMemoryRange));
518 EXPECT_CALL(memory_list, GetMemoryRegionForAddress(kTestStartOfMemoryRange)).
519 WillRepeatedly(Return(reinterpret_cast<MinidumpMemoryRegion*>(NULL)));
520
521 MDRawContextX86 no_memory_thread_raw_context;
522 memset(&no_memory_thread_raw_context, 0,
523 sizeof(no_memory_thread_raw_context));
524 no_memory_thread_raw_context.context_flags = MD_CONTEXT_X86_FULL;
525 const uint32_t kExpectedEIP = 0xabcd1234;
526 no_memory_thread_raw_context.eip = kExpectedEIP;
527 TestMinidumpContext no_memory_thread_context(no_memory_thread_raw_context);
528 EXPECT_CALL(no_memory_thread, GetContext()).
529 WillRepeatedly(Return(&no_memory_thread_context));
530
531 EXPECT_CALL(thread_list, thread_count()).
532 WillRepeatedly(Return(1));
533 EXPECT_CALL(thread_list, GetThreadAtIndex(0)).
534 WillOnce(Return(&no_memory_thread));
535
536 MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
537 ProcessState state;
538 EXPECT_EQ(processor.Process(&dump, &state),
539 google_breakpad::PROCESS_OK);
540
541 // Should have a single thread with a single frame in it.
542 ASSERT_EQ(1U, state.threads()->size());
543 ASSERT_EQ(1U, state.threads()->at(0)->frames()->size());
544 ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction);
545 }
546
TEST_F(MinidumpProcessorTest,GetProcessCreateTime)547 TEST_F(MinidumpProcessorTest, GetProcessCreateTime) {
548 const uint32_t kProcessCreateTime = 2000;
549 const uint32_t kTimeDateStamp = 5000;
550 MockMinidump dump;
551 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
552 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
553
554 // Set time of crash.
555 MDRawHeader fake_header;
556 fake_header.time_date_stamp = kTimeDateStamp;
557 EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
558
559 // Set process create time.
560 MDRawMiscInfo raw_misc_info;
561 memset(&raw_misc_info, 0, sizeof(raw_misc_info));
562 raw_misc_info.process_create_time = kProcessCreateTime;
563 raw_misc_info.flags1 |= MD_MISCINFO_FLAGS1_PROCESS_TIMES;
564 google_breakpad::TestMinidumpMiscInfo dump_misc_info(raw_misc_info);
565 EXPECT_CALL(dump, GetMiscInfo()).WillRepeatedly(Return(&dump_misc_info));
566
567 // No threads
568 MockMinidumpThreadList thread_list;
569 EXPECT_CALL(dump, GetThreadList()).WillOnce(Return(&thread_list));
570 EXPECT_CALL(thread_list, thread_count()).WillRepeatedly(Return(0));
571
572 MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
573 ProcessState state;
574 EXPECT_EQ(google_breakpad::PROCESS_OK, processor.Process(&dump, &state));
575
576 // Verify the time stamps.
577 ASSERT_EQ(kTimeDateStamp, state.time_date_stamp());
578 ASSERT_EQ(kProcessCreateTime, state.process_create_time());
579 }
580
TEST_F(MinidumpProcessorTest,TestThreadMissingContext)581 TEST_F(MinidumpProcessorTest, TestThreadMissingContext) {
582 MockMinidump dump;
583 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
584 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
585
586 MDRawHeader fake_header;
587 fake_header.time_date_stamp = 0;
588 EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
589
590 MDRawSystemInfo raw_system_info;
591 memset(&raw_system_info, 0, sizeof(raw_system_info));
592 raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86;
593 raw_system_info.platform_id = MD_OS_WIN32_NT;
594 TestMinidumpSystemInfo dump_system_info(raw_system_info);
595
596 EXPECT_CALL(dump, GetSystemInfo()).
597 WillRepeatedly(Return(&dump_system_info));
598
599 MockMinidumpThreadList thread_list;
600 EXPECT_CALL(dump, GetThreadList()).
601 WillOnce(Return(&thread_list));
602
603 MockMinidumpMemoryList memory_list;
604 EXPECT_CALL(dump, GetMemoryList()).
605 WillOnce(Return(&memory_list));
606
607 // Return a thread missing a thread context.
608 MockMinidumpThread no_context_thread;
609 EXPECT_CALL(no_context_thread, GetThreadID(_)).
610 WillRepeatedly(DoAll(SetArgumentPointee<0>(1),
611 Return(true)));
612 EXPECT_CALL(no_context_thread, GetContext()).
613 WillRepeatedly(Return(reinterpret_cast<MinidumpContext*>(NULL)));
614
615 // The memory contents don't really matter here, since it won't be used.
616 MockMinidumpMemoryRegion no_context_thread_memory(0x1234, "xxx");
617 EXPECT_CALL(no_context_thread, GetMemory()).
618 WillRepeatedly(Return(&no_context_thread_memory));
619 EXPECT_CALL(no_context_thread, GetStartOfStackMemoryRange()).
620 Times(0);
621 EXPECT_CALL(memory_list, GetMemoryRegionForAddress(_)).
622 Times(0);
623
624 EXPECT_CALL(thread_list, thread_count()).
625 WillRepeatedly(Return(1));
626 EXPECT_CALL(thread_list, GetThreadAtIndex(0)).
627 WillOnce(Return(&no_context_thread));
628
629 MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
630 ProcessState state;
631 EXPECT_EQ(processor.Process(&dump, &state),
632 google_breakpad::PROCESS_OK);
633
634 // Should have a single thread with zero frames.
635 ASSERT_EQ(1U, state.threads()->size());
636 ASSERT_EQ(0U, state.threads()->at(0)->frames()->size());
637 }
638
639 } // namespace
640
main(int argc,char * argv[])641 int main(int argc, char *argv[]) {
642 ::testing::InitGoogleTest(&argc, argv);
643 return RUN_ALL_TESTS();
644 }
645