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 
47 namespace {
48 
49 using google_breakpad::Minidump;
50 using google_breakpad::MinidumpContext;
51 using google_breakpad::MinidumpException;
52 using google_breakpad::MinidumpMemoryInfo;
53 using google_breakpad::MinidumpMemoryInfoList;
54 using google_breakpad::MinidumpMemoryList;
55 using google_breakpad::MinidumpMemoryRegion;
56 using google_breakpad::MinidumpModule;
57 using google_breakpad::MinidumpModuleList;
58 using google_breakpad::MinidumpSystemInfo;
59 using google_breakpad::MinidumpThread;
60 using google_breakpad::MinidumpThreadList;
61 using google_breakpad::SynthMinidump::Context;
62 using google_breakpad::SynthMinidump::Dump;
63 using google_breakpad::SynthMinidump::Exception;
64 using google_breakpad::SynthMinidump::Memory;
65 using google_breakpad::SynthMinidump::Module;
66 using google_breakpad::SynthMinidump::Stream;
67 using google_breakpad::SynthMinidump::String;
68 using google_breakpad::SynthMinidump::SystemInfo;
69 using google_breakpad::SynthMinidump::Thread;
70 using google_breakpad::test_assembler::kBigEndian;
71 using google_breakpad::test_assembler::kLittleEndian;
72 using std::ifstream;
73 using std::istringstream;
74 using std::vector;
75 using ::testing::Return;
76 
77 class MinidumpTest : public ::testing::Test {
78 public:
SetUp()79   void SetUp() {
80     minidump_file_ = string(getenv("srcdir") ? getenv("srcdir") : ".") +
81       "/src/processor/testdata/minidump2.dmp";
82   }
83   string minidump_file_;
84 };
85 
TEST_F(MinidumpTest,TestMinidumpFromFile)86 TEST_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 
TEST_F(MinidumpTest,TestMinidumpFromStream)96 TEST_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 
TEST(Dump,ReadBackEmpty)122 TEST(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 
TEST(Dump,ReadBackEmptyBigEndian)133 TEST(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 
TEST(Dump,OneStream)144 TEST(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 
TEST(Dump,OneMemory)180 TEST(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.
TEST(Dump,OneThread)210 TEST(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 
TEST(Dump,ThreadMissingMemory)301 TEST(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 
TEST(Dump,ThreadMissingContext)346 TEST(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 
TEST(Dump,OneModule)388 TEST(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 
TEST(Dump,OneSystemInfo)447 TEST(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 
TEST(Dump,BigDump)475 TEST(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 
TEST(Dump,OneMemoryInfo)632 TEST(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 
TEST(Dump,OneExceptionX86)687 TEST(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 
TEST(Dump,OneExceptionX86XState)760 TEST(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
TEST(Dump,OneExceptionX86NoCPUFlags)836 TEST(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.
TEST(Dump,OneExceptionX86NoCPUFlagsNoSystemInfo)927 TEST(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 
TEST(Dump,OneExceptionARM)986 TEST(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 
TEST(Dump,OneExceptionARMOldFlags)1069 TEST(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 
TEST(Dump,OneExceptionMIPS)1153 TEST(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