1// Copyright (c) 2010, 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 Minidump.  Uses a pre-generated minidump and
31// verifies that certain streams are correct.
32
33#include <iostream>
34#include <fstream>
35#include <sstream>
36#include <stdlib.h>
37#include <string>
38#include <vector>
39
40#include "breakpad_googletest_includes.h"
41#include "common/using_std_string.h"
42#include "google_breakpad/common/minidump_format.h"
43#include "google_breakpad/processor/minidump.h"
44#include "processor/logging.h"
45#include "processor/synth_minidump.h"
46
47namespace {
48
49using google_breakpad::Minidump;
50using google_breakpad::MinidumpContext;
51using google_breakpad::MinidumpException;
52using google_breakpad::MinidumpMemoryInfo;
53using google_breakpad::MinidumpMemoryInfoList;
54using google_breakpad::MinidumpMemoryList;
55using google_breakpad::MinidumpMemoryRegion;
56using google_breakpad::MinidumpModule;
57using google_breakpad::MinidumpModuleList;
58using google_breakpad::MinidumpSystemInfo;
59using google_breakpad::MinidumpThread;
60using google_breakpad::MinidumpThreadList;
61using google_breakpad::SynthMinidump::Context;
62using google_breakpad::SynthMinidump::Dump;
63using google_breakpad::SynthMinidump::Exception;
64using google_breakpad::SynthMinidump::Memory;
65using google_breakpad::SynthMinidump::Module;
66using google_breakpad::SynthMinidump::Stream;
67using google_breakpad::SynthMinidump::String;
68using google_breakpad::SynthMinidump::SystemInfo;
69using google_breakpad::SynthMinidump::Thread;
70using google_breakpad::test_assembler::kBigEndian;
71using google_breakpad::test_assembler::kLittleEndian;
72using std::ifstream;
73using std::istringstream;
74using std::vector;
75using ::testing::Return;
76
77class MinidumpTest : public ::testing::Test {
78public:
79  void SetUp() {
80    minidump_file_ = string(getenv("srcdir") ? getenv("srcdir") : ".") +
81      "/src/processor/testdata/minidump2.dmp";
82  }
83  string minidump_file_;
84};
85
86TEST_F(MinidumpTest, TestMinidumpFromFile) {
87  Minidump minidump(minidump_file_);
88  ASSERT_EQ(minidump.path(), minidump_file_);
89  ASSERT_TRUE(minidump.Read());
90  const MDRawHeader* header = minidump.header();
91  ASSERT_NE(header, (MDRawHeader*)NULL);
92  ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE));
93  //TODO: add more checks here
94}
95
96TEST_F(MinidumpTest, TestMinidumpFromStream) {
97  // read minidump contents into memory, construct a stringstream around them
98  ifstream file_stream(minidump_file_.c_str(), std::ios::in);
99  ASSERT_TRUE(file_stream.good());
100  vector<char> bytes;
101  file_stream.seekg(0, std::ios_base::end);
102  ASSERT_TRUE(file_stream.good());
103  bytes.resize(file_stream.tellg());
104  file_stream.seekg(0, std::ios_base::beg);
105  ASSERT_TRUE(file_stream.good());
106  file_stream.read(&bytes[0], bytes.size());
107  ASSERT_TRUE(file_stream.good());
108  string str(&bytes[0], bytes.size());
109  istringstream stream(str);
110  ASSERT_TRUE(stream.good());
111
112  // now read minidump from stringstream
113  Minidump minidump(stream);
114  ASSERT_EQ(minidump.path(), "");
115  ASSERT_TRUE(minidump.Read());
116  const MDRawHeader* header = minidump.header();
117  ASSERT_NE(header, (MDRawHeader*)NULL);
118  ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE));
119  //TODO: add more checks here
120}
121
122TEST(Dump, ReadBackEmpty) {
123  Dump dump(0);
124  dump.Finish();
125  string contents;
126  ASSERT_TRUE(dump.GetContents(&contents));
127  istringstream stream(contents);
128  Minidump minidump(stream);
129  ASSERT_TRUE(minidump.Read());
130  ASSERT_EQ(0U, minidump.GetDirectoryEntryCount());
131}
132
133TEST(Dump, ReadBackEmptyBigEndian) {
134  Dump big_minidump(0, kBigEndian);
135  big_minidump.Finish();
136  string contents;
137  ASSERT_TRUE(big_minidump.GetContents(&contents));
138  istringstream stream(contents);
139  Minidump minidump(stream);
140  ASSERT_TRUE(minidump.Read());
141  ASSERT_EQ(0U, minidump.GetDirectoryEntryCount());
142}
143
144TEST(Dump, OneStream) {
145  Dump dump(0, kBigEndian);
146  Stream stream(dump, 0xfbb7fa2bU);
147  stream.Append("stream contents");
148  dump.Add(&stream);
149  dump.Finish();
150
151  string contents;
152  ASSERT_TRUE(dump.GetContents(&contents));
153  istringstream minidump_stream(contents);
154  Minidump minidump(minidump_stream);
155  ASSERT_TRUE(minidump.Read());
156  ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
157
158  const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
159  ASSERT_TRUE(dir != NULL);
160  EXPECT_EQ(0xfbb7fa2bU, dir->stream_type);
161
162  uint32_t stream_length;
163  ASSERT_TRUE(minidump.SeekToStreamType(0xfbb7fa2bU, &stream_length));
164  ASSERT_EQ(15U, stream_length);
165  char stream_contents[15];
166  ASSERT_TRUE(minidump.ReadBytes(stream_contents, sizeof(stream_contents)));
167  EXPECT_EQ(string("stream contents"),
168            string(stream_contents, sizeof(stream_contents)));
169
170  EXPECT_FALSE(minidump.GetThreadList());
171  EXPECT_FALSE(minidump.GetModuleList());
172  EXPECT_FALSE(minidump.GetMemoryList());
173  EXPECT_FALSE(minidump.GetException());
174  EXPECT_FALSE(minidump.GetAssertion());
175  EXPECT_FALSE(minidump.GetSystemInfo());
176  EXPECT_FALSE(minidump.GetMiscInfo());
177  EXPECT_FALSE(minidump.GetBreakpadInfo());
178}
179
180TEST(Dump, OneMemory) {
181  Dump dump(0, kBigEndian);
182  Memory memory(dump, 0x309d68010bd21b2cULL);
183  memory.Append("memory contents");
184  dump.Add(&memory);
185  dump.Finish();
186
187  string contents;
188  ASSERT_TRUE(dump.GetContents(&contents));
189  istringstream minidump_stream(contents);
190  Minidump minidump(minidump_stream);
191  ASSERT_TRUE(minidump.Read());
192  ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
193
194  const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
195  ASSERT_TRUE(dir != NULL);
196  EXPECT_EQ((uint32_t) MD_MEMORY_LIST_STREAM, dir->stream_type);
197
198  MinidumpMemoryList *memory_list = minidump.GetMemoryList();
199  ASSERT_TRUE(memory_list != NULL);
200  ASSERT_EQ(1U, memory_list->region_count());
201
202  MinidumpMemoryRegion *region1 = memory_list->GetMemoryRegionAtIndex(0);
203  ASSERT_EQ(0x309d68010bd21b2cULL, region1->GetBase());
204  ASSERT_EQ(15U, region1->GetSize());
205  const uint8_t *region1_bytes = region1->GetMemory();
206  ASSERT_TRUE(memcmp("memory contents", region1_bytes, 15) == 0);
207}
208
209// One thread --- and its requisite entourage.
210TEST(Dump, OneThread) {
211  Dump dump(0, kLittleEndian);
212  Memory stack(dump, 0x2326a0fa);
213  stack.Append("stack for thread");
214
215  MDRawContextX86 raw_context;
216  const uint32_t kExpectedEIP = 0x6913f540;
217  raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL;
218  raw_context.edi = 0x3ecba80d;
219  raw_context.esi = 0x382583b9;
220  raw_context.ebx = 0x7fccc03f;
221  raw_context.edx = 0xf62f8ec2;
222  raw_context.ecx = 0x46a6a6a8;
223  raw_context.eax = 0x6a5025e2;
224  raw_context.ebp = 0xd9fabb4a;
225  raw_context.eip = kExpectedEIP;
226  raw_context.cs = 0xbffe6eda;
227  raw_context.eflags = 0xb2ce1e2d;
228  raw_context.esp = 0x659caaa4;
229  raw_context.ss = 0x2e951ef7;
230  Context context(dump, raw_context);
231
232  Thread thread(dump, 0xa898f11b, stack, context,
233                0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL);
234
235  dump.Add(&stack);
236  dump.Add(&context);
237  dump.Add(&thread);
238  dump.Finish();
239
240  string contents;
241  ASSERT_TRUE(dump.GetContents(&contents));
242
243  istringstream minidump_stream(contents);
244  Minidump minidump(minidump_stream);
245  ASSERT_TRUE(minidump.Read());
246  ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
247
248  MinidumpMemoryList *md_memory_list = minidump.GetMemoryList();
249  ASSERT_TRUE(md_memory_list != NULL);
250  ASSERT_EQ(1U, md_memory_list->region_count());
251
252  MinidumpMemoryRegion *md_region = md_memory_list->GetMemoryRegionAtIndex(0);
253  ASSERT_EQ(0x2326a0faU, md_region->GetBase());
254  ASSERT_EQ(16U, md_region->GetSize());
255  const uint8_t *region_bytes = md_region->GetMemory();
256  ASSERT_TRUE(memcmp("stack for thread", region_bytes, 16) == 0);
257
258  MinidumpThreadList *thread_list = minidump.GetThreadList();
259  ASSERT_TRUE(thread_list != NULL);
260  ASSERT_EQ(1U, thread_list->thread_count());
261
262  MinidumpThread *md_thread = thread_list->GetThreadAtIndex(0);
263  ASSERT_TRUE(md_thread != NULL);
264  uint32_t thread_id;
265  ASSERT_TRUE(md_thread->GetThreadID(&thread_id));
266  ASSERT_EQ(0xa898f11bU, thread_id);
267  MinidumpMemoryRegion *md_stack = md_thread->GetMemory();
268  ASSERT_TRUE(md_stack != NULL);
269  ASSERT_EQ(0x2326a0faU, md_stack->GetBase());
270  ASSERT_EQ(16U, md_stack->GetSize());
271  const uint8_t *md_stack_bytes = md_stack->GetMemory();
272  ASSERT_TRUE(memcmp("stack for thread", md_stack_bytes, 16) == 0);
273
274  MinidumpContext *md_context = md_thread->GetContext();
275  ASSERT_TRUE(md_context != NULL);
276  ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
277
278  uint64_t eip;
279  ASSERT_TRUE(md_context->GetInstructionPointer(&eip));
280  EXPECT_EQ(kExpectedEIP, eip);
281
282  const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
283  ASSERT_TRUE(md_raw_context != NULL);
284  ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL),
285            (md_raw_context->context_flags
286             & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL)));
287  EXPECT_EQ(0x3ecba80dU, raw_context.edi);
288  EXPECT_EQ(0x382583b9U, raw_context.esi);
289  EXPECT_EQ(0x7fccc03fU, raw_context.ebx);
290  EXPECT_EQ(0xf62f8ec2U, raw_context.edx);
291  EXPECT_EQ(0x46a6a6a8U, raw_context.ecx);
292  EXPECT_EQ(0x6a5025e2U, raw_context.eax);
293  EXPECT_EQ(0xd9fabb4aU, raw_context.ebp);
294  EXPECT_EQ(kExpectedEIP, raw_context.eip);
295  EXPECT_EQ(0xbffe6edaU, raw_context.cs);
296  EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags);
297  EXPECT_EQ(0x659caaa4U, raw_context.esp);
298  EXPECT_EQ(0x2e951ef7U, raw_context.ss);
299}
300
301TEST(Dump, ThreadMissingMemory) {
302  Dump dump(0, kLittleEndian);
303  Memory stack(dump, 0x2326a0fa);
304  // Stack has no contents.
305
306  MDRawContextX86 raw_context;
307  memset(&raw_context, 0, sizeof(raw_context));
308  raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL;
309  Context context(dump, raw_context);
310
311  Thread thread(dump, 0xa898f11b, stack, context,
312                0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL);
313
314  dump.Add(&stack);
315  dump.Add(&context);
316  dump.Add(&thread);
317  dump.Finish();
318
319  string contents;
320  ASSERT_TRUE(dump.GetContents(&contents));
321
322  istringstream minidump_stream(contents);
323  Minidump minidump(minidump_stream);
324  ASSERT_TRUE(minidump.Read());
325  ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
326
327  // This should succeed even though the thread has no stack memory.
328  MinidumpThreadList* thread_list = minidump.GetThreadList();
329  ASSERT_TRUE(thread_list != NULL);
330  ASSERT_EQ(1U, thread_list->thread_count());
331
332  MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0);
333  ASSERT_TRUE(md_thread != NULL);
334
335  uint32_t thread_id;
336  ASSERT_TRUE(md_thread->GetThreadID(&thread_id));
337  ASSERT_EQ(0xa898f11bU, thread_id);
338
339  MinidumpContext* md_context = md_thread->GetContext();
340  ASSERT_NE(reinterpret_cast<MinidumpContext*>(NULL), md_context);
341
342  MinidumpMemoryRegion* md_stack = md_thread->GetMemory();
343  ASSERT_EQ(reinterpret_cast<MinidumpMemoryRegion*>(NULL), md_stack);
344}
345
346TEST(Dump, ThreadMissingContext) {
347  Dump dump(0, kLittleEndian);
348  Memory stack(dump, 0x2326a0fa);
349  stack.Append("stack for thread");
350
351  // Context is empty.
352  Context context(dump);
353
354  Thread thread(dump, 0xa898f11b, stack, context,
355                0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL);
356
357  dump.Add(&stack);
358  dump.Add(&context);
359  dump.Add(&thread);
360  dump.Finish();
361
362  string contents;
363  ASSERT_TRUE(dump.GetContents(&contents));
364
365  istringstream minidump_stream(contents);
366  Minidump minidump(minidump_stream);
367  ASSERT_TRUE(minidump.Read());
368  ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
369
370  // This should succeed even though the thread has no stack memory.
371  MinidumpThreadList* thread_list = minidump.GetThreadList();
372  ASSERT_TRUE(thread_list != NULL);
373  ASSERT_EQ(1U, thread_list->thread_count());
374
375  MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0);
376  ASSERT_TRUE(md_thread != NULL);
377
378  uint32_t thread_id;
379  ASSERT_TRUE(md_thread->GetThreadID(&thread_id));
380  ASSERT_EQ(0xa898f11bU, thread_id);
381  MinidumpMemoryRegion* md_stack = md_thread->GetMemory();
382  ASSERT_NE(reinterpret_cast<MinidumpMemoryRegion*>(NULL), md_stack);
383
384  MinidumpContext* md_context = md_thread->GetContext();
385  ASSERT_EQ(reinterpret_cast<MinidumpContext*>(NULL), md_context);
386}
387
388TEST(Dump, OneModule) {
389  static const MDVSFixedFileInfo fixed_file_info = {
390    0xb2fba33a,                           // signature
391    0x33d7a728,                           // struct_version
392    0x31afcb20,                           // file_version_hi
393    0xe51cdab1,                           // file_version_lo
394    0xd1ea6907,                           // product_version_hi
395    0x03032857,                           // product_version_lo
396    0x11bf71d7,                           // file_flags_mask
397    0x5fb8cdbf,                           // file_flags
398    0xe45d0d5d,                           // file_os
399    0x107d9562,                           // file_type
400    0x5a8844d4,                           // file_subtype
401    0xa8d30b20,                           // file_date_hi
402    0x651c3e4e                            // file_date_lo
403  };
404
405  Dump dump(0, kBigEndian);
406  String module_name(dump, "single module");
407  Module module(dump, 0xa90206ca83eb2852ULL, 0xada542bd,
408                module_name,
409                0xb1054d2a,
410                0x34571371,
411                fixed_file_info, // from synth_minidump_unittest_data.h
412                NULL, NULL);
413
414  dump.Add(&module);
415  dump.Add(&module_name);
416  dump.Finish();
417
418  string contents;
419  ASSERT_TRUE(dump.GetContents(&contents));
420  istringstream minidump_stream(contents);
421  Minidump minidump(minidump_stream);
422  ASSERT_TRUE(minidump.Read());
423  ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
424
425  const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
426  ASSERT_TRUE(dir != NULL);
427  EXPECT_EQ((uint32_t) MD_MODULE_LIST_STREAM, dir->stream_type);
428
429  MinidumpModuleList *md_module_list = minidump.GetModuleList();
430  ASSERT_TRUE(md_module_list != NULL);
431  ASSERT_EQ(1U, md_module_list->module_count());
432
433  const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0);
434  ASSERT_TRUE(md_module != NULL);
435  ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address());
436  ASSERT_EQ(0xada542bd, md_module->size());
437  ASSERT_EQ("single module", md_module->code_file());
438
439  const MDRawModule *md_raw_module = md_module->module();
440  ASSERT_TRUE(md_raw_module != NULL);
441  ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp);
442  ASSERT_EQ(0x34571371U, md_raw_module->checksum);
443  ASSERT_TRUE(memcmp(&md_raw_module->version_info, &fixed_file_info,
444                     sizeof(fixed_file_info)) == 0);
445}
446
447TEST(Dump, OneSystemInfo) {
448  Dump dump(0, kLittleEndian);
449  String csd_version(dump, "Petulant Pierogi");
450  SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version);
451
452  dump.Add(&system_info);
453  dump.Add(&csd_version);
454  dump.Finish();
455
456  string contents;
457  ASSERT_TRUE(dump.GetContents(&contents));
458  istringstream minidump_stream(contents);
459  Minidump minidump(minidump_stream);
460  ASSERT_TRUE(minidump.Read());
461  ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
462
463  const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
464  ASSERT_TRUE(dir != NULL);
465  EXPECT_EQ((uint32_t) MD_SYSTEM_INFO_STREAM, dir->stream_type);
466
467  MinidumpSystemInfo *md_system_info = minidump.GetSystemInfo();
468  ASSERT_TRUE(md_system_info != NULL);
469  ASSERT_EQ("windows", md_system_info->GetOS());
470  ASSERT_EQ("x86", md_system_info->GetCPU());
471  ASSERT_EQ("Petulant Pierogi", *md_system_info->GetCSDVersion());
472  ASSERT_EQ("GenuineIntel", *md_system_info->GetCPUVendor());
473}
474
475TEST(Dump, BigDump) {
476  Dump dump(0, kLittleEndian);
477
478  // A SystemInfo stream.
479  String csd_version(dump, "Munificent Macaque");
480  SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version);
481  dump.Add(&csd_version);
482  dump.Add(&system_info);
483
484  // Five threads!
485  Memory stack0(dump, 0x70b9ebfc);
486  stack0.Append("stack for thread zero");
487  MDRawContextX86 raw_context0;
488  raw_context0.context_flags = MD_CONTEXT_X86_INTEGER;
489  raw_context0.eip = 0xaf0709e4;
490  Context context0(dump, raw_context0);
491  Thread thread0(dump, 0xbbef4432, stack0, context0,
492                 0xd0377e7b, 0xdb8eb0cf, 0xd73bc314, 0x09d357bac7f9a163ULL);
493  dump.Add(&stack0);
494  dump.Add(&context0);
495  dump.Add(&thread0);
496
497  Memory stack1(dump, 0xf988cc45);
498  stack1.Append("stack for thread one");
499  MDRawContextX86 raw_context1;
500  raw_context1.context_flags = MD_CONTEXT_X86_INTEGER;
501  raw_context1.eip = 0xe4f56f81;
502  Context context1(dump, raw_context1);
503  Thread thread1(dump, 0x657c3f58, stack1, context1,
504                 0xa68fa182, 0x6f3cf8dd, 0xe3a78ccf, 0x78cc84775e4534bbULL);
505  dump.Add(&stack1);
506  dump.Add(&context1);
507  dump.Add(&thread1);
508
509  Memory stack2(dump, 0xc8a92e7c);
510  stack2.Append("stack for thread two");
511  MDRawContextX86 raw_context2;
512  raw_context2.context_flags = MD_CONTEXT_X86_INTEGER;
513  raw_context2.eip = 0xb336a438;
514  Context context2(dump, raw_context2);
515  Thread thread2(dump, 0xdf4b8a71, stack2, context2,
516                 0x674c26b6, 0x445d7120, 0x7e700c56, 0xd89bf778e7793e17ULL);
517  dump.Add(&stack2);
518  dump.Add(&context2);
519  dump.Add(&thread2);
520
521  Memory stack3(dump, 0x36d08e08);
522  stack3.Append("stack for thread three");
523  MDRawContextX86 raw_context3;
524  raw_context3.context_flags = MD_CONTEXT_X86_INTEGER;
525  raw_context3.eip = 0xdf99a60c;
526  Context context3(dump, raw_context3);
527  Thread thread3(dump, 0x86e6c341, stack3, context3,
528                 0x32dc5c55, 0x17a2aba8, 0xe0cc75e7, 0xa46393994dae83aeULL);
529  dump.Add(&stack3);
530  dump.Add(&context3);
531  dump.Add(&thread3);
532
533  Memory stack4(dump, 0x1e0ab4fa);
534  stack4.Append("stack for thread four");
535  MDRawContextX86 raw_context4;
536  raw_context4.context_flags = MD_CONTEXT_X86_INTEGER;
537  raw_context4.eip = 0xaa646267;
538  Context context4(dump, raw_context4);
539  Thread thread4(dump, 0x261a28d4, stack4, context4,
540                 0x6ebd389e, 0xa0cd4759, 0x30168846, 0x164f650a0cf39d35ULL);
541  dump.Add(&stack4);
542  dump.Add(&context4);
543  dump.Add(&thread4);
544
545  // Three modules!
546  String module1_name(dump, "module one");
547  Module module1(dump, 0xeb77da57b5d4cbdaULL, 0x83cd5a37, module1_name);
548  dump.Add(&module1_name);
549  dump.Add(&module1);
550
551  String module2_name(dump, "module two");
552  Module module2(dump, 0x8675884adfe5ac90ULL, 0xb11e4ea3, module2_name);
553  dump.Add(&module2_name);
554  dump.Add(&module2);
555
556  String module3_name(dump, "module three");
557  Module module3(dump, 0x95fc1544da321b6cULL, 0x7c2bf081, module3_name);
558  dump.Add(&module3_name);
559  dump.Add(&module3);
560
561  // Add one more memory region, on top of the five stacks.
562  Memory memory5(dump, 0x61979e828040e564ULL);
563  memory5.Append("contents of memory 5");
564  dump.Add(&memory5);
565
566  dump.Finish();
567
568  string contents;
569  ASSERT_TRUE(dump.GetContents(&contents));
570  istringstream minidump_stream(contents);
571  Minidump minidump(minidump_stream);
572  ASSERT_TRUE(minidump.Read());
573  ASSERT_EQ(4U, minidump.GetDirectoryEntryCount());
574
575  // Check the threads.
576  MinidumpThreadList *thread_list = minidump.GetThreadList();
577  ASSERT_TRUE(thread_list != NULL);
578  ASSERT_EQ(5U, thread_list->thread_count());
579  uint32_t thread_id;
580  ASSERT_TRUE(thread_list->GetThreadAtIndex(0)->GetThreadID(&thread_id));
581  ASSERT_EQ(0xbbef4432U, thread_id);
582  ASSERT_EQ(0x70b9ebfcU,
583            thread_list->GetThreadAtIndex(0)->GetMemory()->GetBase());
584  ASSERT_EQ(0xaf0709e4U,
585            thread_list->GetThreadAtIndex(0)->GetContext()->GetContextX86()
586            ->eip);
587
588  ASSERT_TRUE(thread_list->GetThreadAtIndex(1)->GetThreadID(&thread_id));
589  ASSERT_EQ(0x657c3f58U, thread_id);
590  ASSERT_EQ(0xf988cc45U,
591            thread_list->GetThreadAtIndex(1)->GetMemory()->GetBase());
592  ASSERT_EQ(0xe4f56f81U,
593            thread_list->GetThreadAtIndex(1)->GetContext()->GetContextX86()
594            ->eip);
595
596  ASSERT_TRUE(thread_list->GetThreadAtIndex(2)->GetThreadID(&thread_id));
597  ASSERT_EQ(0xdf4b8a71U, thread_id);
598  ASSERT_EQ(0xc8a92e7cU,
599            thread_list->GetThreadAtIndex(2)->GetMemory()->GetBase());
600  ASSERT_EQ(0xb336a438U,
601            thread_list->GetThreadAtIndex(2)->GetContext()->GetContextX86()
602            ->eip);
603
604  ASSERT_TRUE(thread_list->GetThreadAtIndex(3)->GetThreadID(&thread_id));
605  ASSERT_EQ(0x86e6c341U, thread_id);
606  ASSERT_EQ(0x36d08e08U,
607            thread_list->GetThreadAtIndex(3)->GetMemory()->GetBase());
608  ASSERT_EQ(0xdf99a60cU,
609            thread_list->GetThreadAtIndex(3)->GetContext()->GetContextX86()
610            ->eip);
611
612  ASSERT_TRUE(thread_list->GetThreadAtIndex(4)->GetThreadID(&thread_id));
613  ASSERT_EQ(0x261a28d4U, thread_id);
614  ASSERT_EQ(0x1e0ab4faU,
615            thread_list->GetThreadAtIndex(4)->GetMemory()->GetBase());
616  ASSERT_EQ(0xaa646267U,
617            thread_list->GetThreadAtIndex(4)->GetContext()->GetContextX86()
618            ->eip);
619
620  // Check the modules.
621  MinidumpModuleList *md_module_list = minidump.GetModuleList();
622  ASSERT_TRUE(md_module_list != NULL);
623  ASSERT_EQ(3U, md_module_list->module_count());
624  EXPECT_EQ(0xeb77da57b5d4cbdaULL,
625            md_module_list->GetModuleAtIndex(0)->base_address());
626  EXPECT_EQ(0x8675884adfe5ac90ULL,
627            md_module_list->GetModuleAtIndex(1)->base_address());
628  EXPECT_EQ(0x95fc1544da321b6cULL,
629            md_module_list->GetModuleAtIndex(2)->base_address());
630}
631
632TEST(Dump, OneMemoryInfo) {
633  Dump dump(0, kBigEndian);
634  Stream stream(dump, MD_MEMORY_INFO_LIST_STREAM);
635
636  // Add the MDRawMemoryInfoList header.
637  const uint64_t kNumberOfEntries = 1;
638  stream.D32(sizeof(MDRawMemoryInfoList))  // size_of_header
639        .D32(sizeof(MDRawMemoryInfo))      // size_of_entry
640        .D64(kNumberOfEntries);            // number_of_entries
641
642
643  // Now add a MDRawMemoryInfo entry.
644  const uint64_t kBaseAddress = 0x1000;
645  const uint64_t kRegionSize = 0x2000;
646  stream.D64(kBaseAddress)                         // base_address
647        .D64(kBaseAddress)                         // allocation_base
648        .D32(MD_MEMORY_PROTECT_EXECUTE_READWRITE)  // allocation_protection
649        .D32(0)                                    // __alignment1
650        .D64(kRegionSize)                          // region_size
651        .D32(MD_MEMORY_STATE_COMMIT)               // state
652        .D32(MD_MEMORY_PROTECT_EXECUTE_READWRITE)  // protection
653        .D32(MD_MEMORY_TYPE_PRIVATE)               // type
654        .D32(0);                                   // __alignment2
655
656  dump.Add(&stream);
657  dump.Finish();
658
659  string contents;
660  ASSERT_TRUE(dump.GetContents(&contents));
661  istringstream minidump_stream(contents);
662  Minidump minidump(minidump_stream);
663  ASSERT_TRUE(minidump.Read());
664  ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
665
666  const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
667  ASSERT_TRUE(dir != NULL);
668  EXPECT_EQ((uint32_t) MD_MEMORY_INFO_LIST_STREAM, dir->stream_type);
669
670  MinidumpMemoryInfoList *info_list = minidump.GetMemoryInfoList();
671  ASSERT_TRUE(info_list != NULL);
672  ASSERT_EQ(1U, info_list->info_count());
673
674  const MinidumpMemoryInfo *info1 = info_list->GetMemoryInfoAtIndex(0);
675  ASSERT_EQ(kBaseAddress, info1->GetBase());
676  ASSERT_EQ(kRegionSize, info1->GetSize());
677  ASSERT_TRUE(info1->IsExecutable());
678  ASSERT_TRUE(info1->IsWritable());
679
680  // Should get back the same memory region here.
681  const MinidumpMemoryInfo *info2 =
682      info_list->GetMemoryInfoForAddress(kBaseAddress + kRegionSize / 2);
683  ASSERT_EQ(kBaseAddress, info2->GetBase());
684  ASSERT_EQ(kRegionSize, info2->GetSize());
685}
686
687TEST(Dump, OneExceptionX86) {
688  Dump dump(0, kLittleEndian);
689
690  MDRawContextX86 raw_context;
691  raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL;
692  raw_context.edi = 0x3ecba80d;
693  raw_context.esi = 0x382583b9;
694  raw_context.ebx = 0x7fccc03f;
695  raw_context.edx = 0xf62f8ec2;
696  raw_context.ecx = 0x46a6a6a8;
697  raw_context.eax = 0x6a5025e2;
698  raw_context.ebp = 0xd9fabb4a;
699  raw_context.eip = 0x6913f540;
700  raw_context.cs = 0xbffe6eda;
701  raw_context.eflags = 0xb2ce1e2d;
702  raw_context.esp = 0x659caaa4;
703  raw_context.ss = 0x2e951ef7;
704  Context context(dump, raw_context);
705
706  Exception exception(dump, context,
707                      0x1234abcd, // thread id
708                      0xdcba4321, // exception code
709                      0xf0e0d0c0, // exception flags
710                      0x0919a9b9c9d9e9f9ULL); // exception address
711
712  dump.Add(&context);
713  dump.Add(&exception);
714  dump.Finish();
715
716  string contents;
717  ASSERT_TRUE(dump.GetContents(&contents));
718
719  istringstream minidump_stream(contents);
720  Minidump minidump(minidump_stream);
721  ASSERT_TRUE(minidump.Read());
722  ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
723
724  MinidumpException *md_exception = minidump.GetException();
725  ASSERT_TRUE(md_exception != NULL);
726
727  uint32_t thread_id;
728  ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
729  ASSERT_EQ(0x1234abcdU, thread_id);
730
731  const MDRawExceptionStream* raw_exception = md_exception->exception();
732  ASSERT_TRUE(raw_exception != NULL);
733  EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
734  EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
735  EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
736            raw_exception->exception_record.exception_address);
737
738  MinidumpContext *md_context = md_exception->GetContext();
739  ASSERT_TRUE(md_context != NULL);
740  ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
741  const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
742  ASSERT_TRUE(md_raw_context != NULL);
743  ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL),
744            (md_raw_context->context_flags
745             & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL)));
746  EXPECT_EQ(0x3ecba80dU, raw_context.edi);
747  EXPECT_EQ(0x382583b9U, raw_context.esi);
748  EXPECT_EQ(0x7fccc03fU, raw_context.ebx);
749  EXPECT_EQ(0xf62f8ec2U, raw_context.edx);
750  EXPECT_EQ(0x46a6a6a8U, raw_context.ecx);
751  EXPECT_EQ(0x6a5025e2U, raw_context.eax);
752  EXPECT_EQ(0xd9fabb4aU, raw_context.ebp);
753  EXPECT_EQ(0x6913f540U, raw_context.eip);
754  EXPECT_EQ(0xbffe6edaU, raw_context.cs);
755  EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags);
756  EXPECT_EQ(0x659caaa4U, raw_context.esp);
757  EXPECT_EQ(0x2e951ef7U, raw_context.ss);
758}
759
760TEST(Dump, OneExceptionX86XState) {
761  Dump dump(0, kLittleEndian);
762
763  MDRawContextX86 raw_context;
764  raw_context.context_flags = MD_CONTEXT_X86_INTEGER |
765    MD_CONTEXT_X86_CONTROL | MD_CONTEXT_X86_XSTATE;
766  raw_context.edi = 0x3ecba80d;
767  raw_context.esi = 0x382583b9;
768  raw_context.ebx = 0x7fccc03f;
769  raw_context.edx = 0xf62f8ec2;
770  raw_context.ecx = 0x46a6a6a8;
771  raw_context.eax = 0x6a5025e2;
772  raw_context.ebp = 0xd9fabb4a;
773  raw_context.eip = 0x6913f540;
774  raw_context.cs = 0xbffe6eda;
775  raw_context.eflags = 0xb2ce1e2d;
776  raw_context.esp = 0x659caaa4;
777  raw_context.ss = 0x2e951ef7;
778  Context context(dump, raw_context);
779
780  Exception exception(dump, context,
781                      0x1234abcd, // thread id
782                      0xdcba4321, // exception code
783                      0xf0e0d0c0, // exception flags
784                      0x0919a9b9c9d9e9f9ULL); // exception address
785
786  dump.Add(&context);
787  dump.Add(&exception);
788  dump.Finish();
789
790  string contents;
791  ASSERT_TRUE(dump.GetContents(&contents));
792
793  istringstream minidump_stream(contents);
794  Minidump minidump(minidump_stream);
795  ASSERT_TRUE(minidump.Read());
796  ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
797
798  MinidumpException *md_exception = minidump.GetException();
799  ASSERT_TRUE(md_exception != NULL);
800
801  uint32_t thread_id;
802  ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
803  ASSERT_EQ(0x1234abcdU, thread_id);
804
805  const MDRawExceptionStream* raw_exception = md_exception->exception();
806  ASSERT_TRUE(raw_exception != NULL);
807  EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
808  EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
809  EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
810            raw_exception->exception_record.exception_address);
811
812  MinidumpContext *md_context = md_exception->GetContext();
813  ASSERT_TRUE(md_context != NULL);
814  ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
815  const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
816  ASSERT_TRUE(md_raw_context != NULL);
817  ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL),
818            (md_raw_context->context_flags
819             & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL)));
820  EXPECT_EQ(0x3ecba80dU, raw_context.edi);
821  EXPECT_EQ(0x382583b9U, raw_context.esi);
822  EXPECT_EQ(0x7fccc03fU, raw_context.ebx);
823  EXPECT_EQ(0xf62f8ec2U, raw_context.edx);
824  EXPECT_EQ(0x46a6a6a8U, raw_context.ecx);
825  EXPECT_EQ(0x6a5025e2U, raw_context.eax);
826  EXPECT_EQ(0xd9fabb4aU, raw_context.ebp);
827  EXPECT_EQ(0x6913f540U, raw_context.eip);
828  EXPECT_EQ(0xbffe6edaU, raw_context.cs);
829  EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags);
830  EXPECT_EQ(0x659caaa4U, raw_context.esp);
831  EXPECT_EQ(0x2e951ef7U, raw_context.ss);
832}
833
834// Testing that the CPU type can be loaded from a system info stream when
835// the CPU flags are missing from the context_flags of an exception record
836TEST(Dump, OneExceptionX86NoCPUFlags) {
837  Dump dump(0, kLittleEndian);
838
839  MDRawContextX86 raw_context;
840  // Intentionally not setting CPU type in the context_flags
841  raw_context.context_flags = 0;
842  raw_context.edi = 0x3ecba80d;
843  raw_context.esi = 0x382583b9;
844  raw_context.ebx = 0x7fccc03f;
845  raw_context.edx = 0xf62f8ec2;
846  raw_context.ecx = 0x46a6a6a8;
847  raw_context.eax = 0x6a5025e2;
848  raw_context.ebp = 0xd9fabb4a;
849  raw_context.eip = 0x6913f540;
850  raw_context.cs = 0xbffe6eda;
851  raw_context.eflags = 0xb2ce1e2d;
852  raw_context.esp = 0x659caaa4;
853  raw_context.ss = 0x2e951ef7;
854  Context context(dump, raw_context);
855
856  Exception exception(dump, context,
857                      0x1234abcd, // thread id
858                      0xdcba4321, // exception code
859                      0xf0e0d0c0, // exception flags
860                      0x0919a9b9c9d9e9f9ULL); // exception address
861
862  dump.Add(&context);
863  dump.Add(&exception);
864
865  // Add system info.  This is needed as an alternative source for CPU type
866  // information.  Note, that the CPU flags were intentionally skipped from
867  // the context_flags and this alternative source is required.
868  String csd_version(dump, "Service Pack 2");
869  SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version);
870  dump.Add(&system_info);
871  dump.Add(&csd_version);
872
873  dump.Finish();
874
875  string contents;
876  ASSERT_TRUE(dump.GetContents(&contents));
877
878  istringstream minidump_stream(contents);
879  Minidump minidump(minidump_stream);
880  ASSERT_TRUE(minidump.Read());
881  ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
882
883  MinidumpException *md_exception = minidump.GetException();
884  ASSERT_TRUE(md_exception != NULL);
885
886  uint32_t thread_id;
887  ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
888  ASSERT_EQ(0x1234abcdU, thread_id);
889
890  const MDRawExceptionStream* raw_exception = md_exception->exception();
891  ASSERT_TRUE(raw_exception != NULL);
892  EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
893  EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
894  EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
895            raw_exception->exception_record.exception_address);
896
897  MinidumpContext *md_context = md_exception->GetContext();
898  ASSERT_TRUE(md_context != NULL);
899
900  ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
901  const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
902  ASSERT_TRUE(md_raw_context != NULL);
903
904  // Even though the CPU flags were missing from the context_flags, the
905  // GetContext call above is expected to load the missing CPU flags from the
906  // system info stream and set the CPU type bits in context_flags.
907  ASSERT_EQ((uint32_t) (MD_CONTEXT_X86), md_raw_context->context_flags);
908
909  EXPECT_EQ(0x3ecba80dU, raw_context.edi);
910  EXPECT_EQ(0x382583b9U, raw_context.esi);
911  EXPECT_EQ(0x7fccc03fU, raw_context.ebx);
912  EXPECT_EQ(0xf62f8ec2U, raw_context.edx);
913  EXPECT_EQ(0x46a6a6a8U, raw_context.ecx);
914  EXPECT_EQ(0x6a5025e2U, raw_context.eax);
915  EXPECT_EQ(0xd9fabb4aU, raw_context.ebp);
916  EXPECT_EQ(0x6913f540U, raw_context.eip);
917  EXPECT_EQ(0xbffe6edaU, raw_context.cs);
918  EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags);
919  EXPECT_EQ(0x659caaa4U, raw_context.esp);
920  EXPECT_EQ(0x2e951ef7U, raw_context.ss);
921}
922
923// This test covers a scenario where a dump contains an exception but the
924// context record of the exception is missing the CPU type information in its
925// context_flags.  The dump has no system info stream so it is imposible to
926// deduce the CPU type, hence the context record is unusable.
927TEST(Dump, OneExceptionX86NoCPUFlagsNoSystemInfo) {
928  Dump dump(0, kLittleEndian);
929
930  MDRawContextX86 raw_context;
931  // Intentionally not setting CPU type in the context_flags
932  raw_context.context_flags = 0;
933  raw_context.edi = 0x3ecba80d;
934  raw_context.esi = 0x382583b9;
935  raw_context.ebx = 0x7fccc03f;
936  raw_context.edx = 0xf62f8ec2;
937  raw_context.ecx = 0x46a6a6a8;
938  raw_context.eax = 0x6a5025e2;
939  raw_context.ebp = 0xd9fabb4a;
940  raw_context.eip = 0x6913f540;
941  raw_context.cs = 0xbffe6eda;
942  raw_context.eflags = 0xb2ce1e2d;
943  raw_context.esp = 0x659caaa4;
944  raw_context.ss = 0x2e951ef7;
945  Context context(dump, raw_context);
946
947  Exception exception(dump, context,
948                      0x1234abcd, // thread id
949                      0xdcba4321, // exception code
950                      0xf0e0d0c0, // exception flags
951                      0x0919a9b9c9d9e9f9ULL); // exception address
952
953  dump.Add(&context);
954  dump.Add(&exception);
955  dump.Finish();
956
957  string contents;
958  ASSERT_TRUE(dump.GetContents(&contents));
959
960  istringstream minidump_stream(contents);
961  Minidump minidump(minidump_stream);
962  ASSERT_TRUE(minidump.Read());
963  ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
964
965  MinidumpException *md_exception = minidump.GetException();
966  ASSERT_TRUE(md_exception != NULL);
967
968  uint32_t thread_id;
969  ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
970  ASSERT_EQ(0x1234abcdU, thread_id);
971
972  const MDRawExceptionStream* raw_exception = md_exception->exception();
973  ASSERT_TRUE(raw_exception != NULL);
974  EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
975  EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
976  EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
977            raw_exception->exception_record.exception_address);
978
979  // The context record of the exception is unusable because the context_flags
980  // don't have CPU type information and at the same time the minidump lacks
981  // system info stream so it is impossible to deduce the CPU type.
982  MinidumpContext *md_context = md_exception->GetContext();
983  ASSERT_EQ(NULL, md_context);
984}
985
986TEST(Dump, OneExceptionARM) {
987  Dump dump(0, kLittleEndian);
988
989  MDRawContextARM raw_context;
990  raw_context.context_flags = MD_CONTEXT_ARM_INTEGER;
991  raw_context.iregs[0] = 0x3ecba80d;
992  raw_context.iregs[1] = 0x382583b9;
993  raw_context.iregs[2] = 0x7fccc03f;
994  raw_context.iregs[3] = 0xf62f8ec2;
995  raw_context.iregs[4] = 0x46a6a6a8;
996  raw_context.iregs[5] = 0x6a5025e2;
997  raw_context.iregs[6] = 0xd9fabb4a;
998  raw_context.iregs[7] = 0x6913f540;
999  raw_context.iregs[8] = 0xbffe6eda;
1000  raw_context.iregs[9] = 0xb2ce1e2d;
1001  raw_context.iregs[10] = 0x659caaa4;
1002  raw_context.iregs[11] = 0xf0e0d0c0;
1003  raw_context.iregs[12] = 0xa9b8c7d6;
1004  raw_context.iregs[13] = 0x12345678;
1005  raw_context.iregs[14] = 0xabcd1234;
1006  raw_context.iregs[15] = 0x10203040;
1007  raw_context.cpsr = 0x2e951ef7;
1008  Context context(dump, raw_context);
1009
1010  Exception exception(dump, context,
1011                      0x1234abcd, // thread id
1012                      0xdcba4321, // exception code
1013                      0xf0e0d0c0, // exception flags
1014                      0x0919a9b9c9d9e9f9ULL); // exception address
1015
1016  dump.Add(&context);
1017  dump.Add(&exception);
1018  dump.Finish();
1019
1020  string contents;
1021  ASSERT_TRUE(dump.GetContents(&contents));
1022
1023  istringstream minidump_stream(contents);
1024  Minidump minidump(minidump_stream);
1025  ASSERT_TRUE(minidump.Read());
1026  ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
1027
1028  MinidumpException *md_exception = minidump.GetException();
1029  ASSERT_TRUE(md_exception != NULL);
1030
1031  uint32_t thread_id;
1032  ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
1033  ASSERT_EQ(0x1234abcdU, thread_id);
1034
1035  const MDRawExceptionStream* raw_exception = md_exception->exception();
1036  ASSERT_TRUE(raw_exception != NULL);
1037  EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
1038  EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
1039  EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
1040            raw_exception->exception_record.exception_address);
1041
1042  MinidumpContext *md_context = md_exception->GetContext();
1043  ASSERT_TRUE(md_context != NULL);
1044  ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU());
1045  const MDRawContextARM *md_raw_context = md_context->GetContextARM();
1046  ASSERT_TRUE(md_raw_context != NULL);
1047  ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER,
1048            (md_raw_context->context_flags
1049             & MD_CONTEXT_ARM_INTEGER));
1050  EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]);
1051  EXPECT_EQ(0x382583b9U, raw_context.iregs[1]);
1052  EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]);
1053  EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]);
1054  EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]);
1055  EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]);
1056  EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]);
1057  EXPECT_EQ(0x6913f540U, raw_context.iregs[7]);
1058  EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]);
1059  EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]);
1060  EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]);
1061  EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]);
1062  EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]);
1063  EXPECT_EQ(0x12345678U, raw_context.iregs[13]);
1064  EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]);
1065  EXPECT_EQ(0x10203040U, raw_context.iregs[15]);
1066  EXPECT_EQ(0x2e951ef7U, raw_context.cpsr);
1067}
1068
1069TEST(Dump, OneExceptionARMOldFlags) {
1070  Dump dump(0, kLittleEndian);
1071
1072  MDRawContextARM raw_context;
1073  // MD_CONTEXT_ARM_INTEGER, but with _OLD
1074  raw_context.context_flags = MD_CONTEXT_ARM_OLD | 0x00000002;
1075  raw_context.iregs[0] = 0x3ecba80d;
1076  raw_context.iregs[1] = 0x382583b9;
1077  raw_context.iregs[2] = 0x7fccc03f;
1078  raw_context.iregs[3] = 0xf62f8ec2;
1079  raw_context.iregs[4] = 0x46a6a6a8;
1080  raw_context.iregs[5] = 0x6a5025e2;
1081  raw_context.iregs[6] = 0xd9fabb4a;
1082  raw_context.iregs[7] = 0x6913f540;
1083  raw_context.iregs[8] = 0xbffe6eda;
1084  raw_context.iregs[9] = 0xb2ce1e2d;
1085  raw_context.iregs[10] = 0x659caaa4;
1086  raw_context.iregs[11] = 0xf0e0d0c0;
1087  raw_context.iregs[12] = 0xa9b8c7d6;
1088  raw_context.iregs[13] = 0x12345678;
1089  raw_context.iregs[14] = 0xabcd1234;
1090  raw_context.iregs[15] = 0x10203040;
1091  raw_context.cpsr = 0x2e951ef7;
1092  Context context(dump, raw_context);
1093
1094  Exception exception(dump, context,
1095                      0x1234abcd, // thread id
1096                      0xdcba4321, // exception code
1097                      0xf0e0d0c0, // exception flags
1098                      0x0919a9b9c9d9e9f9ULL); // exception address
1099
1100  dump.Add(&context);
1101  dump.Add(&exception);
1102  dump.Finish();
1103
1104  string contents;
1105  ASSERT_TRUE(dump.GetContents(&contents));
1106
1107  istringstream minidump_stream(contents);
1108  Minidump minidump(minidump_stream);
1109  ASSERT_TRUE(minidump.Read());
1110  ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
1111
1112  MinidumpException *md_exception = minidump.GetException();
1113  ASSERT_TRUE(md_exception != NULL);
1114
1115  uint32_t thread_id;
1116  ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
1117  ASSERT_EQ(0x1234abcdU, thread_id);
1118
1119  const MDRawExceptionStream* raw_exception = md_exception->exception();
1120  ASSERT_TRUE(raw_exception != NULL);
1121  EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
1122  EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
1123  EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
1124            raw_exception->exception_record.exception_address);
1125
1126  MinidumpContext *md_context = md_exception->GetContext();
1127  ASSERT_TRUE(md_context != NULL);
1128  ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU());
1129  const MDRawContextARM *md_raw_context = md_context->GetContextARM();
1130  ASSERT_TRUE(md_raw_context != NULL);
1131  ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER,
1132            (md_raw_context->context_flags
1133             & MD_CONTEXT_ARM_INTEGER));
1134  EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]);
1135  EXPECT_EQ(0x382583b9U, raw_context.iregs[1]);
1136  EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]);
1137  EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]);
1138  EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]);
1139  EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]);
1140  EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]);
1141  EXPECT_EQ(0x6913f540U, raw_context.iregs[7]);
1142  EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]);
1143  EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]);
1144  EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]);
1145  EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]);
1146  EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]);
1147  EXPECT_EQ(0x12345678U, raw_context.iregs[13]);
1148  EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]);
1149  EXPECT_EQ(0x10203040U, raw_context.iregs[15]);
1150  EXPECT_EQ(0x2e951ef7U, raw_context.cpsr);
1151}
1152
1153TEST(Dump, OneExceptionMIPS) {
1154  Dump dump(0, kLittleEndian);
1155
1156  MDRawContextMIPS raw_context;
1157  raw_context.context_flags = MD_CONTEXT_MIPS_INTEGER;
1158  raw_context.iregs[0] = 0x3ecba80d;
1159  raw_context.iregs[1] = 0x382583b9;
1160  raw_context.iregs[2] = 0x7fccc03f;
1161  raw_context.iregs[3] = 0xf62f8ec2;
1162  raw_context.iregs[4] = 0x46a6a6a8;
1163  raw_context.iregs[5] = 0x6a5025e2;
1164  raw_context.iregs[6] = 0xd9fabb4a;
1165  raw_context.iregs[7] = 0x6913f540;
1166  raw_context.iregs[8] = 0xbffe6eda;
1167  raw_context.iregs[9] = 0xb2ce1e2d;
1168  raw_context.iregs[10] = 0x659caaa4;
1169  raw_context.iregs[11] = 0xf0e0d0c0;
1170  raw_context.iregs[12] = 0xa9b8c7d6;
1171  raw_context.iregs[13] = 0x12345678;
1172  raw_context.iregs[14] = 0xabcd1234;
1173  raw_context.iregs[15] = 0x10203040;
1174  raw_context.iregs[16] = 0xa80d3ecb;
1175  raw_context.iregs[17] = 0x83b93825;
1176  raw_context.iregs[18] = 0xc03f7fcc;
1177  raw_context.iregs[19] = 0x8ec2f62f;
1178  raw_context.iregs[20] = 0xa6a846a6;
1179  raw_context.iregs[21] = 0x25e26a50;
1180  raw_context.iregs[22] = 0xbb4ad9fa;
1181  raw_context.iregs[23] = 0xf5406913;
1182  raw_context.iregs[24] = 0x6edabffe;
1183  raw_context.iregs[25] = 0x1e2db2ce;
1184  raw_context.iregs[26] = 0xaaa4659c;
1185  raw_context.iregs[27] = 0xd0c0f0e0;
1186  raw_context.iregs[28] = 0xc7d6a9b8;
1187  raw_context.iregs[29] = 0x56781234;
1188  raw_context.iregs[30] = 0x1234abcd;
1189  raw_context.iregs[31] = 0x30401020;
1190
1191  Context context(dump, raw_context);
1192
1193  Exception exception(dump, context,
1194                      0x1234abcd,  // Thread id.
1195                      0xdcba4321,  // Exception code.
1196                      0xf0e0d0c0,  // Exception flags.
1197                      0x0919a9b9); // Exception address.
1198
1199  dump.Add(&context);
1200  dump.Add(&exception);
1201  dump.Finish();
1202
1203  string contents;
1204  ASSERT_TRUE(dump.GetContents(&contents));
1205
1206  istringstream minidump_stream(contents);
1207  Minidump minidump(minidump_stream);
1208  ASSERT_TRUE(minidump.Read());
1209  ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
1210
1211  MinidumpException *md_exception = minidump.GetException();
1212  ASSERT_TRUE(md_exception != NULL);
1213
1214  uint32_t thread_id;
1215  ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
1216  ASSERT_EQ(0x1234abcdU, thread_id);
1217
1218  const MDRawExceptionStream* raw_exception = md_exception->exception();
1219  ASSERT_TRUE(raw_exception != NULL);
1220  EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
1221  EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
1222  EXPECT_EQ(0x0919a9b9U,
1223            raw_exception->exception_record.exception_address);
1224
1225  MinidumpContext* md_context = md_exception->GetContext();
1226  ASSERT_TRUE(md_context != NULL);
1227  ASSERT_EQ((uint32_t) MD_CONTEXT_MIPS, md_context->GetContextCPU());
1228  const MDRawContextMIPS* md_raw_context = md_context->GetContextMIPS();
1229  ASSERT_TRUE(md_raw_context != NULL);
1230  ASSERT_EQ((uint32_t) MD_CONTEXT_MIPS_INTEGER,
1231            (md_raw_context->context_flags & MD_CONTEXT_MIPS_INTEGER));
1232  EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]);
1233  EXPECT_EQ(0x382583b9U, raw_context.iregs[1]);
1234  EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]);
1235  EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]);
1236  EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]);
1237  EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]);
1238  EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]);
1239  EXPECT_EQ(0x6913f540U, raw_context.iregs[7]);
1240  EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]);
1241  EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]);
1242  EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]);
1243  EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]);
1244  EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]);
1245  EXPECT_EQ(0x12345678U, raw_context.iregs[13]);
1246  EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]);
1247  EXPECT_EQ(0x10203040U, raw_context.iregs[15]);
1248  EXPECT_EQ(0xa80d3ecbU, raw_context.iregs[16]);
1249  EXPECT_EQ(0x83b93825U, raw_context.iregs[17]);
1250  EXPECT_EQ(0xc03f7fccU, raw_context.iregs[18]);
1251  EXPECT_EQ(0x8ec2f62fU, raw_context.iregs[19]);
1252  EXPECT_EQ(0xa6a846a6U, raw_context.iregs[20]);
1253  EXPECT_EQ(0x25e26a50U, raw_context.iregs[21]);
1254  EXPECT_EQ(0xbb4ad9faU, raw_context.iregs[22]);
1255  EXPECT_EQ(0xf5406913U, raw_context.iregs[23]);
1256  EXPECT_EQ(0x6edabffeU, raw_context.iregs[24]);
1257  EXPECT_EQ(0x1e2db2ceU, raw_context.iregs[25]);
1258  EXPECT_EQ(0xaaa4659cU, raw_context.iregs[26]);
1259  EXPECT_EQ(0xd0c0f0e0U, raw_context.iregs[27]);
1260  EXPECT_EQ(0xc7d6a9b8U, raw_context.iregs[28]);
1261  EXPECT_EQ(0x56781234U, raw_context.iregs[29]);
1262  EXPECT_EQ(0x1234abcdU, raw_context.iregs[30]);
1263  EXPECT_EQ(0x30401020U, raw_context.iregs[31]);
1264}
1265
1266}  // namespace
1267