1 // Copyright (c) 2006, Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
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
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.
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.
30 // Unit test for MinidumpProcessor. Uses a pre-generated minidump and
31 // corresponding symbol file, and checks the stack frames for correctness.
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"
58 namespace google_breakpad {
59 class MockMinidump : public Minidump {
61 MockMinidump() : Minidump("") {
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(GetBreakpadInfo, MinidumpBreakpadInfo*());
70 MOCK_METHOD0(GetException, MinidumpException*());
71 MOCK_METHOD0(GetAssertion, MinidumpAssertion*());
72 MOCK_METHOD0(GetModuleList, MinidumpModuleList*());
73 MOCK_METHOD0(GetMemoryList, MinidumpMemoryList*());
76 class MockMinidumpThreadList : public MinidumpThreadList {
78 MockMinidumpThreadList() : MinidumpThreadList(NULL) {}
80 MOCK_CONST_METHOD0(thread_count, unsigned int());
81 MOCK_CONST_METHOD1(GetThreadAtIndex, MinidumpThread*(unsigned int));
84 class MockMinidumpMemoryList : public MinidumpMemoryList {
86 MockMinidumpMemoryList() : MinidumpMemoryList(NULL) {}
88 MOCK_METHOD1(GetMemoryRegionForAddress, MinidumpMemoryRegion*(uint64_t));
91 class MockMinidumpThread : public MinidumpThread {
93 MockMinidumpThread() : MinidumpThread(NULL) {}
95 MOCK_CONST_METHOD1(GetThreadID, bool(uint32_t*));
96 MOCK_METHOD0(GetContext, MinidumpContext*());
97 MOCK_METHOD0(GetMemory, MinidumpMemoryRegion*());
98 MOCK_CONST_METHOD0(GetStartOfStackMemoryRange, uint64_t());
101 // This is crappy, but MinidumpProcessor really does want a
102 // MinidumpMemoryRegion.
103 class MockMinidumpMemoryRegion : public MinidumpMemoryRegion {
105 MockMinidumpMemoryRegion(uint64_t base, const string& contents) :
106 MinidumpMemoryRegion(NULL) {
107 region_.Init(base, contents);
110 uint64_t GetBase() const { return region_.GetBase(); }
111 uint32_t GetSize() const { return region_.GetSize(); }
113 bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const {
114 return region_.GetMemoryAtAddress(address, value);
116 bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
117 return region_.GetMemoryAtAddress(address, value);
119 bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
120 return region_.GetMemoryAtAddress(address, value);
122 bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
123 return region_.GetMemoryAtAddress(address, value);
126 MockMemoryRegion region_;
129 } // namespace google_breakpad
133 using google_breakpad::BasicSourceLineResolver;
134 using google_breakpad::CallStack;
135 using google_breakpad::CodeModule;
136 using google_breakpad::MinidumpContext;
137 using google_breakpad::MinidumpMemoryRegion;
138 using google_breakpad::MinidumpProcessor;
139 using google_breakpad::MinidumpSystemInfo;
140 using google_breakpad::MinidumpThreadList;
141 using google_breakpad::MinidumpThread;
142 using google_breakpad::MockMinidump;
143 using google_breakpad::MockMinidumpMemoryList;
144 using google_breakpad::MockMinidumpMemoryRegion;
145 using google_breakpad::MockMinidumpThread;
146 using google_breakpad::MockMinidumpThreadList;
147 using google_breakpad::ProcessState;
148 using google_breakpad::scoped_ptr;
149 using google_breakpad::SymbolSupplier;
150 using google_breakpad::SystemInfo;
152 using ::testing::AnyNumber;
153 using ::testing::DoAll;
154 using ::testing::Mock;
156 using ::testing::Property;
157 using ::testing::Return;
158 using ::testing::SetArgumentPointee;
160 static const char *kSystemInfoOS = "Windows NT";
161 static const char *kSystemInfoOSShort = "windows";
162 static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2";
163 static const char *kSystemInfoCPU = "x86";
164 static const char *kSystemInfoCPUInfo =
165 "GenuineIntel family 6 model 13 stepping 8";
167 #define ASSERT_TRUE_ABORT(cond) \
169 fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \
173 #define ASSERT_EQ_ABORT(e1, e2) ASSERT_TRUE_ABORT((e1) == (e2))
175 class TestSymbolSupplier : public SymbolSupplier {
177 TestSymbolSupplier() : interrupt_(false) {}
179 virtual SymbolResult GetSymbolFile(const CodeModule *module,
180 const SystemInfo *system_info,
181 string *symbol_file);
183 virtual SymbolResult GetSymbolFile(const CodeModule *module,
184 const SystemInfo *system_info,
186 string *symbol_data);
188 virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
189 const SystemInfo *system_info,
192 size_t *symbol_data_size);
194 virtual void FreeSymbolData(const CodeModule *module);
196 // When set to true, causes the SymbolSupplier to return INTERRUPT
197 void set_interrupt(bool interrupt) { interrupt_ = interrupt; }
201 map<string, char *> memory_buffers_;
204 SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
205 const CodeModule *module,
206 const SystemInfo *system_info,
207 string *symbol_file) {
208 ASSERT_TRUE_ABORT(module);
209 ASSERT_TRUE_ABORT(system_info);
210 ASSERT_EQ_ABORT(system_info->cpu, kSystemInfoCPU);
211 ASSERT_EQ_ABORT(system_info->cpu_info, kSystemInfoCPUInfo);
212 ASSERT_EQ_ABORT(system_info->os, kSystemInfoOS);
213 ASSERT_EQ_ABORT(system_info->os_short, kSystemInfoOSShort);
214 ASSERT_EQ_ABORT(system_info->os_version, kSystemInfoOSVersion);
220 if (module && module->code_file() == "c:\\test_app.exe") {
221 *symbol_file = string(getenv("srcdir") ? getenv("srcdir") : ".") +
222 "/src/processor/testdata/symbols/test_app.pdb/" +
223 module->debug_identifier() +
231 SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
232 const CodeModule *module,
233 const SystemInfo *system_info,
235 string *symbol_data) {
236 SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info,
239 std::ifstream in(symbol_file->c_str());
240 std::getline(in, *symbol_data, string::traits_type::to_char_type(
241 string::traits_type::eof()));
248 SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData(
249 const CodeModule *module,
250 const SystemInfo *system_info,
253 size_t *symbol_data_size) {
254 string symbol_data_string;
255 SymbolSupplier::SymbolResult s = GetSymbolFile(module,
258 &symbol_data_string);
260 *symbol_data_size = symbol_data_string.size() + 1;
261 *symbol_data = new char[*symbol_data_size];
262 if (*symbol_data == NULL) {
263 BPLOG(ERROR) << "Memory allocation failed for module: "
264 << module->code_file() << " size: " << *symbol_data_size;
267 memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size());
268 (*symbol_data)[symbol_data_string.size()] = '\0';
269 memory_buffers_.insert(make_pair(module->code_file(), *symbol_data));
275 void TestSymbolSupplier::FreeSymbolData(const CodeModule *module) {
276 map<string, char *>::iterator it = memory_buffers_.find(module->code_file());
277 if (it != memory_buffers_.end()) {
278 delete [] it->second;
279 memory_buffers_.erase(it);
283 // A test system info stream, just returns values from the
284 // MDRawSystemInfo fed to it.
285 class TestMinidumpSystemInfo : public MinidumpSystemInfo {
287 explicit TestMinidumpSystemInfo(MDRawSystemInfo info) :
288 MinidumpSystemInfo(NULL) {
291 csd_version_ = new string("");
295 // A test minidump context, just returns the MDRawContextX86
297 class TestMinidumpContext : public MinidumpContext {
299 explicit TestMinidumpContext(const MDRawContextX86& context) :
300 MinidumpContext(NULL) {
302 SetContextX86(new MDRawContextX86(context));
303 SetContextFlags(MD_CONTEXT_X86);
307 class MinidumpProcessorTest : public ::testing::Test {
310 TEST_F(MinidumpProcessorTest, TestCorruptMinidumps) {
312 TestSymbolSupplier supplier;
313 BasicSourceLineResolver resolver;
314 MinidumpProcessor processor(&supplier, &resolver);
317 EXPECT_EQ(processor.Process("nonexistent minidump", &state),
318 google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND);
320 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
321 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
323 MDRawHeader fakeHeader;
324 fakeHeader.time_date_stamp = 0;
325 EXPECT_CALL(dump, header()).
326 WillOnce(Return(reinterpret_cast<MDRawHeader*>(NULL))).
327 WillRepeatedly(Return(&fakeHeader));
329 EXPECT_EQ(processor.Process(&dump, &state),
330 google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER);
332 EXPECT_CALL(dump, GetThreadList()).
333 WillOnce(Return(reinterpret_cast<MinidumpThreadList*>(NULL)));
334 EXPECT_CALL(dump, GetSystemInfo()).
335 WillRepeatedly(Return(reinterpret_cast<MinidumpSystemInfo*>(NULL)));
337 EXPECT_EQ(processor.Process(&dump, &state),
338 google_breakpad::PROCESS_ERROR_NO_THREAD_LIST);
341 // This test case verifies that the symbol supplier is only consulted
342 // once per minidump per module.
343 TEST_F(MinidumpProcessorTest, TestSymbolSupplierLookupCounts) {
344 MockSymbolSupplier supplier;
345 BasicSourceLineResolver resolver;
346 MinidumpProcessor processor(&supplier, &resolver);
348 string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") +
349 "/src/processor/testdata/minidump2.dmp";
351 EXPECT_CALL(supplier, GetCStringSymbolData(
352 Property(&google_breakpad::CodeModule::code_file,
354 _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
355 EXPECT_CALL(supplier, GetCStringSymbolData(
356 Property(&google_breakpad::CodeModule::code_file,
357 Ne("c:\\test_app.exe")),
358 _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
359 // Avoid GMOCK WARNING "Uninteresting mock function call - returning
360 // directly" for FreeSymbolData().
361 EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber());
362 ASSERT_EQ(processor.Process(minidump_file, &state),
363 google_breakpad::PROCESS_OK);
365 ASSERT_TRUE(Mock::VerifyAndClearExpectations(&supplier));
367 // We need to verify that across minidumps, the processor will refetch
368 // symbol files, even with the same symbol supplier.
369 EXPECT_CALL(supplier, GetCStringSymbolData(
370 Property(&google_breakpad::CodeModule::code_file,
372 _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
373 EXPECT_CALL(supplier, GetCStringSymbolData(
374 Property(&google_breakpad::CodeModule::code_file,
375 Ne("c:\\test_app.exe")),
376 _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
377 // Avoid GMOCK WARNING "Uninteresting mock function call - returning
378 // directly" for FreeSymbolData().
379 EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber());
380 ASSERT_EQ(processor.Process(minidump_file, &state),
381 google_breakpad::PROCESS_OK);
384 TEST_F(MinidumpProcessorTest, TestBasicProcessing) {
385 TestSymbolSupplier supplier;
386 BasicSourceLineResolver resolver;
387 MinidumpProcessor processor(&supplier, &resolver);
389 string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") +
390 "/src/processor/testdata/minidump2.dmp";
393 ASSERT_EQ(processor.Process(minidump_file, &state),
394 google_breakpad::PROCESS_OK);
395 ASSERT_EQ(state.system_info()->os, kSystemInfoOS);
396 ASSERT_EQ(state.system_info()->os_short, kSystemInfoOSShort);
397 ASSERT_EQ(state.system_info()->os_version, kSystemInfoOSVersion);
398 ASSERT_EQ(state.system_info()->cpu, kSystemInfoCPU);
399 ASSERT_EQ(state.system_info()->cpu_info, kSystemInfoCPUInfo);
400 ASSERT_TRUE(state.crashed());
401 ASSERT_EQ(state.crash_reason(), "EXCEPTION_ACCESS_VIOLATION_WRITE");
402 ASSERT_EQ(state.crash_address(), 0x45U);
403 ASSERT_EQ(state.threads()->size(), size_t(1));
404 ASSERT_EQ(state.requesting_thread(), 0);
406 CallStack *stack = state.threads()->at(0);
408 ASSERT_EQ(stack->frames()->size(), 4U);
410 ASSERT_TRUE(stack->frames()->at(0)->module);
411 ASSERT_EQ(stack->frames()->at(0)->module->base_address(), 0x400000U);
412 ASSERT_EQ(stack->frames()->at(0)->module->code_file(), "c:\\test_app.exe");
413 ASSERT_EQ(stack->frames()->at(0)->function_name,
414 "`anonymous namespace'::CrashFunction");
415 ASSERT_EQ(stack->frames()->at(0)->source_file_name, "c:\\test_app.cc");
416 ASSERT_EQ(stack->frames()->at(0)->source_line, 58);
418 ASSERT_TRUE(stack->frames()->at(1)->module);
419 ASSERT_EQ(stack->frames()->at(1)->module->base_address(), 0x400000U);
420 ASSERT_EQ(stack->frames()->at(1)->module->code_file(), "c:\\test_app.exe");
421 ASSERT_EQ(stack->frames()->at(1)->function_name, "main");
422 ASSERT_EQ(stack->frames()->at(1)->source_file_name, "c:\\test_app.cc");
423 ASSERT_EQ(stack->frames()->at(1)->source_line, 65);
425 // This comes from the CRT
426 ASSERT_TRUE(stack->frames()->at(2)->module);
427 ASSERT_EQ(stack->frames()->at(2)->module->base_address(), 0x400000U);
428 ASSERT_EQ(stack->frames()->at(2)->module->code_file(), "c:\\test_app.exe");
429 ASSERT_EQ(stack->frames()->at(2)->function_name, "__tmainCRTStartup");
430 ASSERT_EQ(stack->frames()->at(2)->source_file_name,
431 "f:\\sp\\vctools\\crt_bld\\self_x86\\crt\\src\\crt0.c");
432 ASSERT_EQ(stack->frames()->at(2)->source_line, 327);
434 // No debug info available for kernel32.dll
435 ASSERT_TRUE(stack->frames()->at(3)->module);
436 ASSERT_EQ(stack->frames()->at(3)->module->base_address(), 0x7c800000U);
437 ASSERT_EQ(stack->frames()->at(3)->module->code_file(),
438 "C:\\WINDOWS\\system32\\kernel32.dll");
439 ASSERT_TRUE(stack->frames()->at(3)->function_name.empty());
440 ASSERT_TRUE(stack->frames()->at(3)->source_file_name.empty());
441 ASSERT_EQ(stack->frames()->at(3)->source_line, 0);
443 ASSERT_EQ(state.modules()->module_count(), 13U);
444 ASSERT_TRUE(state.modules()->GetMainModule());
445 ASSERT_EQ(state.modules()->GetMainModule()->code_file(), "c:\\test_app.exe");
446 ASSERT_FALSE(state.modules()->GetModuleForAddress(0));
447 ASSERT_EQ(state.modules()->GetMainModule(),
448 state.modules()->GetModuleForAddress(0x400000));
449 ASSERT_EQ(state.modules()->GetModuleForAddress(0x7c801234)->debug_file(),
451 ASSERT_EQ(state.modules()->GetModuleForAddress(0x77d43210)->version(),
454 // Test that disabled exploitability engine defaults to
455 // EXPLOITABILITY_NOT_ANALYZED.
456 ASSERT_EQ(google_breakpad::EXPLOITABILITY_NOT_ANALYZED,
457 state.exploitability());
459 // Test that the symbol supplier can interrupt processing
461 supplier.set_interrupt(true);
462 ASSERT_EQ(processor.Process(minidump_file, &state),
463 google_breakpad::PROCESS_SYMBOL_SUPPLIER_INTERRUPTED);
466 TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) {
468 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
469 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
471 MDRawHeader fake_header;
472 fake_header.time_date_stamp = 0;
473 EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
475 MDRawSystemInfo raw_system_info;
476 memset(&raw_system_info, 0, sizeof(raw_system_info));
477 raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86;
478 raw_system_info.platform_id = MD_OS_WIN32_NT;
479 TestMinidumpSystemInfo dump_system_info(raw_system_info);
481 EXPECT_CALL(dump, GetSystemInfo()).
482 WillRepeatedly(Return(&dump_system_info));
484 MockMinidumpThreadList thread_list;
485 EXPECT_CALL(dump, GetThreadList()).
486 WillOnce(Return(&thread_list));
488 MockMinidumpMemoryList memory_list;
489 EXPECT_CALL(dump, GetMemoryList()).
490 WillOnce(Return(&memory_list));
492 // Return a thread missing stack memory.
493 MockMinidumpThread no_memory_thread;
494 EXPECT_CALL(no_memory_thread, GetThreadID(_)).
495 WillRepeatedly(DoAll(SetArgumentPointee<0>(1),
497 EXPECT_CALL(no_memory_thread, GetMemory()).
498 WillRepeatedly(Return(reinterpret_cast<MinidumpMemoryRegion*>(NULL)));
500 const uint64_t kTestStartOfMemoryRange = 0x1234;
501 EXPECT_CALL(no_memory_thread, GetStartOfStackMemoryRange()).
502 WillRepeatedly(Return(kTestStartOfMemoryRange));
503 EXPECT_CALL(memory_list, GetMemoryRegionForAddress(kTestStartOfMemoryRange)).
504 WillRepeatedly(Return(reinterpret_cast<MinidumpMemoryRegion*>(NULL)));
506 MDRawContextX86 no_memory_thread_raw_context;
507 memset(&no_memory_thread_raw_context, 0,
508 sizeof(no_memory_thread_raw_context));
509 no_memory_thread_raw_context.context_flags = MD_CONTEXT_X86_FULL;
510 const uint32_t kExpectedEIP = 0xabcd1234;
511 no_memory_thread_raw_context.eip = kExpectedEIP;
512 TestMinidumpContext no_memory_thread_context(no_memory_thread_raw_context);
513 EXPECT_CALL(no_memory_thread, GetContext()).
514 WillRepeatedly(Return(&no_memory_thread_context));
516 EXPECT_CALL(thread_list, thread_count()).
517 WillRepeatedly(Return(1));
518 EXPECT_CALL(thread_list, GetThreadAtIndex(0)).
519 WillOnce(Return(&no_memory_thread));
521 MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
523 EXPECT_EQ(processor.Process(&dump, &state),
524 google_breakpad::PROCESS_OK);
526 // Should have a single thread with a single frame in it.
527 ASSERT_EQ(1U, state.threads()->size());
528 ASSERT_EQ(1U, state.threads()->at(0)->frames()->size());
529 ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction);
532 TEST_F(MinidumpProcessorTest, TestThreadMissingContext) {
534 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
535 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
537 MDRawHeader fake_header;
538 fake_header.time_date_stamp = 0;
539 EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
541 MDRawSystemInfo raw_system_info;
542 memset(&raw_system_info, 0, sizeof(raw_system_info));
543 raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86;
544 raw_system_info.platform_id = MD_OS_WIN32_NT;
545 TestMinidumpSystemInfo dump_system_info(raw_system_info);
547 EXPECT_CALL(dump, GetSystemInfo()).
548 WillRepeatedly(Return(&dump_system_info));
550 MockMinidumpThreadList thread_list;
551 EXPECT_CALL(dump, GetThreadList()).
552 WillOnce(Return(&thread_list));
554 MockMinidumpMemoryList memory_list;
555 EXPECT_CALL(dump, GetMemoryList()).
556 WillOnce(Return(&memory_list));
558 // Return a thread missing a thread context.
559 MockMinidumpThread no_context_thread;
560 EXPECT_CALL(no_context_thread, GetThreadID(_)).
561 WillRepeatedly(DoAll(SetArgumentPointee<0>(1),
563 EXPECT_CALL(no_context_thread, GetContext()).
564 WillRepeatedly(Return(reinterpret_cast<MinidumpContext*>(NULL)));
566 // The memory contents don't really matter here, since it won't be used.
567 MockMinidumpMemoryRegion no_context_thread_memory(0x1234, "xxx");
568 EXPECT_CALL(no_context_thread, GetMemory()).
569 WillRepeatedly(Return(&no_context_thread_memory));
570 EXPECT_CALL(no_context_thread, GetStartOfStackMemoryRange()).
572 EXPECT_CALL(memory_list, GetMemoryRegionForAddress(_)).
575 EXPECT_CALL(thread_list, thread_count()).
576 WillRepeatedly(Return(1));
577 EXPECT_CALL(thread_list, GetThreadAtIndex(0)).
578 WillOnce(Return(&no_context_thread));
580 MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
582 EXPECT_EQ(processor.Process(&dump, &state),
583 google_breakpad::PROCESS_OK);
585 // Should have a single thread with zero frames.
586 ASSERT_EQ(1U, state.threads()->size());
587 ASSERT_EQ(0U, state.threads()->at(0)->frames()->size());
592 int main(int argc, char *argv[]) {
593 ::testing::InitGoogleTest(&argc, argv);
594 return RUN_ALL_TESTS();