1 // Copyright 2010 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 // * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 // Original author: Jim Blandy <[email protected]> <[email protected]>
30
31 // synth_minidump_unittest.cc: Unit tests for google_breakpad::SynthMinidump
32 // classes.
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h> // Must come first
36 #endif
37
38 #include <sstream>
39 #include <string>
40
41 #include "breakpad_googletest_includes.h"
42 #include "common/using_std_string.h"
43 #include "google_breakpad/common/minidump_format.h"
44 #include "processor/synth_minidump.h"
45 #include "processor/synth_minidump_unittest_data.h"
46
47 using google_breakpad::SynthMinidump::Context;
48 using google_breakpad::SynthMinidump::Dump;
49 using google_breakpad::SynthMinidump::Exception;
50 using google_breakpad::SynthMinidump::List;
51 using google_breakpad::SynthMinidump::Memory;
52 using google_breakpad::SynthMinidump::Module;
53 using google_breakpad::SynthMinidump::Section;
54 using google_breakpad::SynthMinidump::Stream;
55 using google_breakpad::SynthMinidump::String;
56 using google_breakpad::SynthMinidump::SystemInfo;
57 using google_breakpad::test_assembler::kBigEndian;
58 using google_breakpad::test_assembler::kLittleEndian;
59 using google_breakpad::test_assembler::Label;
60
TEST(Section,Simple)61 TEST(Section, Simple) {
62 Dump dump(0);
63 Section section(dump);
64 section.L32(0x12345678);
65 section.Finish(0);
66 string contents;
67 ASSERT_TRUE(section.GetContents(&contents));
68 EXPECT_EQ(string("\x78\x56\x34\x12", 4), contents);
69 }
70
TEST(Section,CiteLocationIn)71 TEST(Section, CiteLocationIn) {
72 Dump dump(0, kBigEndian);
73 Section section1(dump), section2(dump);
74 section1.Append("order");
75 section2.Append("mayhem");
76 section2.Finish(0x32287ec2);
77 section2.CiteLocationIn(§ion1);
78 string contents;
79 ASSERT_TRUE(section1.GetContents(&contents));
80 string expected("order\0\0\0\x06\x32\x28\x7e\xc2", 13);
81 EXPECT_EQ(expected, contents);
82 }
83
TEST(Stream,CiteStreamIn)84 TEST(Stream, CiteStreamIn) {
85 Dump dump(0, kLittleEndian);
86 Stream stream(dump, 0x40cae2b3);
87 Section section(dump);
88 stream.Append("stream contents");
89 section.Append("section contents");
90 stream.Finish(0x41424344);
91 stream.CiteStreamIn(§ion);
92 string contents;
93 ASSERT_TRUE(section.GetContents(&contents));
94 string expected("section contents"
95 "\xb3\xe2\xca\x40"
96 "\x0f\0\0\0"
97 "\x44\x43\x42\x41",
98 16 + 4 + 4 + 4);
99 EXPECT_EQ(expected, contents);
100 }
101
TEST(Memory,CiteMemoryIn)102 TEST(Memory, CiteMemoryIn) {
103 Dump dump(0, kBigEndian);
104 Memory memory(dump, 0x76d010874ab019f9ULL);
105 Section section(dump);
106 memory.Append("memory contents");
107 section.Append("section contents");
108 memory.Finish(0x51525354);
109 memory.CiteMemoryIn(§ion);
110 string contents;
111 ASSERT_TRUE(section.GetContents(&contents));
112 string expected("section contents"
113 "\x76\xd0\x10\x87\x4a\xb0\x19\xf9"
114 "\0\0\0\x0f"
115 "\x51\x52\x53\x54",
116 16 + 8 + 4 + 4);
117 EXPECT_EQ(contents, expected);
118 }
119
TEST(Memory,Here)120 TEST(Memory, Here) {
121 Dump dump(0, kBigEndian);
122 Memory memory(dump, 0x89979731eb060ed4ULL);
123 memory.Append(1729, 42);
124 Label l = memory.Here();
125 ASSERT_EQ(0x89979731eb060ed4ULL + 1729, l.Value());
126 }
127
TEST(Context,X86)128 TEST(Context, X86) {
129 Dump dump(0, kLittleEndian);
130 assert(x86_raw_context.context_flags & MD_CONTEXT_X86);
131 Context context(dump, x86_raw_context);
132 string contents;
133 ASSERT_TRUE(context.GetContents(&contents));
134 EXPECT_EQ(sizeof(x86_expected_contents), contents.size());
135 EXPECT_TRUE(memcmp(contents.data(), x86_expected_contents, contents.size())
136 == 0);
137 }
138
TEST(Context,ARM)139 TEST(Context, ARM) {
140 Dump dump(0, kLittleEndian);
141 assert(arm_raw_context.context_flags & MD_CONTEXT_ARM);
142 Context context(dump, arm_raw_context);
143 string contents;
144 ASSERT_TRUE(context.GetContents(&contents));
145 EXPECT_EQ(sizeof(arm_expected_contents), contents.size());
146 EXPECT_TRUE(memcmp(contents.data(), arm_expected_contents, contents.size())
147 == 0);
148 }
149
TEST(ContextDeathTest,X86BadFlags)150 TEST(ContextDeathTest, X86BadFlags) {
151 Dump dump(0, kLittleEndian);
152 MDRawContextX86 raw;
153 raw.context_flags = MD_CONTEXT_AMD64;
154 ASSERT_DEATH(Context context(dump, raw);,
155 "context\\.context_flags & (0x[0-9a-f]+|MD_CONTEXT_X86)");
156 }
157
TEST(ContextDeathTest,X86BadEndianness)158 TEST(ContextDeathTest, X86BadEndianness) {
159 Dump dump(0, kBigEndian);
160 MDRawContextX86 raw;
161 raw.context_flags = MD_CONTEXT_X86;
162 ASSERT_DEATH(Context context(dump, raw);,
163 "dump\\.endianness\\(\\) == kLittleEndian");
164 }
165
TEST(Thread,Simple)166 TEST(Thread, Simple) {
167 Dump dump(0, kLittleEndian);
168 Context context(dump, x86_raw_context);
169 context.Finish(0x8665da0c);
170 Memory stack(dump, 0xaad55a93cc3c0efcULL);
171 stack.Append("stack contents");
172 stack.Finish(0xe08cdbd1);
173 google_breakpad::SynthMinidump::Thread thread(
174 dump, 0x3d7ec360, stack, context,
175 0x3593f44d, // suspend count
176 0xab352b82, // priority class
177 0x2753d838, // priority
178 0xeb2de4be3f29e3e9ULL); // thread environment block
179 string contents;
180 ASSERT_TRUE(thread.GetContents(&contents));
181 static const uint8_t expected_bytes[] = {
182 0x60, 0xc3, 0x7e, 0x3d, // thread id
183 0x4d, 0xf4, 0x93, 0x35, // suspend count
184 0x82, 0x2b, 0x35, 0xab, // priority class
185 0x38, 0xd8, 0x53, 0x27, // priority
186 0xe9, 0xe3, 0x29, 0x3f, 0xbe, 0xe4, 0x2d, 0xeb, // thread environment block
187 0xfc, 0x0e, 0x3c, 0xcc, 0x93, 0x5a, 0xd5, 0xaa, // stack address
188 0x0e, 0x00, 0x00, 0x00, // stack size
189 0xd1, 0xdb, 0x8c, 0xe0, // stack MDRVA
190 0xcc, 0x02, 0x00, 0x00, // context size
191 0x0c, 0xda, 0x65, 0x86 // context MDRVA
192 };
193 EXPECT_EQ(sizeof(expected_bytes), contents.size());
194 EXPECT_TRUE(memcmp(contents.data(), expected_bytes, contents.size()) == 0);
195 }
196
TEST(Exception,Simple)197 TEST(Exception, Simple) {
198 Dump dump(0, kLittleEndian);
199 Context context(dump, x86_raw_context);
200 context.Finish(0x8665da0c);
201
202 Exception exception(dump, context,
203 0x1234abcd, // thread id
204 0xdcba4321, // exception code
205 0xf0e0d0c0, // exception flags
206 0x0919a9b9c9d9e9f9ULL); // exception address
207 string contents;
208 ASSERT_TRUE(exception.GetContents(&contents));
209 static const uint8_t expected_bytes[] = {
210 0xcd, 0xab, 0x34, 0x12, // thread id
211 0x00, 0x00, 0x00, 0x00, // __align
212 0x21, 0x43, 0xba, 0xdc, // exception code
213 0xc0, 0xd0, 0xe0, 0xf0, // exception flags
214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception record
215 0xf9, 0xe9, 0xd9, 0xc9, 0xb9, 0xa9, 0x19, 0x09, // exception address
216 0x00, 0x00, 0x00, 0x00, // number parameters
217 0x00, 0x00, 0x00, 0x00, // __align
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
233 0xcc, 0x02, 0x00, 0x00, // context size
234 0x0c, 0xda, 0x65, 0x86 // context MDRVA
235 };
236 EXPECT_EQ(sizeof(expected_bytes), contents.size());
237 EXPECT_TRUE(memcmp(contents.data(), expected_bytes, contents.size()) == 0);
238 }
239
TEST(String,Simple)240 TEST(String, Simple) {
241 Dump dump(0, kBigEndian);
242 String s(dump, "All mimsy were the borogoves");
243 string contents;
244 ASSERT_TRUE(s.GetContents(&contents));
245 static const char expected[] =
246 "\x00\x00\x00\x38\0A\0l\0l\0 \0m\0i\0m\0s\0y\0 \0w\0e\0r\0e"
247 "\0 \0t\0h\0e\0 \0b\0o\0r\0o\0g\0o\0v\0e\0s";
248 string expected_string(expected, sizeof(expected) - 1);
249 EXPECT_EQ(expected_string, contents);
250 }
251
TEST(String,CiteStringIn)252 TEST(String, CiteStringIn) {
253 Dump dump(0, kLittleEndian);
254 String s(dump, "and the mome wraths outgrabe");
255 Section section(dump);
256 section.Append("initial");
257 s.CiteStringIn(§ion);
258 s.Finish(0xdc2bb469);
259 string contents;
260 ASSERT_TRUE(section.GetContents(&contents));
261 EXPECT_EQ(string("initial\x69\xb4\x2b\xdc", 7 + 4), contents);
262 }
263
TEST(List,Empty)264 TEST(List, Empty) {
265 Dump dump(0, kBigEndian);
266 List<Section> list(dump, 0x2442779c);
267 EXPECT_TRUE(list.Empty());
268 list.Finish(0x84e09808);
269 string contents;
270 ASSERT_TRUE(list.GetContents(&contents));
271 EXPECT_EQ(string("\0\0\0\0", 4), contents);
272 }
273
TEST(List,Two)274 TEST(List, Two) {
275 Dump dump(0, kBigEndian);
276 List<Section> list(dump, 0x26c9f498);
277 Section section1(dump);
278 section1.Append("section one contents");
279 EXPECT_TRUE(list.Empty());
280 list.Add(§ion1);
281 EXPECT_FALSE(list.Empty());
282 Section section2(dump);
283 section2.Append("section two contents");
284 list.Add(§ion2);
285 list.Finish(0x1e5bb60e);
286 string contents;
287 ASSERT_TRUE(list.GetContents(&contents));
288 EXPECT_EQ(string("\0\0\0\x02section one contentssection two contents", 44),
289 contents);
290 }
291
TEST(Dump,Header)292 TEST(Dump, Header) {
293 Dump dump(0x9f738b33685cc84cULL, kLittleEndian, 0xb3817faf, 0x2c741c0a);
294 dump.Finish();
295 string contents;
296 ASSERT_TRUE(dump.GetContents(&contents));
297 ASSERT_EQ(string("\x4d\x44\x4d\x50" // signature
298 "\xaf\x7f\x81\xb3" // version
299 "\0\0\0\0" // stream count
300 "\x20\0\0\0" // directory RVA (could be anything)
301 "\0\0\0\0" // checksum
302 "\x0a\x1c\x74\x2c" // time_date_stamp
303 "\x4c\xc8\x5c\x68\x33\x8b\x73\x9f", // flags
304 32),
305 contents);
306 }
307
TEST(Dump,HeaderBigEndian)308 TEST(Dump, HeaderBigEndian) {
309 Dump dump(0x206ce3cc6fb8e0f0ULL, kBigEndian, 0x161693e2, 0x35667744);
310 dump.Finish();
311 string contents;
312 ASSERT_TRUE(dump.GetContents(&contents));
313 ASSERT_EQ(string("\x50\x4d\x44\x4d" // signature
314 "\x16\x16\x93\xe2" // version
315 "\0\0\0\0" // stream count
316 "\0\0\0\x20" // directory RVA (could be anything)
317 "\0\0\0\0" // checksum
318 "\x35\x66\x77\x44" // time_date_stamp
319 "\x20\x6c\xe3\xcc\x6f\xb8\xe0\xf0", // flags
320 32),
321 contents);
322 }
323
TEST(Dump,OneSection)324 TEST(Dump, OneSection) {
325 Dump dump(0, kLittleEndian);
326 Section section(dump);
327 section.Append("section contents");
328 dump.Add(§ion);
329 dump.Finish();
330 string dump_contents;
331 // Just check for undefined labels; don't worry about the contents.
332 ASSERT_TRUE(dump.GetContents(&dump_contents));
333
334 Section referencing_section(dump);
335 section.CiteLocationIn(&referencing_section);
336 string contents;
337 ASSERT_TRUE(referencing_section.GetContents(&contents));
338 ASSERT_EQ(string("\x10\0\0\0\x20\0\0\0", 8), contents);
339 }
340