|  | // Copyright (c) 2010, Google Inc. | 
|  | // All rights reserved. | 
|  | // | 
|  | // Redistribution and use in source and binary forms, with or without | 
|  | // modification, are permitted provided that the following conditions are | 
|  | // met: | 
|  | // | 
|  | //     * Redistributions of source code must retain the above copyright | 
|  | // notice, this list of conditions and the following disclaimer. | 
|  | //     * Redistributions in binary form must reproduce the above | 
|  | // copyright notice, this list of conditions and the following disclaimer | 
|  | // in the documentation and/or other materials provided with the | 
|  | // distribution. | 
|  | //     * Neither the name of Google Inc. nor the names of its | 
|  | // contributors may be used to endorse or promote products derived from | 
|  | // this software without specific prior written permission. | 
|  | // | 
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  |  | 
|  | // Unit test for Minidump.  Uses a pre-generated minidump and | 
|  | // verifies that certain streams are correct. | 
|  |  | 
|  | #include <iostream> | 
|  | #include <fstream> | 
|  | #include <sstream> | 
|  | #include <stdlib.h> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "breakpad_googletest_includes.h" | 
|  | #include "common/using_std_string.h" | 
|  | #include "google_breakpad/common/minidump_format.h" | 
|  | #include "google_breakpad/processor/minidump.h" | 
|  | #include "processor/logging.h" | 
|  | #include "processor/synth_minidump.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | using google_breakpad::Minidump; | 
|  | using google_breakpad::MinidumpContext; | 
|  | using google_breakpad::MinidumpException; | 
|  | using google_breakpad::MinidumpMemoryInfo; | 
|  | using google_breakpad::MinidumpMemoryInfoList; | 
|  | using google_breakpad::MinidumpMemoryList; | 
|  | using google_breakpad::MinidumpMemoryRegion; | 
|  | using google_breakpad::MinidumpModule; | 
|  | using google_breakpad::MinidumpModuleList; | 
|  | using google_breakpad::MinidumpSystemInfo; | 
|  | using google_breakpad::MinidumpUnloadedModule; | 
|  | using google_breakpad::MinidumpUnloadedModuleList; | 
|  | using google_breakpad::MinidumpThread; | 
|  | using google_breakpad::MinidumpThreadList; | 
|  | using google_breakpad::SynthMinidump::Context; | 
|  | using google_breakpad::SynthMinidump::Dump; | 
|  | using google_breakpad::SynthMinidump::Exception; | 
|  | using google_breakpad::SynthMinidump::Memory; | 
|  | using google_breakpad::SynthMinidump::Module; | 
|  | using google_breakpad::SynthMinidump::UnloadedModule; | 
|  | using google_breakpad::SynthMinidump::Section; | 
|  | using google_breakpad::SynthMinidump::Stream; | 
|  | using google_breakpad::SynthMinidump::String; | 
|  | using google_breakpad::SynthMinidump::SystemInfo; | 
|  | using google_breakpad::SynthMinidump::Thread; | 
|  | using google_breakpad::test_assembler::kBigEndian; | 
|  | using google_breakpad::test_assembler::kLittleEndian; | 
|  | using std::ifstream; | 
|  | using std::istringstream; | 
|  | using std::vector; | 
|  | using ::testing::Return; | 
|  |  | 
|  | class MinidumpTest : public ::testing::Test { | 
|  | public: | 
|  | void SetUp() { | 
|  | minidump_file_ = string(getenv("srcdir") ? getenv("srcdir") : ".") + | 
|  | "/src/processor/testdata/minidump2.dmp"; | 
|  | } | 
|  | string minidump_file_; | 
|  | }; | 
|  |  | 
|  | TEST_F(MinidumpTest, TestMinidumpFromFile) { | 
|  | Minidump minidump(minidump_file_); | 
|  | ASSERT_EQ(minidump.path(), minidump_file_); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | const MDRawHeader* header = minidump.header(); | 
|  | ASSERT_NE(header, (MDRawHeader*)NULL); | 
|  | ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE)); | 
|  |  | 
|  | MinidumpModuleList* md_module_list = minidump.GetModuleList(); | 
|  | ASSERT_TRUE(md_module_list != NULL); | 
|  | const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); | 
|  | ASSERT_TRUE(md_module != NULL); | 
|  | ASSERT_EQ("c:\\test_app.exe", md_module->code_file()); | 
|  | ASSERT_EQ("c:\\test_app.pdb", md_module->debug_file()); | 
|  | ASSERT_EQ("45D35F6C2d000", md_module->code_identifier()); | 
|  | ASSERT_EQ("5A9832E5287241C1838ED98914E9B7FF1", md_module->debug_identifier()); | 
|  | } | 
|  |  | 
|  | TEST_F(MinidumpTest, TestMinidumpFromStream) { | 
|  | // read minidump contents into memory, construct a stringstream around them | 
|  | ifstream file_stream(minidump_file_.c_str(), std::ios::in); | 
|  | ASSERT_TRUE(file_stream.good()); | 
|  | vector<char> bytes; | 
|  | file_stream.seekg(0, std::ios_base::end); | 
|  | ASSERT_TRUE(file_stream.good()); | 
|  | bytes.resize(file_stream.tellg()); | 
|  | file_stream.seekg(0, std::ios_base::beg); | 
|  | ASSERT_TRUE(file_stream.good()); | 
|  | file_stream.read(&bytes[0], bytes.size()); | 
|  | ASSERT_TRUE(file_stream.good()); | 
|  | string str(&bytes[0], bytes.size()); | 
|  | istringstream stream(str); | 
|  | ASSERT_TRUE(stream.good()); | 
|  |  | 
|  | // now read minidump from stringstream | 
|  | Minidump minidump(stream); | 
|  | ASSERT_EQ(minidump.path(), ""); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | const MDRawHeader* header = minidump.header(); | 
|  | ASSERT_NE(header, (MDRawHeader*)NULL); | 
|  | ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE)); | 
|  | //TODO: add more checks here | 
|  | } | 
|  |  | 
|  | TEST(Dump, ReadBackEmpty) { | 
|  | Dump dump(0); | 
|  | dump.Finish(); | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  | istringstream stream(contents); | 
|  | Minidump minidump(stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(0U, minidump.GetDirectoryEntryCount()); | 
|  | } | 
|  |  | 
|  | TEST(Dump, ReadBackEmptyBigEndian) { | 
|  | Dump big_minidump(0, kBigEndian); | 
|  | big_minidump.Finish(); | 
|  | string contents; | 
|  | ASSERT_TRUE(big_minidump.GetContents(&contents)); | 
|  | istringstream stream(contents); | 
|  | Minidump minidump(stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(0U, minidump.GetDirectoryEntryCount()); | 
|  | } | 
|  |  | 
|  | TEST(Dump, OneStream) { | 
|  | Dump dump(0, kBigEndian); | 
|  | Stream stream(dump, 0xfbb7fa2bU); | 
|  | stream.Append("stream contents"); | 
|  | dump.Add(&stream); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); | 
|  | ASSERT_TRUE(dir != NULL); | 
|  | EXPECT_EQ(0xfbb7fa2bU, dir->stream_type); | 
|  |  | 
|  | uint32_t stream_length; | 
|  | ASSERT_TRUE(minidump.SeekToStreamType(0xfbb7fa2bU, &stream_length)); | 
|  | ASSERT_EQ(15U, stream_length); | 
|  | char stream_contents[15]; | 
|  | ASSERT_TRUE(minidump.ReadBytes(stream_contents, sizeof(stream_contents))); | 
|  | EXPECT_EQ(string("stream contents"), | 
|  | string(stream_contents, sizeof(stream_contents))); | 
|  |  | 
|  | EXPECT_FALSE(minidump.GetThreadList()); | 
|  | EXPECT_FALSE(minidump.GetModuleList()); | 
|  | EXPECT_FALSE(minidump.GetMemoryList()); | 
|  | EXPECT_FALSE(minidump.GetException()); | 
|  | EXPECT_FALSE(minidump.GetAssertion()); | 
|  | EXPECT_FALSE(minidump.GetSystemInfo()); | 
|  | EXPECT_FALSE(minidump.GetMiscInfo()); | 
|  | EXPECT_FALSE(minidump.GetBreakpadInfo()); | 
|  | } | 
|  |  | 
|  | TEST(Dump, OneMemory) { | 
|  | Dump dump(0, kBigEndian); | 
|  | Memory memory(dump, 0x309d68010bd21b2cULL); | 
|  | memory.Append("memory contents"); | 
|  | dump.Add(&memory); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); | 
|  | ASSERT_TRUE(dir != NULL); | 
|  | EXPECT_EQ((uint32_t) MD_MEMORY_LIST_STREAM, dir->stream_type); | 
|  |  | 
|  | MinidumpMemoryList* memory_list = minidump.GetMemoryList(); | 
|  | ASSERT_TRUE(memory_list != NULL); | 
|  | ASSERT_EQ(1U, memory_list->region_count()); | 
|  |  | 
|  | MinidumpMemoryRegion* region1 = memory_list->GetMemoryRegionAtIndex(0); | 
|  | ASSERT_EQ(0x309d68010bd21b2cULL, region1->GetBase()); | 
|  | ASSERT_EQ(15U, region1->GetSize()); | 
|  | const uint8_t* region1_bytes = region1->GetMemory(); | 
|  | ASSERT_TRUE(memcmp("memory contents", region1_bytes, 15) == 0); | 
|  | } | 
|  |  | 
|  | // One thread --- and its requisite entourage. | 
|  | TEST(Dump, OneThread) { | 
|  | Dump dump(0, kLittleEndian); | 
|  | Memory stack(dump, 0x2326a0fa); | 
|  | stack.Append("stack for thread"); | 
|  |  | 
|  | MDRawContextX86 raw_context; | 
|  | const uint32_t kExpectedEIP = 0x6913f540; | 
|  | raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL; | 
|  | raw_context.edi = 0x3ecba80d; | 
|  | raw_context.esi = 0x382583b9; | 
|  | raw_context.ebx = 0x7fccc03f; | 
|  | raw_context.edx = 0xf62f8ec2; | 
|  | raw_context.ecx = 0x46a6a6a8; | 
|  | raw_context.eax = 0x6a5025e2; | 
|  | raw_context.ebp = 0xd9fabb4a; | 
|  | raw_context.eip = kExpectedEIP; | 
|  | raw_context.cs = 0xbffe6eda; | 
|  | raw_context.eflags = 0xb2ce1e2d; | 
|  | raw_context.esp = 0x659caaa4; | 
|  | raw_context.ss = 0x2e951ef7; | 
|  | Context context(dump, raw_context); | 
|  |  | 
|  | Thread thread(dump, 0xa898f11b, stack, context, | 
|  | 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL); | 
|  |  | 
|  | dump.Add(&stack); | 
|  | dump.Add(&context); | 
|  | dump.Add(&thread); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  |  | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | MinidumpMemoryList* md_memory_list = minidump.GetMemoryList(); | 
|  | ASSERT_TRUE(md_memory_list != NULL); | 
|  | ASSERT_EQ(1U, md_memory_list->region_count()); | 
|  |  | 
|  | MinidumpMemoryRegion* md_region = md_memory_list->GetMemoryRegionAtIndex(0); | 
|  | ASSERT_EQ(0x2326a0faU, md_region->GetBase()); | 
|  | ASSERT_EQ(16U, md_region->GetSize()); | 
|  | const uint8_t* region_bytes = md_region->GetMemory(); | 
|  | ASSERT_TRUE(memcmp("stack for thread", region_bytes, 16) == 0); | 
|  |  | 
|  | MinidumpThreadList* thread_list = minidump.GetThreadList(); | 
|  | ASSERT_TRUE(thread_list != NULL); | 
|  | ASSERT_EQ(1U, thread_list->thread_count()); | 
|  |  | 
|  | MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0); | 
|  | ASSERT_TRUE(md_thread != NULL); | 
|  | uint32_t thread_id; | 
|  | ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0xa898f11bU, thread_id); | 
|  | MinidumpMemoryRegion* md_stack = md_thread->GetMemory(); | 
|  | ASSERT_TRUE(md_stack != NULL); | 
|  | ASSERT_EQ(0x2326a0faU, md_stack->GetBase()); | 
|  | ASSERT_EQ(16U, md_stack->GetSize()); | 
|  | const uint8_t* md_stack_bytes = md_stack->GetMemory(); | 
|  | ASSERT_TRUE(memcmp("stack for thread", md_stack_bytes, 16) == 0); | 
|  |  | 
|  | MinidumpContext* md_context = md_thread->GetContext(); | 
|  | ASSERT_TRUE(md_context != NULL); | 
|  | ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); | 
|  |  | 
|  | uint64_t eip; | 
|  | ASSERT_TRUE(md_context->GetInstructionPointer(&eip)); | 
|  | EXPECT_EQ(kExpectedEIP, eip); | 
|  |  | 
|  | const MDRawContextX86* md_raw_context = md_context->GetContextX86(); | 
|  | ASSERT_TRUE(md_raw_context != NULL); | 
|  | ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), | 
|  | (md_raw_context->context_flags | 
|  | & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); | 
|  | EXPECT_EQ(0x3ecba80dU, raw_context.edi); | 
|  | EXPECT_EQ(0x382583b9U, raw_context.esi); | 
|  | EXPECT_EQ(0x7fccc03fU, raw_context.ebx); | 
|  | EXPECT_EQ(0xf62f8ec2U, raw_context.edx); | 
|  | EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); | 
|  | EXPECT_EQ(0x6a5025e2U, raw_context.eax); | 
|  | EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); | 
|  | EXPECT_EQ(kExpectedEIP, raw_context.eip); | 
|  | EXPECT_EQ(0xbffe6edaU, raw_context.cs); | 
|  | EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); | 
|  | EXPECT_EQ(0x659caaa4U, raw_context.esp); | 
|  | EXPECT_EQ(0x2e951ef7U, raw_context.ss); | 
|  | } | 
|  |  | 
|  | TEST(Dump, ThreadMissingMemory) { | 
|  | Dump dump(0, kLittleEndian); | 
|  | Memory stack(dump, 0x2326a0fa); | 
|  | // Stack has no contents. | 
|  |  | 
|  | MDRawContextX86 raw_context; | 
|  | memset(&raw_context, 0, sizeof(raw_context)); | 
|  | raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL; | 
|  | Context context(dump, raw_context); | 
|  |  | 
|  | Thread thread(dump, 0xa898f11b, stack, context, | 
|  | 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL); | 
|  |  | 
|  | dump.Add(&stack); | 
|  | dump.Add(&context); | 
|  | dump.Add(&thread); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  |  | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | // This should succeed even though the thread has no stack memory. | 
|  | MinidumpThreadList* thread_list = minidump.GetThreadList(); | 
|  | ASSERT_TRUE(thread_list != NULL); | 
|  | ASSERT_EQ(1U, thread_list->thread_count()); | 
|  |  | 
|  | MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0); | 
|  | ASSERT_TRUE(md_thread != NULL); | 
|  |  | 
|  | uint32_t thread_id; | 
|  | ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0xa898f11bU, thread_id); | 
|  |  | 
|  | MinidumpContext* md_context = md_thread->GetContext(); | 
|  | ASSERT_NE(reinterpret_cast<MinidumpContext*>(NULL), md_context); | 
|  |  | 
|  | MinidumpMemoryRegion* md_stack = md_thread->GetMemory(); | 
|  | ASSERT_EQ(reinterpret_cast<MinidumpMemoryRegion*>(NULL), md_stack); | 
|  | } | 
|  |  | 
|  | TEST(Dump, ThreadMissingContext) { | 
|  | Dump dump(0, kLittleEndian); | 
|  | Memory stack(dump, 0x2326a0fa); | 
|  | stack.Append("stack for thread"); | 
|  |  | 
|  | // Context is empty. | 
|  | Context context(dump); | 
|  |  | 
|  | Thread thread(dump, 0xa898f11b, stack, context, | 
|  | 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL); | 
|  |  | 
|  | dump.Add(&stack); | 
|  | dump.Add(&context); | 
|  | dump.Add(&thread); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  |  | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | // This should succeed even though the thread has no stack memory. | 
|  | MinidumpThreadList* thread_list = minidump.GetThreadList(); | 
|  | ASSERT_TRUE(thread_list != NULL); | 
|  | ASSERT_EQ(1U, thread_list->thread_count()); | 
|  |  | 
|  | MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0); | 
|  | ASSERT_TRUE(md_thread != NULL); | 
|  |  | 
|  | uint32_t thread_id; | 
|  | ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0xa898f11bU, thread_id); | 
|  | MinidumpMemoryRegion* md_stack = md_thread->GetMemory(); | 
|  | ASSERT_NE(reinterpret_cast<MinidumpMemoryRegion*>(NULL), md_stack); | 
|  |  | 
|  | MinidumpContext* md_context = md_thread->GetContext(); | 
|  | ASSERT_EQ(reinterpret_cast<MinidumpContext*>(NULL), md_context); | 
|  | } | 
|  |  | 
|  | TEST(Dump, OneUnloadedModule) { | 
|  | Dump dump(0, kBigEndian); | 
|  | String module_name(dump, "unloaded module"); | 
|  |  | 
|  | String csd_version(dump, "Windows 9000"); | 
|  | SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); | 
|  |  | 
|  | UnloadedModule unloaded_module( | 
|  | dump, | 
|  | 0xa90206ca83eb2852ULL, | 
|  | 0xada542bd, | 
|  | module_name, | 
|  | 0x34571371, | 
|  | 0xb1054d2a); | 
|  |  | 
|  | dump.Add(&unloaded_module); | 
|  | dump.Add(&module_name); | 
|  | dump.Add(&system_info); | 
|  | dump.Add(&csd_version); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(1); | 
|  | ASSERT_TRUE(dir != NULL); | 
|  | EXPECT_EQ((uint32_t) MD_UNLOADED_MODULE_LIST_STREAM, dir->stream_type); | 
|  |  | 
|  | MinidumpUnloadedModuleList* md_unloaded_module_list = | 
|  | minidump.GetUnloadedModuleList(); | 
|  | ASSERT_TRUE(md_unloaded_module_list != NULL); | 
|  | ASSERT_EQ(1U, md_unloaded_module_list->module_count()); | 
|  |  | 
|  | const MinidumpUnloadedModule* md_unloaded_module = | 
|  | md_unloaded_module_list->GetModuleAtIndex(0); | 
|  | ASSERT_TRUE(md_unloaded_module != NULL); | 
|  | ASSERT_EQ(0xa90206ca83eb2852ULL, md_unloaded_module->base_address()); | 
|  | ASSERT_EQ(0xada542bd, md_unloaded_module->size()); | 
|  | ASSERT_EQ("unloaded module", md_unloaded_module->code_file()); | 
|  | ASSERT_EQ("", md_unloaded_module->debug_file()); | 
|  | // time_date_stamp and size_of_image concatenated | 
|  | ASSERT_EQ("B1054D2Aada542bd", md_unloaded_module->code_identifier()); | 
|  | ASSERT_EQ("", md_unloaded_module->debug_identifier()); | 
|  |  | 
|  | const MDRawUnloadedModule* md_raw_unloaded_module = | 
|  | md_unloaded_module->module(); | 
|  | ASSERT_TRUE(md_raw_unloaded_module != NULL); | 
|  | ASSERT_EQ(0xb1054d2aU, md_raw_unloaded_module->time_date_stamp); | 
|  | ASSERT_EQ(0x34571371U, md_raw_unloaded_module->checksum); | 
|  | } | 
|  |  | 
|  | static const MDVSFixedFileInfo fixed_file_info = { | 
|  | 0xb2fba33a,                           // signature | 
|  | 0x33d7a728,                           // struct_version | 
|  | 0x31afcb20,                           // file_version_hi | 
|  | 0xe51cdab1,                           // file_version_lo | 
|  | 0xd1ea6907,                           // product_version_hi | 
|  | 0x03032857,                           // product_version_lo | 
|  | 0x11bf71d7,                           // file_flags_mask | 
|  | 0x5fb8cdbf,                           // file_flags | 
|  | 0xe45d0d5d,                           // file_os | 
|  | 0x107d9562,                           // file_type | 
|  | 0x5a8844d4,                           // file_subtype | 
|  | 0xa8d30b20,                           // file_date_hi | 
|  | 0x651c3e4e                            // file_date_lo | 
|  | }; | 
|  |  | 
|  | TEST(Dump, OneModule) { | 
|  | Dump dump(0, kBigEndian); | 
|  | String module_name(dump, "single module"); | 
|  | Section cv_info(dump); | 
|  | cv_info | 
|  | .D32(MD_CVINFOPDB70_SIGNATURE)  // signature | 
|  | // signature, a MDGUID | 
|  | .D32(0xabcd1234) | 
|  | .D16(0xf00d) | 
|  | .D16(0xbeef) | 
|  | .Append("\x01\x02\x03\x04\x05\x06\x07\x08") | 
|  | .D32(1) // age | 
|  | .AppendCString("c:\\foo\\file.pdb");  // pdb_file_name | 
|  |  | 
|  | String csd_version(dump, "Windows 9000"); | 
|  | SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); | 
|  |  | 
|  | Module module(dump, 0xa90206ca83eb2852ULL, 0xada542bd, | 
|  | module_name, | 
|  | 0xb1054d2a, | 
|  | 0x34571371, | 
|  | fixed_file_info, // from synth_minidump_unittest_data.h | 
|  | &cv_info, nullptr); | 
|  |  | 
|  | dump.Add(&module); | 
|  | dump.Add(&module_name); | 
|  | dump.Add(&cv_info); | 
|  | dump.Add(&system_info); | 
|  | dump.Add(&csd_version); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(1); | 
|  | ASSERT_TRUE(dir != NULL); | 
|  | EXPECT_EQ((uint32_t) MD_MODULE_LIST_STREAM, dir->stream_type); | 
|  |  | 
|  | MinidumpModuleList* md_module_list = minidump.GetModuleList(); | 
|  | ASSERT_TRUE(md_module_list != NULL); | 
|  | ASSERT_EQ(1U, md_module_list->module_count()); | 
|  |  | 
|  | const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); | 
|  | ASSERT_TRUE(md_module != NULL); | 
|  | ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address()); | 
|  | ASSERT_EQ(0xada542bd, md_module->size()); | 
|  | ASSERT_EQ("single module", md_module->code_file()); | 
|  | ASSERT_EQ("c:\\foo\\file.pdb", md_module->debug_file()); | 
|  | // time_date_stamp and size_of_image concatenated | 
|  | ASSERT_EQ("B1054D2Aada542bd", md_module->code_identifier()); | 
|  | ASSERT_EQ("ABCD1234F00DBEEF01020304050607081", md_module->debug_identifier()); | 
|  |  | 
|  | const MDRawModule* md_raw_module = md_module->module(); | 
|  | ASSERT_TRUE(md_raw_module != NULL); | 
|  | ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp); | 
|  | ASSERT_EQ(0x34571371U, md_raw_module->checksum); | 
|  | ASSERT_TRUE(memcmp(&md_raw_module->version_info, &fixed_file_info, | 
|  | sizeof(fixed_file_info)) == 0); | 
|  | } | 
|  |  | 
|  | // Test that a module with a MDCVInfoELF CV record is handled properly. | 
|  | TEST(Dump, OneModuleCVELF) { | 
|  | Dump dump(0, kLittleEndian); | 
|  | String module_name(dump, "elf module"); | 
|  | Section cv_info(dump); | 
|  | cv_info | 
|  | .D32(MD_CVINFOELF_SIGNATURE)  // signature | 
|  | // build_id | 
|  | .Append("\x5f\xa9\xcd\xb4\x10\x53\xdf\x1b\x86\xfa\xb7\x33\xb4\xdf" | 
|  | "\x37\x38\xce\xa3\x4a\x87"); | 
|  |  | 
|  | const MDRawSystemInfo linux_x86 = { | 
|  | MD_CPU_ARCHITECTURE_X86,              // processor_architecture | 
|  | 6,                                    // processor_level | 
|  | 0xd08,                                // processor_revision | 
|  | 1,                                    // number_of_processors | 
|  | 0,                                    // product_type | 
|  | 0,                                    // major_version | 
|  | 0,                                    // minor_version | 
|  | 0,                                    // build_number | 
|  | MD_OS_LINUX,                          // platform_id | 
|  | 0xdeadbeef,                           // csd_version_rva | 
|  | 0x100,                                // suite_mask | 
|  | 0,                                    // reserved2 | 
|  | {                                     // cpu | 
|  | { // x86_cpu_info | 
|  | { 0x756e6547, 0x49656e69, 0x6c65746e }, // vendor_id | 
|  | 0x6d8,                                  // version_information | 
|  | 0xafe9fbff,                             // feature_information | 
|  | 0xffffffff                              // amd_extended_cpu_features | 
|  | } | 
|  | } | 
|  | }; | 
|  | String csd_version(dump, "Literally Linux"); | 
|  | SystemInfo system_info(dump, linux_x86, csd_version); | 
|  |  | 
|  | Module module(dump, 0xa90206ca83eb2852ULL, 0xada542bd, | 
|  | module_name, | 
|  | 0xb1054d2a, | 
|  | 0x34571371, | 
|  | fixed_file_info, // from synth_minidump_unittest_data.h | 
|  | &cv_info, nullptr); | 
|  |  | 
|  | dump.Add(&module); | 
|  | dump.Add(&module_name); | 
|  | dump.Add(&cv_info); | 
|  | dump.Add(&system_info); | 
|  | dump.Add(&csd_version); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  |  | 
|  | MinidumpModuleList* md_module_list = minidump.GetModuleList(); | 
|  | ASSERT_TRUE(md_module_list != NULL); | 
|  | ASSERT_EQ(1U, md_module_list->module_count()); | 
|  |  | 
|  | const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); | 
|  | ASSERT_TRUE(md_module != NULL); | 
|  | ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address()); | 
|  | ASSERT_EQ(0xada542bd, md_module->size()); | 
|  | ASSERT_EQ("elf module", md_module->code_file()); | 
|  | // debug_file == code_file | 
|  | ASSERT_EQ("elf module", md_module->debug_file()); | 
|  | // just the build_id, directly | 
|  | ASSERT_EQ("5fa9cdb41053df1b86fab733b4df3738cea34a87", | 
|  | md_module->code_identifier()); | 
|  | // build_id truncted to GUID length and treated as such, with zero | 
|  | // age appended | 
|  | ASSERT_EQ("B4CDA95F53101BDF86FAB733B4DF37380", md_module->debug_identifier()); | 
|  |  | 
|  | const MDRawModule* md_raw_module = md_module->module(); | 
|  | ASSERT_TRUE(md_raw_module != NULL); | 
|  | ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp); | 
|  | ASSERT_EQ(0x34571371U, md_raw_module->checksum); | 
|  | ASSERT_TRUE(memcmp(&md_raw_module->version_info, &fixed_file_info, | 
|  | sizeof(fixed_file_info)) == 0); | 
|  | } | 
|  |  | 
|  | // Test that a build_id that's shorter than a GUID is handled properly. | 
|  | TEST(Dump, CVELFShort) { | 
|  | Dump dump(0, kLittleEndian); | 
|  | String module_name(dump, "elf module"); | 
|  | Section cv_info(dump); | 
|  | cv_info | 
|  | .D32(MD_CVINFOELF_SIGNATURE)  // signature | 
|  | // build_id, shorter than a GUID | 
|  | .Append("\x5f\xa9\xcd\xb4"); | 
|  |  | 
|  | const MDRawSystemInfo linux_x86 = { | 
|  | MD_CPU_ARCHITECTURE_X86,              // processor_architecture | 
|  | 6,                                    // processor_level | 
|  | 0xd08,                                // processor_revision | 
|  | 1,                                    // number_of_processors | 
|  | 0,                                    // product_type | 
|  | 0,                                    // major_version | 
|  | 0,                                    // minor_version | 
|  | 0,                                    // build_number | 
|  | MD_OS_LINUX,                          // platform_id | 
|  | 0xdeadbeef,                           // csd_version_rva | 
|  | 0x100,                                // suite_mask | 
|  | 0,                                    // reserved2 | 
|  | {                                     // cpu | 
|  | { // x86_cpu_info | 
|  | { 0x756e6547, 0x49656e69, 0x6c65746e }, // vendor_id | 
|  | 0x6d8,                                  // version_information | 
|  | 0xafe9fbff,                             // feature_information | 
|  | 0xffffffff                              // amd_extended_cpu_features | 
|  | } | 
|  | } | 
|  | }; | 
|  | String csd_version(dump, "Literally Linux"); | 
|  | SystemInfo system_info(dump, linux_x86, csd_version); | 
|  |  | 
|  | Module module(dump, 0xa90206ca83eb2852ULL, 0xada542bd, | 
|  | module_name, | 
|  | 0xb1054d2a, | 
|  | 0x34571371, | 
|  | fixed_file_info, // from synth_minidump_unittest_data.h | 
|  | &cv_info, nullptr); | 
|  |  | 
|  | dump.Add(&module); | 
|  | dump.Add(&module_name); | 
|  | dump.Add(&cv_info); | 
|  | dump.Add(&system_info); | 
|  | dump.Add(&csd_version); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | MinidumpModuleList* md_module_list = minidump.GetModuleList(); | 
|  | ASSERT_TRUE(md_module_list != NULL); | 
|  | ASSERT_EQ(1U, md_module_list->module_count()); | 
|  |  | 
|  | const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); | 
|  | ASSERT_TRUE(md_module != NULL); | 
|  | // just the build_id, directly | 
|  | ASSERT_EQ("5fa9cdb4", md_module->code_identifier()); | 
|  | // build_id expanded to GUID length and treated as such, with zero | 
|  | // age appended | 
|  | ASSERT_EQ("B4CDA95F0000000000000000000000000", md_module->debug_identifier()); | 
|  | } | 
|  |  | 
|  | // Test that a build_id that's very long is handled properly. | 
|  | TEST(Dump, CVELFLong) { | 
|  | Dump dump(0, kLittleEndian); | 
|  | String module_name(dump, "elf module"); | 
|  | Section cv_info(dump); | 
|  | cv_info | 
|  | .D32(MD_CVINFOELF_SIGNATURE)  // signature | 
|  | // build_id, lots of bytes | 
|  | .Append("\x5f\xa9\xcd\xb4\x10\x53\xdf\x1b\x86\xfa\xb7\x33\xb4\xdf" | 
|  | "\x37\x38\xce\xa3\x4a\x87\x01\x02\x03\x04\x05\x06\x07\x08" | 
|  | "\x09\x0a\x0b\x0c\x0d\x0e\x0f"); | 
|  |  | 
|  |  | 
|  | const MDRawSystemInfo linux_x86 = { | 
|  | MD_CPU_ARCHITECTURE_X86,              // processor_architecture | 
|  | 6,                                    // processor_level | 
|  | 0xd08,                                // processor_revision | 
|  | 1,                                    // number_of_processors | 
|  | 0,                                    // product_type | 
|  | 0,                                    // major_version | 
|  | 0,                                    // minor_version | 
|  | 0,                                    // build_number | 
|  | MD_OS_LINUX,                          // platform_id | 
|  | 0xdeadbeef,                           // csd_version_rva | 
|  | 0x100,                                // suite_mask | 
|  | 0,                                    // reserved2 | 
|  | {                                     // cpu | 
|  | { // x86_cpu_info | 
|  | { 0x756e6547, 0x49656e69, 0x6c65746e }, // vendor_id | 
|  | 0x6d8,                                  // version_information | 
|  | 0xafe9fbff,                             // feature_information | 
|  | 0xffffffff                              // amd_extended_cpu_features | 
|  | } | 
|  | } | 
|  | }; | 
|  | String csd_version(dump, "Literally Linux"); | 
|  | SystemInfo system_info(dump, linux_x86, csd_version); | 
|  |  | 
|  | Module module(dump, 0xa90206ca83eb2852ULL, 0xada542bd, | 
|  | module_name, | 
|  | 0xb1054d2a, | 
|  | 0x34571371, | 
|  | fixed_file_info, // from synth_minidump_unittest_data.h | 
|  | &cv_info, nullptr); | 
|  |  | 
|  | dump.Add(&module); | 
|  | dump.Add(&module_name); | 
|  | dump.Add(&cv_info); | 
|  | dump.Add(&system_info); | 
|  | dump.Add(&csd_version); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | MinidumpModuleList* md_module_list = minidump.GetModuleList(); | 
|  | ASSERT_TRUE(md_module_list != NULL); | 
|  | ASSERT_EQ(1U, md_module_list->module_count()); | 
|  |  | 
|  | const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); | 
|  | ASSERT_TRUE(md_module != NULL); | 
|  | // just the build_id, directly | 
|  | ASSERT_EQ( | 
|  | "5fa9cdb41053df1b86fab733b4df3738cea34a870102030405060708090a0b0c0d0e0f", | 
|  | md_module->code_identifier()); | 
|  | // build_id truncated to GUID length and treated as such, with zero | 
|  | // age appended. | 
|  | ASSERT_EQ("B4CDA95F53101BDF86FAB733B4DF37380", md_module->debug_identifier()); | 
|  | } | 
|  |  | 
|  | TEST(Dump, OneSystemInfo) { | 
|  | Dump dump(0, kLittleEndian); | 
|  | String csd_version(dump, "Petulant Pierogi"); | 
|  | SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); | 
|  |  | 
|  | dump.Add(&system_info); | 
|  | dump.Add(&csd_version); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); | 
|  | ASSERT_TRUE(dir != NULL); | 
|  | EXPECT_EQ((uint32_t) MD_SYSTEM_INFO_STREAM, dir->stream_type); | 
|  |  | 
|  | MinidumpSystemInfo* md_system_info = minidump.GetSystemInfo(); | 
|  | ASSERT_TRUE(md_system_info != NULL); | 
|  | ASSERT_EQ("windows", md_system_info->GetOS()); | 
|  | ASSERT_EQ("x86", md_system_info->GetCPU()); | 
|  | ASSERT_EQ("Petulant Pierogi", *md_system_info->GetCSDVersion()); | 
|  | ASSERT_EQ("GenuineIntel", *md_system_info->GetCPUVendor()); | 
|  | } | 
|  |  | 
|  | TEST(Dump, BigDump) { | 
|  | Dump dump(0, kLittleEndian); | 
|  |  | 
|  | // A SystemInfo stream. | 
|  | String csd_version(dump, "Munificent Macaque"); | 
|  | SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); | 
|  | dump.Add(&csd_version); | 
|  | dump.Add(&system_info); | 
|  |  | 
|  | // Five threads! | 
|  | Memory stack0(dump, 0x70b9ebfc); | 
|  | stack0.Append("stack for thread zero"); | 
|  | MDRawContextX86 raw_context0; | 
|  | raw_context0.context_flags = MD_CONTEXT_X86_INTEGER; | 
|  | raw_context0.eip = 0xaf0709e4; | 
|  | Context context0(dump, raw_context0); | 
|  | Thread thread0(dump, 0xbbef4432, stack0, context0, | 
|  | 0xd0377e7b, 0xdb8eb0cf, 0xd73bc314, 0x09d357bac7f9a163ULL); | 
|  | dump.Add(&stack0); | 
|  | dump.Add(&context0); | 
|  | dump.Add(&thread0); | 
|  |  | 
|  | Memory stack1(dump, 0xf988cc45); | 
|  | stack1.Append("stack for thread one"); | 
|  | MDRawContextX86 raw_context1; | 
|  | raw_context1.context_flags = MD_CONTEXT_X86_INTEGER; | 
|  | raw_context1.eip = 0xe4f56f81; | 
|  | Context context1(dump, raw_context1); | 
|  | Thread thread1(dump, 0x657c3f58, stack1, context1, | 
|  | 0xa68fa182, 0x6f3cf8dd, 0xe3a78ccf, 0x78cc84775e4534bbULL); | 
|  | dump.Add(&stack1); | 
|  | dump.Add(&context1); | 
|  | dump.Add(&thread1); | 
|  |  | 
|  | Memory stack2(dump, 0xc8a92e7c); | 
|  | stack2.Append("stack for thread two"); | 
|  | MDRawContextX86 raw_context2; | 
|  | raw_context2.context_flags = MD_CONTEXT_X86_INTEGER; | 
|  | raw_context2.eip = 0xb336a438; | 
|  | Context context2(dump, raw_context2); | 
|  | Thread thread2(dump, 0xdf4b8a71, stack2, context2, | 
|  | 0x674c26b6, 0x445d7120, 0x7e700c56, 0xd89bf778e7793e17ULL); | 
|  | dump.Add(&stack2); | 
|  | dump.Add(&context2); | 
|  | dump.Add(&thread2); | 
|  |  | 
|  | Memory stack3(dump, 0x36d08e08); | 
|  | stack3.Append("stack for thread three"); | 
|  | MDRawContextX86 raw_context3; | 
|  | raw_context3.context_flags = MD_CONTEXT_X86_INTEGER; | 
|  | raw_context3.eip = 0xdf99a60c; | 
|  | Context context3(dump, raw_context3); | 
|  | Thread thread3(dump, 0x86e6c341, stack3, context3, | 
|  | 0x32dc5c55, 0x17a2aba8, 0xe0cc75e7, 0xa46393994dae83aeULL); | 
|  | dump.Add(&stack3); | 
|  | dump.Add(&context3); | 
|  | dump.Add(&thread3); | 
|  |  | 
|  | Memory stack4(dump, 0x1e0ab4fa); | 
|  | stack4.Append("stack for thread four"); | 
|  | MDRawContextX86 raw_context4; | 
|  | raw_context4.context_flags = MD_CONTEXT_X86_INTEGER; | 
|  | raw_context4.eip = 0xaa646267; | 
|  | Context context4(dump, raw_context4); | 
|  | Thread thread4(dump, 0x261a28d4, stack4, context4, | 
|  | 0x6ebd389e, 0xa0cd4759, 0x30168846, 0x164f650a0cf39d35ULL); | 
|  | dump.Add(&stack4); | 
|  | dump.Add(&context4); | 
|  | dump.Add(&thread4); | 
|  |  | 
|  | // Three modules! | 
|  | String module1_name(dump, "module one"); | 
|  | Module module1(dump, 0xeb77da57b5d4cbdaULL, 0x83cd5a37, module1_name); | 
|  | dump.Add(&module1_name); | 
|  | dump.Add(&module1); | 
|  |  | 
|  | String module2_name(dump, "module two"); | 
|  | Module module2(dump, 0x8675884adfe5ac90ULL, 0xb11e4ea3, module2_name); | 
|  | dump.Add(&module2_name); | 
|  | dump.Add(&module2); | 
|  |  | 
|  | String module3_name(dump, "module three"); | 
|  | Module module3(dump, 0x95fc1544da321b6cULL, 0x7c2bf081, module3_name); | 
|  | dump.Add(&module3_name); | 
|  | dump.Add(&module3); | 
|  |  | 
|  | // Unloaded modules! | 
|  | uint64_t umodule1_base = 0xeb77da57b5d4cbdaULL; | 
|  | uint32_t umodule1_size = 0x83cd5a37; | 
|  | String umodule1_name(dump, "unloaded module one"); | 
|  | UnloadedModule unloaded_module1(dump, umodule1_base, umodule1_size, | 
|  | umodule1_name); | 
|  | dump.Add(&umodule1_name); | 
|  | dump.Add(&unloaded_module1); | 
|  |  | 
|  | uint64_t umodule2_base = 0xeb77da57b5d4cbdaULL; | 
|  | uint32_t umodule2_size = 0x83cd5a37; | 
|  | String umodule2_name(dump, "unloaded module two"); | 
|  | UnloadedModule unloaded_module2(dump, umodule2_base, umodule2_size, | 
|  | umodule2_name); | 
|  | dump.Add(&umodule2_name); | 
|  | dump.Add(&unloaded_module2); | 
|  |  | 
|  | uint64_t umodule3_base = 0xeb77da5839a20000ULL; | 
|  | uint32_t umodule3_size = 0x83cd5a37; | 
|  | String umodule3_name(dump, "unloaded module three"); | 
|  | UnloadedModule unloaded_module3(dump, umodule3_base, umodule3_size, | 
|  | umodule3_name); | 
|  | dump.Add(&umodule3_name); | 
|  | dump.Add(&unloaded_module3); | 
|  |  | 
|  |  | 
|  | // Add one more memory region, on top of the five stacks. | 
|  | Memory memory5(dump, 0x61979e828040e564ULL); | 
|  | memory5.Append("contents of memory 5"); | 
|  | dump.Add(&memory5); | 
|  |  | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(5U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | // Check the threads. | 
|  | MinidumpThreadList* thread_list = minidump.GetThreadList(); | 
|  | ASSERT_TRUE(thread_list != NULL); | 
|  | ASSERT_EQ(5U, thread_list->thread_count()); | 
|  | uint32_t thread_id; | 
|  | ASSERT_TRUE(thread_list->GetThreadAtIndex(0)->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0xbbef4432U, thread_id); | 
|  | ASSERT_EQ(0x70b9ebfcU, | 
|  | thread_list->GetThreadAtIndex(0)->GetMemory()->GetBase()); | 
|  | ASSERT_EQ(0xaf0709e4U, | 
|  | thread_list->GetThreadAtIndex(0)->GetContext()->GetContextX86() | 
|  | ->eip); | 
|  |  | 
|  | ASSERT_TRUE(thread_list->GetThreadAtIndex(1)->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0x657c3f58U, thread_id); | 
|  | ASSERT_EQ(0xf988cc45U, | 
|  | thread_list->GetThreadAtIndex(1)->GetMemory()->GetBase()); | 
|  | ASSERT_EQ(0xe4f56f81U, | 
|  | thread_list->GetThreadAtIndex(1)->GetContext()->GetContextX86() | 
|  | ->eip); | 
|  |  | 
|  | ASSERT_TRUE(thread_list->GetThreadAtIndex(2)->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0xdf4b8a71U, thread_id); | 
|  | ASSERT_EQ(0xc8a92e7cU, | 
|  | thread_list->GetThreadAtIndex(2)->GetMemory()->GetBase()); | 
|  | ASSERT_EQ(0xb336a438U, | 
|  | thread_list->GetThreadAtIndex(2)->GetContext()->GetContextX86() | 
|  | ->eip); | 
|  |  | 
|  | ASSERT_TRUE(thread_list->GetThreadAtIndex(3)->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0x86e6c341U, thread_id); | 
|  | ASSERT_EQ(0x36d08e08U, | 
|  | thread_list->GetThreadAtIndex(3)->GetMemory()->GetBase()); | 
|  | ASSERT_EQ(0xdf99a60cU, | 
|  | thread_list->GetThreadAtIndex(3)->GetContext()->GetContextX86() | 
|  | ->eip); | 
|  |  | 
|  | ASSERT_TRUE(thread_list->GetThreadAtIndex(4)->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0x261a28d4U, thread_id); | 
|  | ASSERT_EQ(0x1e0ab4faU, | 
|  | thread_list->GetThreadAtIndex(4)->GetMemory()->GetBase()); | 
|  | ASSERT_EQ(0xaa646267U, | 
|  | thread_list->GetThreadAtIndex(4)->GetContext()->GetContextX86() | 
|  | ->eip); | 
|  |  | 
|  | // Check the modules. | 
|  | MinidumpModuleList* md_module_list = minidump.GetModuleList(); | 
|  | ASSERT_TRUE(md_module_list != NULL); | 
|  | ASSERT_EQ(3U, md_module_list->module_count()); | 
|  | EXPECT_EQ(0xeb77da57b5d4cbdaULL, | 
|  | md_module_list->GetModuleAtIndex(0)->base_address()); | 
|  | EXPECT_EQ(0x8675884adfe5ac90ULL, | 
|  | md_module_list->GetModuleAtIndex(1)->base_address()); | 
|  | EXPECT_EQ(0x95fc1544da321b6cULL, | 
|  | md_module_list->GetModuleAtIndex(2)->base_address()); | 
|  |  | 
|  | // Check unloaded modules | 
|  | MinidumpUnloadedModuleList* md_unloaded_module_list = | 
|  | minidump.GetUnloadedModuleList(); | 
|  | ASSERT_TRUE(md_unloaded_module_list != NULL); | 
|  | ASSERT_EQ(3U, md_unloaded_module_list->module_count()); | 
|  | EXPECT_EQ(umodule1_base, | 
|  | md_unloaded_module_list->GetModuleAtIndex(0)->base_address()); | 
|  | EXPECT_EQ(umodule2_base, | 
|  | md_unloaded_module_list->GetModuleAtIndex(1)->base_address()); | 
|  | EXPECT_EQ(umodule3_base, | 
|  | md_unloaded_module_list->GetModuleAtIndex(2)->base_address()); | 
|  |  | 
|  | const MinidumpUnloadedModule* umodule = | 
|  | md_unloaded_module_list->GetModuleForAddress( | 
|  | umodule1_base + umodule1_size / 2); | 
|  | EXPECT_EQ(umodule1_base, umodule->base_address()); | 
|  |  | 
|  | umodule = md_unloaded_module_list->GetModuleAtSequence(0); | 
|  | EXPECT_EQ(umodule1_base, umodule->base_address()); | 
|  |  | 
|  | EXPECT_EQ(NULL, md_unloaded_module_list->GetMainModule()); | 
|  |  | 
|  | } | 
|  |  | 
|  | TEST(Dump, OneMemoryInfo) { | 
|  | Dump dump(0, kBigEndian); | 
|  | Stream stream(dump, MD_MEMORY_INFO_LIST_STREAM); | 
|  |  | 
|  | // Add the MDRawMemoryInfoList header. | 
|  | const uint64_t kNumberOfEntries = 1; | 
|  | stream.D32(sizeof(MDRawMemoryInfoList))  // size_of_header | 
|  | .D32(sizeof(MDRawMemoryInfo))      // size_of_entry | 
|  | .D64(kNumberOfEntries);            // number_of_entries | 
|  |  | 
|  |  | 
|  | // Now add a MDRawMemoryInfo entry. | 
|  | const uint64_t kBaseAddress = 0x1000; | 
|  | const uint64_t kRegionSize = 0x2000; | 
|  | stream.D64(kBaseAddress)                         // base_address | 
|  | .D64(kBaseAddress)                         // allocation_base | 
|  | .D32(MD_MEMORY_PROTECT_EXECUTE_READWRITE)  // allocation_protection | 
|  | .D32(0)                                    // __alignment1 | 
|  | .D64(kRegionSize)                          // region_size | 
|  | .D32(MD_MEMORY_STATE_COMMIT)               // state | 
|  | .D32(MD_MEMORY_PROTECT_EXECUTE_READWRITE)  // protection | 
|  | .D32(MD_MEMORY_TYPE_PRIVATE)               // type | 
|  | .D32(0);                                   // __alignment2 | 
|  |  | 
|  | dump.Add(&stream); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); | 
|  | ASSERT_TRUE(dir != NULL); | 
|  | EXPECT_EQ((uint32_t) MD_MEMORY_INFO_LIST_STREAM, dir->stream_type); | 
|  |  | 
|  | MinidumpMemoryInfoList* info_list = minidump.GetMemoryInfoList(); | 
|  | ASSERT_TRUE(info_list != NULL); | 
|  | ASSERT_EQ(1U, info_list->info_count()); | 
|  |  | 
|  | const MinidumpMemoryInfo* info1 = info_list->GetMemoryInfoAtIndex(0); | 
|  | ASSERT_EQ(kBaseAddress, info1->GetBase()); | 
|  | ASSERT_EQ(kRegionSize, info1->GetSize()); | 
|  | ASSERT_TRUE(info1->IsExecutable()); | 
|  | ASSERT_TRUE(info1->IsWritable()); | 
|  |  | 
|  | // Should get back the same memory region here. | 
|  | const MinidumpMemoryInfo* info2 = | 
|  | info_list->GetMemoryInfoForAddress(kBaseAddress + kRegionSize / 2); | 
|  | ASSERT_EQ(kBaseAddress, info2->GetBase()); | 
|  | ASSERT_EQ(kRegionSize, info2->GetSize()); | 
|  | } | 
|  |  | 
|  | TEST(Dump, OneExceptionX86) { | 
|  | Dump dump(0, kLittleEndian); | 
|  |  | 
|  | MDRawContextX86 raw_context; | 
|  | raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL; | 
|  | raw_context.edi = 0x3ecba80d; | 
|  | raw_context.esi = 0x382583b9; | 
|  | raw_context.ebx = 0x7fccc03f; | 
|  | raw_context.edx = 0xf62f8ec2; | 
|  | raw_context.ecx = 0x46a6a6a8; | 
|  | raw_context.eax = 0x6a5025e2; | 
|  | raw_context.ebp = 0xd9fabb4a; | 
|  | raw_context.eip = 0x6913f540; | 
|  | raw_context.cs = 0xbffe6eda; | 
|  | raw_context.eflags = 0xb2ce1e2d; | 
|  | raw_context.esp = 0x659caaa4; | 
|  | raw_context.ss = 0x2e951ef7; | 
|  | Context context(dump, raw_context); | 
|  |  | 
|  | Exception exception(dump, context, | 
|  | 0x1234abcd, // thread id | 
|  | 0xdcba4321, // exception code | 
|  | 0xf0e0d0c0, // exception flags | 
|  | 0x0919a9b9c9d9e9f9ULL); // exception address | 
|  |  | 
|  | dump.Add(&context); | 
|  | dump.Add(&exception); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  |  | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | MinidumpException* md_exception = minidump.GetException(); | 
|  | ASSERT_TRUE(md_exception != NULL); | 
|  |  | 
|  | uint32_t thread_id; | 
|  | ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0x1234abcdU, thread_id); | 
|  |  | 
|  | const MDRawExceptionStream* raw_exception = md_exception->exception(); | 
|  | ASSERT_TRUE(raw_exception != NULL); | 
|  | EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); | 
|  | EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); | 
|  | EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, | 
|  | raw_exception->exception_record.exception_address); | 
|  |  | 
|  | MinidumpContext* md_context = md_exception->GetContext(); | 
|  | ASSERT_TRUE(md_context != NULL); | 
|  | ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); | 
|  | const MDRawContextX86* md_raw_context = md_context->GetContextX86(); | 
|  | ASSERT_TRUE(md_raw_context != NULL); | 
|  | ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), | 
|  | (md_raw_context->context_flags | 
|  | & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); | 
|  | EXPECT_EQ(0x3ecba80dU, raw_context.edi); | 
|  | EXPECT_EQ(0x382583b9U, raw_context.esi); | 
|  | EXPECT_EQ(0x7fccc03fU, raw_context.ebx); | 
|  | EXPECT_EQ(0xf62f8ec2U, raw_context.edx); | 
|  | EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); | 
|  | EXPECT_EQ(0x6a5025e2U, raw_context.eax); | 
|  | EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); | 
|  | EXPECT_EQ(0x6913f540U, raw_context.eip); | 
|  | EXPECT_EQ(0xbffe6edaU, raw_context.cs); | 
|  | EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); | 
|  | EXPECT_EQ(0x659caaa4U, raw_context.esp); | 
|  | EXPECT_EQ(0x2e951ef7U, raw_context.ss); | 
|  | } | 
|  |  | 
|  | TEST(Dump, OneExceptionX86XState) { | 
|  | Dump dump(0, kLittleEndian); | 
|  |  | 
|  | MDRawContextX86 raw_context; | 
|  | raw_context.context_flags = MD_CONTEXT_X86_INTEGER | | 
|  | MD_CONTEXT_X86_CONTROL | MD_CONTEXT_X86_XSTATE; | 
|  | raw_context.edi = 0x3ecba80d; | 
|  | raw_context.esi = 0x382583b9; | 
|  | raw_context.ebx = 0x7fccc03f; | 
|  | raw_context.edx = 0xf62f8ec2; | 
|  | raw_context.ecx = 0x46a6a6a8; | 
|  | raw_context.eax = 0x6a5025e2; | 
|  | raw_context.ebp = 0xd9fabb4a; | 
|  | raw_context.eip = 0x6913f540; | 
|  | raw_context.cs = 0xbffe6eda; | 
|  | raw_context.eflags = 0xb2ce1e2d; | 
|  | raw_context.esp = 0x659caaa4; | 
|  | raw_context.ss = 0x2e951ef7; | 
|  | Context context(dump, raw_context); | 
|  |  | 
|  | Exception exception(dump, context, | 
|  | 0x1234abcd, // thread id | 
|  | 0xdcba4321, // exception code | 
|  | 0xf0e0d0c0, // exception flags | 
|  | 0x0919a9b9c9d9e9f9ULL); // exception address | 
|  |  | 
|  | dump.Add(&context); | 
|  | dump.Add(&exception); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  |  | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | MinidumpException* md_exception = minidump.GetException(); | 
|  | ASSERT_TRUE(md_exception != NULL); | 
|  |  | 
|  | uint32_t thread_id; | 
|  | ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0x1234abcdU, thread_id); | 
|  |  | 
|  | const MDRawExceptionStream* raw_exception = md_exception->exception(); | 
|  | ASSERT_TRUE(raw_exception != NULL); | 
|  | EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); | 
|  | EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); | 
|  | EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, | 
|  | raw_exception->exception_record.exception_address); | 
|  |  | 
|  | MinidumpContext* md_context = md_exception->GetContext(); | 
|  | ASSERT_TRUE(md_context != NULL); | 
|  | ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); | 
|  | const MDRawContextX86* md_raw_context = md_context->GetContextX86(); | 
|  | ASSERT_TRUE(md_raw_context != NULL); | 
|  | ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), | 
|  | (md_raw_context->context_flags | 
|  | & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); | 
|  | EXPECT_EQ(0x3ecba80dU, raw_context.edi); | 
|  | EXPECT_EQ(0x382583b9U, raw_context.esi); | 
|  | EXPECT_EQ(0x7fccc03fU, raw_context.ebx); | 
|  | EXPECT_EQ(0xf62f8ec2U, raw_context.edx); | 
|  | EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); | 
|  | EXPECT_EQ(0x6a5025e2U, raw_context.eax); | 
|  | EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); | 
|  | EXPECT_EQ(0x6913f540U, raw_context.eip); | 
|  | EXPECT_EQ(0xbffe6edaU, raw_context.cs); | 
|  | EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); | 
|  | EXPECT_EQ(0x659caaa4U, raw_context.esp); | 
|  | EXPECT_EQ(0x2e951ef7U, raw_context.ss); | 
|  | } | 
|  |  | 
|  | // Testing that the CPU type can be loaded from a system info stream when | 
|  | // the CPU flags are missing from the context_flags of an exception record | 
|  | TEST(Dump, OneExceptionX86NoCPUFlags) { | 
|  | Dump dump(0, kLittleEndian); | 
|  |  | 
|  | MDRawContextX86 raw_context; | 
|  | // Intentionally not setting CPU type in the context_flags | 
|  | raw_context.context_flags = 0; | 
|  | raw_context.edi = 0x3ecba80d; | 
|  | raw_context.esi = 0x382583b9; | 
|  | raw_context.ebx = 0x7fccc03f; | 
|  | raw_context.edx = 0xf62f8ec2; | 
|  | raw_context.ecx = 0x46a6a6a8; | 
|  | raw_context.eax = 0x6a5025e2; | 
|  | raw_context.ebp = 0xd9fabb4a; | 
|  | raw_context.eip = 0x6913f540; | 
|  | raw_context.cs = 0xbffe6eda; | 
|  | raw_context.eflags = 0xb2ce1e2d; | 
|  | raw_context.esp = 0x659caaa4; | 
|  | raw_context.ss = 0x2e951ef7; | 
|  | Context context(dump, raw_context); | 
|  |  | 
|  | Exception exception(dump, context, | 
|  | 0x1234abcd, // thread id | 
|  | 0xdcba4321, // exception code | 
|  | 0xf0e0d0c0, // exception flags | 
|  | 0x0919a9b9c9d9e9f9ULL); // exception address | 
|  |  | 
|  | dump.Add(&context); | 
|  | dump.Add(&exception); | 
|  |  | 
|  | // Add system info.  This is needed as an alternative source for CPU type | 
|  | // information.  Note, that the CPU flags were intentionally skipped from | 
|  | // the context_flags and this alternative source is required. | 
|  | String csd_version(dump, "Service Pack 2"); | 
|  | SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); | 
|  | dump.Add(&system_info); | 
|  | dump.Add(&csd_version); | 
|  |  | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  |  | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | MinidumpException* md_exception = minidump.GetException(); | 
|  | ASSERT_TRUE(md_exception != NULL); | 
|  |  | 
|  | uint32_t thread_id; | 
|  | ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0x1234abcdU, thread_id); | 
|  |  | 
|  | const MDRawExceptionStream* raw_exception = md_exception->exception(); | 
|  | ASSERT_TRUE(raw_exception != NULL); | 
|  | EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); | 
|  | EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); | 
|  | EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, | 
|  | raw_exception->exception_record.exception_address); | 
|  |  | 
|  | MinidumpContext* md_context = md_exception->GetContext(); | 
|  | ASSERT_TRUE(md_context != NULL); | 
|  |  | 
|  | ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); | 
|  | const MDRawContextX86* md_raw_context = md_context->GetContextX86(); | 
|  | ASSERT_TRUE(md_raw_context != NULL); | 
|  |  | 
|  | // Even though the CPU flags were missing from the context_flags, the | 
|  | // GetContext call above is expected to load the missing CPU flags from the | 
|  | // system info stream and set the CPU type bits in context_flags. | 
|  | ASSERT_EQ((uint32_t) (MD_CONTEXT_X86), md_raw_context->context_flags); | 
|  |  | 
|  | EXPECT_EQ(0x3ecba80dU, raw_context.edi); | 
|  | EXPECT_EQ(0x382583b9U, raw_context.esi); | 
|  | EXPECT_EQ(0x7fccc03fU, raw_context.ebx); | 
|  | EXPECT_EQ(0xf62f8ec2U, raw_context.edx); | 
|  | EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); | 
|  | EXPECT_EQ(0x6a5025e2U, raw_context.eax); | 
|  | EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); | 
|  | EXPECT_EQ(0x6913f540U, raw_context.eip); | 
|  | EXPECT_EQ(0xbffe6edaU, raw_context.cs); | 
|  | EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); | 
|  | EXPECT_EQ(0x659caaa4U, raw_context.esp); | 
|  | EXPECT_EQ(0x2e951ef7U, raw_context.ss); | 
|  | } | 
|  |  | 
|  | // This test covers a scenario where a dump contains an exception but the | 
|  | // context record of the exception is missing the CPU type information in its | 
|  | // context_flags.  The dump has no system info stream so it is imposible to | 
|  | // deduce the CPU type, hence the context record is unusable. | 
|  | TEST(Dump, OneExceptionX86NoCPUFlagsNoSystemInfo) { | 
|  | Dump dump(0, kLittleEndian); | 
|  |  | 
|  | MDRawContextX86 raw_context; | 
|  | // Intentionally not setting CPU type in the context_flags | 
|  | raw_context.context_flags = 0; | 
|  | raw_context.edi = 0x3ecba80d; | 
|  | raw_context.esi = 0x382583b9; | 
|  | raw_context.ebx = 0x7fccc03f; | 
|  | raw_context.edx = 0xf62f8ec2; | 
|  | raw_context.ecx = 0x46a6a6a8; | 
|  | raw_context.eax = 0x6a5025e2; | 
|  | raw_context.ebp = 0xd9fabb4a; | 
|  | raw_context.eip = 0x6913f540; | 
|  | raw_context.cs = 0xbffe6eda; | 
|  | raw_context.eflags = 0xb2ce1e2d; | 
|  | raw_context.esp = 0x659caaa4; | 
|  | raw_context.ss = 0x2e951ef7; | 
|  | Context context(dump, raw_context); | 
|  |  | 
|  | Exception exception(dump, context, | 
|  | 0x1234abcd, // thread id | 
|  | 0xdcba4321, // exception code | 
|  | 0xf0e0d0c0, // exception flags | 
|  | 0x0919a9b9c9d9e9f9ULL); // exception address | 
|  |  | 
|  | dump.Add(&context); | 
|  | dump.Add(&exception); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  |  | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | MinidumpException* md_exception = minidump.GetException(); | 
|  | ASSERT_TRUE(md_exception != NULL); | 
|  |  | 
|  | uint32_t thread_id; | 
|  | ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0x1234abcdU, thread_id); | 
|  |  | 
|  | const MDRawExceptionStream* raw_exception = md_exception->exception(); | 
|  | ASSERT_TRUE(raw_exception != NULL); | 
|  | EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); | 
|  | EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); | 
|  | EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, | 
|  | raw_exception->exception_record.exception_address); | 
|  |  | 
|  | // The context record of the exception is unusable because the context_flags | 
|  | // don't have CPU type information and at the same time the minidump lacks | 
|  | // system info stream so it is impossible to deduce the CPU type. | 
|  | MinidumpContext* md_context = md_exception->GetContext(); | 
|  | ASSERT_EQ(NULL, md_context); | 
|  | } | 
|  |  | 
|  | TEST(Dump, OneExceptionARM) { | 
|  | Dump dump(0, kLittleEndian); | 
|  |  | 
|  | MDRawContextARM raw_context; | 
|  | raw_context.context_flags = MD_CONTEXT_ARM_INTEGER; | 
|  | raw_context.iregs[0] = 0x3ecba80d; | 
|  | raw_context.iregs[1] = 0x382583b9; | 
|  | raw_context.iregs[2] = 0x7fccc03f; | 
|  | raw_context.iregs[3] = 0xf62f8ec2; | 
|  | raw_context.iregs[4] = 0x46a6a6a8; | 
|  | raw_context.iregs[5] = 0x6a5025e2; | 
|  | raw_context.iregs[6] = 0xd9fabb4a; | 
|  | raw_context.iregs[7] = 0x6913f540; | 
|  | raw_context.iregs[8] = 0xbffe6eda; | 
|  | raw_context.iregs[9] = 0xb2ce1e2d; | 
|  | raw_context.iregs[10] = 0x659caaa4; | 
|  | raw_context.iregs[11] = 0xf0e0d0c0; | 
|  | raw_context.iregs[12] = 0xa9b8c7d6; | 
|  | raw_context.iregs[13] = 0x12345678; | 
|  | raw_context.iregs[14] = 0xabcd1234; | 
|  | raw_context.iregs[15] = 0x10203040; | 
|  | raw_context.cpsr = 0x2e951ef7; | 
|  | Context context(dump, raw_context); | 
|  |  | 
|  | Exception exception(dump, context, | 
|  | 0x1234abcd, // thread id | 
|  | 0xdcba4321, // exception code | 
|  | 0xf0e0d0c0, // exception flags | 
|  | 0x0919a9b9c9d9e9f9ULL); // exception address | 
|  |  | 
|  | dump.Add(&context); | 
|  | dump.Add(&exception); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  |  | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | MinidumpException* md_exception = minidump.GetException(); | 
|  | ASSERT_TRUE(md_exception != NULL); | 
|  |  | 
|  | uint32_t thread_id; | 
|  | ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0x1234abcdU, thread_id); | 
|  |  | 
|  | const MDRawExceptionStream* raw_exception = md_exception->exception(); | 
|  | ASSERT_TRUE(raw_exception != NULL); | 
|  | EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); | 
|  | EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); | 
|  | EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, | 
|  | raw_exception->exception_record.exception_address); | 
|  |  | 
|  | MinidumpContext* md_context = md_exception->GetContext(); | 
|  | ASSERT_TRUE(md_context != NULL); | 
|  | ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU()); | 
|  | const MDRawContextARM* md_raw_context = md_context->GetContextARM(); | 
|  | ASSERT_TRUE(md_raw_context != NULL); | 
|  | ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER, | 
|  | (md_raw_context->context_flags | 
|  | & MD_CONTEXT_ARM_INTEGER)); | 
|  | EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]); | 
|  | EXPECT_EQ(0x382583b9U, raw_context.iregs[1]); | 
|  | EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]); | 
|  | EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]); | 
|  | EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]); | 
|  | EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]); | 
|  | EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]); | 
|  | EXPECT_EQ(0x6913f540U, raw_context.iregs[7]); | 
|  | EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]); | 
|  | EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]); | 
|  | EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]); | 
|  | EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]); | 
|  | EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]); | 
|  | EXPECT_EQ(0x12345678U, raw_context.iregs[13]); | 
|  | EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]); | 
|  | EXPECT_EQ(0x10203040U, raw_context.iregs[15]); | 
|  | EXPECT_EQ(0x2e951ef7U, raw_context.cpsr); | 
|  | } | 
|  |  | 
|  | TEST(Dump, OneExceptionARMOldFlags) { | 
|  | Dump dump(0, kLittleEndian); | 
|  |  | 
|  | MDRawContextARM raw_context; | 
|  | // MD_CONTEXT_ARM_INTEGER, but with _OLD | 
|  | raw_context.context_flags = MD_CONTEXT_ARM_OLD | 0x00000002; | 
|  | raw_context.iregs[0] = 0x3ecba80d; | 
|  | raw_context.iregs[1] = 0x382583b9; | 
|  | raw_context.iregs[2] = 0x7fccc03f; | 
|  | raw_context.iregs[3] = 0xf62f8ec2; | 
|  | raw_context.iregs[4] = 0x46a6a6a8; | 
|  | raw_context.iregs[5] = 0x6a5025e2; | 
|  | raw_context.iregs[6] = 0xd9fabb4a; | 
|  | raw_context.iregs[7] = 0x6913f540; | 
|  | raw_context.iregs[8] = 0xbffe6eda; | 
|  | raw_context.iregs[9] = 0xb2ce1e2d; | 
|  | raw_context.iregs[10] = 0x659caaa4; | 
|  | raw_context.iregs[11] = 0xf0e0d0c0; | 
|  | raw_context.iregs[12] = 0xa9b8c7d6; | 
|  | raw_context.iregs[13] = 0x12345678; | 
|  | raw_context.iregs[14] = 0xabcd1234; | 
|  | raw_context.iregs[15] = 0x10203040; | 
|  | raw_context.cpsr = 0x2e951ef7; | 
|  | Context context(dump, raw_context); | 
|  |  | 
|  | Exception exception(dump, context, | 
|  | 0x1234abcd, // thread id | 
|  | 0xdcba4321, // exception code | 
|  | 0xf0e0d0c0, // exception flags | 
|  | 0x0919a9b9c9d9e9f9ULL); // exception address | 
|  |  | 
|  | dump.Add(&context); | 
|  | dump.Add(&exception); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  |  | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | MinidumpException* md_exception = minidump.GetException(); | 
|  | ASSERT_TRUE(md_exception != NULL); | 
|  |  | 
|  | uint32_t thread_id; | 
|  | ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0x1234abcdU, thread_id); | 
|  |  | 
|  | const MDRawExceptionStream* raw_exception = md_exception->exception(); | 
|  | ASSERT_TRUE(raw_exception != NULL); | 
|  | EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); | 
|  | EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); | 
|  | EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, | 
|  | raw_exception->exception_record.exception_address); | 
|  |  | 
|  | MinidumpContext* md_context = md_exception->GetContext(); | 
|  | ASSERT_TRUE(md_context != NULL); | 
|  | ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU()); | 
|  | const MDRawContextARM* md_raw_context = md_context->GetContextARM(); | 
|  | ASSERT_TRUE(md_raw_context != NULL); | 
|  | ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER, | 
|  | (md_raw_context->context_flags | 
|  | & MD_CONTEXT_ARM_INTEGER)); | 
|  | EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]); | 
|  | EXPECT_EQ(0x382583b9U, raw_context.iregs[1]); | 
|  | EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]); | 
|  | EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]); | 
|  | EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]); | 
|  | EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]); | 
|  | EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]); | 
|  | EXPECT_EQ(0x6913f540U, raw_context.iregs[7]); | 
|  | EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]); | 
|  | EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]); | 
|  | EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]); | 
|  | EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]); | 
|  | EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]); | 
|  | EXPECT_EQ(0x12345678U, raw_context.iregs[13]); | 
|  | EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]); | 
|  | EXPECT_EQ(0x10203040U, raw_context.iregs[15]); | 
|  | EXPECT_EQ(0x2e951ef7U, raw_context.cpsr); | 
|  | } | 
|  |  | 
|  | TEST(Dump, OneExceptionMIPS) { | 
|  | Dump dump(0, kLittleEndian); | 
|  |  | 
|  | MDRawContextMIPS raw_context; | 
|  | raw_context.context_flags = MD_CONTEXT_MIPS_INTEGER; | 
|  | raw_context.iregs[0] = 0x3ecba80d; | 
|  | raw_context.iregs[1] = 0x382583b9; | 
|  | raw_context.iregs[2] = 0x7fccc03f; | 
|  | raw_context.iregs[3] = 0xf62f8ec2; | 
|  | raw_context.iregs[4] = 0x46a6a6a8; | 
|  | raw_context.iregs[5] = 0x6a5025e2; | 
|  | raw_context.iregs[6] = 0xd9fabb4a; | 
|  | raw_context.iregs[7] = 0x6913f540; | 
|  | raw_context.iregs[8] = 0xbffe6eda; | 
|  | raw_context.iregs[9] = 0xb2ce1e2d; | 
|  | raw_context.iregs[10] = 0x659caaa4; | 
|  | raw_context.iregs[11] = 0xf0e0d0c0; | 
|  | raw_context.iregs[12] = 0xa9b8c7d6; | 
|  | raw_context.iregs[13] = 0x12345678; | 
|  | raw_context.iregs[14] = 0xabcd1234; | 
|  | raw_context.iregs[15] = 0x10203040; | 
|  | raw_context.iregs[16] = 0xa80d3ecb; | 
|  | raw_context.iregs[17] = 0x83b93825; | 
|  | raw_context.iregs[18] = 0xc03f7fcc; | 
|  | raw_context.iregs[19] = 0x8ec2f62f; | 
|  | raw_context.iregs[20] = 0xa6a846a6; | 
|  | raw_context.iregs[21] = 0x25e26a50; | 
|  | raw_context.iregs[22] = 0xbb4ad9fa; | 
|  | raw_context.iregs[23] = 0xf5406913; | 
|  | raw_context.iregs[24] = 0x6edabffe; | 
|  | raw_context.iregs[25] = 0x1e2db2ce; | 
|  | raw_context.iregs[26] = 0xaaa4659c; | 
|  | raw_context.iregs[27] = 0xd0c0f0e0; | 
|  | raw_context.iregs[28] = 0xc7d6a9b8; | 
|  | raw_context.iregs[29] = 0x56781234; | 
|  | raw_context.iregs[30] = 0x1234abcd; | 
|  | raw_context.iregs[31] = 0x30401020; | 
|  |  | 
|  | Context context(dump, raw_context); | 
|  |  | 
|  | Exception exception(dump, context, | 
|  | 0x1234abcd,  // Thread id. | 
|  | 0xdcba4321,  // Exception code. | 
|  | 0xf0e0d0c0,  // Exception flags. | 
|  | 0x0919a9b9); // Exception address. | 
|  |  | 
|  | dump.Add(&context); | 
|  | dump.Add(&exception); | 
|  | dump.Finish(); | 
|  |  | 
|  | string contents; | 
|  | ASSERT_TRUE(dump.GetContents(&contents)); | 
|  |  | 
|  | istringstream minidump_stream(contents); | 
|  | Minidump minidump(minidump_stream); | 
|  | ASSERT_TRUE(minidump.Read()); | 
|  | ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); | 
|  |  | 
|  | MinidumpException* md_exception = minidump.GetException(); | 
|  | ASSERT_TRUE(md_exception != NULL); | 
|  |  | 
|  | uint32_t thread_id; | 
|  | ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); | 
|  | ASSERT_EQ(0x1234abcdU, thread_id); | 
|  |  | 
|  | const MDRawExceptionStream* raw_exception = md_exception->exception(); | 
|  | ASSERT_TRUE(raw_exception != NULL); | 
|  | EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); | 
|  | EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); | 
|  | EXPECT_EQ(0x0919a9b9U, | 
|  | raw_exception->exception_record.exception_address); | 
|  |  | 
|  | MinidumpContext* md_context = md_exception->GetContext(); | 
|  | ASSERT_TRUE(md_context != NULL); | 
|  | ASSERT_EQ((uint32_t) MD_CONTEXT_MIPS, md_context->GetContextCPU()); | 
|  | const MDRawContextMIPS* md_raw_context = md_context->GetContextMIPS(); | 
|  | ASSERT_TRUE(md_raw_context != NULL); | 
|  | ASSERT_EQ((uint32_t) MD_CONTEXT_MIPS_INTEGER, | 
|  | (md_raw_context->context_flags & MD_CONTEXT_MIPS_INTEGER)); | 
|  | EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]); | 
|  | EXPECT_EQ(0x382583b9U, raw_context.iregs[1]); | 
|  | EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]); | 
|  | EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]); | 
|  | EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]); | 
|  | EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]); | 
|  | EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]); | 
|  | EXPECT_EQ(0x6913f540U, raw_context.iregs[7]); | 
|  | EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]); | 
|  | EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]); | 
|  | EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]); | 
|  | EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]); | 
|  | EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]); | 
|  | EXPECT_EQ(0x12345678U, raw_context.iregs[13]); | 
|  | EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]); | 
|  | EXPECT_EQ(0x10203040U, raw_context.iregs[15]); | 
|  | EXPECT_EQ(0xa80d3ecbU, raw_context.iregs[16]); | 
|  | EXPECT_EQ(0x83b93825U, raw_context.iregs[17]); | 
|  | EXPECT_EQ(0xc03f7fccU, raw_context.iregs[18]); | 
|  | EXPECT_EQ(0x8ec2f62fU, raw_context.iregs[19]); | 
|  | EXPECT_EQ(0xa6a846a6U, raw_context.iregs[20]); | 
|  | EXPECT_EQ(0x25e26a50U, raw_context.iregs[21]); | 
|  | EXPECT_EQ(0xbb4ad9faU, raw_context.iregs[22]); | 
|  | EXPECT_EQ(0xf5406913U, raw_context.iregs[23]); | 
|  | EXPECT_EQ(0x6edabffeU, raw_context.iregs[24]); | 
|  | EXPECT_EQ(0x1e2db2ceU, raw_context.iregs[25]); | 
|  | EXPECT_EQ(0xaaa4659cU, raw_context.iregs[26]); | 
|  | EXPECT_EQ(0xd0c0f0e0U, raw_context.iregs[27]); | 
|  | EXPECT_EQ(0xc7d6a9b8U, raw_context.iregs[28]); | 
|  | EXPECT_EQ(0x56781234U, raw_context.iregs[29]); | 
|  | EXPECT_EQ(0x1234abcdU, raw_context.iregs[30]); | 
|  | EXPECT_EQ(0x30401020U, raw_context.iregs[31]); | 
|  | } | 
|  |  | 
|  | }  // namespace |