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); |
| 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 // If |expected_pdb_name| is non-NULL, |codeview_record| is used to locate a |
| 91 // CodeView record in |file_contents|, and its fields are compared against the |
| 92 // the |expected_pdb_*| values. If |expected_pdb_uuid| is supplied, the CodeView |
| 93 // record must be a PDB 7.0 link, otherwise, it must be a PDB 2.0 link. If |
| 94 // |expected_pdb_name| is NULL, |codeview_record| must not point to anything. |
| 95 void ExpectCodeViewRecord(const MINIDUMP_LOCATION_DESCRIPTOR* codeview_record, |
| 96 const std::string& file_contents, |
| 97 const char* expected_pdb_name, |
| 98 const UUID* expected_pdb_uuid, |
| 99 time_t expected_pdb_timestamp, |
| 100 uint32_t expected_pdb_age) { |
| 101 if (expected_pdb_name) { |
| 102 EXPECT_NE(0u, codeview_record->Rva); |
| 103 ASSERT_LE(codeview_record->Rva + codeview_record->DataSize, |
| 104 file_contents.size()); |
| 105 |
| 106 std::string observed_pdb_name; |
| 107 if (expected_pdb_uuid) { |
| 108 // The CodeView record should be a PDB 7.0 link. |
| 109 EXPECT_GE(codeview_record->DataSize, |
| 110 sizeof(MinidumpModuleCodeViewRecordPDB70)); |
| 111 const MinidumpModuleCodeViewRecordPDB70* codeview_pdb70_record = |
| 112 reinterpret_cast<const MinidumpModuleCodeViewRecordPDB70*>( |
| 113 &file_contents[codeview_record->Rva]); |
| 114 EXPECT_EQ(MinidumpModuleCodeViewRecordPDB70::kSignature, |
| 115 codeview_pdb70_record->signature); |
| 116 EXPECT_EQ(0, |
| 117 memcmp(expected_pdb_uuid, |
| 118 &codeview_pdb70_record->uuid, |
| 119 sizeof(codeview_pdb70_record->uuid))); |
| 120 EXPECT_EQ(expected_pdb_age, codeview_pdb70_record->age); |
| 121 |
| 122 observed_pdb_name.assign( |
| 123 reinterpret_cast<const char*>(&codeview_pdb70_record->pdb_name[0]), |
| 124 codeview_record->DataSize - |
| 125 offsetof(MinidumpModuleCodeViewRecordPDB70, pdb_name)); |
| 126 } else { |
| 127 // The CodeView record should be a PDB 2.0 link. |
| 128 EXPECT_GE(codeview_record->DataSize, |
| 129 sizeof(MinidumpModuleCodeViewRecordPDB20)); |
| 130 const MinidumpModuleCodeViewRecordPDB20* codeview_pdb20_record = |
| 131 reinterpret_cast<const MinidumpModuleCodeViewRecordPDB20*>( |
| 132 &file_contents[codeview_record->Rva]); |
| 133 EXPECT_EQ(MinidumpModuleCodeViewRecordPDB20::kSignature, |
| 134 codeview_pdb20_record->signature); |
| 135 EXPECT_EQ(expected_pdb_timestamp, codeview_pdb20_record->timestamp); |
| 136 EXPECT_EQ(expected_pdb_age, codeview_pdb20_record->age); |
| 137 |
| 138 observed_pdb_name.assign( |
| 139 reinterpret_cast<const char*>(&codeview_pdb20_record->pdb_name[0]), |
| 140 codeview_record->DataSize - |
| 141 offsetof(MinidumpModuleCodeViewRecordPDB20, pdb_name)); |
| 142 } |
| 143 |
| 144 // Check for, and then remove, the NUL terminator. |
| 145 EXPECT_EQ('\0', observed_pdb_name[observed_pdb_name.size() - 1]); |
| 146 observed_pdb_name.resize(observed_pdb_name.size() - 1); |
| 147 |
| 148 EXPECT_EQ(expected_pdb_name, observed_pdb_name); |
| 149 } else { |
| 150 // There should be no CodeView record. |
| 151 EXPECT_EQ(0u, codeview_record->DataSize); |
| 152 EXPECT_EQ(0u, codeview_record->Rva); |
| 153 } |
| 154 } |
| 155 |
| 156 // If |expected_debug_name| is non-NULL, |misc_record| is used to locate a |
| 157 // miscellanous debugging record in |file_contents|, and its fields are compared |
| 158 // against the the |expected_debug_*| values. If |expected_debug_name| is NULL, |
| 159 // |misc_record| must not point to anything. |
| 160 void ExpectMiscellaneousDebugRecord( |
| 161 const MINIDUMP_LOCATION_DESCRIPTOR* misc_record, |
| 162 const std::string& file_contents, |
| 163 const char* expected_debug_name, |
| 164 uint32_t expected_debug_type, |
| 165 bool expected_debug_utf16) { |
| 166 if (expected_debug_name) { |
| 167 EXPECT_GE(misc_record->DataSize, sizeof(IMAGE_DEBUG_MISC)); |
| 168 EXPECT_NE(0u, misc_record->Rva); |
| 169 ASSERT_LE(misc_record->Rva + misc_record->DataSize, file_contents.size()); |
| 170 const IMAGE_DEBUG_MISC* misc_debug_record = |
| 171 reinterpret_cast<const IMAGE_DEBUG_MISC*>( |
| 172 &file_contents[misc_record->Rva]); |
| 173 EXPECT_EQ(expected_debug_type, misc_debug_record->DataType); |
| 174 EXPECT_EQ(misc_record->DataSize, misc_debug_record->Length); |
| 175 EXPECT_EQ(expected_debug_utf16, misc_debug_record->Unicode); |
| 176 EXPECT_EQ(0u, misc_debug_record->Reserved[0]); |
| 177 EXPECT_EQ(0u, misc_debug_record->Reserved[1]); |
| 178 EXPECT_EQ(0u, misc_debug_record->Reserved[2]); |
| 179 |
| 180 // Check for the NUL terminator. |
| 181 size_t bytes_available = |
| 182 misc_debug_record->Length - offsetof(IMAGE_DEBUG_MISC, Data); |
| 183 EXPECT_EQ('\0', misc_debug_record->Data[bytes_available - 1]); |
| 184 std::string observed_data( |
| 185 reinterpret_cast<const char*>(misc_debug_record->Data)); |
| 186 |
| 187 size_t bytes_used; |
| 188 if (misc_debug_record->Unicode) { |
| 189 string16 observed_data_utf16( |
| 190 reinterpret_cast<const char16*>(misc_debug_record->Data)); |
| 191 bytes_used = (observed_data_utf16.size() + 1) * sizeof(char16); |
| 192 observed_data = base::UTF16ToUTF8(observed_data_utf16); |
| 193 } else { |
| 194 observed_data = reinterpret_cast<const char*>(misc_debug_record->Data); |
| 195 bytes_used = (observed_data.size() + 1) * sizeof(char); |
| 196 } |
| 197 EXPECT_LE(bytes_used, bytes_available); |
| 198 |
| 199 // Make sure that any padding bytes after the first NUL are also NUL. |
| 200 for (size_t index = bytes_used; index < bytes_available; ++index) { |
| 201 EXPECT_EQ('\0', misc_debug_record->Data[index]); |
| 202 } |
| 203 |
| 204 EXPECT_EQ(expected_debug_name, observed_data); |
| 205 } else { |
| 206 // There should be no miscellaneous debugging record. |
| 207 EXPECT_EQ(0u, misc_record->DataSize); |
| 208 EXPECT_EQ(0u, misc_record->Rva); |
| 209 } |
| 210 } |
| 211 |
| 212 // ExpectModule() verifies that |expected| matches |observed|. Fields that are |
| 213 // supposed to contain constant magic numbers are verified against the expected |
| 214 // constants instead of |expected|. Reserved fields are verified to be 0. RVA |
| 215 // and MINIDUMP_LOCATION_DESCRIPTOR fields are not verified against |expected|. |
| 216 // Instead, |ModuleNameRva| is used to locate the module name, which is compared |
| 217 // against |expected_module_name|. ExpectCodeViewRecord() and |
| 218 // ExpectMiscellaneousDebugRecord() are used to verify the |CvRecord| and |
| 219 // |MiscRecord| fields against |expected_pdb_*| and |expected_debug_*| |
| 220 // parameters, respectively. |
| 221 void ExpectModule(const MINIDUMP_MODULE* expected, |
| 222 const MINIDUMP_MODULE* observed, |
| 223 const std::string& file_contents, |
| 224 const std::string& expected_module_name, |
| 225 const char* expected_pdb_name, |
| 226 const UUID* expected_pdb_uuid, |
| 227 time_t expected_pdb_timestamp, |
| 228 uint32_t expected_pdb_age, |
| 229 const char* expected_debug_name, |
| 230 uint32_t expected_debug_type, |
| 231 bool expected_debug_utf16) { |
| 232 EXPECT_EQ(expected->BaseOfImage, observed->BaseOfImage); |
| 233 EXPECT_EQ(expected->SizeOfImage, observed->SizeOfImage); |
| 234 EXPECT_EQ(expected->CheckSum, observed->CheckSum); |
| 235 EXPECT_EQ(expected->TimeDateStamp, observed->TimeDateStamp); |
| 236 EXPECT_EQ(static_cast<uint32_t>(VS_FFI_SIGNATURE), |
| 237 observed->VersionInfo.dwSignature); |
| 238 EXPECT_EQ(static_cast<uint32_t>(VS_FFI_STRUCVERSION), |
| 239 observed->VersionInfo.dwStrucVersion); |
| 240 EXPECT_EQ(expected->VersionInfo.dwFileVersionMS, |
| 241 observed->VersionInfo.dwFileVersionMS); |
| 242 EXPECT_EQ(expected->VersionInfo.dwFileVersionLS, |
| 243 observed->VersionInfo.dwFileVersionLS); |
| 244 EXPECT_EQ(expected->VersionInfo.dwProductVersionMS, |
| 245 observed->VersionInfo.dwProductVersionMS); |
| 246 EXPECT_EQ(expected->VersionInfo.dwProductVersionLS, |
| 247 observed->VersionInfo.dwProductVersionLS); |
| 248 EXPECT_EQ(expected->VersionInfo.dwFileFlagsMask, |
| 249 observed->VersionInfo.dwFileFlagsMask); |
| 250 EXPECT_EQ(expected->VersionInfo.dwFileFlags, |
| 251 observed->VersionInfo.dwFileFlags); |
| 252 EXPECT_EQ(expected->VersionInfo.dwFileOS, observed->VersionInfo.dwFileOS); |
| 253 EXPECT_EQ(expected->VersionInfo.dwFileType, observed->VersionInfo.dwFileType); |
| 254 EXPECT_EQ(expected->VersionInfo.dwFileSubtype, |
| 255 observed->VersionInfo.dwFileSubtype); |
| 256 EXPECT_EQ(expected->VersionInfo.dwFileDateMS, |
| 257 observed->VersionInfo.dwFileDateMS); |
| 258 EXPECT_EQ(expected->VersionInfo.dwFileDateLS, |
| 259 observed->VersionInfo.dwFileDateLS); |
| 260 EXPECT_EQ(0u, observed->Reserved0); |
| 261 EXPECT_EQ(0u, observed->Reserved1); |
| 262 |
| 263 EXPECT_NE(0u, observed->ModuleNameRva); |
| 264 ASSERT_LE(observed->ModuleNameRva, |
| 265 file_contents.size() - sizeof(MINIDUMP_STRING)); |
| 266 const MINIDUMP_STRING* module_name = reinterpret_cast<const MINIDUMP_STRING*>( |
| 267 &file_contents[observed->ModuleNameRva]); |
| 268 ASSERT_LE(observed->ModuleNameRva + sizeof(MINIDUMP_STRING) + |
| 269 (module_name->Length + 1), |
| 270 file_contents.size()); |
| 271 ASSERT_EQ(0u, module_name->Length % 2); |
| 272 string16 observed_module_name_utf16( |
| 273 reinterpret_cast<const char16*>( |
| 274 &file_contents[observed->ModuleNameRva + sizeof(MINIDUMP_STRING)]), |
| 275 module_name->Length / 2); |
| 276 string16 expected_module_name_utf16 = base::UTF8ToUTF16(expected_module_name); |
| 277 EXPECT_EQ(expected_module_name_utf16, observed_module_name_utf16); |
| 278 |
| 279 ExpectCodeViewRecord(&observed->CvRecord, |
| 280 file_contents, |
| 281 expected_pdb_name, |
| 282 expected_pdb_uuid, |
| 283 expected_pdb_timestamp, |
| 284 expected_pdb_age); |
| 285 if (testing::Test::HasFatalFailure()) { |
| 286 return; |
| 287 } |
| 288 |
| 289 ExpectMiscellaneousDebugRecord(&observed->MiscRecord, |
| 290 file_contents, |
| 291 expected_debug_name, |
| 292 expected_debug_type, |
| 293 expected_debug_utf16); |
| 294 if (testing::Test::HasFatalFailure()) { |
| 295 return; |
| 296 } |
| 297 } |
| 298 |
| 299 TEST(MinidumpModuleWriter, EmptyModule) { |
| 300 MinidumpFileWriter minidump_file_writer; |
| 301 MinidumpModuleListWriter module_list_writer; |
| 302 |
| 303 const char kModuleName[] = "test_executable"; |
| 304 |
| 305 MinidumpModuleWriter module_writer; |
| 306 module_writer.SetName(kModuleName); |
| 307 |
| 308 module_list_writer.AddModule(&module_writer); |
| 309 minidump_file_writer.AddStream(&module_list_writer); |
| 310 |
| 311 StringFileWriter file_writer; |
| 312 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| 313 |
| 314 ASSERT_GT(file_writer.string().size(), |
| 315 sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| 316 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); |
| 317 |
| 318 const MINIDUMP_MODULE_LIST* module_list; |
| 319 GetModuleListStream(file_writer.string(), &module_list); |
| 320 if (Test::HasFatalFailure()) { |
| 321 return; |
| 322 } |
| 323 |
| 324 EXPECT_EQ(1u, module_list->NumberOfModules); |
| 325 |
| 326 MINIDUMP_MODULE expected = {}; |
| 327 ExpectModule(&expected, |
| 328 &module_list->Modules[0], |
| 329 file_writer.string(), |
| 330 kModuleName, |
| 331 NULL, |
| 332 NULL, |
| 333 0, |
| 334 0, |
| 335 NULL, |
| 336 0, |
| 337 false); |
| 338 if (Test::HasFatalFailure()) { |
| 339 return; |
| 340 } |
| 341 } |
| 342 |
| 343 TEST(MinidumpModuleWriter, OneModule) { |
| 344 MinidumpFileWriter minidump_file_writer; |
| 345 MinidumpModuleListWriter module_list_writer; |
| 346 |
| 347 const char kModuleName[] = "statically_linked"; |
| 348 const uint64_t kModuleBase = 0x10da69000; |
| 349 const uint32_t kModuleSize = 0x1000; |
| 350 const uint32_t kChecksum = 0x76543210; |
| 351 const time_t kTimestamp = 0x386d4380; |
| 352 const uint32_t kFileVersionMS = 0x00010002; |
| 353 const uint32_t kFileVersionLS = 0x00030004; |
| 354 const uint32_t kProductVersionMS = 0x00050006; |
| 355 const uint32_t kProductVersionLS = 0x00070008; |
| 356 const uint32_t kFileFlagsMask = VS_FF_DEBUG | VS_FF_PRERELEASE | |
| 357 VS_FF_PATCHED | VS_FF_PRIVATEBUILD | |
| 358 VS_FF_INFOINFERRED | VS_FF_SPECIALBUILD; |
| 359 const uint32_t kFileFlags = VS_FF_PRIVATEBUILD | VS_FF_SPECIALBUILD; |
| 360 const uint32_t kFileOS = VOS_DOS; |
| 361 const uint32_t kFileType = VFT_DRV; |
| 362 const uint32_t kFileSubtype = VFT2_DRV_KEYBOARD; |
| 363 const char kPDBName[] = "statical.pdb"; |
| 364 const uint8_t kPDBUUIDBytes[16] = |
| 365 {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, |
| 366 0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f}; |
| 367 UUID pdb_uuid; |
| 368 pdb_uuid.InitializeFromBytes(kPDBUUIDBytes); |
| 369 const uint32_t kPDBAge = 1; |
| 370 const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; |
| 371 const char kDebugName[] = "statical.dbg"; |
| 372 const bool kDebugUTF16 = false; |
| 373 |
| 374 MinidumpModuleWriter module_writer; |
| 375 module_writer.SetName(kModuleName); |
| 376 module_writer.SetImageBaseAddress(kModuleBase); |
| 377 module_writer.SetImageSize(kModuleSize); |
| 378 module_writer.SetChecksum(kChecksum); |
| 379 module_writer.SetTimestamp(kTimestamp); |
| 380 module_writer.SetFileVersion(kFileVersionMS >> 16, |
| 381 kFileVersionMS & 0xffff, |
| 382 kFileVersionLS >> 16, |
| 383 kFileVersionLS & 0xffff); |
| 384 module_writer.SetProductVersion(kProductVersionMS >> 16, |
| 385 kProductVersionMS & 0xffff, |
| 386 kProductVersionLS >> 16, |
| 387 kProductVersionLS & 0xffff); |
| 388 module_writer.SetFileFlagsAndMask(kFileFlags, kFileFlagsMask); |
| 389 module_writer.SetFileOS(kFileOS); |
| 390 module_writer.SetFileTypeAndSubtype(kFileType, kFileSubtype); |
| 391 |
| 392 MinidumpModuleCodeViewRecordPDB70Writer codeview_pdb70_writer; |
| 393 codeview_pdb70_writer.SetPDBName(kPDBName); |
| 394 codeview_pdb70_writer.SetUUIDAndAge(pdb_uuid, kPDBAge); |
| 395 module_writer.SetCodeViewRecord(&codeview_pdb70_writer); |
| 396 |
| 397 MinidumpModuleMiscDebugRecordWriter misc_debug_writer; |
| 398 misc_debug_writer.SetDataType(kDebugType); |
| 399 misc_debug_writer.SetData(kDebugName, kDebugUTF16); |
| 400 module_writer.SetMiscDebugRecord(&misc_debug_writer); |
| 401 |
| 402 module_list_writer.AddModule(&module_writer); |
| 403 minidump_file_writer.AddStream(&module_list_writer); |
| 404 |
| 405 StringFileWriter file_writer; |
| 406 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| 407 |
| 408 ASSERT_GT(file_writer.string().size(), |
| 409 sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| 410 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); |
| 411 |
| 412 const MINIDUMP_MODULE_LIST* module_list; |
| 413 GetModuleListStream(file_writer.string(), &module_list); |
| 414 if (Test::HasFatalFailure()) { |
| 415 return; |
| 416 } |
| 417 |
| 418 EXPECT_EQ(1u, module_list->NumberOfModules); |
| 419 |
| 420 MINIDUMP_MODULE expected = {}; |
| 421 expected.BaseOfImage = kModuleBase; |
| 422 expected.SizeOfImage = kModuleSize; |
| 423 expected.CheckSum = kChecksum; |
| 424 expected.TimeDateStamp = kTimestamp; |
| 425 expected.VersionInfo.dwFileVersionMS = kFileVersionMS; |
| 426 expected.VersionInfo.dwFileVersionLS = kFileVersionLS; |
| 427 expected.VersionInfo.dwProductVersionMS = kProductVersionMS; |
| 428 expected.VersionInfo.dwProductVersionLS = kProductVersionLS; |
| 429 expected.VersionInfo.dwFileFlagsMask = kFileFlagsMask; |
| 430 expected.VersionInfo.dwFileFlags = kFileFlags; |
| 431 expected.VersionInfo.dwFileOS = kFileOS; |
| 432 expected.VersionInfo.dwFileType = kFileType; |
| 433 expected.VersionInfo.dwFileSubtype = kFileSubtype; |
| 434 |
| 435 ExpectModule(&expected, |
| 436 &module_list->Modules[0], |
| 437 file_writer.string(), |
| 438 kModuleName, |
| 439 kPDBName, |
| 440 &pdb_uuid, |
| 441 0, |
| 442 kPDBAge, |
| 443 kDebugName, |
| 444 kDebugType, |
| 445 kDebugUTF16); |
| 446 if (Test::HasFatalFailure()) { |
| 447 return; |
| 448 } |
| 449 } |
| 450 |
| 451 TEST(MinidumpModuleWriter, OneModule_CodeViewUsesPDB20_MiscUsesUTF16) { |
| 452 // MinidumpModuleWriter.OneModule tested with a PDB 7.0 link as the CodeView |
| 453 // record and an IMAGE_DEBUG_MISC record in UTF-8. This test exercises the |
| 454 // alternatives, a PDB 2.0 link as the CodeView record and an IMAGE_DEBUG_MISC |
| 455 // record with UTF-16 data. |
| 456 MinidumpFileWriter minidump_file_writer; |
| 457 MinidumpModuleListWriter module_list_writer; |
| 458 |
| 459 const char kModuleName[] = "dinosaur"; |
| 460 const char kPDBName[] = "d1n05.pdb"; |
| 461 const time_t kPDBTimestamp = 0x386d4380; |
| 462 const uint32_t kPDBAge = 1; |
| 463 const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; |
| 464 const char kDebugName[] = "d1n05.dbg"; |
| 465 const bool kDebugUTF16 = true; |
| 466 |
| 467 MinidumpModuleWriter module_writer; |
| 468 module_writer.SetName(kModuleName); |
| 469 |
| 470 MinidumpModuleCodeViewRecordPDB20Writer codeview_pdb20_writer; |
| 471 codeview_pdb20_writer.SetPDBName(kPDBName); |
| 472 codeview_pdb20_writer.SetTimestampAndAge(kPDBTimestamp, kPDBAge); |
| 473 module_writer.SetCodeViewRecord(&codeview_pdb20_writer); |
| 474 |
| 475 MinidumpModuleMiscDebugRecordWriter misc_debug_writer; |
| 476 misc_debug_writer.SetDataType(kDebugType); |
| 477 misc_debug_writer.SetData(kDebugName, kDebugUTF16); |
| 478 module_writer.SetMiscDebugRecord(&misc_debug_writer); |
| 479 |
| 480 module_list_writer.AddModule(&module_writer); |
| 481 minidump_file_writer.AddStream(&module_list_writer); |
| 482 |
| 483 StringFileWriter file_writer; |
| 484 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| 485 |
| 486 ASSERT_GT(file_writer.string().size(), |
| 487 sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| 488 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); |
| 489 |
| 490 const MINIDUMP_MODULE_LIST* module_list; |
| 491 GetModuleListStream(file_writer.string(), &module_list); |
| 492 if (Test::HasFatalFailure()) { |
| 493 return; |
| 494 } |
| 495 |
| 496 EXPECT_EQ(1u, module_list->NumberOfModules); |
| 497 |
| 498 MINIDUMP_MODULE expected = {}; |
| 499 |
| 500 ExpectModule(&expected, |
| 501 &module_list->Modules[0], |
| 502 file_writer.string(), |
| 503 kModuleName, |
| 504 kPDBName, |
| 505 NULL, |
| 506 kPDBTimestamp, |
| 507 kPDBAge, |
| 508 kDebugName, |
| 509 kDebugType, |
| 510 kDebugUTF16); |
| 511 if (Test::HasFatalFailure()) { |
| 512 return; |
| 513 } |
| 514 } |
| 515 |
| 516 TEST(MinidumpModuleWriter, ThreeModules) { |
| 517 // As good exercise, this test uses three modules, one with a PDB 7.0 link as |
| 518 // its CodeView record, one with no CodeView record, and one with a PDB 2.0 |
| 519 // link as its CodeView record. |
| 520 MinidumpFileWriter minidump_file_writer; |
| 521 MinidumpModuleListWriter module_list_writer; |
| 522 |
| 523 const char kModuleName1[] = "main"; |
| 524 const uint64_t kModuleBase1 = 0x100101000; |
| 525 const uint32_t kModuleSize1 = 0xf000; |
| 526 const char kPDBName1[] = "main"; |
| 527 const uint8_t kPDBUUIDBytes1[16] = |
| 528 {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, |
| 529 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}; |
| 530 UUID pdb_uuid_1; |
| 531 pdb_uuid_1.InitializeFromBytes(kPDBUUIDBytes1); |
| 532 const uint32_t kPDBAge1 = 0; |
| 533 |
| 534 const char kModuleName2[] = "ld.so"; |
| 535 const uint64_t kModuleBase2 = 0x200202000; |
| 536 const uint32_t kModuleSize2 = 0x1e000; |
| 537 |
| 538 const char kModuleName3[] = "libc.so"; |
| 539 const uint64_t kModuleBase3 = 0x300303000; |
| 540 const uint32_t kModuleSize3 = 0x2d000; |
| 541 const char kPDBName3[] = "libc.so"; |
| 542 const time_t kPDBTimestamp3 = 0x386d4380; |
| 543 const uint32_t kPDBAge3 = 2; |
| 544 |
| 545 MinidumpModuleWriter module_writer_1; |
| 546 module_writer_1.SetName(kModuleName1); |
| 547 module_writer_1.SetImageBaseAddress(kModuleBase1); |
| 548 module_writer_1.SetImageSize(kModuleSize1); |
| 549 |
| 550 MinidumpModuleCodeViewRecordPDB70Writer codeview_pdb70_writer_1; |
| 551 codeview_pdb70_writer_1.SetPDBName(kPDBName1); |
| 552 codeview_pdb70_writer_1.SetUUIDAndAge(pdb_uuid_1, kPDBAge1); |
| 553 module_writer_1.SetCodeViewRecord(&codeview_pdb70_writer_1); |
| 554 |
| 555 module_list_writer.AddModule(&module_writer_1); |
| 556 |
| 557 MinidumpModuleWriter module_writer_2; |
| 558 module_writer_2.SetName(kModuleName2); |
| 559 module_writer_2.SetImageBaseAddress(kModuleBase2); |
| 560 module_writer_2.SetImageSize(kModuleSize2); |
| 561 |
| 562 module_list_writer.AddModule(&module_writer_2); |
| 563 |
| 564 MinidumpModuleWriter module_writer_3; |
| 565 module_writer_3.SetName(kModuleName3); |
| 566 module_writer_3.SetImageBaseAddress(kModuleBase3); |
| 567 module_writer_3.SetImageSize(kModuleSize3); |
| 568 |
| 569 MinidumpModuleCodeViewRecordPDB20Writer codeview_pdb70_writer_3; |
| 570 codeview_pdb70_writer_3.SetPDBName(kPDBName3); |
| 571 codeview_pdb70_writer_3.SetTimestampAndAge(kPDBTimestamp3, kPDBAge3); |
| 572 module_writer_3.SetCodeViewRecord(&codeview_pdb70_writer_3); |
| 573 |
| 574 module_list_writer.AddModule(&module_writer_3); |
| 575 |
| 576 minidump_file_writer.AddStream(&module_list_writer); |
| 577 |
| 578 StringFileWriter file_writer; |
| 579 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| 580 |
| 581 ASSERT_GT(file_writer.string().size(), |
| 582 sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| 583 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); |
| 584 |
| 585 const MINIDUMP_MODULE_LIST* module_list; |
| 586 GetModuleListStream(file_writer.string(), &module_list); |
| 587 if (Test::HasFatalFailure()) { |
| 588 return; |
| 589 } |
| 590 |
| 591 EXPECT_EQ(3u, module_list->NumberOfModules); |
| 592 |
| 593 MINIDUMP_MODULE expected = {}; |
| 594 |
| 595 { |
| 596 SCOPED_TRACE("module 0"); |
| 597 |
| 598 expected.BaseOfImage = kModuleBase1; |
| 599 expected.SizeOfImage = kModuleSize1; |
| 600 |
| 601 ExpectModule(&expected, |
| 602 &module_list->Modules[0], |
| 603 file_writer.string(), |
| 604 kModuleName1, |
| 605 kPDBName1, |
| 606 &pdb_uuid_1, |
| 607 0, |
| 608 kPDBAge1, |
| 609 NULL, |
| 610 0, |
| 611 false); |
| 612 if (Test::HasFatalFailure()) { |
| 613 return; |
| 614 } |
| 615 } |
| 616 |
| 617 { |
| 618 SCOPED_TRACE("module 1"); |
| 619 |
| 620 expected.BaseOfImage = kModuleBase2; |
| 621 expected.SizeOfImage = kModuleSize2; |
| 622 |
| 623 ExpectModule(&expected, |
| 624 &module_list->Modules[1], |
| 625 file_writer.string(), |
| 626 kModuleName2, |
| 627 NULL, |
| 628 NULL, |
| 629 0, |
| 630 0, |
| 631 NULL, |
| 632 0, |
| 633 false); |
| 634 if (Test::HasFatalFailure()) { |
| 635 return; |
| 636 } |
| 637 } |
| 638 |
| 639 { |
| 640 SCOPED_TRACE("module 2"); |
| 641 |
| 642 expected.BaseOfImage = kModuleBase3; |
| 643 expected.SizeOfImage = kModuleSize3; |
| 644 |
| 645 ExpectModule(&expected, |
| 646 &module_list->Modules[2], |
| 647 file_writer.string(), |
| 648 kModuleName3, |
| 649 kPDBName3, |
| 650 NULL, |
| 651 kPDBTimestamp3, |
| 652 kPDBAge3, |
| 653 NULL, |
| 654 0, |
| 655 false); |
| 656 if (Test::HasFatalFailure()) { |
| 657 return; |
| 658 } |
| 659 } |
| 660 } |
| 661 |
| 662 TEST(MinidumpSystemInfoWriterDeathTest, NoModuleName) { |
| 663 MinidumpFileWriter minidump_file_writer; |
| 664 MinidumpModuleListWriter module_list_writer; |
| 665 MinidumpModuleWriter module_writer; |
| 666 module_list_writer.AddModule(&module_writer); |
| 667 minidump_file_writer.AddStream(&module_list_writer); |
| 668 |
| 669 StringFileWriter file_writer; |
| 670 ASSERT_DEATH(minidump_file_writer.WriteEverything(&file_writer), "name_"); |
| 671 } |
| 672 |
| 673 } // namespace |
OLD | NEW |