michael@0: // Copyright (c) 2010, Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: // Unit test for Minidump. Uses a pre-generated minidump and michael@0: // verifies that certain streams are correct. michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "breakpad_googletest_includes.h" michael@0: #include "common/using_std_string.h" michael@0: #include "google_breakpad/common/minidump_format.h" michael@0: #include "google_breakpad/processor/minidump.h" michael@0: #include "processor/logging.h" michael@0: #include "processor/synth_minidump.h" michael@0: michael@0: namespace { michael@0: michael@0: using google_breakpad::Minidump; michael@0: using google_breakpad::MinidumpContext; michael@0: using google_breakpad::MinidumpException; michael@0: using google_breakpad::MinidumpMemoryInfo; michael@0: using google_breakpad::MinidumpMemoryInfoList; michael@0: using google_breakpad::MinidumpMemoryList; michael@0: using google_breakpad::MinidumpMemoryRegion; michael@0: using google_breakpad::MinidumpModule; michael@0: using google_breakpad::MinidumpModuleList; michael@0: using google_breakpad::MinidumpSystemInfo; michael@0: using google_breakpad::MinidumpThread; michael@0: using google_breakpad::MinidumpThreadList; michael@0: using google_breakpad::SynthMinidump::Context; michael@0: using google_breakpad::SynthMinidump::Dump; michael@0: using google_breakpad::SynthMinidump::Exception; michael@0: using google_breakpad::SynthMinidump::Memory; michael@0: using google_breakpad::SynthMinidump::Module; michael@0: using google_breakpad::SynthMinidump::Stream; michael@0: using google_breakpad::SynthMinidump::String; michael@0: using google_breakpad::SynthMinidump::SystemInfo; michael@0: using google_breakpad::SynthMinidump::Thread; michael@0: using google_breakpad::test_assembler::kBigEndian; michael@0: using google_breakpad::test_assembler::kLittleEndian; michael@0: using std::ifstream; michael@0: using std::istringstream; michael@0: using std::vector; michael@0: using ::testing::Return; michael@0: michael@0: class MinidumpTest : public ::testing::Test { michael@0: public: michael@0: void SetUp() { michael@0: minidump_file_ = string(getenv("srcdir") ? getenv("srcdir") : ".") + michael@0: "/src/processor/testdata/minidump2.dmp"; michael@0: } michael@0: string minidump_file_; michael@0: }; michael@0: michael@0: TEST_F(MinidumpTest, TestMinidumpFromFile) { michael@0: Minidump minidump(minidump_file_); michael@0: ASSERT_EQ(minidump.path(), minidump_file_); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: const MDRawHeader* header = minidump.header(); michael@0: ASSERT_NE(header, (MDRawHeader*)NULL); michael@0: ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE)); michael@0: //TODO: add more checks here michael@0: } michael@0: michael@0: TEST_F(MinidumpTest, TestMinidumpFromStream) { michael@0: // read minidump contents into memory, construct a stringstream around them michael@0: ifstream file_stream(minidump_file_.c_str(), std::ios::in); michael@0: ASSERT_TRUE(file_stream.good()); michael@0: vector bytes; michael@0: file_stream.seekg(0, std::ios_base::end); michael@0: ASSERT_TRUE(file_stream.good()); michael@0: bytes.resize(file_stream.tellg()); michael@0: file_stream.seekg(0, std::ios_base::beg); michael@0: ASSERT_TRUE(file_stream.good()); michael@0: file_stream.read(&bytes[0], bytes.size()); michael@0: ASSERT_TRUE(file_stream.good()); michael@0: string str(&bytes[0], bytes.size()); michael@0: istringstream stream(str); michael@0: ASSERT_TRUE(stream.good()); michael@0: michael@0: // now read minidump from stringstream michael@0: Minidump minidump(stream); michael@0: ASSERT_EQ(minidump.path(), ""); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: const MDRawHeader* header = minidump.header(); michael@0: ASSERT_NE(header, (MDRawHeader*)NULL); michael@0: ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE)); michael@0: //TODO: add more checks here michael@0: } michael@0: michael@0: TEST(Dump, ReadBackEmpty) { michael@0: Dump dump(0); michael@0: dump.Finish(); michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: istringstream stream(contents); michael@0: Minidump minidump(stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(0U, minidump.GetDirectoryEntryCount()); michael@0: } michael@0: michael@0: TEST(Dump, ReadBackEmptyBigEndian) { michael@0: Dump big_minidump(0, kBigEndian); michael@0: big_minidump.Finish(); michael@0: string contents; michael@0: ASSERT_TRUE(big_minidump.GetContents(&contents)); michael@0: istringstream stream(contents); michael@0: Minidump minidump(stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(0U, minidump.GetDirectoryEntryCount()); michael@0: } michael@0: michael@0: TEST(Dump, OneStream) { michael@0: Dump dump(0, kBigEndian); michael@0: Stream stream(dump, 0xfbb7fa2bU); michael@0: stream.Append("stream contents"); michael@0: dump.Add(&stream); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); michael@0: ASSERT_TRUE(dir != NULL); michael@0: EXPECT_EQ(0xfbb7fa2bU, dir->stream_type); michael@0: michael@0: uint32_t stream_length; michael@0: ASSERT_TRUE(minidump.SeekToStreamType(0xfbb7fa2bU, &stream_length)); michael@0: ASSERT_EQ(15U, stream_length); michael@0: char stream_contents[15]; michael@0: ASSERT_TRUE(minidump.ReadBytes(stream_contents, sizeof(stream_contents))); michael@0: EXPECT_EQ(string("stream contents"), michael@0: string(stream_contents, sizeof(stream_contents))); michael@0: michael@0: EXPECT_FALSE(minidump.GetThreadList()); michael@0: EXPECT_FALSE(minidump.GetModuleList()); michael@0: EXPECT_FALSE(minidump.GetMemoryList()); michael@0: EXPECT_FALSE(minidump.GetException()); michael@0: EXPECT_FALSE(minidump.GetAssertion()); michael@0: EXPECT_FALSE(minidump.GetSystemInfo()); michael@0: EXPECT_FALSE(minidump.GetMiscInfo()); michael@0: EXPECT_FALSE(minidump.GetBreakpadInfo()); michael@0: } michael@0: michael@0: TEST(Dump, OneMemory) { michael@0: Dump dump(0, kBigEndian); michael@0: Memory memory(dump, 0x309d68010bd21b2cULL); michael@0: memory.Append("memory contents"); michael@0: dump.Add(&memory); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); michael@0: ASSERT_TRUE(dir != NULL); michael@0: EXPECT_EQ((uint32_t) MD_MEMORY_LIST_STREAM, dir->stream_type); michael@0: michael@0: MinidumpMemoryList *memory_list = minidump.GetMemoryList(); michael@0: ASSERT_TRUE(memory_list != NULL); michael@0: ASSERT_EQ(1U, memory_list->region_count()); michael@0: michael@0: MinidumpMemoryRegion *region1 = memory_list->GetMemoryRegionAtIndex(0); michael@0: ASSERT_EQ(0x309d68010bd21b2cULL, region1->GetBase()); michael@0: ASSERT_EQ(15U, region1->GetSize()); michael@0: const uint8_t *region1_bytes = region1->GetMemory(); michael@0: ASSERT_TRUE(memcmp("memory contents", region1_bytes, 15) == 0); michael@0: } michael@0: michael@0: // One thread --- and its requisite entourage. michael@0: TEST(Dump, OneThread) { michael@0: Dump dump(0, kLittleEndian); michael@0: Memory stack(dump, 0x2326a0fa); michael@0: stack.Append("stack for thread"); michael@0: michael@0: MDRawContextX86 raw_context; michael@0: const uint32_t kExpectedEIP = 0x6913f540; michael@0: raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL; michael@0: raw_context.edi = 0x3ecba80d; michael@0: raw_context.esi = 0x382583b9; michael@0: raw_context.ebx = 0x7fccc03f; michael@0: raw_context.edx = 0xf62f8ec2; michael@0: raw_context.ecx = 0x46a6a6a8; michael@0: raw_context.eax = 0x6a5025e2; michael@0: raw_context.ebp = 0xd9fabb4a; michael@0: raw_context.eip = kExpectedEIP; michael@0: raw_context.cs = 0xbffe6eda; michael@0: raw_context.eflags = 0xb2ce1e2d; michael@0: raw_context.esp = 0x659caaa4; michael@0: raw_context.ss = 0x2e951ef7; michael@0: Context context(dump, raw_context); michael@0: michael@0: Thread thread(dump, 0xa898f11b, stack, context, michael@0: 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL); michael@0: michael@0: dump.Add(&stack); michael@0: dump.Add(&context); michael@0: dump.Add(&thread); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: MinidumpMemoryList *md_memory_list = minidump.GetMemoryList(); michael@0: ASSERT_TRUE(md_memory_list != NULL); michael@0: ASSERT_EQ(1U, md_memory_list->region_count()); michael@0: michael@0: MinidumpMemoryRegion *md_region = md_memory_list->GetMemoryRegionAtIndex(0); michael@0: ASSERT_EQ(0x2326a0faU, md_region->GetBase()); michael@0: ASSERT_EQ(16U, md_region->GetSize()); michael@0: const uint8_t *region_bytes = md_region->GetMemory(); michael@0: ASSERT_TRUE(memcmp("stack for thread", region_bytes, 16) == 0); michael@0: michael@0: MinidumpThreadList *thread_list = minidump.GetThreadList(); michael@0: ASSERT_TRUE(thread_list != NULL); michael@0: ASSERT_EQ(1U, thread_list->thread_count()); michael@0: michael@0: MinidumpThread *md_thread = thread_list->GetThreadAtIndex(0); michael@0: ASSERT_TRUE(md_thread != NULL); michael@0: uint32_t thread_id; michael@0: ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0xa898f11bU, thread_id); michael@0: MinidumpMemoryRegion *md_stack = md_thread->GetMemory(); michael@0: ASSERT_TRUE(md_stack != NULL); michael@0: ASSERT_EQ(0x2326a0faU, md_stack->GetBase()); michael@0: ASSERT_EQ(16U, md_stack->GetSize()); michael@0: const uint8_t *md_stack_bytes = md_stack->GetMemory(); michael@0: ASSERT_TRUE(memcmp("stack for thread", md_stack_bytes, 16) == 0); michael@0: michael@0: MinidumpContext *md_context = md_thread->GetContext(); michael@0: ASSERT_TRUE(md_context != NULL); michael@0: ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); michael@0: michael@0: uint64_t eip; michael@0: ASSERT_TRUE(md_context->GetInstructionPointer(&eip)); michael@0: EXPECT_EQ(kExpectedEIP, eip); michael@0: michael@0: const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); michael@0: ASSERT_TRUE(md_raw_context != NULL); michael@0: ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), michael@0: (md_raw_context->context_flags michael@0: & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); michael@0: EXPECT_EQ(0x3ecba80dU, raw_context.edi); michael@0: EXPECT_EQ(0x382583b9U, raw_context.esi); michael@0: EXPECT_EQ(0x7fccc03fU, raw_context.ebx); michael@0: EXPECT_EQ(0xf62f8ec2U, raw_context.edx); michael@0: EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); michael@0: EXPECT_EQ(0x6a5025e2U, raw_context.eax); michael@0: EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); michael@0: EXPECT_EQ(kExpectedEIP, raw_context.eip); michael@0: EXPECT_EQ(0xbffe6edaU, raw_context.cs); michael@0: EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); michael@0: EXPECT_EQ(0x659caaa4U, raw_context.esp); michael@0: EXPECT_EQ(0x2e951ef7U, raw_context.ss); michael@0: } michael@0: michael@0: TEST(Dump, ThreadMissingMemory) { michael@0: Dump dump(0, kLittleEndian); michael@0: Memory stack(dump, 0x2326a0fa); michael@0: // Stack has no contents. michael@0: michael@0: MDRawContextX86 raw_context; michael@0: memset(&raw_context, 0, sizeof(raw_context)); michael@0: raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL; michael@0: Context context(dump, raw_context); michael@0: michael@0: Thread thread(dump, 0xa898f11b, stack, context, michael@0: 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL); michael@0: michael@0: dump.Add(&stack); michael@0: dump.Add(&context); michael@0: dump.Add(&thread); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: // This should succeed even though the thread has no stack memory. michael@0: MinidumpThreadList* thread_list = minidump.GetThreadList(); michael@0: ASSERT_TRUE(thread_list != NULL); michael@0: ASSERT_EQ(1U, thread_list->thread_count()); michael@0: michael@0: MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0); michael@0: ASSERT_TRUE(md_thread != NULL); michael@0: michael@0: uint32_t thread_id; michael@0: ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0xa898f11bU, thread_id); michael@0: michael@0: MinidumpContext* md_context = md_thread->GetContext(); michael@0: ASSERT_NE(reinterpret_cast(NULL), md_context); michael@0: michael@0: MinidumpMemoryRegion* md_stack = md_thread->GetMemory(); michael@0: ASSERT_EQ(reinterpret_cast(NULL), md_stack); michael@0: } michael@0: michael@0: TEST(Dump, ThreadMissingContext) { michael@0: Dump dump(0, kLittleEndian); michael@0: Memory stack(dump, 0x2326a0fa); michael@0: stack.Append("stack for thread"); michael@0: michael@0: // Context is empty. michael@0: Context context(dump); michael@0: michael@0: Thread thread(dump, 0xa898f11b, stack, context, michael@0: 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL); michael@0: michael@0: dump.Add(&stack); michael@0: dump.Add(&context); michael@0: dump.Add(&thread); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: // This should succeed even though the thread has no stack memory. michael@0: MinidumpThreadList* thread_list = minidump.GetThreadList(); michael@0: ASSERT_TRUE(thread_list != NULL); michael@0: ASSERT_EQ(1U, thread_list->thread_count()); michael@0: michael@0: MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0); michael@0: ASSERT_TRUE(md_thread != NULL); michael@0: michael@0: uint32_t thread_id; michael@0: ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0xa898f11bU, thread_id); michael@0: MinidumpMemoryRegion* md_stack = md_thread->GetMemory(); michael@0: ASSERT_NE(reinterpret_cast(NULL), md_stack); michael@0: michael@0: MinidumpContext* md_context = md_thread->GetContext(); michael@0: ASSERT_EQ(reinterpret_cast(NULL), md_context); michael@0: } michael@0: michael@0: TEST(Dump, OneModule) { michael@0: static const MDVSFixedFileInfo fixed_file_info = { michael@0: 0xb2fba33a, // signature michael@0: 0x33d7a728, // struct_version michael@0: 0x31afcb20, // file_version_hi michael@0: 0xe51cdab1, // file_version_lo michael@0: 0xd1ea6907, // product_version_hi michael@0: 0x03032857, // product_version_lo michael@0: 0x11bf71d7, // file_flags_mask michael@0: 0x5fb8cdbf, // file_flags michael@0: 0xe45d0d5d, // file_os michael@0: 0x107d9562, // file_type michael@0: 0x5a8844d4, // file_subtype michael@0: 0xa8d30b20, // file_date_hi michael@0: 0x651c3e4e // file_date_lo michael@0: }; michael@0: michael@0: Dump dump(0, kBigEndian); michael@0: String module_name(dump, "single module"); michael@0: Module module(dump, 0xa90206ca83eb2852ULL, 0xada542bd, michael@0: module_name, michael@0: 0xb1054d2a, michael@0: 0x34571371, michael@0: fixed_file_info, // from synth_minidump_unittest_data.h michael@0: NULL, NULL); michael@0: michael@0: dump.Add(&module); michael@0: dump.Add(&module_name); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); michael@0: ASSERT_TRUE(dir != NULL); michael@0: EXPECT_EQ((uint32_t) MD_MODULE_LIST_STREAM, dir->stream_type); michael@0: michael@0: MinidumpModuleList *md_module_list = minidump.GetModuleList(); michael@0: ASSERT_TRUE(md_module_list != NULL); michael@0: ASSERT_EQ(1U, md_module_list->module_count()); michael@0: michael@0: const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0); michael@0: ASSERT_TRUE(md_module != NULL); michael@0: ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address()); michael@0: ASSERT_EQ(0xada542bd, md_module->size()); michael@0: ASSERT_EQ("single module", md_module->code_file()); michael@0: michael@0: const MDRawModule *md_raw_module = md_module->module(); michael@0: ASSERT_TRUE(md_raw_module != NULL); michael@0: ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp); michael@0: ASSERT_EQ(0x34571371U, md_raw_module->checksum); michael@0: ASSERT_TRUE(memcmp(&md_raw_module->version_info, &fixed_file_info, michael@0: sizeof(fixed_file_info)) == 0); michael@0: } michael@0: michael@0: TEST(Dump, OneSystemInfo) { michael@0: Dump dump(0, kLittleEndian); michael@0: String csd_version(dump, "Petulant Pierogi"); michael@0: SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); michael@0: michael@0: dump.Add(&system_info); michael@0: dump.Add(&csd_version); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); michael@0: ASSERT_TRUE(dir != NULL); michael@0: EXPECT_EQ((uint32_t) MD_SYSTEM_INFO_STREAM, dir->stream_type); michael@0: michael@0: MinidumpSystemInfo *md_system_info = minidump.GetSystemInfo(); michael@0: ASSERT_TRUE(md_system_info != NULL); michael@0: ASSERT_EQ("windows", md_system_info->GetOS()); michael@0: ASSERT_EQ("x86", md_system_info->GetCPU()); michael@0: ASSERT_EQ("Petulant Pierogi", *md_system_info->GetCSDVersion()); michael@0: ASSERT_EQ("GenuineIntel", *md_system_info->GetCPUVendor()); michael@0: } michael@0: michael@0: TEST(Dump, BigDump) { michael@0: Dump dump(0, kLittleEndian); michael@0: michael@0: // A SystemInfo stream. michael@0: String csd_version(dump, "Munificent Macaque"); michael@0: SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); michael@0: dump.Add(&csd_version); michael@0: dump.Add(&system_info); michael@0: michael@0: // Five threads! michael@0: Memory stack0(dump, 0x70b9ebfc); michael@0: stack0.Append("stack for thread zero"); michael@0: MDRawContextX86 raw_context0; michael@0: raw_context0.context_flags = MD_CONTEXT_X86_INTEGER; michael@0: raw_context0.eip = 0xaf0709e4; michael@0: Context context0(dump, raw_context0); michael@0: Thread thread0(dump, 0xbbef4432, stack0, context0, michael@0: 0xd0377e7b, 0xdb8eb0cf, 0xd73bc314, 0x09d357bac7f9a163ULL); michael@0: dump.Add(&stack0); michael@0: dump.Add(&context0); michael@0: dump.Add(&thread0); michael@0: michael@0: Memory stack1(dump, 0xf988cc45); michael@0: stack1.Append("stack for thread one"); michael@0: MDRawContextX86 raw_context1; michael@0: raw_context1.context_flags = MD_CONTEXT_X86_INTEGER; michael@0: raw_context1.eip = 0xe4f56f81; michael@0: Context context1(dump, raw_context1); michael@0: Thread thread1(dump, 0x657c3f58, stack1, context1, michael@0: 0xa68fa182, 0x6f3cf8dd, 0xe3a78ccf, 0x78cc84775e4534bbULL); michael@0: dump.Add(&stack1); michael@0: dump.Add(&context1); michael@0: dump.Add(&thread1); michael@0: michael@0: Memory stack2(dump, 0xc8a92e7c); michael@0: stack2.Append("stack for thread two"); michael@0: MDRawContextX86 raw_context2; michael@0: raw_context2.context_flags = MD_CONTEXT_X86_INTEGER; michael@0: raw_context2.eip = 0xb336a438; michael@0: Context context2(dump, raw_context2); michael@0: Thread thread2(dump, 0xdf4b8a71, stack2, context2, michael@0: 0x674c26b6, 0x445d7120, 0x7e700c56, 0xd89bf778e7793e17ULL); michael@0: dump.Add(&stack2); michael@0: dump.Add(&context2); michael@0: dump.Add(&thread2); michael@0: michael@0: Memory stack3(dump, 0x36d08e08); michael@0: stack3.Append("stack for thread three"); michael@0: MDRawContextX86 raw_context3; michael@0: raw_context3.context_flags = MD_CONTEXT_X86_INTEGER; michael@0: raw_context3.eip = 0xdf99a60c; michael@0: Context context3(dump, raw_context3); michael@0: Thread thread3(dump, 0x86e6c341, stack3, context3, michael@0: 0x32dc5c55, 0x17a2aba8, 0xe0cc75e7, 0xa46393994dae83aeULL); michael@0: dump.Add(&stack3); michael@0: dump.Add(&context3); michael@0: dump.Add(&thread3); michael@0: michael@0: Memory stack4(dump, 0x1e0ab4fa); michael@0: stack4.Append("stack for thread four"); michael@0: MDRawContextX86 raw_context4; michael@0: raw_context4.context_flags = MD_CONTEXT_X86_INTEGER; michael@0: raw_context4.eip = 0xaa646267; michael@0: Context context4(dump, raw_context4); michael@0: Thread thread4(dump, 0x261a28d4, stack4, context4, michael@0: 0x6ebd389e, 0xa0cd4759, 0x30168846, 0x164f650a0cf39d35ULL); michael@0: dump.Add(&stack4); michael@0: dump.Add(&context4); michael@0: dump.Add(&thread4); michael@0: michael@0: // Three modules! michael@0: String module1_name(dump, "module one"); michael@0: Module module1(dump, 0xeb77da57b5d4cbdaULL, 0x83cd5a37, module1_name); michael@0: dump.Add(&module1_name); michael@0: dump.Add(&module1); michael@0: michael@0: String module2_name(dump, "module two"); michael@0: Module module2(dump, 0x8675884adfe5ac90ULL, 0xb11e4ea3, module2_name); michael@0: dump.Add(&module2_name); michael@0: dump.Add(&module2); michael@0: michael@0: String module3_name(dump, "module three"); michael@0: Module module3(dump, 0x95fc1544da321b6cULL, 0x7c2bf081, module3_name); michael@0: dump.Add(&module3_name); michael@0: dump.Add(&module3); michael@0: michael@0: // Add one more memory region, on top of the five stacks. michael@0: Memory memory5(dump, 0x61979e828040e564ULL); michael@0: memory5.Append("contents of memory 5"); michael@0: dump.Add(&memory5); michael@0: michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(4U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: // Check the threads. michael@0: MinidumpThreadList *thread_list = minidump.GetThreadList(); michael@0: ASSERT_TRUE(thread_list != NULL); michael@0: ASSERT_EQ(5U, thread_list->thread_count()); michael@0: uint32_t thread_id; michael@0: ASSERT_TRUE(thread_list->GetThreadAtIndex(0)->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0xbbef4432U, thread_id); michael@0: ASSERT_EQ(0x70b9ebfcU, michael@0: thread_list->GetThreadAtIndex(0)->GetMemory()->GetBase()); michael@0: ASSERT_EQ(0xaf0709e4U, michael@0: thread_list->GetThreadAtIndex(0)->GetContext()->GetContextX86() michael@0: ->eip); michael@0: michael@0: ASSERT_TRUE(thread_list->GetThreadAtIndex(1)->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0x657c3f58U, thread_id); michael@0: ASSERT_EQ(0xf988cc45U, michael@0: thread_list->GetThreadAtIndex(1)->GetMemory()->GetBase()); michael@0: ASSERT_EQ(0xe4f56f81U, michael@0: thread_list->GetThreadAtIndex(1)->GetContext()->GetContextX86() michael@0: ->eip); michael@0: michael@0: ASSERT_TRUE(thread_list->GetThreadAtIndex(2)->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0xdf4b8a71U, thread_id); michael@0: ASSERT_EQ(0xc8a92e7cU, michael@0: thread_list->GetThreadAtIndex(2)->GetMemory()->GetBase()); michael@0: ASSERT_EQ(0xb336a438U, michael@0: thread_list->GetThreadAtIndex(2)->GetContext()->GetContextX86() michael@0: ->eip); michael@0: michael@0: ASSERT_TRUE(thread_list->GetThreadAtIndex(3)->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0x86e6c341U, thread_id); michael@0: ASSERT_EQ(0x36d08e08U, michael@0: thread_list->GetThreadAtIndex(3)->GetMemory()->GetBase()); michael@0: ASSERT_EQ(0xdf99a60cU, michael@0: thread_list->GetThreadAtIndex(3)->GetContext()->GetContextX86() michael@0: ->eip); michael@0: michael@0: ASSERT_TRUE(thread_list->GetThreadAtIndex(4)->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0x261a28d4U, thread_id); michael@0: ASSERT_EQ(0x1e0ab4faU, michael@0: thread_list->GetThreadAtIndex(4)->GetMemory()->GetBase()); michael@0: ASSERT_EQ(0xaa646267U, michael@0: thread_list->GetThreadAtIndex(4)->GetContext()->GetContextX86() michael@0: ->eip); michael@0: michael@0: // Check the modules. michael@0: MinidumpModuleList *md_module_list = minidump.GetModuleList(); michael@0: ASSERT_TRUE(md_module_list != NULL); michael@0: ASSERT_EQ(3U, md_module_list->module_count()); michael@0: EXPECT_EQ(0xeb77da57b5d4cbdaULL, michael@0: md_module_list->GetModuleAtIndex(0)->base_address()); michael@0: EXPECT_EQ(0x8675884adfe5ac90ULL, michael@0: md_module_list->GetModuleAtIndex(1)->base_address()); michael@0: EXPECT_EQ(0x95fc1544da321b6cULL, michael@0: md_module_list->GetModuleAtIndex(2)->base_address()); michael@0: } michael@0: michael@0: TEST(Dump, OneMemoryInfo) { michael@0: Dump dump(0, kBigEndian); michael@0: Stream stream(dump, MD_MEMORY_INFO_LIST_STREAM); michael@0: michael@0: // Add the MDRawMemoryInfoList header. michael@0: const uint64_t kNumberOfEntries = 1; michael@0: stream.D32(sizeof(MDRawMemoryInfoList)) // size_of_header michael@0: .D32(sizeof(MDRawMemoryInfo)) // size_of_entry michael@0: .D64(kNumberOfEntries); // number_of_entries michael@0: michael@0: michael@0: // Now add a MDRawMemoryInfo entry. michael@0: const uint64_t kBaseAddress = 0x1000; michael@0: const uint64_t kRegionSize = 0x2000; michael@0: stream.D64(kBaseAddress) // base_address michael@0: .D64(kBaseAddress) // allocation_base michael@0: .D32(MD_MEMORY_PROTECT_EXECUTE_READWRITE) // allocation_protection michael@0: .D32(0) // __alignment1 michael@0: .D64(kRegionSize) // region_size michael@0: .D32(MD_MEMORY_STATE_COMMIT) // state michael@0: .D32(MD_MEMORY_PROTECT_EXECUTE_READWRITE) // protection michael@0: .D32(MD_MEMORY_TYPE_PRIVATE) // type michael@0: .D32(0); // __alignment2 michael@0: michael@0: dump.Add(&stream); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); michael@0: ASSERT_TRUE(dir != NULL); michael@0: EXPECT_EQ((uint32_t) MD_MEMORY_INFO_LIST_STREAM, dir->stream_type); michael@0: michael@0: MinidumpMemoryInfoList *info_list = minidump.GetMemoryInfoList(); michael@0: ASSERT_TRUE(info_list != NULL); michael@0: ASSERT_EQ(1U, info_list->info_count()); michael@0: michael@0: const MinidumpMemoryInfo *info1 = info_list->GetMemoryInfoAtIndex(0); michael@0: ASSERT_EQ(kBaseAddress, info1->GetBase()); michael@0: ASSERT_EQ(kRegionSize, info1->GetSize()); michael@0: ASSERT_TRUE(info1->IsExecutable()); michael@0: ASSERT_TRUE(info1->IsWritable()); michael@0: michael@0: // Should get back the same memory region here. michael@0: const MinidumpMemoryInfo *info2 = michael@0: info_list->GetMemoryInfoForAddress(kBaseAddress + kRegionSize / 2); michael@0: ASSERT_EQ(kBaseAddress, info2->GetBase()); michael@0: ASSERT_EQ(kRegionSize, info2->GetSize()); michael@0: } michael@0: michael@0: TEST(Dump, OneExceptionX86) { michael@0: Dump dump(0, kLittleEndian); michael@0: michael@0: MDRawContextX86 raw_context; michael@0: raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL; michael@0: raw_context.edi = 0x3ecba80d; michael@0: raw_context.esi = 0x382583b9; michael@0: raw_context.ebx = 0x7fccc03f; michael@0: raw_context.edx = 0xf62f8ec2; michael@0: raw_context.ecx = 0x46a6a6a8; michael@0: raw_context.eax = 0x6a5025e2; michael@0: raw_context.ebp = 0xd9fabb4a; michael@0: raw_context.eip = 0x6913f540; michael@0: raw_context.cs = 0xbffe6eda; michael@0: raw_context.eflags = 0xb2ce1e2d; michael@0: raw_context.esp = 0x659caaa4; michael@0: raw_context.ss = 0x2e951ef7; michael@0: Context context(dump, raw_context); michael@0: michael@0: Exception exception(dump, context, michael@0: 0x1234abcd, // thread id michael@0: 0xdcba4321, // exception code michael@0: 0xf0e0d0c0, // exception flags michael@0: 0x0919a9b9c9d9e9f9ULL); // exception address michael@0: michael@0: dump.Add(&context); michael@0: dump.Add(&exception); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: MinidumpException *md_exception = minidump.GetException(); michael@0: ASSERT_TRUE(md_exception != NULL); michael@0: michael@0: uint32_t thread_id; michael@0: ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0x1234abcdU, thread_id); michael@0: michael@0: const MDRawExceptionStream* raw_exception = md_exception->exception(); michael@0: ASSERT_TRUE(raw_exception != NULL); michael@0: EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); michael@0: EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); michael@0: EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, michael@0: raw_exception->exception_record.exception_address); michael@0: michael@0: MinidumpContext *md_context = md_exception->GetContext(); michael@0: ASSERT_TRUE(md_context != NULL); michael@0: ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); michael@0: const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); michael@0: ASSERT_TRUE(md_raw_context != NULL); michael@0: ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), michael@0: (md_raw_context->context_flags michael@0: & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); michael@0: EXPECT_EQ(0x3ecba80dU, raw_context.edi); michael@0: EXPECT_EQ(0x382583b9U, raw_context.esi); michael@0: EXPECT_EQ(0x7fccc03fU, raw_context.ebx); michael@0: EXPECT_EQ(0xf62f8ec2U, raw_context.edx); michael@0: EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); michael@0: EXPECT_EQ(0x6a5025e2U, raw_context.eax); michael@0: EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); michael@0: EXPECT_EQ(0x6913f540U, raw_context.eip); michael@0: EXPECT_EQ(0xbffe6edaU, raw_context.cs); michael@0: EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); michael@0: EXPECT_EQ(0x659caaa4U, raw_context.esp); michael@0: EXPECT_EQ(0x2e951ef7U, raw_context.ss); michael@0: } michael@0: michael@0: TEST(Dump, OneExceptionX86XState) { michael@0: Dump dump(0, kLittleEndian); michael@0: michael@0: MDRawContextX86 raw_context; michael@0: raw_context.context_flags = MD_CONTEXT_X86_INTEGER | michael@0: MD_CONTEXT_X86_CONTROL | MD_CONTEXT_X86_XSTATE; michael@0: raw_context.edi = 0x3ecba80d; michael@0: raw_context.esi = 0x382583b9; michael@0: raw_context.ebx = 0x7fccc03f; michael@0: raw_context.edx = 0xf62f8ec2; michael@0: raw_context.ecx = 0x46a6a6a8; michael@0: raw_context.eax = 0x6a5025e2; michael@0: raw_context.ebp = 0xd9fabb4a; michael@0: raw_context.eip = 0x6913f540; michael@0: raw_context.cs = 0xbffe6eda; michael@0: raw_context.eflags = 0xb2ce1e2d; michael@0: raw_context.esp = 0x659caaa4; michael@0: raw_context.ss = 0x2e951ef7; michael@0: Context context(dump, raw_context); michael@0: michael@0: Exception exception(dump, context, michael@0: 0x1234abcd, // thread id michael@0: 0xdcba4321, // exception code michael@0: 0xf0e0d0c0, // exception flags michael@0: 0x0919a9b9c9d9e9f9ULL); // exception address michael@0: michael@0: dump.Add(&context); michael@0: dump.Add(&exception); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: MinidumpException *md_exception = minidump.GetException(); michael@0: ASSERT_TRUE(md_exception != NULL); michael@0: michael@0: uint32_t thread_id; michael@0: ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0x1234abcdU, thread_id); michael@0: michael@0: const MDRawExceptionStream* raw_exception = md_exception->exception(); michael@0: ASSERT_TRUE(raw_exception != NULL); michael@0: EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); michael@0: EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); michael@0: EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, michael@0: raw_exception->exception_record.exception_address); michael@0: michael@0: MinidumpContext *md_context = md_exception->GetContext(); michael@0: ASSERT_TRUE(md_context != NULL); michael@0: ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); michael@0: const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); michael@0: ASSERT_TRUE(md_raw_context != NULL); michael@0: ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), michael@0: (md_raw_context->context_flags michael@0: & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); michael@0: EXPECT_EQ(0x3ecba80dU, raw_context.edi); michael@0: EXPECT_EQ(0x382583b9U, raw_context.esi); michael@0: EXPECT_EQ(0x7fccc03fU, raw_context.ebx); michael@0: EXPECT_EQ(0xf62f8ec2U, raw_context.edx); michael@0: EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); michael@0: EXPECT_EQ(0x6a5025e2U, raw_context.eax); michael@0: EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); michael@0: EXPECT_EQ(0x6913f540U, raw_context.eip); michael@0: EXPECT_EQ(0xbffe6edaU, raw_context.cs); michael@0: EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); michael@0: EXPECT_EQ(0x659caaa4U, raw_context.esp); michael@0: EXPECT_EQ(0x2e951ef7U, raw_context.ss); michael@0: } michael@0: michael@0: // Testing that the CPU type can be loaded from a system info stream when michael@0: // the CPU flags are missing from the context_flags of an exception record michael@0: TEST(Dump, OneExceptionX86NoCPUFlags) { michael@0: Dump dump(0, kLittleEndian); michael@0: michael@0: MDRawContextX86 raw_context; michael@0: // Intentionally not setting CPU type in the context_flags michael@0: raw_context.context_flags = 0; michael@0: raw_context.edi = 0x3ecba80d; michael@0: raw_context.esi = 0x382583b9; michael@0: raw_context.ebx = 0x7fccc03f; michael@0: raw_context.edx = 0xf62f8ec2; michael@0: raw_context.ecx = 0x46a6a6a8; michael@0: raw_context.eax = 0x6a5025e2; michael@0: raw_context.ebp = 0xd9fabb4a; michael@0: raw_context.eip = 0x6913f540; michael@0: raw_context.cs = 0xbffe6eda; michael@0: raw_context.eflags = 0xb2ce1e2d; michael@0: raw_context.esp = 0x659caaa4; michael@0: raw_context.ss = 0x2e951ef7; michael@0: Context context(dump, raw_context); michael@0: michael@0: Exception exception(dump, context, michael@0: 0x1234abcd, // thread id michael@0: 0xdcba4321, // exception code michael@0: 0xf0e0d0c0, // exception flags michael@0: 0x0919a9b9c9d9e9f9ULL); // exception address michael@0: michael@0: dump.Add(&context); michael@0: dump.Add(&exception); michael@0: michael@0: // Add system info. This is needed as an alternative source for CPU type michael@0: // information. Note, that the CPU flags were intentionally skipped from michael@0: // the context_flags and this alternative source is required. michael@0: String csd_version(dump, "Service Pack 2"); michael@0: SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); michael@0: dump.Add(&system_info); michael@0: dump.Add(&csd_version); michael@0: michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: MinidumpException *md_exception = minidump.GetException(); michael@0: ASSERT_TRUE(md_exception != NULL); michael@0: michael@0: uint32_t thread_id; michael@0: ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0x1234abcdU, thread_id); michael@0: michael@0: const MDRawExceptionStream* raw_exception = md_exception->exception(); michael@0: ASSERT_TRUE(raw_exception != NULL); michael@0: EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); michael@0: EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); michael@0: EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, michael@0: raw_exception->exception_record.exception_address); michael@0: michael@0: MinidumpContext *md_context = md_exception->GetContext(); michael@0: ASSERT_TRUE(md_context != NULL); michael@0: michael@0: ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); michael@0: const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); michael@0: ASSERT_TRUE(md_raw_context != NULL); michael@0: michael@0: // Even though the CPU flags were missing from the context_flags, the michael@0: // GetContext call above is expected to load the missing CPU flags from the michael@0: // system info stream and set the CPU type bits in context_flags. michael@0: ASSERT_EQ((uint32_t) (MD_CONTEXT_X86), md_raw_context->context_flags); michael@0: michael@0: EXPECT_EQ(0x3ecba80dU, raw_context.edi); michael@0: EXPECT_EQ(0x382583b9U, raw_context.esi); michael@0: EXPECT_EQ(0x7fccc03fU, raw_context.ebx); michael@0: EXPECT_EQ(0xf62f8ec2U, raw_context.edx); michael@0: EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); michael@0: EXPECT_EQ(0x6a5025e2U, raw_context.eax); michael@0: EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); michael@0: EXPECT_EQ(0x6913f540U, raw_context.eip); michael@0: EXPECT_EQ(0xbffe6edaU, raw_context.cs); michael@0: EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); michael@0: EXPECT_EQ(0x659caaa4U, raw_context.esp); michael@0: EXPECT_EQ(0x2e951ef7U, raw_context.ss); michael@0: } michael@0: michael@0: // This test covers a scenario where a dump contains an exception but the michael@0: // context record of the exception is missing the CPU type information in its michael@0: // context_flags. The dump has no system info stream so it is imposible to michael@0: // deduce the CPU type, hence the context record is unusable. michael@0: TEST(Dump, OneExceptionX86NoCPUFlagsNoSystemInfo) { michael@0: Dump dump(0, kLittleEndian); michael@0: michael@0: MDRawContextX86 raw_context; michael@0: // Intentionally not setting CPU type in the context_flags michael@0: raw_context.context_flags = 0; michael@0: raw_context.edi = 0x3ecba80d; michael@0: raw_context.esi = 0x382583b9; michael@0: raw_context.ebx = 0x7fccc03f; michael@0: raw_context.edx = 0xf62f8ec2; michael@0: raw_context.ecx = 0x46a6a6a8; michael@0: raw_context.eax = 0x6a5025e2; michael@0: raw_context.ebp = 0xd9fabb4a; michael@0: raw_context.eip = 0x6913f540; michael@0: raw_context.cs = 0xbffe6eda; michael@0: raw_context.eflags = 0xb2ce1e2d; michael@0: raw_context.esp = 0x659caaa4; michael@0: raw_context.ss = 0x2e951ef7; michael@0: Context context(dump, raw_context); michael@0: michael@0: Exception exception(dump, context, michael@0: 0x1234abcd, // thread id michael@0: 0xdcba4321, // exception code michael@0: 0xf0e0d0c0, // exception flags michael@0: 0x0919a9b9c9d9e9f9ULL); // exception address michael@0: michael@0: dump.Add(&context); michael@0: dump.Add(&exception); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: MinidumpException *md_exception = minidump.GetException(); michael@0: ASSERT_TRUE(md_exception != NULL); michael@0: michael@0: uint32_t thread_id; michael@0: ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0x1234abcdU, thread_id); michael@0: michael@0: const MDRawExceptionStream* raw_exception = md_exception->exception(); michael@0: ASSERT_TRUE(raw_exception != NULL); michael@0: EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); michael@0: EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); michael@0: EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, michael@0: raw_exception->exception_record.exception_address); michael@0: michael@0: // The context record of the exception is unusable because the context_flags michael@0: // don't have CPU type information and at the same time the minidump lacks michael@0: // system info stream so it is impossible to deduce the CPU type. michael@0: MinidumpContext *md_context = md_exception->GetContext(); michael@0: ASSERT_EQ(NULL, md_context); michael@0: } michael@0: michael@0: TEST(Dump, OneExceptionARM) { michael@0: Dump dump(0, kLittleEndian); michael@0: michael@0: MDRawContextARM raw_context; michael@0: raw_context.context_flags = MD_CONTEXT_ARM_INTEGER; michael@0: raw_context.iregs[0] = 0x3ecba80d; michael@0: raw_context.iregs[1] = 0x382583b9; michael@0: raw_context.iregs[2] = 0x7fccc03f; michael@0: raw_context.iregs[3] = 0xf62f8ec2; michael@0: raw_context.iregs[4] = 0x46a6a6a8; michael@0: raw_context.iregs[5] = 0x6a5025e2; michael@0: raw_context.iregs[6] = 0xd9fabb4a; michael@0: raw_context.iregs[7] = 0x6913f540; michael@0: raw_context.iregs[8] = 0xbffe6eda; michael@0: raw_context.iregs[9] = 0xb2ce1e2d; michael@0: raw_context.iregs[10] = 0x659caaa4; michael@0: raw_context.iregs[11] = 0xf0e0d0c0; michael@0: raw_context.iregs[12] = 0xa9b8c7d6; michael@0: raw_context.iregs[13] = 0x12345678; michael@0: raw_context.iregs[14] = 0xabcd1234; michael@0: raw_context.iregs[15] = 0x10203040; michael@0: raw_context.cpsr = 0x2e951ef7; michael@0: Context context(dump, raw_context); michael@0: michael@0: Exception exception(dump, context, michael@0: 0x1234abcd, // thread id michael@0: 0xdcba4321, // exception code michael@0: 0xf0e0d0c0, // exception flags michael@0: 0x0919a9b9c9d9e9f9ULL); // exception address michael@0: michael@0: dump.Add(&context); michael@0: dump.Add(&exception); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: MinidumpException *md_exception = minidump.GetException(); michael@0: ASSERT_TRUE(md_exception != NULL); michael@0: michael@0: uint32_t thread_id; michael@0: ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0x1234abcdU, thread_id); michael@0: michael@0: const MDRawExceptionStream* raw_exception = md_exception->exception(); michael@0: ASSERT_TRUE(raw_exception != NULL); michael@0: EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); michael@0: EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); michael@0: EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, michael@0: raw_exception->exception_record.exception_address); michael@0: michael@0: MinidumpContext *md_context = md_exception->GetContext(); michael@0: ASSERT_TRUE(md_context != NULL); michael@0: ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU()); michael@0: const MDRawContextARM *md_raw_context = md_context->GetContextARM(); michael@0: ASSERT_TRUE(md_raw_context != NULL); michael@0: ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER, michael@0: (md_raw_context->context_flags michael@0: & MD_CONTEXT_ARM_INTEGER)); michael@0: EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]); michael@0: EXPECT_EQ(0x382583b9U, raw_context.iregs[1]); michael@0: EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]); michael@0: EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]); michael@0: EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]); michael@0: EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]); michael@0: EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]); michael@0: EXPECT_EQ(0x6913f540U, raw_context.iregs[7]); michael@0: EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]); michael@0: EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]); michael@0: EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]); michael@0: EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]); michael@0: EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]); michael@0: EXPECT_EQ(0x12345678U, raw_context.iregs[13]); michael@0: EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]); michael@0: EXPECT_EQ(0x10203040U, raw_context.iregs[15]); michael@0: EXPECT_EQ(0x2e951ef7U, raw_context.cpsr); michael@0: } michael@0: michael@0: TEST(Dump, OneExceptionARMOldFlags) { michael@0: Dump dump(0, kLittleEndian); michael@0: michael@0: MDRawContextARM raw_context; michael@0: // MD_CONTEXT_ARM_INTEGER, but with _OLD michael@0: raw_context.context_flags = MD_CONTEXT_ARM_OLD | 0x00000002; michael@0: raw_context.iregs[0] = 0x3ecba80d; michael@0: raw_context.iregs[1] = 0x382583b9; michael@0: raw_context.iregs[2] = 0x7fccc03f; michael@0: raw_context.iregs[3] = 0xf62f8ec2; michael@0: raw_context.iregs[4] = 0x46a6a6a8; michael@0: raw_context.iregs[5] = 0x6a5025e2; michael@0: raw_context.iregs[6] = 0xd9fabb4a; michael@0: raw_context.iregs[7] = 0x6913f540; michael@0: raw_context.iregs[8] = 0xbffe6eda; michael@0: raw_context.iregs[9] = 0xb2ce1e2d; michael@0: raw_context.iregs[10] = 0x659caaa4; michael@0: raw_context.iregs[11] = 0xf0e0d0c0; michael@0: raw_context.iregs[12] = 0xa9b8c7d6; michael@0: raw_context.iregs[13] = 0x12345678; michael@0: raw_context.iregs[14] = 0xabcd1234; michael@0: raw_context.iregs[15] = 0x10203040; michael@0: raw_context.cpsr = 0x2e951ef7; michael@0: Context context(dump, raw_context); michael@0: michael@0: Exception exception(dump, context, michael@0: 0x1234abcd, // thread id michael@0: 0xdcba4321, // exception code michael@0: 0xf0e0d0c0, // exception flags michael@0: 0x0919a9b9c9d9e9f9ULL); // exception address michael@0: michael@0: dump.Add(&context); michael@0: dump.Add(&exception); michael@0: dump.Finish(); michael@0: michael@0: string contents; michael@0: ASSERT_TRUE(dump.GetContents(&contents)); michael@0: michael@0: istringstream minidump_stream(contents); michael@0: Minidump minidump(minidump_stream); michael@0: ASSERT_TRUE(minidump.Read()); michael@0: ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); michael@0: michael@0: MinidumpException *md_exception = minidump.GetException(); michael@0: ASSERT_TRUE(md_exception != NULL); michael@0: michael@0: uint32_t thread_id; michael@0: ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); michael@0: ASSERT_EQ(0x1234abcdU, thread_id); michael@0: michael@0: const MDRawExceptionStream* raw_exception = md_exception->exception(); michael@0: ASSERT_TRUE(raw_exception != NULL); michael@0: EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); michael@0: EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); michael@0: EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, michael@0: raw_exception->exception_record.exception_address); michael@0: michael@0: MinidumpContext *md_context = md_exception->GetContext(); michael@0: ASSERT_TRUE(md_context != NULL); michael@0: ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU()); michael@0: const MDRawContextARM *md_raw_context = md_context->GetContextARM(); michael@0: ASSERT_TRUE(md_raw_context != NULL); michael@0: ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER, michael@0: (md_raw_context->context_flags michael@0: & MD_CONTEXT_ARM_INTEGER)); michael@0: EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]); michael@0: EXPECT_EQ(0x382583b9U, raw_context.iregs[1]); michael@0: EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]); michael@0: EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]); michael@0: EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]); michael@0: EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]); michael@0: EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]); michael@0: EXPECT_EQ(0x6913f540U, raw_context.iregs[7]); michael@0: EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]); michael@0: EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]); michael@0: EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]); michael@0: EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]); michael@0: EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]); michael@0: EXPECT_EQ(0x12345678U, raw_context.iregs[13]); michael@0: EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]); michael@0: EXPECT_EQ(0x10203040U, raw_context.iregs[15]); michael@0: EXPECT_EQ(0x2e951ef7U, raw_context.cpsr); michael@0: } michael@0: michael@0: } // namespace