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// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
31
32// synth_minidump_unittest.cc: Unit tests for google_breakpad::SynthMinidump
33// classes.
34
35#include <sstream>
36#include <string>
37
38#include "breakpad_googletest_includes.h"
39#include "common/using_std_string.h"
40#include "google_breakpad/common/minidump_format.h"
41#include "processor/synth_minidump.h"
42#include "processor/synth_minidump_unittest_data.h"
43
44using google_breakpad::SynthMinidump::Context;
45using google_breakpad::SynthMinidump::Dump;
46using google_breakpad::SynthMinidump::Exception;
47using google_breakpad::SynthMinidump::List;
48using google_breakpad::SynthMinidump::Memory;
49using google_breakpad::SynthMinidump::Module;
50using google_breakpad::SynthMinidump::Section;
51using google_breakpad::SynthMinidump::Stream;
52using google_breakpad::SynthMinidump::String;
53using google_breakpad::SynthMinidump::SystemInfo;
54using google_breakpad::test_assembler::kBigEndian;
55using google_breakpad::test_assembler::kLittleEndian;
56using google_breakpad::test_assembler::Label;
57
58TEST(Section, Simple) {
59  Dump dump(0);
60  Section section(dump);
61  section.L32(0x12345678);
62  section.Finish(0);
63  string contents;
64  ASSERT_TRUE(section.GetContents(&contents));
65  EXPECT_EQ(string("\x78\x56\x34\x12", 4), contents);
66}
67
68TEST(Section, CiteLocationIn) {
69  Dump dump(0, kBigEndian);
70  Section section1(dump), section2(dump);
71  section1.Append("order");
72  section2.Append("mayhem");
73  section2.Finish(0x32287ec2);
74  section2.CiteLocationIn(&section1);
75  string contents;
76  ASSERT_TRUE(section1.GetContents(&contents));
77  string expected("order\0\0\0\x06\x32\x28\x7e\xc2", 13);
78  EXPECT_EQ(expected, contents);
79}
80
81TEST(Stream, CiteStreamIn) {
82  Dump dump(0, kLittleEndian);
83  Stream stream(dump, 0x40cae2b3);
84  Section section(dump);
85  stream.Append("stream contents");
86  section.Append("section contents");
87  stream.Finish(0x41424344);
88  stream.CiteStreamIn(&section);
89  string contents;
90  ASSERT_TRUE(section.GetContents(&contents));
91  string expected("section contents"
92                  "\xb3\xe2\xca\x40"
93                  "\x0f\0\0\0"
94                  "\x44\x43\x42\x41",
95                  16 + 4 + 4 + 4);
96  EXPECT_EQ(expected, contents);
97}
98
99TEST(Memory, CiteMemoryIn) {
100  Dump dump(0, kBigEndian);
101  Memory memory(dump, 0x76d010874ab019f9ULL);
102  Section section(dump);
103  memory.Append("memory contents");
104  section.Append("section contents");
105  memory.Finish(0x51525354);
106  memory.CiteMemoryIn(&section);
107  string contents;
108  ASSERT_TRUE(section.GetContents(&contents));
109  string expected("section contents"
110                  "\x76\xd0\x10\x87\x4a\xb0\x19\xf9"
111                  "\0\0\0\x0f"
112                  "\x51\x52\x53\x54",
113                  16 + 8 + 4 + 4);
114  EXPECT_EQ(contents, expected);
115}
116
117TEST(Memory, Here) {
118  Dump dump(0, kBigEndian);
119  Memory memory(dump, 0x89979731eb060ed4ULL);
120  memory.Append(1729, 42);
121  Label l = memory.Here();
122  ASSERT_EQ(0x89979731eb060ed4ULL + 1729, l.Value());
123}
124
125TEST(Context, X86) {
126  Dump dump(0, kLittleEndian);
127  assert(x86_raw_context.context_flags & MD_CONTEXT_X86);
128  Context context(dump, x86_raw_context);
129  string contents;
130  ASSERT_TRUE(context.GetContents(&contents));
131  EXPECT_EQ(sizeof(x86_expected_contents), contents.size());
132  EXPECT_TRUE(memcmp(contents.data(), x86_expected_contents, contents.size())
133              == 0);
134}
135
136TEST(Context, ARM) {
137  Dump dump(0, kLittleEndian);
138  assert(arm_raw_context.context_flags & MD_CONTEXT_ARM);
139  Context context(dump, arm_raw_context);
140  string contents;
141  ASSERT_TRUE(context.GetContents(&contents));
142  EXPECT_EQ(sizeof(arm_expected_contents), contents.size());
143  EXPECT_TRUE(memcmp(contents.data(), arm_expected_contents, contents.size())
144              == 0);
145}
146
147TEST(ContextDeathTest, X86BadFlags) {
148  Dump dump(0, kLittleEndian);
149  MDRawContextX86 raw;
150  raw.context_flags = MD_CONTEXT_AMD64;
151  ASSERT_DEATH(Context context(dump, raw);,
152               "context\\.context_flags & (0x[0-9a-f]+|MD_CONTEXT_X86)");
153}
154
155TEST(ContextDeathTest, X86BadEndianness) {
156  Dump dump(0, kBigEndian);
157  MDRawContextX86 raw;
158  raw.context_flags = MD_CONTEXT_X86;
159  ASSERT_DEATH(Context context(dump, raw);,
160               "dump\\.endianness\\(\\) == kLittleEndian");
161}
162
163TEST(Thread, Simple) {
164  Dump dump(0, kLittleEndian);
165  Context context(dump, x86_raw_context);
166  context.Finish(0x8665da0c);
167  Memory stack(dump, 0xaad55a93cc3c0efcULL);
168  stack.Append("stack contents");
169  stack.Finish(0xe08cdbd1);
170  google_breakpad::SynthMinidump::Thread thread(
171      dump, 0x3d7ec360, stack, context,
172      0x3593f44d, // suspend count
173      0xab352b82, // priority class
174      0x2753d838, // priority
175      0xeb2de4be3f29e3e9ULL); // thread environment block
176  string contents;
177  ASSERT_TRUE(thread.GetContents(&contents));
178  static const uint8_t expected_bytes[] = {
179    0x60, 0xc3, 0x7e, 0x3d, // thread id
180    0x4d, 0xf4, 0x93, 0x35, // suspend count
181    0x82, 0x2b, 0x35, 0xab, // priority class
182    0x38, 0xd8, 0x53, 0x27, // priority
183    0xe9, 0xe3, 0x29, 0x3f, 0xbe, 0xe4, 0x2d, 0xeb, // thread environment block
184    0xfc, 0x0e, 0x3c, 0xcc, 0x93, 0x5a, 0xd5, 0xaa, // stack address
185    0x0e, 0x00, 0x00, 0x00, // stack size
186    0xd1, 0xdb, 0x8c, 0xe0, // stack MDRVA
187    0xcc, 0x02, 0x00, 0x00, // context size
188    0x0c, 0xda, 0x65, 0x86  // context MDRVA
189  };
190  EXPECT_EQ(sizeof(expected_bytes), contents.size());
191  EXPECT_TRUE(memcmp(contents.data(), expected_bytes, contents.size()) == 0);
192}
193
194TEST(Exception, Simple) {
195  Dump dump(0, kLittleEndian);
196  Context context(dump, x86_raw_context);
197  context.Finish(0x8665da0c);
198
199  Exception exception(dump, context,
200                      0x1234abcd, // thread id
201                      0xdcba4321, // exception code
202                      0xf0e0d0c0, // exception flags
203                      0x0919a9b9c9d9e9f9ULL); // exception address
204  string contents;
205  ASSERT_TRUE(exception.GetContents(&contents));
206  static const uint8_t expected_bytes[] = {
207    0xcd, 0xab, 0x34, 0x12, // thread id
208    0x00, 0x00, 0x00, 0x00, // __align
209    0x21, 0x43, 0xba, 0xdc, // exception code
210    0xc0, 0xd0, 0xe0, 0xf0, // exception flags
211    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception record
212    0xf9, 0xe9, 0xd9, 0xc9, 0xb9, 0xa9, 0x19, 0x09, // exception address
213    0x00, 0x00, 0x00, 0x00, // number parameters
214    0x00, 0x00, 0x00, 0x00, // __align
215    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
216    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
217    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
218    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
219    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
220    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
221    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
222    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
223    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
224    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
225    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
226    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
227    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
228    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
229    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
230    0xcc, 0x02, 0x00, 0x00, // context size
231    0x0c, 0xda, 0x65, 0x86  // context MDRVA
232  };
233  EXPECT_EQ(sizeof(expected_bytes), contents.size());
234  EXPECT_TRUE(memcmp(contents.data(), expected_bytes, contents.size()) == 0);
235}
236
237TEST(String, Simple) {
238  Dump dump(0, kBigEndian);
239  String s(dump, "All mimsy were the borogoves");
240  string contents;
241  ASSERT_TRUE(s.GetContents(&contents));
242  static const char expected[] =
243    "\x00\x00\x00\x38\0A\0l\0l\0 \0m\0i\0m\0s\0y\0 \0w\0e\0r\0e"
244    "\0 \0t\0h\0e\0 \0b\0o\0r\0o\0g\0o\0v\0e\0s";
245  string expected_string(expected, sizeof(expected) - 1);
246  EXPECT_EQ(expected_string, contents);
247}
248
249TEST(String, CiteStringIn) {
250  Dump dump(0, kLittleEndian);
251  String s(dump, "and the mome wraths outgrabe");
252  Section section(dump);
253  section.Append("initial");
254  s.CiteStringIn(&section);
255  s.Finish(0xdc2bb469);
256  string contents;
257  ASSERT_TRUE(section.GetContents(&contents));
258  EXPECT_EQ(string("initial\x69\xb4\x2b\xdc", 7 + 4), contents);
259}
260
261TEST(List, Empty) {
262  Dump dump(0, kBigEndian);
263  List<Section> list(dump, 0x2442779c);
264  EXPECT_TRUE(list.Empty());
265  list.Finish(0x84e09808);
266  string contents;
267  ASSERT_TRUE(list.GetContents(&contents));
268  EXPECT_EQ(string("\0\0\0\0", 4), contents);
269}
270
271TEST(List, Two) {
272  Dump dump(0, kBigEndian);
273  List<Section> list(dump, 0x26c9f498);
274  Section section1(dump);
275  section1.Append("section one contents");
276  EXPECT_TRUE(list.Empty());
277  list.Add(&section1);
278  EXPECT_FALSE(list.Empty());
279  Section section2(dump);
280  section2.Append("section two contents");
281  list.Add(&section2);
282  list.Finish(0x1e5bb60e);
283  string contents;
284  ASSERT_TRUE(list.GetContents(&contents));
285  EXPECT_EQ(string("\0\0\0\x02section one contentssection two contents", 44),
286            contents);
287}
288
289TEST(Dump, Header) {
290  Dump dump(0x9f738b33685cc84cULL, kLittleEndian, 0xb3817faf, 0x2c741c0a);
291  dump.Finish();
292  string contents;
293  ASSERT_TRUE(dump.GetContents(&contents));
294  ASSERT_EQ(string("\x4d\x44\x4d\x50"   // signature
295                   "\xaf\x7f\x81\xb3"   // version
296                   "\0\0\0\0"           // stream count
297                   "\x20\0\0\0"         // directory RVA (could be anything)
298                   "\0\0\0\0"           // checksum
299                   "\x0a\x1c\x74\x2c"   // time_date_stamp
300                   "\x4c\xc8\x5c\x68\x33\x8b\x73\x9f", // flags
301                   32),
302            contents);
303}
304
305TEST(Dump, HeaderBigEndian) {
306  Dump dump(0x206ce3cc6fb8e0f0ULL, kBigEndian, 0x161693e2, 0x35667744);
307  dump.Finish();
308  string contents;
309  ASSERT_TRUE(dump.GetContents(&contents));
310  ASSERT_EQ(string("\x50\x4d\x44\x4d"   // signature
311                   "\x16\x16\x93\xe2"   // version
312                   "\0\0\0\0"           // stream count
313                   "\0\0\0\x20"         // directory RVA (could be anything)
314                   "\0\0\0\0"           // checksum
315                   "\x35\x66\x77\x44"   // time_date_stamp
316                   "\x20\x6c\xe3\xcc\x6f\xb8\xe0\xf0", // flags
317                   32),
318            contents);
319}
320
321TEST(Dump, OneSection) {
322  Dump dump(0, kLittleEndian);
323  Section section(dump);
324  section.Append("section contents");
325  dump.Add(&section);
326  dump.Finish();
327  string dump_contents;
328  // Just check for undefined labels; don't worry about the contents.
329  ASSERT_TRUE(dump.GetContents(&dump_contents));
330
331  Section referencing_section(dump);
332  section.CiteLocationIn(&referencing_section);
333  string contents;
334  ASSERT_TRUE(referencing_section.GetContents(&contents));
335  ASSERT_EQ(string("\x10\0\0\0\x20\0\0\0", 8), contents);
336}
337