toolkit/crashreporter/google-breakpad/src/processor/minidump_unittest.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2010, Google Inc.
michael@0 2 // All rights reserved.
michael@0 3 //
michael@0 4 // Redistribution and use in source and binary forms, with or without
michael@0 5 // modification, are permitted provided that the following conditions are
michael@0 6 // met:
michael@0 7 //
michael@0 8 // * Redistributions of source code must retain the above copyright
michael@0 9 // notice, this list of conditions and the following disclaimer.
michael@0 10 // * Redistributions in binary form must reproduce the above
michael@0 11 // copyright notice, this list of conditions and the following disclaimer
michael@0 12 // in the documentation and/or other materials provided with the
michael@0 13 // distribution.
michael@0 14 // * Neither the name of Google Inc. nor the names of its
michael@0 15 // contributors may be used to endorse or promote products derived from
michael@0 16 // this software without specific prior written permission.
michael@0 17 //
michael@0 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 29
michael@0 30 // Unit test for Minidump. Uses a pre-generated minidump and
michael@0 31 // verifies that certain streams are correct.
michael@0 32
michael@0 33 #include <iostream>
michael@0 34 #include <fstream>
michael@0 35 #include <sstream>
michael@0 36 #include <stdlib.h>
michael@0 37 #include <string>
michael@0 38 #include <vector>
michael@0 39
michael@0 40 #include "breakpad_googletest_includes.h"
michael@0 41 #include "common/using_std_string.h"
michael@0 42 #include "google_breakpad/common/minidump_format.h"
michael@0 43 #include "google_breakpad/processor/minidump.h"
michael@0 44 #include "processor/logging.h"
michael@0 45 #include "processor/synth_minidump.h"
michael@0 46
michael@0 47 namespace {
michael@0 48
michael@0 49 using google_breakpad::Minidump;
michael@0 50 using google_breakpad::MinidumpContext;
michael@0 51 using google_breakpad::MinidumpException;
michael@0 52 using google_breakpad::MinidumpMemoryInfo;
michael@0 53 using google_breakpad::MinidumpMemoryInfoList;
michael@0 54 using google_breakpad::MinidumpMemoryList;
michael@0 55 using google_breakpad::MinidumpMemoryRegion;
michael@0 56 using google_breakpad::MinidumpModule;
michael@0 57 using google_breakpad::MinidumpModuleList;
michael@0 58 using google_breakpad::MinidumpSystemInfo;
michael@0 59 using google_breakpad::MinidumpThread;
michael@0 60 using google_breakpad::MinidumpThreadList;
michael@0 61 using google_breakpad::SynthMinidump::Context;
michael@0 62 using google_breakpad::SynthMinidump::Dump;
michael@0 63 using google_breakpad::SynthMinidump::Exception;
michael@0 64 using google_breakpad::SynthMinidump::Memory;
michael@0 65 using google_breakpad::SynthMinidump::Module;
michael@0 66 using google_breakpad::SynthMinidump::Stream;
michael@0 67 using google_breakpad::SynthMinidump::String;
michael@0 68 using google_breakpad::SynthMinidump::SystemInfo;
michael@0 69 using google_breakpad::SynthMinidump::Thread;
michael@0 70 using google_breakpad::test_assembler::kBigEndian;
michael@0 71 using google_breakpad::test_assembler::kLittleEndian;
michael@0 72 using std::ifstream;
michael@0 73 using std::istringstream;
michael@0 74 using std::vector;
michael@0 75 using ::testing::Return;
michael@0 76
michael@0 77 class MinidumpTest : public ::testing::Test {
michael@0 78 public:
michael@0 79 void SetUp() {
michael@0 80 minidump_file_ = string(getenv("srcdir") ? getenv("srcdir") : ".") +
michael@0 81 "/src/processor/testdata/minidump2.dmp";
michael@0 82 }
michael@0 83 string minidump_file_;
michael@0 84 };
michael@0 85
michael@0 86 TEST_F(MinidumpTest, TestMinidumpFromFile) {
michael@0 87 Minidump minidump(minidump_file_);
michael@0 88 ASSERT_EQ(minidump.path(), minidump_file_);
michael@0 89 ASSERT_TRUE(minidump.Read());
michael@0 90 const MDRawHeader* header = minidump.header();
michael@0 91 ASSERT_NE(header, (MDRawHeader*)NULL);
michael@0 92 ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE));
michael@0 93 //TODO: add more checks here
michael@0 94 }
michael@0 95
michael@0 96 TEST_F(MinidumpTest, TestMinidumpFromStream) {
michael@0 97 // read minidump contents into memory, construct a stringstream around them
michael@0 98 ifstream file_stream(minidump_file_.c_str(), std::ios::in);
michael@0 99 ASSERT_TRUE(file_stream.good());
michael@0 100 vector<char> bytes;
michael@0 101 file_stream.seekg(0, std::ios_base::end);
michael@0 102 ASSERT_TRUE(file_stream.good());
michael@0 103 bytes.resize(file_stream.tellg());
michael@0 104 file_stream.seekg(0, std::ios_base::beg);
michael@0 105 ASSERT_TRUE(file_stream.good());
michael@0 106 file_stream.read(&bytes[0], bytes.size());
michael@0 107 ASSERT_TRUE(file_stream.good());
michael@0 108 string str(&bytes[0], bytes.size());
michael@0 109 istringstream stream(str);
michael@0 110 ASSERT_TRUE(stream.good());
michael@0 111
michael@0 112 // now read minidump from stringstream
michael@0 113 Minidump minidump(stream);
michael@0 114 ASSERT_EQ(minidump.path(), "");
michael@0 115 ASSERT_TRUE(minidump.Read());
michael@0 116 const MDRawHeader* header = minidump.header();
michael@0 117 ASSERT_NE(header, (MDRawHeader*)NULL);
michael@0 118 ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE));
michael@0 119 //TODO: add more checks here
michael@0 120 }
michael@0 121
michael@0 122 TEST(Dump, ReadBackEmpty) {
michael@0 123 Dump dump(0);
michael@0 124 dump.Finish();
michael@0 125 string contents;
michael@0 126 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 127 istringstream stream(contents);
michael@0 128 Minidump minidump(stream);
michael@0 129 ASSERT_TRUE(minidump.Read());
michael@0 130 ASSERT_EQ(0U, minidump.GetDirectoryEntryCount());
michael@0 131 }
michael@0 132
michael@0 133 TEST(Dump, ReadBackEmptyBigEndian) {
michael@0 134 Dump big_minidump(0, kBigEndian);
michael@0 135 big_minidump.Finish();
michael@0 136 string contents;
michael@0 137 ASSERT_TRUE(big_minidump.GetContents(&contents));
michael@0 138 istringstream stream(contents);
michael@0 139 Minidump minidump(stream);
michael@0 140 ASSERT_TRUE(minidump.Read());
michael@0 141 ASSERT_EQ(0U, minidump.GetDirectoryEntryCount());
michael@0 142 }
michael@0 143
michael@0 144 TEST(Dump, OneStream) {
michael@0 145 Dump dump(0, kBigEndian);
michael@0 146 Stream stream(dump, 0xfbb7fa2bU);
michael@0 147 stream.Append("stream contents");
michael@0 148 dump.Add(&stream);
michael@0 149 dump.Finish();
michael@0 150
michael@0 151 string contents;
michael@0 152 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 153 istringstream minidump_stream(contents);
michael@0 154 Minidump minidump(minidump_stream);
michael@0 155 ASSERT_TRUE(minidump.Read());
michael@0 156 ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
michael@0 157
michael@0 158 const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
michael@0 159 ASSERT_TRUE(dir != NULL);
michael@0 160 EXPECT_EQ(0xfbb7fa2bU, dir->stream_type);
michael@0 161
michael@0 162 uint32_t stream_length;
michael@0 163 ASSERT_TRUE(minidump.SeekToStreamType(0xfbb7fa2bU, &stream_length));
michael@0 164 ASSERT_EQ(15U, stream_length);
michael@0 165 char stream_contents[15];
michael@0 166 ASSERT_TRUE(minidump.ReadBytes(stream_contents, sizeof(stream_contents)));
michael@0 167 EXPECT_EQ(string("stream contents"),
michael@0 168 string(stream_contents, sizeof(stream_contents)));
michael@0 169
michael@0 170 EXPECT_FALSE(minidump.GetThreadList());
michael@0 171 EXPECT_FALSE(minidump.GetModuleList());
michael@0 172 EXPECT_FALSE(minidump.GetMemoryList());
michael@0 173 EXPECT_FALSE(minidump.GetException());
michael@0 174 EXPECT_FALSE(minidump.GetAssertion());
michael@0 175 EXPECT_FALSE(minidump.GetSystemInfo());
michael@0 176 EXPECT_FALSE(minidump.GetMiscInfo());
michael@0 177 EXPECT_FALSE(minidump.GetBreakpadInfo());
michael@0 178 }
michael@0 179
michael@0 180 TEST(Dump, OneMemory) {
michael@0 181 Dump dump(0, kBigEndian);
michael@0 182 Memory memory(dump, 0x309d68010bd21b2cULL);
michael@0 183 memory.Append("memory contents");
michael@0 184 dump.Add(&memory);
michael@0 185 dump.Finish();
michael@0 186
michael@0 187 string contents;
michael@0 188 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 189 istringstream minidump_stream(contents);
michael@0 190 Minidump minidump(minidump_stream);
michael@0 191 ASSERT_TRUE(minidump.Read());
michael@0 192 ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
michael@0 193
michael@0 194 const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
michael@0 195 ASSERT_TRUE(dir != NULL);
michael@0 196 EXPECT_EQ((uint32_t) MD_MEMORY_LIST_STREAM, dir->stream_type);
michael@0 197
michael@0 198 MinidumpMemoryList *memory_list = minidump.GetMemoryList();
michael@0 199 ASSERT_TRUE(memory_list != NULL);
michael@0 200 ASSERT_EQ(1U, memory_list->region_count());
michael@0 201
michael@0 202 MinidumpMemoryRegion *region1 = memory_list->GetMemoryRegionAtIndex(0);
michael@0 203 ASSERT_EQ(0x309d68010bd21b2cULL, region1->GetBase());
michael@0 204 ASSERT_EQ(15U, region1->GetSize());
michael@0 205 const uint8_t *region1_bytes = region1->GetMemory();
michael@0 206 ASSERT_TRUE(memcmp("memory contents", region1_bytes, 15) == 0);
michael@0 207 }
michael@0 208
michael@0 209 // One thread --- and its requisite entourage.
michael@0 210 TEST(Dump, OneThread) {
michael@0 211 Dump dump(0, kLittleEndian);
michael@0 212 Memory stack(dump, 0x2326a0fa);
michael@0 213 stack.Append("stack for thread");
michael@0 214
michael@0 215 MDRawContextX86 raw_context;
michael@0 216 const uint32_t kExpectedEIP = 0x6913f540;
michael@0 217 raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL;
michael@0 218 raw_context.edi = 0x3ecba80d;
michael@0 219 raw_context.esi = 0x382583b9;
michael@0 220 raw_context.ebx = 0x7fccc03f;
michael@0 221 raw_context.edx = 0xf62f8ec2;
michael@0 222 raw_context.ecx = 0x46a6a6a8;
michael@0 223 raw_context.eax = 0x6a5025e2;
michael@0 224 raw_context.ebp = 0xd9fabb4a;
michael@0 225 raw_context.eip = kExpectedEIP;
michael@0 226 raw_context.cs = 0xbffe6eda;
michael@0 227 raw_context.eflags = 0xb2ce1e2d;
michael@0 228 raw_context.esp = 0x659caaa4;
michael@0 229 raw_context.ss = 0x2e951ef7;
michael@0 230 Context context(dump, raw_context);
michael@0 231
michael@0 232 Thread thread(dump, 0xa898f11b, stack, context,
michael@0 233 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL);
michael@0 234
michael@0 235 dump.Add(&stack);
michael@0 236 dump.Add(&context);
michael@0 237 dump.Add(&thread);
michael@0 238 dump.Finish();
michael@0 239
michael@0 240 string contents;
michael@0 241 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 242
michael@0 243 istringstream minidump_stream(contents);
michael@0 244 Minidump minidump(minidump_stream);
michael@0 245 ASSERT_TRUE(minidump.Read());
michael@0 246 ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
michael@0 247
michael@0 248 MinidumpMemoryList *md_memory_list = minidump.GetMemoryList();
michael@0 249 ASSERT_TRUE(md_memory_list != NULL);
michael@0 250 ASSERT_EQ(1U, md_memory_list->region_count());
michael@0 251
michael@0 252 MinidumpMemoryRegion *md_region = md_memory_list->GetMemoryRegionAtIndex(0);
michael@0 253 ASSERT_EQ(0x2326a0faU, md_region->GetBase());
michael@0 254 ASSERT_EQ(16U, md_region->GetSize());
michael@0 255 const uint8_t *region_bytes = md_region->GetMemory();
michael@0 256 ASSERT_TRUE(memcmp("stack for thread", region_bytes, 16) == 0);
michael@0 257
michael@0 258 MinidumpThreadList *thread_list = minidump.GetThreadList();
michael@0 259 ASSERT_TRUE(thread_list != NULL);
michael@0 260 ASSERT_EQ(1U, thread_list->thread_count());
michael@0 261
michael@0 262 MinidumpThread *md_thread = thread_list->GetThreadAtIndex(0);
michael@0 263 ASSERT_TRUE(md_thread != NULL);
michael@0 264 uint32_t thread_id;
michael@0 265 ASSERT_TRUE(md_thread->GetThreadID(&thread_id));
michael@0 266 ASSERT_EQ(0xa898f11bU, thread_id);
michael@0 267 MinidumpMemoryRegion *md_stack = md_thread->GetMemory();
michael@0 268 ASSERT_TRUE(md_stack != NULL);
michael@0 269 ASSERT_EQ(0x2326a0faU, md_stack->GetBase());
michael@0 270 ASSERT_EQ(16U, md_stack->GetSize());
michael@0 271 const uint8_t *md_stack_bytes = md_stack->GetMemory();
michael@0 272 ASSERT_TRUE(memcmp("stack for thread", md_stack_bytes, 16) == 0);
michael@0 273
michael@0 274 MinidumpContext *md_context = md_thread->GetContext();
michael@0 275 ASSERT_TRUE(md_context != NULL);
michael@0 276 ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
michael@0 277
michael@0 278 uint64_t eip;
michael@0 279 ASSERT_TRUE(md_context->GetInstructionPointer(&eip));
michael@0 280 EXPECT_EQ(kExpectedEIP, eip);
michael@0 281
michael@0 282 const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
michael@0 283 ASSERT_TRUE(md_raw_context != NULL);
michael@0 284 ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL),
michael@0 285 (md_raw_context->context_flags
michael@0 286 & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL)));
michael@0 287 EXPECT_EQ(0x3ecba80dU, raw_context.edi);
michael@0 288 EXPECT_EQ(0x382583b9U, raw_context.esi);
michael@0 289 EXPECT_EQ(0x7fccc03fU, raw_context.ebx);
michael@0 290 EXPECT_EQ(0xf62f8ec2U, raw_context.edx);
michael@0 291 EXPECT_EQ(0x46a6a6a8U, raw_context.ecx);
michael@0 292 EXPECT_EQ(0x6a5025e2U, raw_context.eax);
michael@0 293 EXPECT_EQ(0xd9fabb4aU, raw_context.ebp);
michael@0 294 EXPECT_EQ(kExpectedEIP, raw_context.eip);
michael@0 295 EXPECT_EQ(0xbffe6edaU, raw_context.cs);
michael@0 296 EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags);
michael@0 297 EXPECT_EQ(0x659caaa4U, raw_context.esp);
michael@0 298 EXPECT_EQ(0x2e951ef7U, raw_context.ss);
michael@0 299 }
michael@0 300
michael@0 301 TEST(Dump, ThreadMissingMemory) {
michael@0 302 Dump dump(0, kLittleEndian);
michael@0 303 Memory stack(dump, 0x2326a0fa);
michael@0 304 // Stack has no contents.
michael@0 305
michael@0 306 MDRawContextX86 raw_context;
michael@0 307 memset(&raw_context, 0, sizeof(raw_context));
michael@0 308 raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL;
michael@0 309 Context context(dump, raw_context);
michael@0 310
michael@0 311 Thread thread(dump, 0xa898f11b, stack, context,
michael@0 312 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL);
michael@0 313
michael@0 314 dump.Add(&stack);
michael@0 315 dump.Add(&context);
michael@0 316 dump.Add(&thread);
michael@0 317 dump.Finish();
michael@0 318
michael@0 319 string contents;
michael@0 320 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 321
michael@0 322 istringstream minidump_stream(contents);
michael@0 323 Minidump minidump(minidump_stream);
michael@0 324 ASSERT_TRUE(minidump.Read());
michael@0 325 ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
michael@0 326
michael@0 327 // This should succeed even though the thread has no stack memory.
michael@0 328 MinidumpThreadList* thread_list = minidump.GetThreadList();
michael@0 329 ASSERT_TRUE(thread_list != NULL);
michael@0 330 ASSERT_EQ(1U, thread_list->thread_count());
michael@0 331
michael@0 332 MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0);
michael@0 333 ASSERT_TRUE(md_thread != NULL);
michael@0 334
michael@0 335 uint32_t thread_id;
michael@0 336 ASSERT_TRUE(md_thread->GetThreadID(&thread_id));
michael@0 337 ASSERT_EQ(0xa898f11bU, thread_id);
michael@0 338
michael@0 339 MinidumpContext* md_context = md_thread->GetContext();
michael@0 340 ASSERT_NE(reinterpret_cast<MinidumpContext*>(NULL), md_context);
michael@0 341
michael@0 342 MinidumpMemoryRegion* md_stack = md_thread->GetMemory();
michael@0 343 ASSERT_EQ(reinterpret_cast<MinidumpMemoryRegion*>(NULL), md_stack);
michael@0 344 }
michael@0 345
michael@0 346 TEST(Dump, ThreadMissingContext) {
michael@0 347 Dump dump(0, kLittleEndian);
michael@0 348 Memory stack(dump, 0x2326a0fa);
michael@0 349 stack.Append("stack for thread");
michael@0 350
michael@0 351 // Context is empty.
michael@0 352 Context context(dump);
michael@0 353
michael@0 354 Thread thread(dump, 0xa898f11b, stack, context,
michael@0 355 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL);
michael@0 356
michael@0 357 dump.Add(&stack);
michael@0 358 dump.Add(&context);
michael@0 359 dump.Add(&thread);
michael@0 360 dump.Finish();
michael@0 361
michael@0 362 string contents;
michael@0 363 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 364
michael@0 365 istringstream minidump_stream(contents);
michael@0 366 Minidump minidump(minidump_stream);
michael@0 367 ASSERT_TRUE(minidump.Read());
michael@0 368 ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
michael@0 369
michael@0 370 // This should succeed even though the thread has no stack memory.
michael@0 371 MinidumpThreadList* thread_list = minidump.GetThreadList();
michael@0 372 ASSERT_TRUE(thread_list != NULL);
michael@0 373 ASSERT_EQ(1U, thread_list->thread_count());
michael@0 374
michael@0 375 MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0);
michael@0 376 ASSERT_TRUE(md_thread != NULL);
michael@0 377
michael@0 378 uint32_t thread_id;
michael@0 379 ASSERT_TRUE(md_thread->GetThreadID(&thread_id));
michael@0 380 ASSERT_EQ(0xa898f11bU, thread_id);
michael@0 381 MinidumpMemoryRegion* md_stack = md_thread->GetMemory();
michael@0 382 ASSERT_NE(reinterpret_cast<MinidumpMemoryRegion*>(NULL), md_stack);
michael@0 383
michael@0 384 MinidumpContext* md_context = md_thread->GetContext();
michael@0 385 ASSERT_EQ(reinterpret_cast<MinidumpContext*>(NULL), md_context);
michael@0 386 }
michael@0 387
michael@0 388 TEST(Dump, OneModule) {
michael@0 389 static const MDVSFixedFileInfo fixed_file_info = {
michael@0 390 0xb2fba33a, // signature
michael@0 391 0x33d7a728, // struct_version
michael@0 392 0x31afcb20, // file_version_hi
michael@0 393 0xe51cdab1, // file_version_lo
michael@0 394 0xd1ea6907, // product_version_hi
michael@0 395 0x03032857, // product_version_lo
michael@0 396 0x11bf71d7, // file_flags_mask
michael@0 397 0x5fb8cdbf, // file_flags
michael@0 398 0xe45d0d5d, // file_os
michael@0 399 0x107d9562, // file_type
michael@0 400 0x5a8844d4, // file_subtype
michael@0 401 0xa8d30b20, // file_date_hi
michael@0 402 0x651c3e4e // file_date_lo
michael@0 403 };
michael@0 404
michael@0 405 Dump dump(0, kBigEndian);
michael@0 406 String module_name(dump, "single module");
michael@0 407 Module module(dump, 0xa90206ca83eb2852ULL, 0xada542bd,
michael@0 408 module_name,
michael@0 409 0xb1054d2a,
michael@0 410 0x34571371,
michael@0 411 fixed_file_info, // from synth_minidump_unittest_data.h
michael@0 412 NULL, NULL);
michael@0 413
michael@0 414 dump.Add(&module);
michael@0 415 dump.Add(&module_name);
michael@0 416 dump.Finish();
michael@0 417
michael@0 418 string contents;
michael@0 419 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 420 istringstream minidump_stream(contents);
michael@0 421 Minidump minidump(minidump_stream);
michael@0 422 ASSERT_TRUE(minidump.Read());
michael@0 423 ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
michael@0 424
michael@0 425 const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
michael@0 426 ASSERT_TRUE(dir != NULL);
michael@0 427 EXPECT_EQ((uint32_t) MD_MODULE_LIST_STREAM, dir->stream_type);
michael@0 428
michael@0 429 MinidumpModuleList *md_module_list = minidump.GetModuleList();
michael@0 430 ASSERT_TRUE(md_module_list != NULL);
michael@0 431 ASSERT_EQ(1U, md_module_list->module_count());
michael@0 432
michael@0 433 const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0);
michael@0 434 ASSERT_TRUE(md_module != NULL);
michael@0 435 ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address());
michael@0 436 ASSERT_EQ(0xada542bd, md_module->size());
michael@0 437 ASSERT_EQ("single module", md_module->code_file());
michael@0 438
michael@0 439 const MDRawModule *md_raw_module = md_module->module();
michael@0 440 ASSERT_TRUE(md_raw_module != NULL);
michael@0 441 ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp);
michael@0 442 ASSERT_EQ(0x34571371U, md_raw_module->checksum);
michael@0 443 ASSERT_TRUE(memcmp(&md_raw_module->version_info, &fixed_file_info,
michael@0 444 sizeof(fixed_file_info)) == 0);
michael@0 445 }
michael@0 446
michael@0 447 TEST(Dump, OneSystemInfo) {
michael@0 448 Dump dump(0, kLittleEndian);
michael@0 449 String csd_version(dump, "Petulant Pierogi");
michael@0 450 SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version);
michael@0 451
michael@0 452 dump.Add(&system_info);
michael@0 453 dump.Add(&csd_version);
michael@0 454 dump.Finish();
michael@0 455
michael@0 456 string contents;
michael@0 457 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 458 istringstream minidump_stream(contents);
michael@0 459 Minidump minidump(minidump_stream);
michael@0 460 ASSERT_TRUE(minidump.Read());
michael@0 461 ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
michael@0 462
michael@0 463 const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
michael@0 464 ASSERT_TRUE(dir != NULL);
michael@0 465 EXPECT_EQ((uint32_t) MD_SYSTEM_INFO_STREAM, dir->stream_type);
michael@0 466
michael@0 467 MinidumpSystemInfo *md_system_info = minidump.GetSystemInfo();
michael@0 468 ASSERT_TRUE(md_system_info != NULL);
michael@0 469 ASSERT_EQ("windows", md_system_info->GetOS());
michael@0 470 ASSERT_EQ("x86", md_system_info->GetCPU());
michael@0 471 ASSERT_EQ("Petulant Pierogi", *md_system_info->GetCSDVersion());
michael@0 472 ASSERT_EQ("GenuineIntel", *md_system_info->GetCPUVendor());
michael@0 473 }
michael@0 474
michael@0 475 TEST(Dump, BigDump) {
michael@0 476 Dump dump(0, kLittleEndian);
michael@0 477
michael@0 478 // A SystemInfo stream.
michael@0 479 String csd_version(dump, "Munificent Macaque");
michael@0 480 SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version);
michael@0 481 dump.Add(&csd_version);
michael@0 482 dump.Add(&system_info);
michael@0 483
michael@0 484 // Five threads!
michael@0 485 Memory stack0(dump, 0x70b9ebfc);
michael@0 486 stack0.Append("stack for thread zero");
michael@0 487 MDRawContextX86 raw_context0;
michael@0 488 raw_context0.context_flags = MD_CONTEXT_X86_INTEGER;
michael@0 489 raw_context0.eip = 0xaf0709e4;
michael@0 490 Context context0(dump, raw_context0);
michael@0 491 Thread thread0(dump, 0xbbef4432, stack0, context0,
michael@0 492 0xd0377e7b, 0xdb8eb0cf, 0xd73bc314, 0x09d357bac7f9a163ULL);
michael@0 493 dump.Add(&stack0);
michael@0 494 dump.Add(&context0);
michael@0 495 dump.Add(&thread0);
michael@0 496
michael@0 497 Memory stack1(dump, 0xf988cc45);
michael@0 498 stack1.Append("stack for thread one");
michael@0 499 MDRawContextX86 raw_context1;
michael@0 500 raw_context1.context_flags = MD_CONTEXT_X86_INTEGER;
michael@0 501 raw_context1.eip = 0xe4f56f81;
michael@0 502 Context context1(dump, raw_context1);
michael@0 503 Thread thread1(dump, 0x657c3f58, stack1, context1,
michael@0 504 0xa68fa182, 0x6f3cf8dd, 0xe3a78ccf, 0x78cc84775e4534bbULL);
michael@0 505 dump.Add(&stack1);
michael@0 506 dump.Add(&context1);
michael@0 507 dump.Add(&thread1);
michael@0 508
michael@0 509 Memory stack2(dump, 0xc8a92e7c);
michael@0 510 stack2.Append("stack for thread two");
michael@0 511 MDRawContextX86 raw_context2;
michael@0 512 raw_context2.context_flags = MD_CONTEXT_X86_INTEGER;
michael@0 513 raw_context2.eip = 0xb336a438;
michael@0 514 Context context2(dump, raw_context2);
michael@0 515 Thread thread2(dump, 0xdf4b8a71, stack2, context2,
michael@0 516 0x674c26b6, 0x445d7120, 0x7e700c56, 0xd89bf778e7793e17ULL);
michael@0 517 dump.Add(&stack2);
michael@0 518 dump.Add(&context2);
michael@0 519 dump.Add(&thread2);
michael@0 520
michael@0 521 Memory stack3(dump, 0x36d08e08);
michael@0 522 stack3.Append("stack for thread three");
michael@0 523 MDRawContextX86 raw_context3;
michael@0 524 raw_context3.context_flags = MD_CONTEXT_X86_INTEGER;
michael@0 525 raw_context3.eip = 0xdf99a60c;
michael@0 526 Context context3(dump, raw_context3);
michael@0 527 Thread thread3(dump, 0x86e6c341, stack3, context3,
michael@0 528 0x32dc5c55, 0x17a2aba8, 0xe0cc75e7, 0xa46393994dae83aeULL);
michael@0 529 dump.Add(&stack3);
michael@0 530 dump.Add(&context3);
michael@0 531 dump.Add(&thread3);
michael@0 532
michael@0 533 Memory stack4(dump, 0x1e0ab4fa);
michael@0 534 stack4.Append("stack for thread four");
michael@0 535 MDRawContextX86 raw_context4;
michael@0 536 raw_context4.context_flags = MD_CONTEXT_X86_INTEGER;
michael@0 537 raw_context4.eip = 0xaa646267;
michael@0 538 Context context4(dump, raw_context4);
michael@0 539 Thread thread4(dump, 0x261a28d4, stack4, context4,
michael@0 540 0x6ebd389e, 0xa0cd4759, 0x30168846, 0x164f650a0cf39d35ULL);
michael@0 541 dump.Add(&stack4);
michael@0 542 dump.Add(&context4);
michael@0 543 dump.Add(&thread4);
michael@0 544
michael@0 545 // Three modules!
michael@0 546 String module1_name(dump, "module one");
michael@0 547 Module module1(dump, 0xeb77da57b5d4cbdaULL, 0x83cd5a37, module1_name);
michael@0 548 dump.Add(&module1_name);
michael@0 549 dump.Add(&module1);
michael@0 550
michael@0 551 String module2_name(dump, "module two");
michael@0 552 Module module2(dump, 0x8675884adfe5ac90ULL, 0xb11e4ea3, module2_name);
michael@0 553 dump.Add(&module2_name);
michael@0 554 dump.Add(&module2);
michael@0 555
michael@0 556 String module3_name(dump, "module three");
michael@0 557 Module module3(dump, 0x95fc1544da321b6cULL, 0x7c2bf081, module3_name);
michael@0 558 dump.Add(&module3_name);
michael@0 559 dump.Add(&module3);
michael@0 560
michael@0 561 // Add one more memory region, on top of the five stacks.
michael@0 562 Memory memory5(dump, 0x61979e828040e564ULL);
michael@0 563 memory5.Append("contents of memory 5");
michael@0 564 dump.Add(&memory5);
michael@0 565
michael@0 566 dump.Finish();
michael@0 567
michael@0 568 string contents;
michael@0 569 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 570 istringstream minidump_stream(contents);
michael@0 571 Minidump minidump(minidump_stream);
michael@0 572 ASSERT_TRUE(minidump.Read());
michael@0 573 ASSERT_EQ(4U, minidump.GetDirectoryEntryCount());
michael@0 574
michael@0 575 // Check the threads.
michael@0 576 MinidumpThreadList *thread_list = minidump.GetThreadList();
michael@0 577 ASSERT_TRUE(thread_list != NULL);
michael@0 578 ASSERT_EQ(5U, thread_list->thread_count());
michael@0 579 uint32_t thread_id;
michael@0 580 ASSERT_TRUE(thread_list->GetThreadAtIndex(0)->GetThreadID(&thread_id));
michael@0 581 ASSERT_EQ(0xbbef4432U, thread_id);
michael@0 582 ASSERT_EQ(0x70b9ebfcU,
michael@0 583 thread_list->GetThreadAtIndex(0)->GetMemory()->GetBase());
michael@0 584 ASSERT_EQ(0xaf0709e4U,
michael@0 585 thread_list->GetThreadAtIndex(0)->GetContext()->GetContextX86()
michael@0 586 ->eip);
michael@0 587
michael@0 588 ASSERT_TRUE(thread_list->GetThreadAtIndex(1)->GetThreadID(&thread_id));
michael@0 589 ASSERT_EQ(0x657c3f58U, thread_id);
michael@0 590 ASSERT_EQ(0xf988cc45U,
michael@0 591 thread_list->GetThreadAtIndex(1)->GetMemory()->GetBase());
michael@0 592 ASSERT_EQ(0xe4f56f81U,
michael@0 593 thread_list->GetThreadAtIndex(1)->GetContext()->GetContextX86()
michael@0 594 ->eip);
michael@0 595
michael@0 596 ASSERT_TRUE(thread_list->GetThreadAtIndex(2)->GetThreadID(&thread_id));
michael@0 597 ASSERT_EQ(0xdf4b8a71U, thread_id);
michael@0 598 ASSERT_EQ(0xc8a92e7cU,
michael@0 599 thread_list->GetThreadAtIndex(2)->GetMemory()->GetBase());
michael@0 600 ASSERT_EQ(0xb336a438U,
michael@0 601 thread_list->GetThreadAtIndex(2)->GetContext()->GetContextX86()
michael@0 602 ->eip);
michael@0 603
michael@0 604 ASSERT_TRUE(thread_list->GetThreadAtIndex(3)->GetThreadID(&thread_id));
michael@0 605 ASSERT_EQ(0x86e6c341U, thread_id);
michael@0 606 ASSERT_EQ(0x36d08e08U,
michael@0 607 thread_list->GetThreadAtIndex(3)->GetMemory()->GetBase());
michael@0 608 ASSERT_EQ(0xdf99a60cU,
michael@0 609 thread_list->GetThreadAtIndex(3)->GetContext()->GetContextX86()
michael@0 610 ->eip);
michael@0 611
michael@0 612 ASSERT_TRUE(thread_list->GetThreadAtIndex(4)->GetThreadID(&thread_id));
michael@0 613 ASSERT_EQ(0x261a28d4U, thread_id);
michael@0 614 ASSERT_EQ(0x1e0ab4faU,
michael@0 615 thread_list->GetThreadAtIndex(4)->GetMemory()->GetBase());
michael@0 616 ASSERT_EQ(0xaa646267U,
michael@0 617 thread_list->GetThreadAtIndex(4)->GetContext()->GetContextX86()
michael@0 618 ->eip);
michael@0 619
michael@0 620 // Check the modules.
michael@0 621 MinidumpModuleList *md_module_list = minidump.GetModuleList();
michael@0 622 ASSERT_TRUE(md_module_list != NULL);
michael@0 623 ASSERT_EQ(3U, md_module_list->module_count());
michael@0 624 EXPECT_EQ(0xeb77da57b5d4cbdaULL,
michael@0 625 md_module_list->GetModuleAtIndex(0)->base_address());
michael@0 626 EXPECT_EQ(0x8675884adfe5ac90ULL,
michael@0 627 md_module_list->GetModuleAtIndex(1)->base_address());
michael@0 628 EXPECT_EQ(0x95fc1544da321b6cULL,
michael@0 629 md_module_list->GetModuleAtIndex(2)->base_address());
michael@0 630 }
michael@0 631
michael@0 632 TEST(Dump, OneMemoryInfo) {
michael@0 633 Dump dump(0, kBigEndian);
michael@0 634 Stream stream(dump, MD_MEMORY_INFO_LIST_STREAM);
michael@0 635
michael@0 636 // Add the MDRawMemoryInfoList header.
michael@0 637 const uint64_t kNumberOfEntries = 1;
michael@0 638 stream.D32(sizeof(MDRawMemoryInfoList)) // size_of_header
michael@0 639 .D32(sizeof(MDRawMemoryInfo)) // size_of_entry
michael@0 640 .D64(kNumberOfEntries); // number_of_entries
michael@0 641
michael@0 642
michael@0 643 // Now add a MDRawMemoryInfo entry.
michael@0 644 const uint64_t kBaseAddress = 0x1000;
michael@0 645 const uint64_t kRegionSize = 0x2000;
michael@0 646 stream.D64(kBaseAddress) // base_address
michael@0 647 .D64(kBaseAddress) // allocation_base
michael@0 648 .D32(MD_MEMORY_PROTECT_EXECUTE_READWRITE) // allocation_protection
michael@0 649 .D32(0) // __alignment1
michael@0 650 .D64(kRegionSize) // region_size
michael@0 651 .D32(MD_MEMORY_STATE_COMMIT) // state
michael@0 652 .D32(MD_MEMORY_PROTECT_EXECUTE_READWRITE) // protection
michael@0 653 .D32(MD_MEMORY_TYPE_PRIVATE) // type
michael@0 654 .D32(0); // __alignment2
michael@0 655
michael@0 656 dump.Add(&stream);
michael@0 657 dump.Finish();
michael@0 658
michael@0 659 string contents;
michael@0 660 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 661 istringstream minidump_stream(contents);
michael@0 662 Minidump minidump(minidump_stream);
michael@0 663 ASSERT_TRUE(minidump.Read());
michael@0 664 ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
michael@0 665
michael@0 666 const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
michael@0 667 ASSERT_TRUE(dir != NULL);
michael@0 668 EXPECT_EQ((uint32_t) MD_MEMORY_INFO_LIST_STREAM, dir->stream_type);
michael@0 669
michael@0 670 MinidumpMemoryInfoList *info_list = minidump.GetMemoryInfoList();
michael@0 671 ASSERT_TRUE(info_list != NULL);
michael@0 672 ASSERT_EQ(1U, info_list->info_count());
michael@0 673
michael@0 674 const MinidumpMemoryInfo *info1 = info_list->GetMemoryInfoAtIndex(0);
michael@0 675 ASSERT_EQ(kBaseAddress, info1->GetBase());
michael@0 676 ASSERT_EQ(kRegionSize, info1->GetSize());
michael@0 677 ASSERT_TRUE(info1->IsExecutable());
michael@0 678 ASSERT_TRUE(info1->IsWritable());
michael@0 679
michael@0 680 // Should get back the same memory region here.
michael@0 681 const MinidumpMemoryInfo *info2 =
michael@0 682 info_list->GetMemoryInfoForAddress(kBaseAddress + kRegionSize / 2);
michael@0 683 ASSERT_EQ(kBaseAddress, info2->GetBase());
michael@0 684 ASSERT_EQ(kRegionSize, info2->GetSize());
michael@0 685 }
michael@0 686
michael@0 687 TEST(Dump, OneExceptionX86) {
michael@0 688 Dump dump(0, kLittleEndian);
michael@0 689
michael@0 690 MDRawContextX86 raw_context;
michael@0 691 raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL;
michael@0 692 raw_context.edi = 0x3ecba80d;
michael@0 693 raw_context.esi = 0x382583b9;
michael@0 694 raw_context.ebx = 0x7fccc03f;
michael@0 695 raw_context.edx = 0xf62f8ec2;
michael@0 696 raw_context.ecx = 0x46a6a6a8;
michael@0 697 raw_context.eax = 0x6a5025e2;
michael@0 698 raw_context.ebp = 0xd9fabb4a;
michael@0 699 raw_context.eip = 0x6913f540;
michael@0 700 raw_context.cs = 0xbffe6eda;
michael@0 701 raw_context.eflags = 0xb2ce1e2d;
michael@0 702 raw_context.esp = 0x659caaa4;
michael@0 703 raw_context.ss = 0x2e951ef7;
michael@0 704 Context context(dump, raw_context);
michael@0 705
michael@0 706 Exception exception(dump, context,
michael@0 707 0x1234abcd, // thread id
michael@0 708 0xdcba4321, // exception code
michael@0 709 0xf0e0d0c0, // exception flags
michael@0 710 0x0919a9b9c9d9e9f9ULL); // exception address
michael@0 711
michael@0 712 dump.Add(&context);
michael@0 713 dump.Add(&exception);
michael@0 714 dump.Finish();
michael@0 715
michael@0 716 string contents;
michael@0 717 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 718
michael@0 719 istringstream minidump_stream(contents);
michael@0 720 Minidump minidump(minidump_stream);
michael@0 721 ASSERT_TRUE(minidump.Read());
michael@0 722 ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
michael@0 723
michael@0 724 MinidumpException *md_exception = minidump.GetException();
michael@0 725 ASSERT_TRUE(md_exception != NULL);
michael@0 726
michael@0 727 uint32_t thread_id;
michael@0 728 ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
michael@0 729 ASSERT_EQ(0x1234abcdU, thread_id);
michael@0 730
michael@0 731 const MDRawExceptionStream* raw_exception = md_exception->exception();
michael@0 732 ASSERT_TRUE(raw_exception != NULL);
michael@0 733 EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
michael@0 734 EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
michael@0 735 EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
michael@0 736 raw_exception->exception_record.exception_address);
michael@0 737
michael@0 738 MinidumpContext *md_context = md_exception->GetContext();
michael@0 739 ASSERT_TRUE(md_context != NULL);
michael@0 740 ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
michael@0 741 const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
michael@0 742 ASSERT_TRUE(md_raw_context != NULL);
michael@0 743 ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL),
michael@0 744 (md_raw_context->context_flags
michael@0 745 & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL)));
michael@0 746 EXPECT_EQ(0x3ecba80dU, raw_context.edi);
michael@0 747 EXPECT_EQ(0x382583b9U, raw_context.esi);
michael@0 748 EXPECT_EQ(0x7fccc03fU, raw_context.ebx);
michael@0 749 EXPECT_EQ(0xf62f8ec2U, raw_context.edx);
michael@0 750 EXPECT_EQ(0x46a6a6a8U, raw_context.ecx);
michael@0 751 EXPECT_EQ(0x6a5025e2U, raw_context.eax);
michael@0 752 EXPECT_EQ(0xd9fabb4aU, raw_context.ebp);
michael@0 753 EXPECT_EQ(0x6913f540U, raw_context.eip);
michael@0 754 EXPECT_EQ(0xbffe6edaU, raw_context.cs);
michael@0 755 EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags);
michael@0 756 EXPECT_EQ(0x659caaa4U, raw_context.esp);
michael@0 757 EXPECT_EQ(0x2e951ef7U, raw_context.ss);
michael@0 758 }
michael@0 759
michael@0 760 TEST(Dump, OneExceptionX86XState) {
michael@0 761 Dump dump(0, kLittleEndian);
michael@0 762
michael@0 763 MDRawContextX86 raw_context;
michael@0 764 raw_context.context_flags = MD_CONTEXT_X86_INTEGER |
michael@0 765 MD_CONTEXT_X86_CONTROL | MD_CONTEXT_X86_XSTATE;
michael@0 766 raw_context.edi = 0x3ecba80d;
michael@0 767 raw_context.esi = 0x382583b9;
michael@0 768 raw_context.ebx = 0x7fccc03f;
michael@0 769 raw_context.edx = 0xf62f8ec2;
michael@0 770 raw_context.ecx = 0x46a6a6a8;
michael@0 771 raw_context.eax = 0x6a5025e2;
michael@0 772 raw_context.ebp = 0xd9fabb4a;
michael@0 773 raw_context.eip = 0x6913f540;
michael@0 774 raw_context.cs = 0xbffe6eda;
michael@0 775 raw_context.eflags = 0xb2ce1e2d;
michael@0 776 raw_context.esp = 0x659caaa4;
michael@0 777 raw_context.ss = 0x2e951ef7;
michael@0 778 Context context(dump, raw_context);
michael@0 779
michael@0 780 Exception exception(dump, context,
michael@0 781 0x1234abcd, // thread id
michael@0 782 0xdcba4321, // exception code
michael@0 783 0xf0e0d0c0, // exception flags
michael@0 784 0x0919a9b9c9d9e9f9ULL); // exception address
michael@0 785
michael@0 786 dump.Add(&context);
michael@0 787 dump.Add(&exception);
michael@0 788 dump.Finish();
michael@0 789
michael@0 790 string contents;
michael@0 791 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 792
michael@0 793 istringstream minidump_stream(contents);
michael@0 794 Minidump minidump(minidump_stream);
michael@0 795 ASSERT_TRUE(minidump.Read());
michael@0 796 ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
michael@0 797
michael@0 798 MinidumpException *md_exception = minidump.GetException();
michael@0 799 ASSERT_TRUE(md_exception != NULL);
michael@0 800
michael@0 801 uint32_t thread_id;
michael@0 802 ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
michael@0 803 ASSERT_EQ(0x1234abcdU, thread_id);
michael@0 804
michael@0 805 const MDRawExceptionStream* raw_exception = md_exception->exception();
michael@0 806 ASSERT_TRUE(raw_exception != NULL);
michael@0 807 EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
michael@0 808 EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
michael@0 809 EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
michael@0 810 raw_exception->exception_record.exception_address);
michael@0 811
michael@0 812 MinidumpContext *md_context = md_exception->GetContext();
michael@0 813 ASSERT_TRUE(md_context != NULL);
michael@0 814 ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
michael@0 815 const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
michael@0 816 ASSERT_TRUE(md_raw_context != NULL);
michael@0 817 ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL),
michael@0 818 (md_raw_context->context_flags
michael@0 819 & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL)));
michael@0 820 EXPECT_EQ(0x3ecba80dU, raw_context.edi);
michael@0 821 EXPECT_EQ(0x382583b9U, raw_context.esi);
michael@0 822 EXPECT_EQ(0x7fccc03fU, raw_context.ebx);
michael@0 823 EXPECT_EQ(0xf62f8ec2U, raw_context.edx);
michael@0 824 EXPECT_EQ(0x46a6a6a8U, raw_context.ecx);
michael@0 825 EXPECT_EQ(0x6a5025e2U, raw_context.eax);
michael@0 826 EXPECT_EQ(0xd9fabb4aU, raw_context.ebp);
michael@0 827 EXPECT_EQ(0x6913f540U, raw_context.eip);
michael@0 828 EXPECT_EQ(0xbffe6edaU, raw_context.cs);
michael@0 829 EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags);
michael@0 830 EXPECT_EQ(0x659caaa4U, raw_context.esp);
michael@0 831 EXPECT_EQ(0x2e951ef7U, raw_context.ss);
michael@0 832 }
michael@0 833
michael@0 834 // Testing that the CPU type can be loaded from a system info stream when
michael@0 835 // the CPU flags are missing from the context_flags of an exception record
michael@0 836 TEST(Dump, OneExceptionX86NoCPUFlags) {
michael@0 837 Dump dump(0, kLittleEndian);
michael@0 838
michael@0 839 MDRawContextX86 raw_context;
michael@0 840 // Intentionally not setting CPU type in the context_flags
michael@0 841 raw_context.context_flags = 0;
michael@0 842 raw_context.edi = 0x3ecba80d;
michael@0 843 raw_context.esi = 0x382583b9;
michael@0 844 raw_context.ebx = 0x7fccc03f;
michael@0 845 raw_context.edx = 0xf62f8ec2;
michael@0 846 raw_context.ecx = 0x46a6a6a8;
michael@0 847 raw_context.eax = 0x6a5025e2;
michael@0 848 raw_context.ebp = 0xd9fabb4a;
michael@0 849 raw_context.eip = 0x6913f540;
michael@0 850 raw_context.cs = 0xbffe6eda;
michael@0 851 raw_context.eflags = 0xb2ce1e2d;
michael@0 852 raw_context.esp = 0x659caaa4;
michael@0 853 raw_context.ss = 0x2e951ef7;
michael@0 854 Context context(dump, raw_context);
michael@0 855
michael@0 856 Exception exception(dump, context,
michael@0 857 0x1234abcd, // thread id
michael@0 858 0xdcba4321, // exception code
michael@0 859 0xf0e0d0c0, // exception flags
michael@0 860 0x0919a9b9c9d9e9f9ULL); // exception address
michael@0 861
michael@0 862 dump.Add(&context);
michael@0 863 dump.Add(&exception);
michael@0 864
michael@0 865 // Add system info. This is needed as an alternative source for CPU type
michael@0 866 // information. Note, that the CPU flags were intentionally skipped from
michael@0 867 // the context_flags and this alternative source is required.
michael@0 868 String csd_version(dump, "Service Pack 2");
michael@0 869 SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version);
michael@0 870 dump.Add(&system_info);
michael@0 871 dump.Add(&csd_version);
michael@0 872
michael@0 873 dump.Finish();
michael@0 874
michael@0 875 string contents;
michael@0 876 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 877
michael@0 878 istringstream minidump_stream(contents);
michael@0 879 Minidump minidump(minidump_stream);
michael@0 880 ASSERT_TRUE(minidump.Read());
michael@0 881 ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
michael@0 882
michael@0 883 MinidumpException *md_exception = minidump.GetException();
michael@0 884 ASSERT_TRUE(md_exception != NULL);
michael@0 885
michael@0 886 uint32_t thread_id;
michael@0 887 ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
michael@0 888 ASSERT_EQ(0x1234abcdU, thread_id);
michael@0 889
michael@0 890 const MDRawExceptionStream* raw_exception = md_exception->exception();
michael@0 891 ASSERT_TRUE(raw_exception != NULL);
michael@0 892 EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
michael@0 893 EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
michael@0 894 EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
michael@0 895 raw_exception->exception_record.exception_address);
michael@0 896
michael@0 897 MinidumpContext *md_context = md_exception->GetContext();
michael@0 898 ASSERT_TRUE(md_context != NULL);
michael@0 899
michael@0 900 ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
michael@0 901 const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
michael@0 902 ASSERT_TRUE(md_raw_context != NULL);
michael@0 903
michael@0 904 // Even though the CPU flags were missing from the context_flags, the
michael@0 905 // GetContext call above is expected to load the missing CPU flags from the
michael@0 906 // system info stream and set the CPU type bits in context_flags.
michael@0 907 ASSERT_EQ((uint32_t) (MD_CONTEXT_X86), md_raw_context->context_flags);
michael@0 908
michael@0 909 EXPECT_EQ(0x3ecba80dU, raw_context.edi);
michael@0 910 EXPECT_EQ(0x382583b9U, raw_context.esi);
michael@0 911 EXPECT_EQ(0x7fccc03fU, raw_context.ebx);
michael@0 912 EXPECT_EQ(0xf62f8ec2U, raw_context.edx);
michael@0 913 EXPECT_EQ(0x46a6a6a8U, raw_context.ecx);
michael@0 914 EXPECT_EQ(0x6a5025e2U, raw_context.eax);
michael@0 915 EXPECT_EQ(0xd9fabb4aU, raw_context.ebp);
michael@0 916 EXPECT_EQ(0x6913f540U, raw_context.eip);
michael@0 917 EXPECT_EQ(0xbffe6edaU, raw_context.cs);
michael@0 918 EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags);
michael@0 919 EXPECT_EQ(0x659caaa4U, raw_context.esp);
michael@0 920 EXPECT_EQ(0x2e951ef7U, raw_context.ss);
michael@0 921 }
michael@0 922
michael@0 923 // This test covers a scenario where a dump contains an exception but the
michael@0 924 // context record of the exception is missing the CPU type information in its
michael@0 925 // context_flags. The dump has no system info stream so it is imposible to
michael@0 926 // deduce the CPU type, hence the context record is unusable.
michael@0 927 TEST(Dump, OneExceptionX86NoCPUFlagsNoSystemInfo) {
michael@0 928 Dump dump(0, kLittleEndian);
michael@0 929
michael@0 930 MDRawContextX86 raw_context;
michael@0 931 // Intentionally not setting CPU type in the context_flags
michael@0 932 raw_context.context_flags = 0;
michael@0 933 raw_context.edi = 0x3ecba80d;
michael@0 934 raw_context.esi = 0x382583b9;
michael@0 935 raw_context.ebx = 0x7fccc03f;
michael@0 936 raw_context.edx = 0xf62f8ec2;
michael@0 937 raw_context.ecx = 0x46a6a6a8;
michael@0 938 raw_context.eax = 0x6a5025e2;
michael@0 939 raw_context.ebp = 0xd9fabb4a;
michael@0 940 raw_context.eip = 0x6913f540;
michael@0 941 raw_context.cs = 0xbffe6eda;
michael@0 942 raw_context.eflags = 0xb2ce1e2d;
michael@0 943 raw_context.esp = 0x659caaa4;
michael@0 944 raw_context.ss = 0x2e951ef7;
michael@0 945 Context context(dump, raw_context);
michael@0 946
michael@0 947 Exception exception(dump, context,
michael@0 948 0x1234abcd, // thread id
michael@0 949 0xdcba4321, // exception code
michael@0 950 0xf0e0d0c0, // exception flags
michael@0 951 0x0919a9b9c9d9e9f9ULL); // exception address
michael@0 952
michael@0 953 dump.Add(&context);
michael@0 954 dump.Add(&exception);
michael@0 955 dump.Finish();
michael@0 956
michael@0 957 string contents;
michael@0 958 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 959
michael@0 960 istringstream minidump_stream(contents);
michael@0 961 Minidump minidump(minidump_stream);
michael@0 962 ASSERT_TRUE(minidump.Read());
michael@0 963 ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
michael@0 964
michael@0 965 MinidumpException *md_exception = minidump.GetException();
michael@0 966 ASSERT_TRUE(md_exception != NULL);
michael@0 967
michael@0 968 uint32_t thread_id;
michael@0 969 ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
michael@0 970 ASSERT_EQ(0x1234abcdU, thread_id);
michael@0 971
michael@0 972 const MDRawExceptionStream* raw_exception = md_exception->exception();
michael@0 973 ASSERT_TRUE(raw_exception != NULL);
michael@0 974 EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
michael@0 975 EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
michael@0 976 EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
michael@0 977 raw_exception->exception_record.exception_address);
michael@0 978
michael@0 979 // The context record of the exception is unusable because the context_flags
michael@0 980 // don't have CPU type information and at the same time the minidump lacks
michael@0 981 // system info stream so it is impossible to deduce the CPU type.
michael@0 982 MinidumpContext *md_context = md_exception->GetContext();
michael@0 983 ASSERT_EQ(NULL, md_context);
michael@0 984 }
michael@0 985
michael@0 986 TEST(Dump, OneExceptionARM) {
michael@0 987 Dump dump(0, kLittleEndian);
michael@0 988
michael@0 989 MDRawContextARM raw_context;
michael@0 990 raw_context.context_flags = MD_CONTEXT_ARM_INTEGER;
michael@0 991 raw_context.iregs[0] = 0x3ecba80d;
michael@0 992 raw_context.iregs[1] = 0x382583b9;
michael@0 993 raw_context.iregs[2] = 0x7fccc03f;
michael@0 994 raw_context.iregs[3] = 0xf62f8ec2;
michael@0 995 raw_context.iregs[4] = 0x46a6a6a8;
michael@0 996 raw_context.iregs[5] = 0x6a5025e2;
michael@0 997 raw_context.iregs[6] = 0xd9fabb4a;
michael@0 998 raw_context.iregs[7] = 0x6913f540;
michael@0 999 raw_context.iregs[8] = 0xbffe6eda;
michael@0 1000 raw_context.iregs[9] = 0xb2ce1e2d;
michael@0 1001 raw_context.iregs[10] = 0x659caaa4;
michael@0 1002 raw_context.iregs[11] = 0xf0e0d0c0;
michael@0 1003 raw_context.iregs[12] = 0xa9b8c7d6;
michael@0 1004 raw_context.iregs[13] = 0x12345678;
michael@0 1005 raw_context.iregs[14] = 0xabcd1234;
michael@0 1006 raw_context.iregs[15] = 0x10203040;
michael@0 1007 raw_context.cpsr = 0x2e951ef7;
michael@0 1008 Context context(dump, raw_context);
michael@0 1009
michael@0 1010 Exception exception(dump, context,
michael@0 1011 0x1234abcd, // thread id
michael@0 1012 0xdcba4321, // exception code
michael@0 1013 0xf0e0d0c0, // exception flags
michael@0 1014 0x0919a9b9c9d9e9f9ULL); // exception address
michael@0 1015
michael@0 1016 dump.Add(&context);
michael@0 1017 dump.Add(&exception);
michael@0 1018 dump.Finish();
michael@0 1019
michael@0 1020 string contents;
michael@0 1021 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 1022
michael@0 1023 istringstream minidump_stream(contents);
michael@0 1024 Minidump minidump(minidump_stream);
michael@0 1025 ASSERT_TRUE(minidump.Read());
michael@0 1026 ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
michael@0 1027
michael@0 1028 MinidumpException *md_exception = minidump.GetException();
michael@0 1029 ASSERT_TRUE(md_exception != NULL);
michael@0 1030
michael@0 1031 uint32_t thread_id;
michael@0 1032 ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
michael@0 1033 ASSERT_EQ(0x1234abcdU, thread_id);
michael@0 1034
michael@0 1035 const MDRawExceptionStream* raw_exception = md_exception->exception();
michael@0 1036 ASSERT_TRUE(raw_exception != NULL);
michael@0 1037 EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
michael@0 1038 EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
michael@0 1039 EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
michael@0 1040 raw_exception->exception_record.exception_address);
michael@0 1041
michael@0 1042 MinidumpContext *md_context = md_exception->GetContext();
michael@0 1043 ASSERT_TRUE(md_context != NULL);
michael@0 1044 ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU());
michael@0 1045 const MDRawContextARM *md_raw_context = md_context->GetContextARM();
michael@0 1046 ASSERT_TRUE(md_raw_context != NULL);
michael@0 1047 ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER,
michael@0 1048 (md_raw_context->context_flags
michael@0 1049 & MD_CONTEXT_ARM_INTEGER));
michael@0 1050 EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]);
michael@0 1051 EXPECT_EQ(0x382583b9U, raw_context.iregs[1]);
michael@0 1052 EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]);
michael@0 1053 EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]);
michael@0 1054 EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]);
michael@0 1055 EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]);
michael@0 1056 EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]);
michael@0 1057 EXPECT_EQ(0x6913f540U, raw_context.iregs[7]);
michael@0 1058 EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]);
michael@0 1059 EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]);
michael@0 1060 EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]);
michael@0 1061 EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]);
michael@0 1062 EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]);
michael@0 1063 EXPECT_EQ(0x12345678U, raw_context.iregs[13]);
michael@0 1064 EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]);
michael@0 1065 EXPECT_EQ(0x10203040U, raw_context.iregs[15]);
michael@0 1066 EXPECT_EQ(0x2e951ef7U, raw_context.cpsr);
michael@0 1067 }
michael@0 1068
michael@0 1069 TEST(Dump, OneExceptionARMOldFlags) {
michael@0 1070 Dump dump(0, kLittleEndian);
michael@0 1071
michael@0 1072 MDRawContextARM raw_context;
michael@0 1073 // MD_CONTEXT_ARM_INTEGER, but with _OLD
michael@0 1074 raw_context.context_flags = MD_CONTEXT_ARM_OLD | 0x00000002;
michael@0 1075 raw_context.iregs[0] = 0x3ecba80d;
michael@0 1076 raw_context.iregs[1] = 0x382583b9;
michael@0 1077 raw_context.iregs[2] = 0x7fccc03f;
michael@0 1078 raw_context.iregs[3] = 0xf62f8ec2;
michael@0 1079 raw_context.iregs[4] = 0x46a6a6a8;
michael@0 1080 raw_context.iregs[5] = 0x6a5025e2;
michael@0 1081 raw_context.iregs[6] = 0xd9fabb4a;
michael@0 1082 raw_context.iregs[7] = 0x6913f540;
michael@0 1083 raw_context.iregs[8] = 0xbffe6eda;
michael@0 1084 raw_context.iregs[9] = 0xb2ce1e2d;
michael@0 1085 raw_context.iregs[10] = 0x659caaa4;
michael@0 1086 raw_context.iregs[11] = 0xf0e0d0c0;
michael@0 1087 raw_context.iregs[12] = 0xa9b8c7d6;
michael@0 1088 raw_context.iregs[13] = 0x12345678;
michael@0 1089 raw_context.iregs[14] = 0xabcd1234;
michael@0 1090 raw_context.iregs[15] = 0x10203040;
michael@0 1091 raw_context.cpsr = 0x2e951ef7;
michael@0 1092 Context context(dump, raw_context);
michael@0 1093
michael@0 1094 Exception exception(dump, context,
michael@0 1095 0x1234abcd, // thread id
michael@0 1096 0xdcba4321, // exception code
michael@0 1097 0xf0e0d0c0, // exception flags
michael@0 1098 0x0919a9b9c9d9e9f9ULL); // exception address
michael@0 1099
michael@0 1100 dump.Add(&context);
michael@0 1101 dump.Add(&exception);
michael@0 1102 dump.Finish();
michael@0 1103
michael@0 1104 string contents;
michael@0 1105 ASSERT_TRUE(dump.GetContents(&contents));
michael@0 1106
michael@0 1107 istringstream minidump_stream(contents);
michael@0 1108 Minidump minidump(minidump_stream);
michael@0 1109 ASSERT_TRUE(minidump.Read());
michael@0 1110 ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
michael@0 1111
michael@0 1112 MinidumpException *md_exception = minidump.GetException();
michael@0 1113 ASSERT_TRUE(md_exception != NULL);
michael@0 1114
michael@0 1115 uint32_t thread_id;
michael@0 1116 ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
michael@0 1117 ASSERT_EQ(0x1234abcdU, thread_id);
michael@0 1118
michael@0 1119 const MDRawExceptionStream* raw_exception = md_exception->exception();
michael@0 1120 ASSERT_TRUE(raw_exception != NULL);
michael@0 1121 EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
michael@0 1122 EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
michael@0 1123 EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
michael@0 1124 raw_exception->exception_record.exception_address);
michael@0 1125
michael@0 1126 MinidumpContext *md_context = md_exception->GetContext();
michael@0 1127 ASSERT_TRUE(md_context != NULL);
michael@0 1128 ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU());
michael@0 1129 const MDRawContextARM *md_raw_context = md_context->GetContextARM();
michael@0 1130 ASSERT_TRUE(md_raw_context != NULL);
michael@0 1131 ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER,
michael@0 1132 (md_raw_context->context_flags
michael@0 1133 & MD_CONTEXT_ARM_INTEGER));
michael@0 1134 EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]);
michael@0 1135 EXPECT_EQ(0x382583b9U, raw_context.iregs[1]);
michael@0 1136 EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]);
michael@0 1137 EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]);
michael@0 1138 EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]);
michael@0 1139 EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]);
michael@0 1140 EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]);
michael@0 1141 EXPECT_EQ(0x6913f540U, raw_context.iregs[7]);
michael@0 1142 EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]);
michael@0 1143 EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]);
michael@0 1144 EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]);
michael@0 1145 EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]);
michael@0 1146 EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]);
michael@0 1147 EXPECT_EQ(0x12345678U, raw_context.iregs[13]);
michael@0 1148 EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]);
michael@0 1149 EXPECT_EQ(0x10203040U, raw_context.iregs[15]);
michael@0 1150 EXPECT_EQ(0x2e951ef7U, raw_context.cpsr);
michael@0 1151 }
michael@0 1152
michael@0 1153 } // namespace

mercurial