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
56using std::map;
57
58namespace google_breakpad {
59class 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(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
77class MockMinidumpThreadList : public MinidumpThreadList {
78 public:
79  MockMinidumpThreadList() : MinidumpThreadList(NULL) {}
80
81  MOCK_CONST_METHOD0(thread_count, unsigned int());
82  MOCK_CONST_METHOD1(GetThreadAtIndex, MinidumpThread*(unsigned int));
83};
84
85class MockMinidumpMemoryList : public MinidumpMemoryList {
86 public:
87  MockMinidumpMemoryList() : MinidumpMemoryList(NULL) {}
88
89  MOCK_METHOD1(GetMemoryRegionForAddress, MinidumpMemoryRegion*(uint64_t));
90};
91
92class MockMinidumpThread : public MinidumpThread {
93 public:
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.
104class MockMinidumpMemoryRegion : public MinidumpMemoryRegion {
105 public:
106  MockMinidumpMemoryRegion(uint64_t base, const string& contents) :
107      MinidumpMemoryRegion(NULL) {
108    region_.Init(base, contents);
109  }
110
111  uint64_t GetBase() const { return region_.GetBase(); }
112  uint32_t GetSize() const { return region_.GetSize(); }
113
114  bool GetMemoryAtAddress(uint64_t address, uint8_t  *value) const {
115    return region_.GetMemoryAtAddress(address, value);
116  }
117  bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
118    return region_.GetMemoryAtAddress(address, value);
119  }
120  bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
121    return region_.GetMemoryAtAddress(address, value);
122  }
123  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.
132class TestMinidumpMiscInfo : public MinidumpMiscInfo {
133 public:
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
143namespace {
144
145using google_breakpad::BasicSourceLineResolver;
146using google_breakpad::CallStack;
147using google_breakpad::CodeModule;
148using google_breakpad::MinidumpContext;
149using google_breakpad::MinidumpMemoryRegion;
150using google_breakpad::MinidumpMiscInfo;
151using google_breakpad::MinidumpProcessor;
152using google_breakpad::MinidumpSystemInfo;
153using google_breakpad::MinidumpThreadList;
154using google_breakpad::MinidumpThread;
155using google_breakpad::MockMinidump;
156using google_breakpad::MockMinidumpMemoryList;
157using google_breakpad::MockMinidumpMemoryRegion;
158using google_breakpad::MockMinidumpThread;
159using google_breakpad::MockMinidumpThreadList;
160using google_breakpad::ProcessState;
161using google_breakpad::scoped_ptr;
162using google_breakpad::SymbolSupplier;
163using google_breakpad::SystemInfo;
164using ::testing::_;
165using ::testing::AnyNumber;
166using ::testing::DoAll;
167using ::testing::Mock;
168using ::testing::Ne;
169using ::testing::Property;
170using ::testing::Return;
171using ::testing::SetArgumentPointee;
172
173static const char *kSystemInfoOS = "Windows NT";
174static const char *kSystemInfoOSShort = "windows";
175static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2";
176static const char *kSystemInfoCPU = "x86";
177static 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
188class TestSymbolSupplier : public SymbolSupplier {
189 public:
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
210  void set_interrupt(bool interrupt) { interrupt_ = interrupt; }
211
212 private:
213  bool interrupt_;
214  map<string, char *> memory_buffers_;
215};
216
217SymbolSupplier::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
244SymbolSupplier::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
261SymbolSupplier::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
288void 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.
298class TestMinidumpSystemInfo : public MinidumpSystemInfo {
299 public:
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.
310class TestMinidumpContext : public MinidumpContext {
311 public:
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
320class MinidumpProcessorTest : public ::testing::Test {
321};
322
323TEST_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.
356TEST_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
397TEST_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
481TEST_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
547TEST_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
581TEST_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
641int main(int argc, char *argv[]) {
642  ::testing::InitGoogleTest(&argc, argv);
643  return RUN_ALL_TESTS();
644}
645