Chromium Code Reviews| Index: minidump/minidump_module_writer_test.cc |
| diff --git a/minidump/minidump_module_writer_test.cc b/minidump/minidump_module_writer_test.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..fc02c6eb1b4a2a06e18fe6d6c82b1975fcde5895 |
| --- /dev/null |
| +++ b/minidump/minidump_module_writer_test.cc |
| @@ -0,0 +1,636 @@ |
| +// Copyright 2014 The Crashpad Authors. All rights reserved. |
| +// |
| +// Licensed under the Apache License, Version 2.0 (the "License"); |
| +// you may not use this file except in compliance with the License. |
| +// You may obtain a copy of the License at |
| +// |
| +// http://www.apache.org/licenses/LICENSE-2.0 |
| +// |
| +// Unless required by applicable law or agreed to in writing, software |
| +// distributed under the License is distributed on an "AS IS" BASIS, |
| +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| +// See the License for the specific language governing permissions and |
| +// limitations under the License. |
| + |
| +#include "minidump/minidump_module_writer.h" |
| + |
| +#include <dbghelp.h> |
| +#include <stdint.h> |
| +#include <string.h> |
| + |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "gtest/gtest.h" |
| +#include "minidump/minidump_extensions.h" |
| +#include "minidump/minidump_file_writer.h" |
| +#include "minidump/minidump_test_util.h" |
| +#include "util/file/string_file_writer.h" |
| +#include "util/misc/uuid.h" |
| + |
| +namespace { |
| + |
| +using namespace crashpad; |
| +using namespace crashpad::test; |
| + |
| +void GetModuleListStream(const std::string& file_contents, |
| + const MINIDUMP_MODULE_LIST** module_list) { |
| + const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); |
| + const size_t kModuleListStreamOffset = |
| + kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); |
| + const size_t kModulesOffset = |
| + kModuleListStreamOffset + sizeof(MINIDUMP_MODULE_LIST); |
| + |
| + ASSERT_GE(file_contents.size(), kModulesOffset); |
| + |
| + const MINIDUMP_HEADER* header = |
| + reinterpret_cast<const MINIDUMP_HEADER*>(&file_contents[0]); |
| + |
| + VerifyMinidumpHeader(header, 1, 0); |
|
Robert Sesek
2014/08/12 22:56:05
IWYU
|
| + if (testing::Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + const MINIDUMP_DIRECTORY* directory = |
| + reinterpret_cast<const MINIDUMP_DIRECTORY*>( |
| + &file_contents[kDirectoryOffset]); |
| + |
| + ASSERT_EQ(kMinidumpStreamTypeModuleList, directory->StreamType); |
| + ASSERT_GE(directory->Location.DataSize, sizeof(MINIDUMP_MODULE_LIST)); |
| + ASSERT_EQ(kModuleListStreamOffset, directory->Location.Rva); |
| + |
| + *module_list = reinterpret_cast<const MINIDUMP_MODULE_LIST*>( |
| + &file_contents[kModuleListStreamOffset]); |
| + |
| + ASSERT_EQ(sizeof(MINIDUMP_MODULE_LIST) + |
| + (*module_list)->NumberOfModules * sizeof(MINIDUMP_MODULE), |
| + directory->Location.DataSize); |
| +} |
| + |
| +TEST(MinidumpModuleWriter, EmptyModuleList) { |
| + MinidumpFileWriter minidump_file_writer; |
| + MinidumpModuleListWriter module_list_writer; |
| + |
| + minidump_file_writer.AddStream(&module_list_writer); |
| + |
| + StringFileWriter file_writer; |
| + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| + |
| + ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| + sizeof(MINIDUMP_MODULE_LIST), |
| + file_writer.string().size()); |
| + |
| + const MINIDUMP_MODULE_LIST* module_list; |
| + GetModuleListStream(file_writer.string(), &module_list); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + EXPECT_EQ(0u, module_list->NumberOfModules); |
| +} |
| + |
| +// ExpectModule() verifies that |expected| matches |observed|. Fields that are |
| +// supposed to contain constant magic numbers are verified against the expected |
| +// constants instead of |expected|. Reserved fields are verified to be 0. RVA |
| +// and MINIDUMP_LOCATION_DESCRIPTOR fields are not verified against |expected|. |
| +// Instead, |ModuleNameRva| is used to locate the module name, which is compared |
| +// against |expected_module_name|. If |expected_pdb_name| is non-NULL, |
| +// |CvRecord| is used to locate a CodeView record, whose fields are compared |
| +// against the |expected_pdb_*| values. If |expected_pdb_uuid| is supplied, the |
| +// CodeView record must be a PDB 7.0 link, otherwise, it must be a PDB 2.0 link. |
| +// If |expected_pdb_name| is NULL, |CvRecord| must be absent. Similarly, |
| +// |expected_debug_name| is used to control verification of |MiscRecord| against |
| +// the |expected_debug_*| values. |
| +void ExpectModule(const MINIDUMP_MODULE* expected, |
| + const MINIDUMP_MODULE* observed, |
| + const std::string& file_contents, |
| + const char* expected_module_name, |
|
Robert Sesek
2014/08/12 22:56:05
Why const char* for the expected names instead of
Mark Mentovai
2014/08/12 23:23:26
rsesek wrote:
|
| + const char* expected_pdb_name, |
| + const UUID* expected_pdb_uuid, |
| + time_t expected_pdb_timestamp, |
| + uint32_t expected_pdb_age, |
| + const char* expected_debug_name, |
| + uint32_t expected_debug_type, |
| + bool expected_debug_utf16) { |
| + EXPECT_EQ(expected->BaseOfImage, observed->BaseOfImage); |
| + EXPECT_EQ(expected->SizeOfImage, observed->SizeOfImage); |
| + EXPECT_EQ(expected->CheckSum, observed->CheckSum); |
| + EXPECT_EQ(expected->TimeDateStamp, observed->TimeDateStamp); |
| + EXPECT_EQ(static_cast<uint32_t>(VS_FFI_SIGNATURE), |
| + observed->VersionInfo.dwSignature); |
| + EXPECT_EQ(static_cast<uint32_t>(VS_FFI_STRUCVERSION), |
| + observed->VersionInfo.dwStrucVersion); |
| + EXPECT_EQ(expected->VersionInfo.dwFileVersionMS, |
| + observed->VersionInfo.dwFileVersionMS); |
| + EXPECT_EQ(expected->VersionInfo.dwFileVersionLS, |
| + observed->VersionInfo.dwFileVersionLS); |
| + EXPECT_EQ(expected->VersionInfo.dwProductVersionMS, |
| + observed->VersionInfo.dwProductVersionMS); |
| + EXPECT_EQ(expected->VersionInfo.dwProductVersionLS, |
| + observed->VersionInfo.dwProductVersionLS); |
| + EXPECT_EQ(expected->VersionInfo.dwFileFlagsMask, |
| + observed->VersionInfo.dwFileFlagsMask); |
| + EXPECT_EQ(expected->VersionInfo.dwFileFlags, |
| + observed->VersionInfo.dwFileFlags); |
| + EXPECT_EQ(expected->VersionInfo.dwFileOS, observed->VersionInfo.dwFileOS); |
| + EXPECT_EQ(expected->VersionInfo.dwFileType, observed->VersionInfo.dwFileType); |
| + EXPECT_EQ(expected->VersionInfo.dwFileSubtype, |
| + observed->VersionInfo.dwFileSubtype); |
| + EXPECT_EQ(expected->VersionInfo.dwFileDateMS, |
| + observed->VersionInfo.dwFileDateMS); |
| + EXPECT_EQ(expected->VersionInfo.dwFileDateLS, |
| + observed->VersionInfo.dwFileDateLS); |
| + EXPECT_EQ(0u, observed->Reserved0); |
| + EXPECT_EQ(0u, observed->Reserved1); |
| + |
| + EXPECT_NE(0u, observed->ModuleNameRva); |
| + ASSERT_LE(observed->ModuleNameRva, |
| + file_contents.size() - sizeof(MINIDUMP_STRING)); |
| + const MINIDUMP_STRING* module_name = reinterpret_cast<const MINIDUMP_STRING*>( |
| + &file_contents[observed->ModuleNameRva]); |
| + ASSERT_LE(observed->ModuleNameRva + sizeof(MINIDUMP_STRING) + |
| + (module_name->Length + 1), |
| + file_contents.size()); |
| + ASSERT_EQ(0u, module_name->Length % 2); |
| + string16 observed_module_name_utf16( |
| + reinterpret_cast<const char16*>( |
| + &file_contents[observed->ModuleNameRva + sizeof(MINIDUMP_STRING)]), |
| + module_name->Length / 2); |
| + string16 expected_module_name_utf16 = base::UTF8ToUTF16(expected_module_name); |
| + EXPECT_EQ(expected_module_name_utf16, observed_module_name_utf16); |
| + |
| + if (expected_pdb_name) { |
|
Robert Sesek
2014/08/12 22:56:05
If this weren't in a test, this is where I'd tell
Mark Mentovai
2014/08/12 23:23:26
rsesek wrote:
|
| + EXPECT_NE(0u, observed->CvRecord.Rva); |
| + ASSERT_LE(observed->CvRecord.Rva + observed->CvRecord.DataSize, |
| + file_contents.size()); |
| + |
| + std::string observed_pdb_name; |
| + if (expected_pdb_uuid) { |
| + // The CodeView record should be a PDB 7.0 link. |
| + EXPECT_GE(observed->CvRecord.DataSize, |
| + sizeof(MinidumpModuleCodeViewRecordPDB70)); |
| + const MinidumpModuleCodeViewRecordPDB70* codeview_pdb70_record = |
| + reinterpret_cast<const MinidumpModuleCodeViewRecordPDB70*>( |
| + &file_contents[observed->CvRecord.Rva]); |
| + EXPECT_EQ(MinidumpModuleCodeViewRecordPDB70::kSignature, |
| + codeview_pdb70_record->signature); |
| + EXPECT_EQ(0, |
| + memcmp(expected_pdb_uuid, |
| + &codeview_pdb70_record->uuid, |
| + sizeof(codeview_pdb70_record->uuid))); |
| + EXPECT_EQ(expected_pdb_age, codeview_pdb70_record->age); |
| + |
| + observed_pdb_name.assign( |
| + reinterpret_cast<const char*>(&codeview_pdb70_record->pdb_name[0]), |
| + observed->CvRecord.DataSize - |
| + offsetof(MinidumpModuleCodeViewRecordPDB70, pdb_name)); |
| + } else { |
| + // The CodeView record should be a PDB 2.0 link. |
| + EXPECT_GE(observed->CvRecord.DataSize, |
| + sizeof(MinidumpModuleCodeViewRecordPDB20)); |
| + const MinidumpModuleCodeViewRecordPDB20* codeview_pdb20_record = |
| + reinterpret_cast<const MinidumpModuleCodeViewRecordPDB20*>( |
| + &file_contents[observed->CvRecord.Rva]); |
| + EXPECT_EQ(MinidumpModuleCodeViewRecordPDB20::kSignature, |
| + codeview_pdb20_record->signature); |
| + EXPECT_EQ(expected_pdb_timestamp, codeview_pdb20_record->timestamp); |
| + EXPECT_EQ(expected_pdb_age, codeview_pdb20_record->age); |
| + |
| + observed_pdb_name.assign( |
| + reinterpret_cast<const char*>(&codeview_pdb20_record->pdb_name[0]), |
| + observed->CvRecord.DataSize - |
| + offsetof(MinidumpModuleCodeViewRecordPDB20, pdb_name)); |
| + } |
| + |
| + // Check for, and then remove, the NUL terminator. |
| + EXPECT_EQ('\0', observed_pdb_name[observed_pdb_name.size() - 1]); |
| + observed_pdb_name.resize(observed_pdb_name.size() - 1); |
| + |
| + EXPECT_EQ(expected_pdb_name, observed_pdb_name); |
| + } else { |
| + // There should be no CodeView record. |
| + EXPECT_EQ(0u, observed->CvRecord.DataSize); |
| + EXPECT_EQ(0u, observed->CvRecord.Rva); |
| + } |
| + |
| + if (expected_debug_name) { |
| + EXPECT_GE(observed->MiscRecord.DataSize, sizeof(IMAGE_DEBUG_MISC)); |
| + EXPECT_NE(0u, observed->MiscRecord.Rva); |
| + ASSERT_LE(observed->MiscRecord.Rva + observed->MiscRecord.DataSize, |
| + file_contents.size()); |
| + const IMAGE_DEBUG_MISC* misc_debug_record = |
| + reinterpret_cast<const IMAGE_DEBUG_MISC*>( |
| + &file_contents[observed->MiscRecord.Rva]); |
| + EXPECT_EQ(expected_debug_type, misc_debug_record->DataType); |
| + EXPECT_EQ(observed->MiscRecord.DataSize, misc_debug_record->Length); |
| + EXPECT_EQ(expected_debug_utf16, misc_debug_record->Unicode); |
| + EXPECT_EQ(0u, misc_debug_record->Reserved[0]); |
| + EXPECT_EQ(0u, misc_debug_record->Reserved[1]); |
| + EXPECT_EQ(0u, misc_debug_record->Reserved[2]); |
| + |
| + // Check for the NUL terminator. |
| + size_t bytes_available = |
| + misc_debug_record->Length - offsetof(IMAGE_DEBUG_MISC, Data); |
| + EXPECT_EQ('\0', misc_debug_record->Data[bytes_available - 1]); |
| + std::string observed_data( |
| + reinterpret_cast<const char*>(misc_debug_record->Data)); |
| + |
| + size_t bytes_used; |
| + if (misc_debug_record->Unicode) { |
| + string16 observed_data_utf16( |
| + reinterpret_cast<const char16*>(misc_debug_record->Data)); |
| + bytes_used = (observed_data_utf16.size() + 1) * sizeof(char16); |
| + observed_data = base::UTF16ToUTF8(observed_data_utf16); |
| + } else { |
| + observed_data = reinterpret_cast<const char*>(misc_debug_record->Data); |
| + bytes_used = (observed_data.size() + 1) * sizeof(char); |
| + } |
| + EXPECT_LE(bytes_used, bytes_available); |
| + |
| + // Make sure that any padding bytes after the first NUL are also NUL. |
| + for (size_t index = bytes_used; index < bytes_available; ++index) { |
| + EXPECT_EQ('\0', misc_debug_record->Data[index]); |
| + } |
| + |
| + EXPECT_EQ(expected_debug_name, observed_data); |
| + } else { |
| + // There should be no miscellaneous debugging record. |
| + EXPECT_EQ(0u, observed->MiscRecord.DataSize); |
| + EXPECT_EQ(0u, observed->MiscRecord.Rva); |
| + } |
| +} |
| + |
| +TEST(MinidumpModuleWriter, EmptyModule) { |
| + MinidumpFileWriter minidump_file_writer; |
| + MinidumpModuleListWriter module_list_writer; |
| + |
| + const char kModuleName[] = "test_executable"; |
| + |
| + MinidumpModuleWriter module_writer; |
| + module_writer.SetName(kModuleName); |
| + |
| + module_list_writer.AddModule(&module_writer); |
| + minidump_file_writer.AddStream(&module_list_writer); |
| + |
| + StringFileWriter file_writer; |
| + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| + |
| + ASSERT_GT(file_writer.string().size(), |
| + sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| + sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); |
| + |
| + const MINIDUMP_MODULE_LIST* module_list; |
| + GetModuleListStream(file_writer.string(), &module_list); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + EXPECT_EQ(1u, module_list->NumberOfModules); |
| + |
| + MINIDUMP_MODULE expected = {}; |
| + ExpectModule(&expected, |
| + &module_list->Modules[0], |
| + file_writer.string(), |
| + kModuleName, |
| + NULL, |
| + NULL, |
| + 0, |
| + 0, |
| + NULL, |
| + 0, |
| + false); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| +} |
| + |
| +TEST(MinidumpModuleWriter, OneModule) { |
| + MinidumpFileWriter minidump_file_writer; |
| + MinidumpModuleListWriter module_list_writer; |
| + |
| + const char kModuleName[] = "statically_linked"; |
| + const uint64_t kModuleBase = 0x000000010da69000ull; |
| + const uint32_t kModuleSize = 0x1000; |
| + const uint32_t kChecksum = 0x76543210; |
| + const time_t kTimestamp = 0x386d4380; |
| + const uint32_t kFileVersionMS = 0x00010002; |
| + const uint32_t kFileVersionLS = 0x00030004; |
| + const uint32_t kProductVersionMS = 0x00050006; |
| + const uint32_t kProductVersionLS = 0x00070008; |
| + const uint32_t kFileFlagsMask = VS_FF_DEBUG | VS_FF_PRERELEASE | |
| + VS_FF_PATCHED | VS_FF_PRIVATEBUILD | |
| + VS_FF_INFOINFERRED | VS_FF_SPECIALBUILD; |
| + const uint32_t kFileFlags = VS_FF_PRIVATEBUILD | VS_FF_SPECIALBUILD; |
| + const uint32_t kFileOS = VOS_DOS; |
| + const uint32_t kFileType = VFT_DRV; |
| + const uint32_t kFileSubtype = VFT2_DRV_KEYBOARD; |
| + const char kPDBName[] = "statical.pdb"; |
| + const uint8_t kPDBUUIDBytes[16] = |
| + {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, |
| + 0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f}; |
| + UUID pdb_uuid; |
| + pdb_uuid.InitializeFromBytes(kPDBUUIDBytes); |
| + const uint32_t kPDBAge = 1; |
| + const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; |
| + const char kDebugName[] = "statical.dbg"; |
| + const bool kDebugUTF16 = false; |
| + |
| + MinidumpModuleWriter module_writer; |
| + module_writer.SetName(kModuleName); |
| + module_writer.SetImageBaseAddress(kModuleBase); |
| + module_writer.SetImageSize(kModuleSize); |
| + module_writer.SetChecksum(kChecksum); |
| + module_writer.SetTimestamp(kTimestamp); |
| + module_writer.SetFileVersion(kFileVersionMS >> 16, |
| + kFileVersionMS & 0xffff, |
| + kFileVersionLS >> 16, |
| + kFileVersionLS & 0xffff); |
| + module_writer.SetProductVersion(kProductVersionMS >> 16, |
| + kProductVersionMS & 0xffff, |
| + kProductVersionLS >> 16, |
| + kProductVersionLS & 0xffff); |
| + module_writer.SetFileFlagsAndMask(kFileFlags, kFileFlagsMask); |
| + module_writer.SetFileOS(kFileOS); |
| + module_writer.SetFileTypeAndSubtype(kFileType, kFileSubtype); |
| + |
| + MinidumpModuleCodeViewRecordPDB70Writer codeview_pdb70_writer; |
| + codeview_pdb70_writer.SetPDBName(kPDBName); |
| + codeview_pdb70_writer.SetUUIDAndAge(pdb_uuid, kPDBAge); |
| + module_writer.SetCodeViewRecord(&codeview_pdb70_writer); |
| + |
| + MinidumpModuleMiscDebugRecordWriter misc_debug_writer; |
| + misc_debug_writer.SetDataType(kDebugType); |
| + misc_debug_writer.SetData(kDebugName, kDebugUTF16); |
| + module_writer.SetMiscDebugRecord(&misc_debug_writer); |
| + |
| + module_list_writer.AddModule(&module_writer); |
| + minidump_file_writer.AddStream(&module_list_writer); |
| + |
| + StringFileWriter file_writer; |
| + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| + |
| + ASSERT_GT(file_writer.string().size(), |
| + sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| + sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); |
| + |
| + const MINIDUMP_MODULE_LIST* module_list; |
| + GetModuleListStream(file_writer.string(), &module_list); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + EXPECT_EQ(1u, module_list->NumberOfModules); |
| + |
| + MINIDUMP_MODULE expected = {}; |
| + expected.BaseOfImage = kModuleBase; |
| + expected.SizeOfImage = kModuleSize; |
| + expected.CheckSum = kChecksum; |
| + expected.TimeDateStamp = kTimestamp; |
| + expected.VersionInfo.dwFileVersionMS = kFileVersionMS; |
| + expected.VersionInfo.dwFileVersionLS = kFileVersionLS; |
| + expected.VersionInfo.dwProductVersionMS = kProductVersionMS; |
| + expected.VersionInfo.dwProductVersionLS = kProductVersionLS; |
| + expected.VersionInfo.dwFileFlagsMask = kFileFlagsMask; |
| + expected.VersionInfo.dwFileFlags = kFileFlags; |
| + expected.VersionInfo.dwFileOS = kFileOS; |
| + expected.VersionInfo.dwFileType = kFileType; |
| + expected.VersionInfo.dwFileSubtype = kFileSubtype; |
| + |
| + ExpectModule(&expected, |
| + &module_list->Modules[0], |
| + file_writer.string(), |
| + kModuleName, |
| + kPDBName, |
| + &pdb_uuid, |
| + 0, |
| + kPDBAge, |
| + kDebugName, |
| + kDebugType, |
| + kDebugUTF16); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| +} |
| + |
| +TEST(MinidumpModuleWriter, OneModule_CodeViewUsesPDB20_MiscUsesUTF16) { |
| + // MinidumpModuleWriter.OneModule tested with a PDB 7.0 link as the CodeView |
| + // record and an IMAGE_DEBUG_MISC record in UTF-8. This test exercises the |
| + // alternatives, a PDB 2.0 link as the CodeView record and an IMAGE_DEBUG_MISC |
| + // record with UTF-16 data. |
| + MinidumpFileWriter minidump_file_writer; |
| + MinidumpModuleListWriter module_list_writer; |
| + |
| + const char kModuleName[] = "dinosaur"; |
| + const char kPDBName[] = "d1n05.pdb"; |
| + const time_t kPDBTimestamp = 0x386d4380; |
| + const uint32_t kPDBAge = 1; |
| + const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; |
| + const char kDebugName[] = "d1n05.dbg"; |
| + const bool kDebugUTF16 = true; |
| + |
| + MinidumpModuleWriter module_writer; |
| + module_writer.SetName(kModuleName); |
| + |
| + MinidumpModuleCodeViewRecordPDB20Writer codeview_pdb20_writer; |
| + codeview_pdb20_writer.SetPDBName(kPDBName); |
| + codeview_pdb20_writer.SetTimestampAndAge(kPDBTimestamp, kPDBAge); |
| + module_writer.SetCodeViewRecord(&codeview_pdb20_writer); |
| + |
| + MinidumpModuleMiscDebugRecordWriter misc_debug_writer; |
| + misc_debug_writer.SetDataType(kDebugType); |
| + misc_debug_writer.SetData(kDebugName, kDebugUTF16); |
| + module_writer.SetMiscDebugRecord(&misc_debug_writer); |
| + |
| + module_list_writer.AddModule(&module_writer); |
| + minidump_file_writer.AddStream(&module_list_writer); |
| + |
| + StringFileWriter file_writer; |
| + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| + |
| + ASSERT_GT(file_writer.string().size(), |
| + sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| + sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); |
| + |
| + const MINIDUMP_MODULE_LIST* module_list; |
| + GetModuleListStream(file_writer.string(), &module_list); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + EXPECT_EQ(1u, module_list->NumberOfModules); |
| + |
| + MINIDUMP_MODULE expected = {}; |
| + |
| + ExpectModule(&expected, |
| + &module_list->Modules[0], |
| + file_writer.string(), |
| + kModuleName, |
| + kPDBName, |
| + NULL, |
| + kPDBTimestamp, |
| + kPDBAge, |
| + kDebugName, |
| + kDebugType, |
| + kDebugUTF16); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| +} |
| + |
| +TEST(MinidumpModuleWriter, ThreeModules) { |
| + MinidumpFileWriter minidump_file_writer; |
| + MinidumpModuleListWriter module_list_writer; |
| + |
| + const char kModuleName1[] = "main"; |
| + const uint64_t kModuleBase1 = 0x0000000100101000ull; |
| + const uint32_t kModuleSize1 = 0xf000; |
| + const char kPDBName1[] = "main"; |
| + const uint8_t kPDBUUIDBytes1[16] = |
| + {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, |
| + 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}; |
| + UUID pdb_uuid_1; |
| + pdb_uuid_1.InitializeFromBytes(kPDBUUIDBytes1); |
| + const uint32_t kPDBAge1 = 0; |
| + |
| + const char kModuleName2[] = "ld.so"; |
| + const uint64_t kModuleBase2 = 0x0000000200202000ull; |
| + const uint32_t kModuleSize2 = 0x1e000; |
| + |
| + const char kModuleName3[] = "libc.so"; |
| + const uint64_t kModuleBase3 = 0x0000000300303000ull; |
| + const uint32_t kModuleSize3 = 0x2d000; |
| + const char kPDBName3[] = "libc.so"; |
| + const uint8_t kPDBUUIDBytes3[16] = |
| + {0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80, |
| + 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00}; |
| + UUID pdb_uuid_3; |
| + pdb_uuid_3.InitializeFromBytes(kPDBUUIDBytes3); |
| + const uint32_t kPDBAge3 = 0; |
| + |
| + MinidumpModuleWriter module_writer_1; |
| + module_writer_1.SetName(kModuleName1); |
| + module_writer_1.SetImageBaseAddress(kModuleBase1); |
| + module_writer_1.SetImageSize(kModuleSize1); |
| + |
| + MinidumpModuleCodeViewRecordPDB70Writer codeview_pdb70_writer_1; |
| + codeview_pdb70_writer_1.SetPDBName(kPDBName1); |
| + codeview_pdb70_writer_1.SetUUIDAndAge(pdb_uuid_1, kPDBAge1); |
| + module_writer_1.SetCodeViewRecord(&codeview_pdb70_writer_1); |
| + |
| + module_list_writer.AddModule(&module_writer_1); |
| + |
| + MinidumpModuleWriter module_writer_2; |
| + module_writer_2.SetName(kModuleName2); |
| + module_writer_2.SetImageBaseAddress(kModuleBase2); |
| + module_writer_2.SetImageSize(kModuleSize2); |
| + |
| + module_list_writer.AddModule(&module_writer_2); |
| + |
| + MinidumpModuleWriter module_writer_3; |
| + module_writer_3.SetName(kModuleName3); |
| + module_writer_3.SetImageBaseAddress(kModuleBase3); |
| + module_writer_3.SetImageSize(kModuleSize3); |
| + |
| + MinidumpModuleCodeViewRecordPDB70Writer codeview_pdb70_writer_3; |
| + codeview_pdb70_writer_3.SetPDBName(kPDBName3); |
| + codeview_pdb70_writer_3.SetUUIDAndAge(pdb_uuid_3, kPDBAge3); |
| + module_writer_3.SetCodeViewRecord(&codeview_pdb70_writer_3); |
| + |
| + module_list_writer.AddModule(&module_writer_3); |
| + |
| + minidump_file_writer.AddStream(&module_list_writer); |
| + |
| + StringFileWriter file_writer; |
| + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| + |
| + ASSERT_GT(file_writer.string().size(), |
| + sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| + sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); |
| + |
| + const MINIDUMP_MODULE_LIST* module_list; |
| + GetModuleListStream(file_writer.string(), &module_list); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + EXPECT_EQ(3u, module_list->NumberOfModules); |
| + |
| + MINIDUMP_MODULE expected = {}; |
| + |
| + { |
| + SCOPED_TRACE("module 0"); |
| + |
| + expected.BaseOfImage = kModuleBase1; |
| + expected.SizeOfImage = kModuleSize1; |
| + |
| + ExpectModule(&expected, |
| + &module_list->Modules[0], |
| + file_writer.string(), |
| + kModuleName1, |
| + kPDBName1, |
| + &pdb_uuid_1, |
| + 0, |
| + kPDBAge1, |
| + NULL, |
| + 0, |
| + false); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + } |
| + |
| + { |
| + SCOPED_TRACE("module 1"); |
| + |
| + expected.BaseOfImage = kModuleBase2; |
| + expected.SizeOfImage = kModuleSize2; |
| + |
| + ExpectModule(&expected, |
| + &module_list->Modules[1], |
| + file_writer.string(), |
| + kModuleName2, |
| + NULL, |
| + NULL, |
| + 0, |
| + 0, |
| + NULL, |
| + 0, |
| + false); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + } |
| + |
| + { |
| + SCOPED_TRACE("module 2"); |
| + |
| + expected.BaseOfImage = kModuleBase3; |
| + expected.SizeOfImage = kModuleSize3; |
| + |
| + ExpectModule(&expected, |
| + &module_list->Modules[2], |
| + file_writer.string(), |
| + kModuleName3, |
| + kPDBName3, |
| + &pdb_uuid_3, |
| + 0, |
| + kPDBAge3, |
| + NULL, |
| + 0, |
| + false); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + } |
| +} |
| + |
|
Robert Sesek
2014/08/12 22:56:05
I assume you can mix and match modules with differ
Mark Mentovai
2014/08/12 23:23:26
rsesek wrote:
|
| +TEST(MinidumpSystemInfoWriterDeathTest, NoModuleName) { |
| + MinidumpFileWriter minidump_file_writer; |
| + MinidumpModuleListWriter module_list_writer; |
| + MinidumpModuleWriter module_writer; |
| + module_list_writer.AddModule(&module_writer); |
| + minidump_file_writer.AddStream(&module_list_writer); |
| + |
| + StringFileWriter file_writer; |
| + ASSERT_DEATH(minidump_file_writer.WriteEverything(&file_writer), "name_"); |
| +} |
| + |
| +} // namespace |