Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / breakpad / src / processor / minidump_processor_unittest.cc
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:
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(GetBreakpadInfo, MinidumpBreakpadInfo*());
70   MOCK_METHOD0(GetException, MinidumpException*());
71   MOCK_METHOD0(GetAssertion, MinidumpAssertion*());
72   MOCK_METHOD0(GetModuleList, MinidumpModuleList*());
73   MOCK_METHOD0(GetMemoryList, MinidumpMemoryList*());
74 };
75
76 class MockMinidumpThreadList : public MinidumpThreadList {
77  public:
78   MockMinidumpThreadList() : MinidumpThreadList(NULL) {}
79
80   MOCK_CONST_METHOD0(thread_count, unsigned int());
81   MOCK_CONST_METHOD1(GetThreadAtIndex, MinidumpThread*(unsigned int));
82 };
83
84 class MockMinidumpMemoryList : public MinidumpMemoryList {
85  public:
86   MockMinidumpMemoryList() : MinidumpMemoryList(NULL) {}
87
88   MOCK_METHOD1(GetMemoryRegionForAddress, MinidumpMemoryRegion*(uint64_t));
89 };
90
91 class MockMinidumpThread : public MinidumpThread {
92  public:
93   MockMinidumpThread() : MinidumpThread(NULL) {}
94
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());
99 };
100
101 // This is crappy, but MinidumpProcessor really does want a
102 // MinidumpMemoryRegion.
103 class MockMinidumpMemoryRegion : public MinidumpMemoryRegion {
104  public:
105   MockMinidumpMemoryRegion(uint64_t base, const string& contents) :
106       MinidumpMemoryRegion(NULL) {
107     region_.Init(base, contents);
108   }
109
110   uint64_t GetBase() const { return region_.GetBase(); }
111   uint32_t GetSize() const { return region_.GetSize(); }
112
113   bool GetMemoryAtAddress(uint64_t address, uint8_t  *value) const {
114     return region_.GetMemoryAtAddress(address, value);
115   }
116   bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
117     return region_.GetMemoryAtAddress(address, value);
118   }
119   bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
120     return region_.GetMemoryAtAddress(address, value);
121   }
122   bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
123     return region_.GetMemoryAtAddress(address, value);
124   }
125
126   MockMemoryRegion region_;
127 };
128
129 }  // namespace google_breakpad
130
131 namespace {
132
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;
151 using ::testing::_;
152 using ::testing::AnyNumber;
153 using ::testing::DoAll;
154 using ::testing::Mock;
155 using ::testing::Ne;
156 using ::testing::Property;
157 using ::testing::Return;
158 using ::testing::SetArgumentPointee;
159
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";
166
167 #define ASSERT_TRUE_ABORT(cond) \
168   if (!(cond)) {                                                        \
169     fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \
170     abort(); \
171   }
172
173 #define ASSERT_EQ_ABORT(e1, e2) ASSERT_TRUE_ABORT((e1) == (e2))
174
175 class TestSymbolSupplier : public SymbolSupplier {
176  public:
177   TestSymbolSupplier() : interrupt_(false) {}
178
179   virtual SymbolResult GetSymbolFile(const CodeModule *module,
180                                      const SystemInfo *system_info,
181                                      string *symbol_file);
182
183   virtual SymbolResult GetSymbolFile(const CodeModule *module,
184                                      const SystemInfo *system_info,
185                                      string *symbol_file,
186                                      string *symbol_data);
187
188   virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
189                                             const SystemInfo *system_info,
190                                             string *symbol_file,
191                                             char **symbol_data,
192                                             size_t *symbol_data_size);
193
194   virtual void FreeSymbolData(const CodeModule *module);
195
196   // When set to true, causes the SymbolSupplier to return INTERRUPT
197   void set_interrupt(bool interrupt) { interrupt_ = interrupt; }
198
199  private:
200   bool interrupt_;
201   map<string, char *> memory_buffers_;
202 };
203
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);
215
216   if (interrupt_) {
217     return INTERRUPT;
218   }
219
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() +
224                      "/test_app.sym";
225     return FOUND;
226   }
227
228   return NOT_FOUND;
229 }
230
231 SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
232     const CodeModule *module,
233     const SystemInfo *system_info,
234     string *symbol_file,
235     string *symbol_data) {
236   SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info,
237                                                  symbol_file);
238   if (s == FOUND) {
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()));
242     in.close();
243   }
244
245   return s;
246 }
247
248 SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData(
249     const CodeModule *module,
250     const SystemInfo *system_info,
251     string *symbol_file,
252     char **symbol_data,
253     size_t *symbol_data_size) {
254   string symbol_data_string;
255   SymbolSupplier::SymbolResult s = GetSymbolFile(module,
256                                                  system_info,
257                                                  symbol_file,
258                                                  &symbol_data_string);
259   if (s == FOUND) {
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;
265       return INTERRUPT;
266     }
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));
270   }
271
272   return s;
273 }
274
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);
280   }
281 }
282
283 // A test system info stream, just returns values from the
284 // MDRawSystemInfo fed to it.
285 class TestMinidumpSystemInfo : public MinidumpSystemInfo {
286  public:
287   explicit TestMinidumpSystemInfo(MDRawSystemInfo info) :
288       MinidumpSystemInfo(NULL) {
289     valid_ = true;
290     system_info_ = info;
291     csd_version_ = new string("");
292   }
293 };
294
295 // A test minidump context, just returns the MDRawContextX86
296 // fed to it.
297 class TestMinidumpContext : public MinidumpContext {
298  public:
299   explicit TestMinidumpContext(const MDRawContextX86& context) :
300       MinidumpContext(NULL) {
301     valid_ = true;
302     SetContextX86(new MDRawContextX86(context));
303     SetContextFlags(MD_CONTEXT_X86);
304   }
305 };
306
307 class MinidumpProcessorTest : public ::testing::Test {
308 };
309
310 TEST_F(MinidumpProcessorTest, TestCorruptMinidumps) {
311   MockMinidump dump;
312   TestSymbolSupplier supplier;
313   BasicSourceLineResolver resolver;
314   MinidumpProcessor processor(&supplier, &resolver);
315   ProcessState state;
316
317   EXPECT_EQ(processor.Process("nonexistent minidump", &state),
318             google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND);
319
320   EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
321   EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
322
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));
328
329   EXPECT_EQ(processor.Process(&dump, &state),
330             google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER);
331
332   EXPECT_CALL(dump, GetThreadList()).
333       WillOnce(Return(reinterpret_cast<MinidumpThreadList*>(NULL)));
334   EXPECT_CALL(dump, GetSystemInfo()).
335       WillRepeatedly(Return(reinterpret_cast<MinidumpSystemInfo*>(NULL)));
336
337   EXPECT_EQ(processor.Process(&dump, &state),
338             google_breakpad::PROCESS_ERROR_NO_THREAD_LIST);
339 }
340
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);
347
348   string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") +
349                          "/src/processor/testdata/minidump2.dmp";
350   ProcessState state;
351   EXPECT_CALL(supplier, GetCStringSymbolData(
352       Property(&google_breakpad::CodeModule::code_file,
353                "c:\\test_app.exe"),
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);
364
365   ASSERT_TRUE(Mock::VerifyAndClearExpectations(&supplier));
366
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,
371                "c:\\test_app.exe"),
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);
382 }
383
384 TEST_F(MinidumpProcessorTest, TestBasicProcessing) {
385   TestSymbolSupplier supplier;
386   BasicSourceLineResolver resolver;
387   MinidumpProcessor processor(&supplier, &resolver);
388
389   string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") +
390                          "/src/processor/testdata/minidump2.dmp";
391
392   ProcessState state;
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);
405
406   CallStack *stack = state.threads()->at(0);
407   ASSERT_TRUE(stack);
408   ASSERT_EQ(stack->frames()->size(), 4U);
409
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);
417
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);
424
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);
433
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);
442
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(),
450             "kernel32.pdb");
451   ASSERT_EQ(state.modules()->GetModuleForAddress(0x77d43210)->version(),
452             "5.1.2600.2622");
453
454   // Test that disabled exploitability engine defaults to
455   // EXPLOITABILITY_NOT_ANALYZED.
456   ASSERT_EQ(google_breakpad::EXPLOITABILITY_NOT_ANALYZED,
457             state.exploitability());
458
459   // Test that the symbol supplier can interrupt processing
460   state.Clear();
461   supplier.set_interrupt(true);
462   ASSERT_EQ(processor.Process(minidump_file, &state),
463             google_breakpad::PROCESS_SYMBOL_SUPPLIER_INTERRUPTED);
464 }
465
466 TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) {
467   MockMinidump dump;
468   EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
469   EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
470
471   MDRawHeader fake_header;
472   fake_header.time_date_stamp = 0;
473   EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
474
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);
480
481   EXPECT_CALL(dump, GetSystemInfo()).
482       WillRepeatedly(Return(&dump_system_info));
483
484   MockMinidumpThreadList thread_list;
485   EXPECT_CALL(dump, GetThreadList()).
486       WillOnce(Return(&thread_list));
487
488   MockMinidumpMemoryList memory_list;
489   EXPECT_CALL(dump, GetMemoryList()).
490       WillOnce(Return(&memory_list));
491
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),
496                          Return(true)));
497   EXPECT_CALL(no_memory_thread, GetMemory()).
498     WillRepeatedly(Return(reinterpret_cast<MinidumpMemoryRegion*>(NULL)));
499
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)));
505
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));
515
516   EXPECT_CALL(thread_list, thread_count()).
517     WillRepeatedly(Return(1));
518   EXPECT_CALL(thread_list, GetThreadAtIndex(0)).
519     WillOnce(Return(&no_memory_thread));
520
521   MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
522   ProcessState state;
523   EXPECT_EQ(processor.Process(&dump, &state),
524             google_breakpad::PROCESS_OK);
525
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);
530 }
531
532 TEST_F(MinidumpProcessorTest, TestThreadMissingContext) {
533   MockMinidump dump;
534   EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
535   EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
536
537   MDRawHeader fake_header;
538   fake_header.time_date_stamp = 0;
539   EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
540
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);
546
547   EXPECT_CALL(dump, GetSystemInfo()).
548       WillRepeatedly(Return(&dump_system_info));
549
550   MockMinidumpThreadList thread_list;
551   EXPECT_CALL(dump, GetThreadList()).
552       WillOnce(Return(&thread_list));
553
554   MockMinidumpMemoryList memory_list;
555   EXPECT_CALL(dump, GetMemoryList()).
556       WillOnce(Return(&memory_list));
557
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),
562                          Return(true)));
563   EXPECT_CALL(no_context_thread, GetContext()).
564     WillRepeatedly(Return(reinterpret_cast<MinidumpContext*>(NULL)));
565
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()).
571     Times(0);
572   EXPECT_CALL(memory_list, GetMemoryRegionForAddress(_)).
573     Times(0);
574
575   EXPECT_CALL(thread_list, thread_count()).
576     WillRepeatedly(Return(1));
577   EXPECT_CALL(thread_list, GetThreadAtIndex(0)).
578     WillOnce(Return(&no_context_thread));
579
580   MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
581   ProcessState state;
582   EXPECT_EQ(processor.Process(&dump, &state),
583             google_breakpad::PROCESS_OK);
584
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());
588 }
589
590 }  // namespace
591
592 int main(int argc, char *argv[]) {
593   ::testing::InitGoogleTest(&argc, argv);
594   return RUN_ALL_TESTS();
595 }