|
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: |
|
79 void SetUp() { |
|
80 minidump_file_ = string(getenv("srcdir") ? getenv("srcdir") : ".") + |
|
81 "/src/processor/testdata/minidump2.dmp"; |
|
82 } |
|
83 string minidump_file_; |
|
84 }; |
|
85 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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. |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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. |
|
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 |
|
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 |
|
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 |
|
1153 } // namespace |