|
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 |
|
44 using google_breakpad::SynthMinidump::Context; |
|
45 using google_breakpad::SynthMinidump::Dump; |
|
46 using google_breakpad::SynthMinidump::Exception; |
|
47 using google_breakpad::SynthMinidump::List; |
|
48 using google_breakpad::SynthMinidump::Memory; |
|
49 using google_breakpad::SynthMinidump::Module; |
|
50 using google_breakpad::SynthMinidump::Section; |
|
51 using google_breakpad::SynthMinidump::Stream; |
|
52 using google_breakpad::SynthMinidump::String; |
|
53 using google_breakpad::SynthMinidump::SystemInfo; |
|
54 using google_breakpad::test_assembler::kBigEndian; |
|
55 using google_breakpad::test_assembler::kLittleEndian; |
|
56 using google_breakpad::test_assembler::Label; |
|
57 |
|
58 TEST(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 |
|
68 TEST(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(§ion1); |
|
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 |
|
81 TEST(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(§ion); |
|
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 |
|
99 TEST(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(§ion); |
|
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 |
|
117 TEST(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 |
|
125 TEST(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 |
|
136 TEST(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 |
|
147 TEST(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 |
|
155 TEST(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 |
|
163 TEST(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 |
|
194 TEST(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 |
|
237 TEST(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 |
|
249 TEST(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(§ion); |
|
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 |
|
261 TEST(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 |
|
271 TEST(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(§ion1); |
|
278 EXPECT_FALSE(list.Empty()); |
|
279 Section section2(dump); |
|
280 section2.Append("section two contents"); |
|
281 list.Add(§ion2); |
|
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 |
|
289 TEST(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 |
|
305 TEST(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 |
|
321 TEST(Dump, OneSection) { |
|
322 Dump dump(0, kLittleEndian); |
|
323 Section section(dump); |
|
324 section.Append("section contents"); |
|
325 dump.Add(§ion); |
|
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 } |