Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 | |
| 15 #include "minidump/minidump_module_writer.h" | |
| 16 | |
| 17 #include <dbghelp.h> | |
| 18 #include <stdint.h> | |
| 19 #include <string.h> | |
| 20 | |
| 21 #include "base/strings/utf_string_conversions.h" | |
| 22 #include "gtest/gtest.h" | |
| 23 #include "minidump/minidump_extensions.h" | |
| 24 #include "minidump/minidump_file_writer.h" | |
| 25 #include "minidump/minidump_test_util.h" | |
| 26 #include "util/file/string_file_writer.h" | |
| 27 #include "util/misc/uuid.h" | |
| 28 | |
| 29 namespace { | |
| 30 | |
| 31 using namespace crashpad; | |
| 32 using namespace crashpad::test; | |
| 33 | |
| 34 void GetModuleListStream(const std::string& file_contents, | |
| 35 const MINIDUMP_MODULE_LIST** module_list) { | |
| 36 const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); | |
| 37 const size_t kModuleListStreamOffset = | |
| 38 kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); | |
| 39 const size_t kModulesOffset = | |
| 40 kModuleListStreamOffset + sizeof(MINIDUMP_MODULE_LIST); | |
| 41 | |
| 42 ASSERT_GE(file_contents.size(), kModulesOffset); | |
| 43 | |
| 44 const MINIDUMP_HEADER* header = | |
| 45 reinterpret_cast<const MINIDUMP_HEADER*>(&file_contents[0]); | |
| 46 | |
| 47 VerifyMinidumpHeader(header, 1, 0); | |
|
Robert Sesek
2014/08/12 22:56:05
IWYU
| |
| 48 if (testing::Test::HasFatalFailure()) { | |
| 49 return; | |
| 50 } | |
| 51 | |
| 52 const MINIDUMP_DIRECTORY* directory = | |
| 53 reinterpret_cast<const MINIDUMP_DIRECTORY*>( | |
| 54 &file_contents[kDirectoryOffset]); | |
| 55 | |
| 56 ASSERT_EQ(kMinidumpStreamTypeModuleList, directory->StreamType); | |
| 57 ASSERT_GE(directory->Location.DataSize, sizeof(MINIDUMP_MODULE_LIST)); | |
| 58 ASSERT_EQ(kModuleListStreamOffset, directory->Location.Rva); | |
| 59 | |
| 60 *module_list = reinterpret_cast<const MINIDUMP_MODULE_LIST*>( | |
| 61 &file_contents[kModuleListStreamOffset]); | |
| 62 | |
| 63 ASSERT_EQ(sizeof(MINIDUMP_MODULE_LIST) + | |
| 64 (*module_list)->NumberOfModules * sizeof(MINIDUMP_MODULE), | |
| 65 directory->Location.DataSize); | |
| 66 } | |
| 67 | |
| 68 TEST(MinidumpModuleWriter, EmptyModuleList) { | |
| 69 MinidumpFileWriter minidump_file_writer; | |
| 70 MinidumpModuleListWriter module_list_writer; | |
| 71 | |
| 72 minidump_file_writer.AddStream(&module_list_writer); | |
| 73 | |
| 74 StringFileWriter file_writer; | |
| 75 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); | |
| 76 | |
| 77 ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + | |
| 78 sizeof(MINIDUMP_MODULE_LIST), | |
| 79 file_writer.string().size()); | |
| 80 | |
| 81 const MINIDUMP_MODULE_LIST* module_list; | |
| 82 GetModuleListStream(file_writer.string(), &module_list); | |
| 83 if (Test::HasFatalFailure()) { | |
| 84 return; | |
| 85 } | |
| 86 | |
| 87 EXPECT_EQ(0u, module_list->NumberOfModules); | |
| 88 } | |
| 89 | |
| 90 // ExpectModule() verifies that |expected| matches |observed|. Fields that are | |
| 91 // supposed to contain constant magic numbers are verified against the expected | |
| 92 // constants instead of |expected|. Reserved fields are verified to be 0. RVA | |
| 93 // and MINIDUMP_LOCATION_DESCRIPTOR fields are not verified against |expected|. | |
| 94 // Instead, |ModuleNameRva| is used to locate the module name, which is compared | |
| 95 // against |expected_module_name|. If |expected_pdb_name| is non-NULL, | |
| 96 // |CvRecord| is used to locate a CodeView record, whose fields are compared | |
| 97 // against the |expected_pdb_*| values. If |expected_pdb_uuid| is supplied, the | |
| 98 // CodeView record must be a PDB 7.0 link, otherwise, it must be a PDB 2.0 link. | |
| 99 // If |expected_pdb_name| is NULL, |CvRecord| must be absent. Similarly, | |
| 100 // |expected_debug_name| is used to control verification of |MiscRecord| against | |
| 101 // the |expected_debug_*| values. | |
| 102 void ExpectModule(const MINIDUMP_MODULE* expected, | |
| 103 const MINIDUMP_MODULE* observed, | |
| 104 const std::string& file_contents, | |
| 105 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:
| |
| 106 const char* expected_pdb_name, | |
| 107 const UUID* expected_pdb_uuid, | |
| 108 time_t expected_pdb_timestamp, | |
| 109 uint32_t expected_pdb_age, | |
| 110 const char* expected_debug_name, | |
| 111 uint32_t expected_debug_type, | |
| 112 bool expected_debug_utf16) { | |
| 113 EXPECT_EQ(expected->BaseOfImage, observed->BaseOfImage); | |
| 114 EXPECT_EQ(expected->SizeOfImage, observed->SizeOfImage); | |
| 115 EXPECT_EQ(expected->CheckSum, observed->CheckSum); | |
| 116 EXPECT_EQ(expected->TimeDateStamp, observed->TimeDateStamp); | |
| 117 EXPECT_EQ(static_cast<uint32_t>(VS_FFI_SIGNATURE), | |
| 118 observed->VersionInfo.dwSignature); | |
| 119 EXPECT_EQ(static_cast<uint32_t>(VS_FFI_STRUCVERSION), | |
| 120 observed->VersionInfo.dwStrucVersion); | |
| 121 EXPECT_EQ(expected->VersionInfo.dwFileVersionMS, | |
| 122 observed->VersionInfo.dwFileVersionMS); | |
| 123 EXPECT_EQ(expected->VersionInfo.dwFileVersionLS, | |
| 124 observed->VersionInfo.dwFileVersionLS); | |
| 125 EXPECT_EQ(expected->VersionInfo.dwProductVersionMS, | |
| 126 observed->VersionInfo.dwProductVersionMS); | |
| 127 EXPECT_EQ(expected->VersionInfo.dwProductVersionLS, | |
| 128 observed->VersionInfo.dwProductVersionLS); | |
| 129 EXPECT_EQ(expected->VersionInfo.dwFileFlagsMask, | |
| 130 observed->VersionInfo.dwFileFlagsMask); | |
| 131 EXPECT_EQ(expected->VersionInfo.dwFileFlags, | |
| 132 observed->VersionInfo.dwFileFlags); | |
| 133 EXPECT_EQ(expected->VersionInfo.dwFileOS, observed->VersionInfo.dwFileOS); | |
| 134 EXPECT_EQ(expected->VersionInfo.dwFileType, observed->VersionInfo.dwFileType); | |
| 135 EXPECT_EQ(expected->VersionInfo.dwFileSubtype, | |
| 136 observed->VersionInfo.dwFileSubtype); | |
| 137 EXPECT_EQ(expected->VersionInfo.dwFileDateMS, | |
| 138 observed->VersionInfo.dwFileDateMS); | |
| 139 EXPECT_EQ(expected->VersionInfo.dwFileDateLS, | |
| 140 observed->VersionInfo.dwFileDateLS); | |
| 141 EXPECT_EQ(0u, observed->Reserved0); | |
| 142 EXPECT_EQ(0u, observed->Reserved1); | |
| 143 | |
| 144 EXPECT_NE(0u, observed->ModuleNameRva); | |
| 145 ASSERT_LE(observed->ModuleNameRva, | |
| 146 file_contents.size() - sizeof(MINIDUMP_STRING)); | |
| 147 const MINIDUMP_STRING* module_name = reinterpret_cast<const MINIDUMP_STRING*>( | |
| 148 &file_contents[observed->ModuleNameRva]); | |
| 149 ASSERT_LE(observed->ModuleNameRva + sizeof(MINIDUMP_STRING) + | |
| 150 (module_name->Length + 1), | |
| 151 file_contents.size()); | |
| 152 ASSERT_EQ(0u, module_name->Length % 2); | |
| 153 string16 observed_module_name_utf16( | |
| 154 reinterpret_cast<const char16*>( | |
| 155 &file_contents[observed->ModuleNameRva + sizeof(MINIDUMP_STRING)]), | |
| 156 module_name->Length / 2); | |
| 157 string16 expected_module_name_utf16 = base::UTF8ToUTF16(expected_module_name); | |
| 158 EXPECT_EQ(expected_module_name_utf16, observed_module_name_utf16); | |
| 159 | |
| 160 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:
| |
| 161 EXPECT_NE(0u, observed->CvRecord.Rva); | |
| 162 ASSERT_LE(observed->CvRecord.Rva + observed->CvRecord.DataSize, | |
| 163 file_contents.size()); | |
| 164 | |
| 165 std::string observed_pdb_name; | |
| 166 if (expected_pdb_uuid) { | |
| 167 // The CodeView record should be a PDB 7.0 link. | |
| 168 EXPECT_GE(observed->CvRecord.DataSize, | |
| 169 sizeof(MinidumpModuleCodeViewRecordPDB70)); | |
| 170 const MinidumpModuleCodeViewRecordPDB70* codeview_pdb70_record = | |
| 171 reinterpret_cast<const MinidumpModuleCodeViewRecordPDB70*>( | |
| 172 &file_contents[observed->CvRecord.Rva]); | |
| 173 EXPECT_EQ(MinidumpModuleCodeViewRecordPDB70::kSignature, | |
| 174 codeview_pdb70_record->signature); | |
| 175 EXPECT_EQ(0, | |
| 176 memcmp(expected_pdb_uuid, | |
| 177 &codeview_pdb70_record->uuid, | |
| 178 sizeof(codeview_pdb70_record->uuid))); | |
| 179 EXPECT_EQ(expected_pdb_age, codeview_pdb70_record->age); | |
| 180 | |
| 181 observed_pdb_name.assign( | |
| 182 reinterpret_cast<const char*>(&codeview_pdb70_record->pdb_name[0]), | |
| 183 observed->CvRecord.DataSize - | |
| 184 offsetof(MinidumpModuleCodeViewRecordPDB70, pdb_name)); | |
| 185 } else { | |
| 186 // The CodeView record should be a PDB 2.0 link. | |
| 187 EXPECT_GE(observed->CvRecord.DataSize, | |
| 188 sizeof(MinidumpModuleCodeViewRecordPDB20)); | |
| 189 const MinidumpModuleCodeViewRecordPDB20* codeview_pdb20_record = | |
| 190 reinterpret_cast<const MinidumpModuleCodeViewRecordPDB20*>( | |
| 191 &file_contents[observed->CvRecord.Rva]); | |
| 192 EXPECT_EQ(MinidumpModuleCodeViewRecordPDB20::kSignature, | |
| 193 codeview_pdb20_record->signature); | |
| 194 EXPECT_EQ(expected_pdb_timestamp, codeview_pdb20_record->timestamp); | |
| 195 EXPECT_EQ(expected_pdb_age, codeview_pdb20_record->age); | |
| 196 | |
| 197 observed_pdb_name.assign( | |
| 198 reinterpret_cast<const char*>(&codeview_pdb20_record->pdb_name[0]), | |
| 199 observed->CvRecord.DataSize - | |
| 200 offsetof(MinidumpModuleCodeViewRecordPDB20, pdb_name)); | |
| 201 } | |
| 202 | |
| 203 // Check for, and then remove, the NUL terminator. | |
| 204 EXPECT_EQ('\0', observed_pdb_name[observed_pdb_name.size() - 1]); | |
| 205 observed_pdb_name.resize(observed_pdb_name.size() - 1); | |
| 206 | |
| 207 EXPECT_EQ(expected_pdb_name, observed_pdb_name); | |
| 208 } else { | |
| 209 // There should be no CodeView record. | |
| 210 EXPECT_EQ(0u, observed->CvRecord.DataSize); | |
| 211 EXPECT_EQ(0u, observed->CvRecord.Rva); | |
| 212 } | |
| 213 | |
| 214 if (expected_debug_name) { | |
| 215 EXPECT_GE(observed->MiscRecord.DataSize, sizeof(IMAGE_DEBUG_MISC)); | |
| 216 EXPECT_NE(0u, observed->MiscRecord.Rva); | |
| 217 ASSERT_LE(observed->MiscRecord.Rva + observed->MiscRecord.DataSize, | |
| 218 file_contents.size()); | |
| 219 const IMAGE_DEBUG_MISC* misc_debug_record = | |
| 220 reinterpret_cast<const IMAGE_DEBUG_MISC*>( | |
| 221 &file_contents[observed->MiscRecord.Rva]); | |
| 222 EXPECT_EQ(expected_debug_type, misc_debug_record->DataType); | |
| 223 EXPECT_EQ(observed->MiscRecord.DataSize, misc_debug_record->Length); | |
| 224 EXPECT_EQ(expected_debug_utf16, misc_debug_record->Unicode); | |
| 225 EXPECT_EQ(0u, misc_debug_record->Reserved[0]); | |
| 226 EXPECT_EQ(0u, misc_debug_record->Reserved[1]); | |
| 227 EXPECT_EQ(0u, misc_debug_record->Reserved[2]); | |
| 228 | |
| 229 // Check for the NUL terminator. | |
| 230 size_t bytes_available = | |
| 231 misc_debug_record->Length - offsetof(IMAGE_DEBUG_MISC, Data); | |
| 232 EXPECT_EQ('\0', misc_debug_record->Data[bytes_available - 1]); | |
| 233 std::string observed_data( | |
| 234 reinterpret_cast<const char*>(misc_debug_record->Data)); | |
| 235 | |
| 236 size_t bytes_used; | |
| 237 if (misc_debug_record->Unicode) { | |
| 238 string16 observed_data_utf16( | |
| 239 reinterpret_cast<const char16*>(misc_debug_record->Data)); | |
| 240 bytes_used = (observed_data_utf16.size() + 1) * sizeof(char16); | |
| 241 observed_data = base::UTF16ToUTF8(observed_data_utf16); | |
| 242 } else { | |
| 243 observed_data = reinterpret_cast<const char*>(misc_debug_record->Data); | |
| 244 bytes_used = (observed_data.size() + 1) * sizeof(char); | |
| 245 } | |
| 246 EXPECT_LE(bytes_used, bytes_available); | |
| 247 | |
| 248 // Make sure that any padding bytes after the first NUL are also NUL. | |
| 249 for (size_t index = bytes_used; index < bytes_available; ++index) { | |
| 250 EXPECT_EQ('\0', misc_debug_record->Data[index]); | |
| 251 } | |
| 252 | |
| 253 EXPECT_EQ(expected_debug_name, observed_data); | |
| 254 } else { | |
| 255 // There should be no miscellaneous debugging record. | |
| 256 EXPECT_EQ(0u, observed->MiscRecord.DataSize); | |
| 257 EXPECT_EQ(0u, observed->MiscRecord.Rva); | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 TEST(MinidumpModuleWriter, EmptyModule) { | |
| 262 MinidumpFileWriter minidump_file_writer; | |
| 263 MinidumpModuleListWriter module_list_writer; | |
| 264 | |
| 265 const char kModuleName[] = "test_executable"; | |
| 266 | |
| 267 MinidumpModuleWriter module_writer; | |
| 268 module_writer.SetName(kModuleName); | |
| 269 | |
| 270 module_list_writer.AddModule(&module_writer); | |
| 271 minidump_file_writer.AddStream(&module_list_writer); | |
| 272 | |
| 273 StringFileWriter file_writer; | |
| 274 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); | |
| 275 | |
| 276 ASSERT_GT(file_writer.string().size(), | |
| 277 sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + | |
| 278 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); | |
| 279 | |
| 280 const MINIDUMP_MODULE_LIST* module_list; | |
| 281 GetModuleListStream(file_writer.string(), &module_list); | |
| 282 if (Test::HasFatalFailure()) { | |
| 283 return; | |
| 284 } | |
| 285 | |
| 286 EXPECT_EQ(1u, module_list->NumberOfModules); | |
| 287 | |
| 288 MINIDUMP_MODULE expected = {}; | |
| 289 ExpectModule(&expected, | |
| 290 &module_list->Modules[0], | |
| 291 file_writer.string(), | |
| 292 kModuleName, | |
| 293 NULL, | |
| 294 NULL, | |
| 295 0, | |
| 296 0, | |
| 297 NULL, | |
| 298 0, | |
| 299 false); | |
| 300 if (Test::HasFatalFailure()) { | |
| 301 return; | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 TEST(MinidumpModuleWriter, OneModule) { | |
| 306 MinidumpFileWriter minidump_file_writer; | |
| 307 MinidumpModuleListWriter module_list_writer; | |
| 308 | |
| 309 const char kModuleName[] = "statically_linked"; | |
| 310 const uint64_t kModuleBase = 0x000000010da69000ull; | |
| 311 const uint32_t kModuleSize = 0x1000; | |
| 312 const uint32_t kChecksum = 0x76543210; | |
| 313 const time_t kTimestamp = 0x386d4380; | |
| 314 const uint32_t kFileVersionMS = 0x00010002; | |
| 315 const uint32_t kFileVersionLS = 0x00030004; | |
| 316 const uint32_t kProductVersionMS = 0x00050006; | |
| 317 const uint32_t kProductVersionLS = 0x00070008; | |
| 318 const uint32_t kFileFlagsMask = VS_FF_DEBUG | VS_FF_PRERELEASE | | |
| 319 VS_FF_PATCHED | VS_FF_PRIVATEBUILD | | |
| 320 VS_FF_INFOINFERRED | VS_FF_SPECIALBUILD; | |
| 321 const uint32_t kFileFlags = VS_FF_PRIVATEBUILD | VS_FF_SPECIALBUILD; | |
| 322 const uint32_t kFileOS = VOS_DOS; | |
| 323 const uint32_t kFileType = VFT_DRV; | |
| 324 const uint32_t kFileSubtype = VFT2_DRV_KEYBOARD; | |
| 325 const char kPDBName[] = "statical.pdb"; | |
| 326 const uint8_t kPDBUUIDBytes[16] = | |
| 327 {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, | |
| 328 0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f}; | |
| 329 UUID pdb_uuid; | |
| 330 pdb_uuid.InitializeFromBytes(kPDBUUIDBytes); | |
| 331 const uint32_t kPDBAge = 1; | |
| 332 const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; | |
| 333 const char kDebugName[] = "statical.dbg"; | |
| 334 const bool kDebugUTF16 = false; | |
| 335 | |
| 336 MinidumpModuleWriter module_writer; | |
| 337 module_writer.SetName(kModuleName); | |
| 338 module_writer.SetImageBaseAddress(kModuleBase); | |
| 339 module_writer.SetImageSize(kModuleSize); | |
| 340 module_writer.SetChecksum(kChecksum); | |
| 341 module_writer.SetTimestamp(kTimestamp); | |
| 342 module_writer.SetFileVersion(kFileVersionMS >> 16, | |
| 343 kFileVersionMS & 0xffff, | |
| 344 kFileVersionLS >> 16, | |
| 345 kFileVersionLS & 0xffff); | |
| 346 module_writer.SetProductVersion(kProductVersionMS >> 16, | |
| 347 kProductVersionMS & 0xffff, | |
| 348 kProductVersionLS >> 16, | |
| 349 kProductVersionLS & 0xffff); | |
| 350 module_writer.SetFileFlagsAndMask(kFileFlags, kFileFlagsMask); | |
| 351 module_writer.SetFileOS(kFileOS); | |
| 352 module_writer.SetFileTypeAndSubtype(kFileType, kFileSubtype); | |
| 353 | |
| 354 MinidumpModuleCodeViewRecordPDB70Writer codeview_pdb70_writer; | |
| 355 codeview_pdb70_writer.SetPDBName(kPDBName); | |
| 356 codeview_pdb70_writer.SetUUIDAndAge(pdb_uuid, kPDBAge); | |
| 357 module_writer.SetCodeViewRecord(&codeview_pdb70_writer); | |
| 358 | |
| 359 MinidumpModuleMiscDebugRecordWriter misc_debug_writer; | |
| 360 misc_debug_writer.SetDataType(kDebugType); | |
| 361 misc_debug_writer.SetData(kDebugName, kDebugUTF16); | |
| 362 module_writer.SetMiscDebugRecord(&misc_debug_writer); | |
| 363 | |
| 364 module_list_writer.AddModule(&module_writer); | |
| 365 minidump_file_writer.AddStream(&module_list_writer); | |
| 366 | |
| 367 StringFileWriter file_writer; | |
| 368 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); | |
| 369 | |
| 370 ASSERT_GT(file_writer.string().size(), | |
| 371 sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + | |
| 372 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); | |
| 373 | |
| 374 const MINIDUMP_MODULE_LIST* module_list; | |
| 375 GetModuleListStream(file_writer.string(), &module_list); | |
| 376 if (Test::HasFatalFailure()) { | |
| 377 return; | |
| 378 } | |
| 379 | |
| 380 EXPECT_EQ(1u, module_list->NumberOfModules); | |
| 381 | |
| 382 MINIDUMP_MODULE expected = {}; | |
| 383 expected.BaseOfImage = kModuleBase; | |
| 384 expected.SizeOfImage = kModuleSize; | |
| 385 expected.CheckSum = kChecksum; | |
| 386 expected.TimeDateStamp = kTimestamp; | |
| 387 expected.VersionInfo.dwFileVersionMS = kFileVersionMS; | |
| 388 expected.VersionInfo.dwFileVersionLS = kFileVersionLS; | |
| 389 expected.VersionInfo.dwProductVersionMS = kProductVersionMS; | |
| 390 expected.VersionInfo.dwProductVersionLS = kProductVersionLS; | |
| 391 expected.VersionInfo.dwFileFlagsMask = kFileFlagsMask; | |
| 392 expected.VersionInfo.dwFileFlags = kFileFlags; | |
| 393 expected.VersionInfo.dwFileOS = kFileOS; | |
| 394 expected.VersionInfo.dwFileType = kFileType; | |
| 395 expected.VersionInfo.dwFileSubtype = kFileSubtype; | |
| 396 | |
| 397 ExpectModule(&expected, | |
| 398 &module_list->Modules[0], | |
| 399 file_writer.string(), | |
| 400 kModuleName, | |
| 401 kPDBName, | |
| 402 &pdb_uuid, | |
| 403 0, | |
| 404 kPDBAge, | |
| 405 kDebugName, | |
| 406 kDebugType, | |
| 407 kDebugUTF16); | |
| 408 if (Test::HasFatalFailure()) { | |
| 409 return; | |
| 410 } | |
| 411 } | |
| 412 | |
| 413 TEST(MinidumpModuleWriter, OneModule_CodeViewUsesPDB20_MiscUsesUTF16) { | |
| 414 // MinidumpModuleWriter.OneModule tested with a PDB 7.0 link as the CodeView | |
| 415 // record and an IMAGE_DEBUG_MISC record in UTF-8. This test exercises the | |
| 416 // alternatives, a PDB 2.0 link as the CodeView record and an IMAGE_DEBUG_MISC | |
| 417 // record with UTF-16 data. | |
| 418 MinidumpFileWriter minidump_file_writer; | |
| 419 MinidumpModuleListWriter module_list_writer; | |
| 420 | |
| 421 const char kModuleName[] = "dinosaur"; | |
| 422 const char kPDBName[] = "d1n05.pdb"; | |
| 423 const time_t kPDBTimestamp = 0x386d4380; | |
| 424 const uint32_t kPDBAge = 1; | |
| 425 const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; | |
| 426 const char kDebugName[] = "d1n05.dbg"; | |
| 427 const bool kDebugUTF16 = true; | |
| 428 | |
| 429 MinidumpModuleWriter module_writer; | |
| 430 module_writer.SetName(kModuleName); | |
| 431 | |
| 432 MinidumpModuleCodeViewRecordPDB20Writer codeview_pdb20_writer; | |
| 433 codeview_pdb20_writer.SetPDBName(kPDBName); | |
| 434 codeview_pdb20_writer.SetTimestampAndAge(kPDBTimestamp, kPDBAge); | |
| 435 module_writer.SetCodeViewRecord(&codeview_pdb20_writer); | |
| 436 | |
| 437 MinidumpModuleMiscDebugRecordWriter misc_debug_writer; | |
| 438 misc_debug_writer.SetDataType(kDebugType); | |
| 439 misc_debug_writer.SetData(kDebugName, kDebugUTF16); | |
| 440 module_writer.SetMiscDebugRecord(&misc_debug_writer); | |
| 441 | |
| 442 module_list_writer.AddModule(&module_writer); | |
| 443 minidump_file_writer.AddStream(&module_list_writer); | |
| 444 | |
| 445 StringFileWriter file_writer; | |
| 446 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); | |
| 447 | |
| 448 ASSERT_GT(file_writer.string().size(), | |
| 449 sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + | |
| 450 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); | |
| 451 | |
| 452 const MINIDUMP_MODULE_LIST* module_list; | |
| 453 GetModuleListStream(file_writer.string(), &module_list); | |
| 454 if (Test::HasFatalFailure()) { | |
| 455 return; | |
| 456 } | |
| 457 | |
| 458 EXPECT_EQ(1u, module_list->NumberOfModules); | |
| 459 | |
| 460 MINIDUMP_MODULE expected = {}; | |
| 461 | |
| 462 ExpectModule(&expected, | |
| 463 &module_list->Modules[0], | |
| 464 file_writer.string(), | |
| 465 kModuleName, | |
| 466 kPDBName, | |
| 467 NULL, | |
| 468 kPDBTimestamp, | |
| 469 kPDBAge, | |
| 470 kDebugName, | |
| 471 kDebugType, | |
| 472 kDebugUTF16); | |
| 473 if (Test::HasFatalFailure()) { | |
| 474 return; | |
| 475 } | |
| 476 } | |
| 477 | |
| 478 TEST(MinidumpModuleWriter, ThreeModules) { | |
| 479 MinidumpFileWriter minidump_file_writer; | |
| 480 MinidumpModuleListWriter module_list_writer; | |
| 481 | |
| 482 const char kModuleName1[] = "main"; | |
| 483 const uint64_t kModuleBase1 = 0x0000000100101000ull; | |
| 484 const uint32_t kModuleSize1 = 0xf000; | |
| 485 const char kPDBName1[] = "main"; | |
| 486 const uint8_t kPDBUUIDBytes1[16] = | |
| 487 {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, | |
| 488 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}; | |
| 489 UUID pdb_uuid_1; | |
| 490 pdb_uuid_1.InitializeFromBytes(kPDBUUIDBytes1); | |
| 491 const uint32_t kPDBAge1 = 0; | |
| 492 | |
| 493 const char kModuleName2[] = "ld.so"; | |
| 494 const uint64_t kModuleBase2 = 0x0000000200202000ull; | |
| 495 const uint32_t kModuleSize2 = 0x1e000; | |
| 496 | |
| 497 const char kModuleName3[] = "libc.so"; | |
| 498 const uint64_t kModuleBase3 = 0x0000000300303000ull; | |
| 499 const uint32_t kModuleSize3 = 0x2d000; | |
| 500 const char kPDBName3[] = "libc.so"; | |
| 501 const uint8_t kPDBUUIDBytes3[16] = | |
| 502 {0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80, | |
| 503 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00}; | |
| 504 UUID pdb_uuid_3; | |
| 505 pdb_uuid_3.InitializeFromBytes(kPDBUUIDBytes3); | |
| 506 const uint32_t kPDBAge3 = 0; | |
| 507 | |
| 508 MinidumpModuleWriter module_writer_1; | |
| 509 module_writer_1.SetName(kModuleName1); | |
| 510 module_writer_1.SetImageBaseAddress(kModuleBase1); | |
| 511 module_writer_1.SetImageSize(kModuleSize1); | |
| 512 | |
| 513 MinidumpModuleCodeViewRecordPDB70Writer codeview_pdb70_writer_1; | |
| 514 codeview_pdb70_writer_1.SetPDBName(kPDBName1); | |
| 515 codeview_pdb70_writer_1.SetUUIDAndAge(pdb_uuid_1, kPDBAge1); | |
| 516 module_writer_1.SetCodeViewRecord(&codeview_pdb70_writer_1); | |
| 517 | |
| 518 module_list_writer.AddModule(&module_writer_1); | |
| 519 | |
| 520 MinidumpModuleWriter module_writer_2; | |
| 521 module_writer_2.SetName(kModuleName2); | |
| 522 module_writer_2.SetImageBaseAddress(kModuleBase2); | |
| 523 module_writer_2.SetImageSize(kModuleSize2); | |
| 524 | |
| 525 module_list_writer.AddModule(&module_writer_2); | |
| 526 | |
| 527 MinidumpModuleWriter module_writer_3; | |
| 528 module_writer_3.SetName(kModuleName3); | |
| 529 module_writer_3.SetImageBaseAddress(kModuleBase3); | |
| 530 module_writer_3.SetImageSize(kModuleSize3); | |
| 531 | |
| 532 MinidumpModuleCodeViewRecordPDB70Writer codeview_pdb70_writer_3; | |
| 533 codeview_pdb70_writer_3.SetPDBName(kPDBName3); | |
| 534 codeview_pdb70_writer_3.SetUUIDAndAge(pdb_uuid_3, kPDBAge3); | |
| 535 module_writer_3.SetCodeViewRecord(&codeview_pdb70_writer_3); | |
| 536 | |
| 537 module_list_writer.AddModule(&module_writer_3); | |
| 538 | |
| 539 minidump_file_writer.AddStream(&module_list_writer); | |
| 540 | |
| 541 StringFileWriter file_writer; | |
| 542 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); | |
| 543 | |
| 544 ASSERT_GT(file_writer.string().size(), | |
| 545 sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + | |
| 546 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); | |
| 547 | |
| 548 const MINIDUMP_MODULE_LIST* module_list; | |
| 549 GetModuleListStream(file_writer.string(), &module_list); | |
| 550 if (Test::HasFatalFailure()) { | |
| 551 return; | |
| 552 } | |
| 553 | |
| 554 EXPECT_EQ(3u, module_list->NumberOfModules); | |
| 555 | |
| 556 MINIDUMP_MODULE expected = {}; | |
| 557 | |
| 558 { | |
| 559 SCOPED_TRACE("module 0"); | |
| 560 | |
| 561 expected.BaseOfImage = kModuleBase1; | |
| 562 expected.SizeOfImage = kModuleSize1; | |
| 563 | |
| 564 ExpectModule(&expected, | |
| 565 &module_list->Modules[0], | |
| 566 file_writer.string(), | |
| 567 kModuleName1, | |
| 568 kPDBName1, | |
| 569 &pdb_uuid_1, | |
| 570 0, | |
| 571 kPDBAge1, | |
| 572 NULL, | |
| 573 0, | |
| 574 false); | |
| 575 if (Test::HasFatalFailure()) { | |
| 576 return; | |
| 577 } | |
| 578 } | |
| 579 | |
| 580 { | |
| 581 SCOPED_TRACE("module 1"); | |
| 582 | |
| 583 expected.BaseOfImage = kModuleBase2; | |
| 584 expected.SizeOfImage = kModuleSize2; | |
| 585 | |
| 586 ExpectModule(&expected, | |
| 587 &module_list->Modules[1], | |
| 588 file_writer.string(), | |
| 589 kModuleName2, | |
| 590 NULL, | |
| 591 NULL, | |
| 592 0, | |
| 593 0, | |
| 594 NULL, | |
| 595 0, | |
| 596 false); | |
| 597 if (Test::HasFatalFailure()) { | |
| 598 return; | |
| 599 } | |
| 600 } | |
| 601 | |
| 602 { | |
| 603 SCOPED_TRACE("module 2"); | |
| 604 | |
| 605 expected.BaseOfImage = kModuleBase3; | |
| 606 expected.SizeOfImage = kModuleSize3; | |
| 607 | |
| 608 ExpectModule(&expected, | |
| 609 &module_list->Modules[2], | |
| 610 file_writer.string(), | |
| 611 kModuleName3, | |
| 612 kPDBName3, | |
| 613 &pdb_uuid_3, | |
| 614 0, | |
| 615 kPDBAge3, | |
| 616 NULL, | |
| 617 0, | |
| 618 false); | |
| 619 if (Test::HasFatalFailure()) { | |
| 620 return; | |
| 621 } | |
| 622 } | |
| 623 } | |
| 624 | |
|
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:
| |
| 625 TEST(MinidumpSystemInfoWriterDeathTest, NoModuleName) { | |
| 626 MinidumpFileWriter minidump_file_writer; | |
| 627 MinidumpModuleListWriter module_list_writer; | |
| 628 MinidumpModuleWriter module_writer; | |
| 629 module_list_writer.AddModule(&module_writer); | |
| 630 minidump_file_writer.AddStream(&module_list_writer); | |
| 631 | |
| 632 StringFileWriter file_writer; | |
| 633 ASSERT_DEATH(minidump_file_writer.WriteEverything(&file_writer), "name_"); | |
| 634 } | |
| 635 | |
| 636 } // namespace | |
| OLD | NEW |