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 <stddef.h>
18 #include <string.h>
19 
20 #include <utility>
21 
22 #include "base/format_macros.h"
23 #include "base/stl_util.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "gtest/gtest.h"
27 #include "minidump/minidump_file_writer.h"
28 #include "minidump/test/minidump_file_writer_test_util.h"
29 #include "minidump/test/minidump_string_writer_test_util.h"
30 #include "minidump/test/minidump_writable_test_util.h"
31 #include "snapshot/test/test_module_snapshot.h"
32 #include "test/gtest_death.h"
33 #include "util/file/string_file.h"
34 #include "util/misc/implicit_cast.h"
35 #include "util/misc/uuid.h"
36 
37 namespace crashpad {
38 namespace test {
39 namespace {
40 
GetModuleListStream(const std::string & file_contents,const MINIDUMP_MODULE_LIST ** module_list)41 void GetModuleListStream(const std::string& file_contents,
42                          const MINIDUMP_MODULE_LIST** module_list) {
43   constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
44   constexpr size_t kModuleListStreamOffset =
45       kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
46   constexpr size_t kModulesOffset =
47       kModuleListStreamOffset + sizeof(MINIDUMP_MODULE_LIST);
48 
49   ASSERT_GE(file_contents.size(), kModulesOffset);
50 
51   const MINIDUMP_DIRECTORY* directory;
52   const MINIDUMP_HEADER* header =
53       MinidumpHeaderAtStart(file_contents, &directory);
54   ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0));
55   ASSERT_TRUE(directory);
56 
57   ASSERT_EQ(directory[0].StreamType, kMinidumpStreamTypeModuleList);
58   EXPECT_EQ(directory[0].Location.Rva, kModuleListStreamOffset);
59 
60   *module_list = MinidumpWritableAtLocationDescriptor<MINIDUMP_MODULE_LIST>(
61       file_contents, directory[0].Location);
62   ASSERT_TRUE(module_list);
63 }
64 
TEST(MinidumpModuleWriter,EmptyModuleList)65 TEST(MinidumpModuleWriter, EmptyModuleList) {
66   MinidumpFileWriter minidump_file_writer;
67   auto module_list_writer = std::make_unique<MinidumpModuleListWriter>();
68 
69   ASSERT_TRUE(minidump_file_writer.AddStream(std::move(module_list_writer)));
70 
71   StringFile string_file;
72   ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
73 
74   ASSERT_EQ(string_file.string().size(),
75             sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) +
76                 sizeof(MINIDUMP_MODULE_LIST));
77 
78   const MINIDUMP_MODULE_LIST* module_list = nullptr;
79   ASSERT_NO_FATAL_FAILURE(
80       GetModuleListStream(string_file.string(), &module_list));
81 
82   EXPECT_EQ(module_list->NumberOfModules, 0u);
83 }
84 
85 // If |expected_pdb_name| is not nullptr, |codeview_record| is used to locate a
86 // CodeView record in |file_contents|, and its fields are compared against the
87 // |expected_pdb_*| values. If |expected_pdb_uuid| is supplied, the CodeView
88 // record must be a PDB 7.0 link, otherwise, it must be a PDB 2.0 link. If
89 // |expected_pdb_name| is nullptr, |codeview_record| must not point to anything.
ExpectCodeViewRecord(const MINIDUMP_LOCATION_DESCRIPTOR * codeview_record,const std::string & file_contents,const char * expected_pdb_name,const UUID * expected_pdb_uuid,time_t expected_pdb_timestamp,uint32_t expected_pdb_age)90 void ExpectCodeViewRecord(const MINIDUMP_LOCATION_DESCRIPTOR* codeview_record,
91                           const std::string& file_contents,
92                           const char* expected_pdb_name,
93                           const UUID* expected_pdb_uuid,
94                           time_t expected_pdb_timestamp,
95                           uint32_t expected_pdb_age) {
96   if (expected_pdb_name) {
97     EXPECT_NE(codeview_record->Rva, 0u);
98 
99     std::string observed_pdb_name;
100     if (expected_pdb_uuid) {
101       // The CodeView record should be a PDB 7.0 link.
102       const CodeViewRecordPDB70* codeview_pdb70_record =
103           MinidumpWritableAtLocationDescriptor<CodeViewRecordPDB70>(
104               file_contents, *codeview_record);
105       ASSERT_TRUE(codeview_pdb70_record);
106       EXPECT_EQ(memcmp(expected_pdb_uuid,
107                        &codeview_pdb70_record->uuid,
108                        sizeof(codeview_pdb70_record->uuid)),
109                 0);
110       EXPECT_EQ(codeview_pdb70_record->age, expected_pdb_age);
111 
112       observed_pdb_name.assign(
113           reinterpret_cast<const char*>(&codeview_pdb70_record->pdb_name[0]),
114           codeview_record->DataSize - offsetof(CodeViewRecordPDB70, pdb_name));
115     } else {
116       // The CodeView record should be a PDB 2.0 link.
117       const CodeViewRecordPDB20* codeview_pdb20_record =
118           MinidumpWritableAtLocationDescriptor<CodeViewRecordPDB20>(
119               file_contents, *codeview_record);
120       ASSERT_TRUE(codeview_pdb20_record);
121       EXPECT_EQ(codeview_pdb20_record->timestamp,
122                 static_cast<uint32_t>(expected_pdb_timestamp));
123       EXPECT_EQ(codeview_pdb20_record->age, expected_pdb_age);
124 
125       observed_pdb_name.assign(
126           reinterpret_cast<const char*>(&codeview_pdb20_record->pdb_name[0]),
127           codeview_record->DataSize - offsetof(CodeViewRecordPDB20, pdb_name));
128     }
129 
130     // Check for, and then remove, the NUL terminator.
131     EXPECT_EQ(observed_pdb_name[observed_pdb_name.size() - 1], '\0');
132     observed_pdb_name.resize(observed_pdb_name.size() - 1);
133 
134     EXPECT_EQ(observed_pdb_name, expected_pdb_name);
135   } else {
136     // There should be no CodeView record.
137     EXPECT_EQ(codeview_record->DataSize, 0u);
138     EXPECT_EQ(codeview_record->Rva, 0u);
139   }
140 }
141 
142 // If |expected_debug_name| is not nullptr, |misc_record| is used to locate a
143 // miscellanous debugging record in |file_contents|, and its fields are compared
144 // against the the |expected_debug_*| values. If |expected_debug_name| is
145 // nullptr, |misc_record| must not point to anything.
ExpectMiscellaneousDebugRecord(const MINIDUMP_LOCATION_DESCRIPTOR * misc_record,const std::string & file_contents,const char * expected_debug_name,uint32_t expected_debug_type,bool expected_debug_utf16)146 void ExpectMiscellaneousDebugRecord(
147     const MINIDUMP_LOCATION_DESCRIPTOR* misc_record,
148     const std::string& file_contents,
149     const char* expected_debug_name,
150     uint32_t expected_debug_type,
151     bool expected_debug_utf16) {
152   if (expected_debug_name) {
153     EXPECT_NE(misc_record->Rva, 0u);
154     const IMAGE_DEBUG_MISC* misc_debug_record =
155         MinidumpWritableAtLocationDescriptor<IMAGE_DEBUG_MISC>(file_contents,
156                                                                *misc_record);
157     ASSERT_TRUE(misc_debug_record);
158     EXPECT_EQ(misc_debug_record->DataType, expected_debug_type);
159     EXPECT_EQ(misc_debug_record->Unicode != 0, expected_debug_utf16);
160     EXPECT_EQ(misc_debug_record->Reserved[0], 0u);
161     EXPECT_EQ(misc_debug_record->Reserved[1], 0u);
162     EXPECT_EQ(misc_debug_record->Reserved[2], 0u);
163 
164     // Check for the NUL terminator.
165     size_t bytes_available =
166         misc_debug_record->Length - offsetof(IMAGE_DEBUG_MISC, Data);
167     EXPECT_EQ(misc_debug_record->Data[bytes_available - 1], '\0');
168     std::string observed_data(
169         reinterpret_cast<const char*>(misc_debug_record->Data));
170 
171     size_t bytes_used;
172     if (misc_debug_record->Unicode) {
173       base::string16 observed_data_utf16(
174           reinterpret_cast<const base::char16*>(misc_debug_record->Data));
175       bytes_used = (observed_data_utf16.size() + 1) * sizeof(base::char16);
176       observed_data = base::UTF16ToUTF8(observed_data_utf16);
177     } else {
178       observed_data = reinterpret_cast<const char*>(misc_debug_record->Data);
179       bytes_used = (observed_data.size() + 1) * sizeof(char);
180     }
181     EXPECT_LE(bytes_used, bytes_available);
182 
183     // Make sure that any padding bytes after the first NUL are also NUL.
184     for (size_t index = bytes_used; index < bytes_available; ++index) {
185       EXPECT_EQ(misc_debug_record->Data[index], '\0');
186     }
187 
188     EXPECT_EQ(observed_data, expected_debug_name);
189   } else {
190     // There should be no miscellaneous debugging record.
191     EXPECT_EQ(misc_record->DataSize, 0u);
192     EXPECT_EQ(misc_record->Rva, 0u);
193   }
194 }
195 
196 // ExpectModule() verifies that |expected| matches |observed|. Fields that are
197 // supposed to contain constant magic numbers are verified against the expected
198 // constants instead of |expected|. Reserved fields are verified to be 0. RVA
199 // and MINIDUMP_LOCATION_DESCRIPTOR fields are not verified against |expected|.
200 // Instead, |ModuleNameRva| is used to locate the module name, which is compared
201 // against |expected_module_name|. ExpectCodeViewRecord() and
202 // ExpectMiscellaneousDebugRecord() are used to verify the |CvRecord| and
203 // |MiscRecord| fields against |expected_pdb_*| and |expected_debug_*|
204 // parameters, respectively.
ExpectModule(const MINIDUMP_MODULE * expected,const MINIDUMP_MODULE * observed,const std::string & file_contents,const std::string & expected_module_name,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)205 void ExpectModule(const MINIDUMP_MODULE* expected,
206                   const MINIDUMP_MODULE* observed,
207                   const std::string& file_contents,
208                   const std::string& expected_module_name,
209                   const char* expected_pdb_name,
210                   const UUID* expected_pdb_uuid,
211                   time_t expected_pdb_timestamp,
212                   uint32_t expected_pdb_age,
213                   const char* expected_debug_name,
214                   uint32_t expected_debug_type,
215                   bool expected_debug_utf16) {
216   EXPECT_EQ(observed->BaseOfImage, expected->BaseOfImage);
217   EXPECT_EQ(observed->SizeOfImage, expected->SizeOfImage);
218   EXPECT_EQ(observed->CheckSum, expected->CheckSum);
219   EXPECT_EQ(observed->TimeDateStamp, expected->TimeDateStamp);
220   EXPECT_EQ(observed->VersionInfo.dwSignature,
221             implicit_cast<uint32_t>(VS_FFI_SIGNATURE));
222   EXPECT_EQ(observed->VersionInfo.dwStrucVersion,
223             implicit_cast<uint32_t>(VS_FFI_STRUCVERSION));
224   EXPECT_EQ(observed->VersionInfo.dwFileVersionMS,
225             expected->VersionInfo.dwFileVersionMS);
226   EXPECT_EQ(observed->VersionInfo.dwFileVersionLS,
227             expected->VersionInfo.dwFileVersionLS);
228   EXPECT_EQ(observed->VersionInfo.dwProductVersionMS,
229             expected->VersionInfo.dwProductVersionMS);
230   EXPECT_EQ(observed->VersionInfo.dwProductVersionLS,
231             expected->VersionInfo.dwProductVersionLS);
232   EXPECT_EQ(observed->VersionInfo.dwFileFlagsMask,
233             expected->VersionInfo.dwFileFlagsMask);
234   EXPECT_EQ(observed->VersionInfo.dwFileFlags,
235             expected->VersionInfo.dwFileFlags);
236   EXPECT_EQ(observed->VersionInfo.dwFileOS, expected->VersionInfo.dwFileOS);
237   EXPECT_EQ(observed->VersionInfo.dwFileType, expected->VersionInfo.dwFileType);
238   EXPECT_EQ(observed->VersionInfo.dwFileSubtype,
239             expected->VersionInfo.dwFileSubtype);
240   EXPECT_EQ(observed->VersionInfo.dwFileDateMS,
241             expected->VersionInfo.dwFileDateMS);
242   EXPECT_EQ(observed->VersionInfo.dwFileDateLS,
243             expected->VersionInfo.dwFileDateLS);
244   EXPECT_EQ(observed->Reserved0, 0u);
245   EXPECT_EQ(observed->Reserved1, 0u);
246 
247   EXPECT_NE(observed->ModuleNameRva, 0u);
248   base::string16 observed_module_name_utf16 =
249       MinidumpStringAtRVAAsString(file_contents, observed->ModuleNameRva);
250   base::string16 expected_module_name_utf16 =
251       base::UTF8ToUTF16(expected_module_name);
252   EXPECT_EQ(observed_module_name_utf16, expected_module_name_utf16);
253 
254   ASSERT_NO_FATAL_FAILURE(ExpectCodeViewRecord(&observed->CvRecord,
255                                                file_contents,
256                                                expected_pdb_name,
257                                                expected_pdb_uuid,
258                                                expected_pdb_timestamp,
259                                                expected_pdb_age));
260 
261   ASSERT_NO_FATAL_FAILURE(ExpectMiscellaneousDebugRecord(&observed->MiscRecord,
262                                                          file_contents,
263                                                          expected_debug_name,
264                                                          expected_debug_type,
265                                                          expected_debug_utf16));
266 }
267 
268 // ExpectModuleWithBuildIDCv() is like ExpectModule( but expects the module to
269 // have a BuildID CodeView Record.
ExpectModuleWithBuildIDCv(const MINIDUMP_MODULE * expected,const MINIDUMP_MODULE * observed,const std::string & file_contents,const std::string & expected_module_name,const std::vector<uint8_t> & expected_build_id)270 void ExpectModuleWithBuildIDCv(const MINIDUMP_MODULE* expected,
271                                const MINIDUMP_MODULE* observed,
272                                const std::string& file_contents,
273                                const std::string& expected_module_name,
274                                const std::vector<uint8_t>& expected_build_id) {
275   EXPECT_EQ(observed->BaseOfImage, expected->BaseOfImage);
276   EXPECT_EQ(observed->SizeOfImage, expected->SizeOfImage);
277   EXPECT_EQ(observed->CheckSum, expected->CheckSum);
278   EXPECT_EQ(observed->TimeDateStamp, expected->TimeDateStamp);
279   EXPECT_EQ(observed->VersionInfo.dwSignature,
280             implicit_cast<uint32_t>(VS_FFI_SIGNATURE));
281   EXPECT_EQ(observed->VersionInfo.dwStrucVersion,
282             implicit_cast<uint32_t>(VS_FFI_STRUCVERSION));
283   EXPECT_EQ(observed->VersionInfo.dwFileVersionMS,
284             expected->VersionInfo.dwFileVersionMS);
285   EXPECT_EQ(observed->VersionInfo.dwFileVersionLS,
286             expected->VersionInfo.dwFileVersionLS);
287   EXPECT_EQ(observed->VersionInfo.dwProductVersionMS,
288             expected->VersionInfo.dwProductVersionMS);
289   EXPECT_EQ(observed->VersionInfo.dwProductVersionLS,
290             expected->VersionInfo.dwProductVersionLS);
291   EXPECT_EQ(observed->VersionInfo.dwFileFlagsMask,
292             expected->VersionInfo.dwFileFlagsMask);
293   EXPECT_EQ(observed->VersionInfo.dwFileFlags,
294             expected->VersionInfo.dwFileFlags);
295   EXPECT_EQ(observed->VersionInfo.dwFileOS, expected->VersionInfo.dwFileOS);
296   EXPECT_EQ(observed->VersionInfo.dwFileType, expected->VersionInfo.dwFileType);
297   EXPECT_EQ(observed->VersionInfo.dwFileSubtype,
298             expected->VersionInfo.dwFileSubtype);
299   EXPECT_EQ(observed->VersionInfo.dwFileDateMS,
300             expected->VersionInfo.dwFileDateMS);
301   EXPECT_EQ(observed->VersionInfo.dwFileDateLS,
302             expected->VersionInfo.dwFileDateLS);
303   EXPECT_EQ(observed->Reserved0, 0u);
304   EXPECT_EQ(observed->Reserved1, 0u);
305 
306   EXPECT_NE(observed->ModuleNameRva, 0u);
307   base::string16 observed_module_name_utf16 =
308       MinidumpStringAtRVAAsString(file_contents, observed->ModuleNameRva);
309   base::string16 expected_module_name_utf16 =
310       base::UTF8ToUTF16(expected_module_name);
311   EXPECT_EQ(observed_module_name_utf16, expected_module_name_utf16);
312 
313   const CodeViewRecordBuildID* codeview_build_id_record =
314       MinidumpWritableAtLocationDescriptor<CodeViewRecordBuildID>(
315           file_contents, observed->CvRecord);
316   ASSERT_TRUE(codeview_build_id_record);
317   EXPECT_EQ(memcmp(expected_build_id.data(),
318                    &codeview_build_id_record->build_id,
319                    expected_build_id.size()),
320             0);
321 }
322 
TEST(MinidumpModuleWriter,EmptyModule)323 TEST(MinidumpModuleWriter, EmptyModule) {
324   MinidumpFileWriter minidump_file_writer;
325   auto module_list_writer = std::make_unique<MinidumpModuleListWriter>();
326 
327   static constexpr char kModuleName[] = "test_executable";
328 
329   auto module_writer = std::make_unique<MinidumpModuleWriter>();
330   module_writer->SetName(kModuleName);
331 
332   module_list_writer->AddModule(std::move(module_writer));
333   ASSERT_TRUE(minidump_file_writer.AddStream(std::move(module_list_writer)));
334 
335   StringFile string_file;
336   ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
337 
338   ASSERT_GT(string_file.string().size(),
339             sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) +
340                 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE));
341 
342   const MINIDUMP_MODULE_LIST* module_list = nullptr;
343   ASSERT_NO_FATAL_FAILURE(
344       GetModuleListStream(string_file.string(), &module_list));
345 
346   EXPECT_EQ(module_list->NumberOfModules, 1u);
347 
348   MINIDUMP_MODULE expected = {};
349   ASSERT_NO_FATAL_FAILURE(ExpectModule(&expected,
350                                        &module_list->Modules[0],
351                                        string_file.string(),
352                                        kModuleName,
353                                        nullptr,
354                                        nullptr,
355                                        0,
356                                        0,
357                                        nullptr,
358                                        0,
359                                        false));
360 }
361 
TEST(MinidumpModuleWriter,OneModule)362 TEST(MinidumpModuleWriter, OneModule) {
363   MinidumpFileWriter minidump_file_writer;
364   auto module_list_writer = std::make_unique<MinidumpModuleListWriter>();
365 
366   static constexpr char kModuleName[] = "statically_linked";
367   constexpr uint64_t kModuleBase = 0x10da69000;
368   constexpr uint32_t kModuleSize = 0x1000;
369   constexpr uint32_t kChecksum = 0x76543210;
370   constexpr time_t kTimestamp = 0x386d4380;
371   constexpr uint32_t kFileVersionMS = 0x00010002;
372   constexpr uint32_t kFileVersionLS = 0x00030004;
373   constexpr uint32_t kProductVersionMS = 0x00050006;
374   constexpr uint32_t kProductVersionLS = 0x00070008;
375   constexpr uint32_t kFileFlagsMask = VS_FF_DEBUG | VS_FF_PRERELEASE |
376                                       VS_FF_PATCHED | VS_FF_PRIVATEBUILD |
377                                       VS_FF_INFOINFERRED | VS_FF_SPECIALBUILD;
378   constexpr uint32_t kFileFlags = VS_FF_PRIVATEBUILD | VS_FF_SPECIALBUILD;
379   constexpr uint32_t kFileOS = VOS_DOS;
380   constexpr uint32_t kFileType = VFT_DRV;
381   constexpr uint32_t kFileSubtype = VFT2_DRV_KEYBOARD;
382   static constexpr char kPDBName[] = "statical.pdb";
383   static constexpr uint8_t kPDBUUIDBytes[16] = {0xfe,
384                                                 0xdc,
385                                                 0xba,
386                                                 0x98,
387                                                 0x76,
388                                                 0x54,
389                                                 0x32,
390                                                 0x10,
391                                                 0x08,
392                                                 0x19,
393                                                 0x2a,
394                                                 0x3b,
395                                                 0x4c,
396                                                 0x5d,
397                                                 0x6e,
398                                                 0x7f};
399   UUID pdb_uuid;
400   pdb_uuid.InitializeFromBytes(kPDBUUIDBytes);
401   constexpr uint32_t kPDBAge = 1;
402   constexpr uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME;
403   static constexpr char kDebugName[] = "statical.dbg";
404   constexpr bool kDebugUTF16 = false;
405 
406   auto module_writer = std::make_unique<MinidumpModuleWriter>();
407   module_writer->SetName(kModuleName);
408   module_writer->SetImageBaseAddress(kModuleBase);
409   module_writer->SetImageSize(kModuleSize);
410   module_writer->SetChecksum(kChecksum);
411   module_writer->SetTimestamp(kTimestamp);
412   module_writer->SetFileVersion(kFileVersionMS >> 16,
413                                 kFileVersionMS & 0xffff,
414                                 kFileVersionLS >> 16,
415                                 kFileVersionLS & 0xffff);
416   module_writer->SetProductVersion(kProductVersionMS >> 16,
417                                    kProductVersionMS & 0xffff,
418                                    kProductVersionLS >> 16,
419                                    kProductVersionLS & 0xffff);
420   module_writer->SetFileFlagsAndMask(kFileFlags, kFileFlagsMask);
421   module_writer->SetFileOS(kFileOS);
422   module_writer->SetFileTypeAndSubtype(kFileType, kFileSubtype);
423 
424   auto codeview_pdb70_writer =
425       std::make_unique<MinidumpModuleCodeViewRecordPDB70Writer>();
426   codeview_pdb70_writer->SetPDBName(kPDBName);
427   codeview_pdb70_writer->SetUUIDAndAge(pdb_uuid, kPDBAge);
428   module_writer->SetCodeViewRecord(std::move(codeview_pdb70_writer));
429 
430   auto misc_debug_writer =
431       std::make_unique<MinidumpModuleMiscDebugRecordWriter>();
432   misc_debug_writer->SetDataType(kDebugType);
433   misc_debug_writer->SetData(kDebugName, kDebugUTF16);
434   module_writer->SetMiscDebugRecord(std::move(misc_debug_writer));
435 
436   module_list_writer->AddModule(std::move(module_writer));
437   ASSERT_TRUE(minidump_file_writer.AddStream(std::move(module_list_writer)));
438 
439   StringFile string_file;
440   ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
441 
442   ASSERT_GT(string_file.string().size(),
443             sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) +
444                 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE));
445 
446   const MINIDUMP_MODULE_LIST* module_list = nullptr;
447   ASSERT_NO_FATAL_FAILURE(
448       GetModuleListStream(string_file.string(), &module_list));
449 
450   EXPECT_EQ(module_list->NumberOfModules, 1u);
451 
452   MINIDUMP_MODULE expected = {};
453   expected.BaseOfImage = kModuleBase;
454   expected.SizeOfImage = kModuleSize;
455   expected.CheckSum = kChecksum;
456   expected.TimeDateStamp = kTimestamp;
457   expected.VersionInfo.dwFileVersionMS = kFileVersionMS;
458   expected.VersionInfo.dwFileVersionLS = kFileVersionLS;
459   expected.VersionInfo.dwProductVersionMS = kProductVersionMS;
460   expected.VersionInfo.dwProductVersionLS = kProductVersionLS;
461   expected.VersionInfo.dwFileFlagsMask = kFileFlagsMask;
462   expected.VersionInfo.dwFileFlags = kFileFlags;
463   expected.VersionInfo.dwFileOS = kFileOS;
464   expected.VersionInfo.dwFileType = kFileType;
465   expected.VersionInfo.dwFileSubtype = kFileSubtype;
466 
467   ASSERT_NO_FATAL_FAILURE(ExpectModule(&expected,
468                                        &module_list->Modules[0],
469                                        string_file.string(),
470                                        kModuleName,
471                                        kPDBName,
472                                        &pdb_uuid,
473                                        0,
474                                        kPDBAge,
475                                        kDebugName,
476                                        kDebugType,
477                                        kDebugUTF16));
478 }
479 
TEST(MinidumpModuleWriter,OneModule_CodeViewUsesPDB20_MiscUsesUTF16)480 TEST(MinidumpModuleWriter, OneModule_CodeViewUsesPDB20_MiscUsesUTF16) {
481   // MinidumpModuleWriter.OneModule tested with a PDB 7.0 link as the CodeView
482   // record and an IMAGE_DEBUG_MISC record in UTF-8. This test exercises the
483   // alternatives, a PDB 2.0 link as the CodeView record and an IMAGE_DEBUG_MISC
484   // record with UTF-16 data.
485   MinidumpFileWriter minidump_file_writer;
486   auto module_list_writer = std::make_unique<MinidumpModuleListWriter>();
487 
488   static constexpr char kModuleName[] = "dinosaur";
489   static constexpr char kPDBName[] = "d1n05.pdb";
490   constexpr time_t kPDBTimestamp = 0x386d4380;
491   constexpr uint32_t kPDBAge = 1;
492   constexpr uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME;
493   static constexpr char kDebugName[] = "d1n05.dbg";
494   constexpr bool kDebugUTF16 = true;
495 
496   auto module_writer = std::make_unique<MinidumpModuleWriter>();
497   module_writer->SetName(kModuleName);
498 
499   auto codeview_pdb20_writer =
500       std::make_unique<MinidumpModuleCodeViewRecordPDB20Writer>();
501   codeview_pdb20_writer->SetPDBName(kPDBName);
502   codeview_pdb20_writer->SetTimestampAndAge(kPDBTimestamp, kPDBAge);
503   module_writer->SetCodeViewRecord(std::move(codeview_pdb20_writer));
504 
505   auto misc_debug_writer =
506       std::make_unique<MinidumpModuleMiscDebugRecordWriter>();
507   misc_debug_writer->SetDataType(kDebugType);
508   misc_debug_writer->SetData(kDebugName, kDebugUTF16);
509   module_writer->SetMiscDebugRecord(std::move(misc_debug_writer));
510 
511   module_list_writer->AddModule(std::move(module_writer));
512   ASSERT_TRUE(minidump_file_writer.AddStream(std::move(module_list_writer)));
513 
514   StringFile string_file;
515   ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
516 
517   ASSERT_GT(string_file.string().size(),
518             sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) +
519                 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE));
520 
521   const MINIDUMP_MODULE_LIST* module_list = nullptr;
522   ASSERT_NO_FATAL_FAILURE(
523       GetModuleListStream(string_file.string(), &module_list));
524 
525   EXPECT_EQ(module_list->NumberOfModules, 1u);
526 
527   MINIDUMP_MODULE expected = {};
528 
529   ASSERT_NO_FATAL_FAILURE(ExpectModule(&expected,
530                                        &module_list->Modules[0],
531                                        string_file.string(),
532                                        kModuleName,
533                                        kPDBName,
534                                        nullptr,
535                                        kPDBTimestamp,
536                                        kPDBAge,
537                                        kDebugName,
538                                        kDebugType,
539                                        kDebugUTF16));
540 }
541 
TEST(MinidumpModuleWriter,OneModule_CodeViewBuildID)542 TEST(MinidumpModuleWriter, OneModule_CodeViewBuildID) {
543   // MinidumpModuleWriter.OneModule tested with a BuildID CodeView
544   MinidumpFileWriter minidump_file_writer;
545   auto module_list_writer = std::make_unique<MinidumpModuleListWriter>();
546 
547   static constexpr char kModuleName[] = "dinosaur";
548   static constexpr char kBuildID[] =
549       "averylonghashcodeormaybeitsjustrandomnumbershardtosay";
550 
551   std::vector<uint8_t> build_id_data(kBuildID, kBuildID + 53);
552 
553   auto module_writer = std::make_unique<MinidumpModuleWriter>();
554   module_writer->SetName(kModuleName);
555 
556   auto codeview_build_id_writer =
557       std::make_unique<MinidumpModuleCodeViewRecordBuildIDWriter>();
558   codeview_build_id_writer->SetBuildID(build_id_data);
559   module_writer->SetCodeViewRecord(std::move(codeview_build_id_writer));
560 
561   module_list_writer->AddModule(std::move(module_writer));
562   ASSERT_TRUE(minidump_file_writer.AddStream(std::move(module_list_writer)));
563 
564   StringFile string_file;
565   ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
566 
567   ASSERT_GT(string_file.string().size(),
568             sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) +
569                 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE));
570 
571   const MINIDUMP_MODULE_LIST* module_list = nullptr;
572   ASSERT_NO_FATAL_FAILURE(
573       GetModuleListStream(string_file.string(), &module_list));
574 
575   EXPECT_EQ(module_list->NumberOfModules, 1u);
576 
577   MINIDUMP_MODULE expected = {};
578 
579   ASSERT_NO_FATAL_FAILURE(ExpectModuleWithBuildIDCv(&expected,
580                                                     &module_list->Modules[0],
581                                                     string_file.string(),
582                                                     kModuleName,
583                                                     build_id_data));
584 }
585 
TEST(MinidumpModuleWriter,ThreeModules)586 TEST(MinidumpModuleWriter, ThreeModules) {
587   // As good exercise, this test uses three modules, one with a PDB 7.0 link as
588   // its CodeView record, one with no CodeView record, and one with a PDB 2.0
589   // link as its CodeView record.
590   MinidumpFileWriter minidump_file_writer;
591   auto module_list_writer = std::make_unique<MinidumpModuleListWriter>();
592 
593   static constexpr char kModuleName0[] = "main";
594   constexpr uint64_t kModuleBase0 = 0x100101000;
595   constexpr uint32_t kModuleSize0 = 0xf000;
596   static constexpr char kPDBName0[] = "main";
597   static constexpr uint8_t kPDBUUIDBytes0[16] = {0xaa,
598                                                  0xbb,
599                                                  0xcc,
600                                                  0xdd,
601                                                  0xee,
602                                                  0xff,
603                                                  0x00,
604                                                  0x11,
605                                                  0x22,
606                                                  0x33,
607                                                  0x44,
608                                                  0x55,
609                                                  0x66,
610                                                  0x77,
611                                                  0x88,
612                                                  0x99};
613   UUID pdb_uuid_0;
614   pdb_uuid_0.InitializeFromBytes(kPDBUUIDBytes0);
615   constexpr uint32_t kPDBAge0 = 0;
616 
617   static constexpr char kModuleName1[] = "ld.so";
618   constexpr uint64_t kModuleBase1 = 0x200202000;
619   constexpr uint32_t kModuleSize1 = 0x1e000;
620 
621   static constexpr char kModuleName2[] = "libc.so";
622   constexpr uint64_t kModuleBase2 = 0x300303000;
623   constexpr uint32_t kModuleSize2 = 0x2d000;
624   static constexpr char kPDBName2[] = "libc.so";
625   constexpr time_t kPDBTimestamp2 = 0x386d4380;
626   constexpr uint32_t kPDBAge2 = 2;
627 
628   auto module_writer_0 = std::make_unique<MinidumpModuleWriter>();
629   module_writer_0->SetName(kModuleName0);
630   module_writer_0->SetImageBaseAddress(kModuleBase0);
631   module_writer_0->SetImageSize(kModuleSize0);
632 
633   auto codeview_pdb70_writer_0 =
634       std::make_unique<MinidumpModuleCodeViewRecordPDB70Writer>();
635   codeview_pdb70_writer_0->SetPDBName(kPDBName0);
636   codeview_pdb70_writer_0->SetUUIDAndAge(pdb_uuid_0, kPDBAge0);
637   module_writer_0->SetCodeViewRecord(std::move(codeview_pdb70_writer_0));
638 
639   module_list_writer->AddModule(std::move(module_writer_0));
640 
641   auto module_writer_1 = std::make_unique<MinidumpModuleWriter>();
642   module_writer_1->SetName(kModuleName1);
643   module_writer_1->SetImageBaseAddress(kModuleBase1);
644   module_writer_1->SetImageSize(kModuleSize1);
645 
646   module_list_writer->AddModule(std::move(module_writer_1));
647 
648   auto module_writer_2 = std::make_unique<MinidumpModuleWriter>();
649   module_writer_2->SetName(kModuleName2);
650   module_writer_2->SetImageBaseAddress(kModuleBase2);
651   module_writer_2->SetImageSize(kModuleSize2);
652 
653   auto codeview_pdb70_writer_2 =
654       std::make_unique<MinidumpModuleCodeViewRecordPDB20Writer>();
655   codeview_pdb70_writer_2->SetPDBName(kPDBName2);
656   codeview_pdb70_writer_2->SetTimestampAndAge(kPDBTimestamp2, kPDBAge2);
657   module_writer_2->SetCodeViewRecord(std::move(codeview_pdb70_writer_2));
658 
659   module_list_writer->AddModule(std::move(module_writer_2));
660 
661   ASSERT_TRUE(minidump_file_writer.AddStream(std::move(module_list_writer)));
662 
663   StringFile string_file;
664   ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
665 
666   ASSERT_GT(string_file.string().size(),
667             sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) +
668                 sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE));
669 
670   const MINIDUMP_MODULE_LIST* module_list = nullptr;
671   ASSERT_NO_FATAL_FAILURE(
672       GetModuleListStream(string_file.string(), &module_list));
673 
674   EXPECT_EQ(module_list->NumberOfModules, 3u);
675 
676   MINIDUMP_MODULE expected = {};
677 
678   {
679     SCOPED_TRACE("module 0");
680 
681     expected.BaseOfImage = kModuleBase0;
682     expected.SizeOfImage = kModuleSize0;
683 
684     ASSERT_NO_FATAL_FAILURE(ExpectModule(&expected,
685                                          &module_list->Modules[0],
686                                          string_file.string(),
687                                          kModuleName0,
688                                          kPDBName0,
689                                          &pdb_uuid_0,
690                                          0,
691                                          kPDBAge0,
692                                          nullptr,
693                                          0,
694                                          false));
695   }
696 
697   {
698     SCOPED_TRACE("module 1");
699 
700     expected.BaseOfImage = kModuleBase1;
701     expected.SizeOfImage = kModuleSize1;
702 
703     ASSERT_NO_FATAL_FAILURE(ExpectModule(&expected,
704                                          &module_list->Modules[1],
705                                          string_file.string(),
706                                          kModuleName1,
707                                          nullptr,
708                                          nullptr,
709                                          0,
710                                          0,
711                                          nullptr,
712                                          0,
713                                          false));
714   }
715 
716   {
717     SCOPED_TRACE("module 2");
718 
719     expected.BaseOfImage = kModuleBase2;
720     expected.SizeOfImage = kModuleSize2;
721 
722     ASSERT_NO_FATAL_FAILURE(ExpectModule(&expected,
723                                          &module_list->Modules[2],
724                                          string_file.string(),
725                                          kModuleName2,
726                                          kPDBName2,
727                                          nullptr,
728                                          kPDBTimestamp2,
729                                          kPDBAge2,
730                                          nullptr,
731                                          0,
732                                          false));
733   }
734 }
735 
InitializeTestModuleSnapshotFromMinidumpModule(TestModuleSnapshot * module_snapshot,const MINIDUMP_MODULE & minidump_module,const std::string & name,const std::string & pdb_name,const crashpad::UUID & uuid,uint32_t age)736 void InitializeTestModuleSnapshotFromMinidumpModule(
737     TestModuleSnapshot* module_snapshot,
738     const MINIDUMP_MODULE& minidump_module,
739     const std::string& name,
740     const std::string& pdb_name,
741     const crashpad::UUID& uuid,
742     uint32_t age) {
743   module_snapshot->SetName(name);
744 
745   module_snapshot->SetAddressAndSize(minidump_module.BaseOfImage,
746                                      minidump_module.SizeOfImage);
747   module_snapshot->SetTimestamp(minidump_module.TimeDateStamp);
748   module_snapshot->SetFileVersion(
749       minidump_module.VersionInfo.dwFileVersionMS >> 16,
750       minidump_module.VersionInfo.dwFileVersionMS & 0xffff,
751       minidump_module.VersionInfo.dwFileVersionLS >> 16,
752       minidump_module.VersionInfo.dwFileVersionLS & 0xffff);
753   module_snapshot->SetSourceVersion(
754       minidump_module.VersionInfo.dwProductVersionMS >> 16,
755       minidump_module.VersionInfo.dwProductVersionMS & 0xffff,
756       minidump_module.VersionInfo.dwProductVersionLS >> 16,
757       minidump_module.VersionInfo.dwProductVersionLS & 0xffff);
758 
759   ModuleSnapshot::ModuleType module_type;
760   switch (minidump_module.VersionInfo.dwFileType) {
761     case VFT_APP:
762       module_type = ModuleSnapshot::kModuleTypeExecutable;
763       break;
764     case VFT_DLL:
765       module_type = ModuleSnapshot::kModuleTypeSharedLibrary;
766       break;
767     default:
768       module_type = ModuleSnapshot::kModuleTypeUnknown;
769       break;
770   }
771   module_snapshot->SetModuleType(module_type);
772 
773   module_snapshot->SetUUIDAndAge(uuid, age);
774   module_snapshot->SetDebugFileName(pdb_name);
775 }
776 
TEST(MinidumpModuleWriter,InitializeFromSnapshot)777 TEST(MinidumpModuleWriter, InitializeFromSnapshot) {
778   MINIDUMP_MODULE expect_modules[3] = {};
779   const char* module_paths[base::size(expect_modules)] = {};
780   const char* module_pdbs[base::size(expect_modules)] = {};
781   UUID uuids[base::size(expect_modules)] = {};
782   uint32_t ages[base::size(expect_modules)] = {};
783 
784   expect_modules[0].BaseOfImage = 0x100101000;
785   expect_modules[0].SizeOfImage = 0xf000;
786   expect_modules[0].TimeDateStamp = 0x01234567;
787   expect_modules[0].VersionInfo.dwFileVersionMS = 0x00010002;
788   expect_modules[0].VersionInfo.dwFileVersionLS = 0x00030004;
789   expect_modules[0].VersionInfo.dwProductVersionMS = 0x00050006;
790   expect_modules[0].VersionInfo.dwProductVersionLS = 0x00070008;
791   expect_modules[0].VersionInfo.dwFileType = VFT_APP;
792   module_paths[0] = "/usr/bin/true";
793   module_pdbs[0] = "true";
794   static constexpr uint8_t kUUIDBytes0[16] = {0x00,
795                                               0x11,
796                                               0x22,
797                                               0x33,
798                                               0x44,
799                                               0x55,
800                                               0x66,
801                                               0x77,
802                                               0x88,
803                                               0x99,
804                                               0xaa,
805                                               0xbb,
806                                               0xcc,
807                                               0xdd,
808                                               0xee,
809                                               0xff};
810   uuids[0].InitializeFromBytes(kUUIDBytes0);
811   ages[0] = 10;
812 
813   expect_modules[1].BaseOfImage = 0x200202000;
814   expect_modules[1].SizeOfImage = 0x1e1000;
815   expect_modules[1].TimeDateStamp = 0x89abcdef;
816   expect_modules[1].VersionInfo.dwFileVersionMS = 0x0009000a;
817   expect_modules[1].VersionInfo.dwFileVersionLS = 0x000b000c;
818   expect_modules[1].VersionInfo.dwProductVersionMS = 0x000d000e;
819   expect_modules[1].VersionInfo.dwProductVersionLS = 0x000f0000;
820   expect_modules[1].VersionInfo.dwFileType = VFT_DLL;
821   module_paths[1] = "/usr/lib/libSystem.B.dylib";
822   module_pdbs[1] = "libSystem.B.dylib.pdb";
823   static constexpr uint8_t kUUIDBytes1[16] = {0x00,
824                                               0x01,
825                                               0x02,
826                                               0x03,
827                                               0x04,
828                                               0x05,
829                                               0x06,
830                                               0x07,
831                                               0x08,
832                                               0x09,
833                                               0x0a,
834                                               0x0b,
835                                               0x0c,
836                                               0x0d,
837                                               0x0e,
838                                               0x0f};
839   uuids[1].InitializeFromBytes(kUUIDBytes1);
840   ages[1] = 20;
841 
842   expect_modules[2].BaseOfImage = 0x300303000;
843   expect_modules[2].SizeOfImage = 0x2d000;
844   expect_modules[2].TimeDateStamp = 0x76543210;
845   expect_modules[2].VersionInfo.dwFileVersionMS = 0x11112222;
846   expect_modules[2].VersionInfo.dwFileVersionLS = 0x33334444;
847   expect_modules[2].VersionInfo.dwProductVersionMS = 0x9999aaaa;
848   expect_modules[2].VersionInfo.dwProductVersionLS = 0xbbbbcccc;
849   expect_modules[2].VersionInfo.dwFileType = VFT_UNKNOWN;
850   module_paths[2] = "/usr/lib/dyld";
851   module_pdbs[2] = "/usr/lib/dyld.pdb";
852   static constexpr uint8_t kUUIDBytes2[16] = {0xff,
853                                               0xfe,
854                                               0xfd,
855                                               0xfc,
856                                               0xfb,
857                                               0xfa,
858                                               0xf9,
859                                               0xf8,
860                                               0xf7,
861                                               0xf6,
862                                               0xf5,
863                                               0xf4,
864                                               0xf3,
865                                               0xf2,
866                                               0xf1,
867                                               0xf0};
868   uuids[2].InitializeFromBytes(kUUIDBytes2);
869   ages[2] = 30;
870 
871   std::vector<std::unique_ptr<TestModuleSnapshot>> module_snapshots_owner;
872   std::vector<const ModuleSnapshot*> module_snapshots;
873   for (size_t index = 0; index < base::size(expect_modules); ++index) {
874     module_snapshots_owner.push_back(std::make_unique<TestModuleSnapshot>());
875     TestModuleSnapshot* module_snapshot = module_snapshots_owner.back().get();
876     InitializeTestModuleSnapshotFromMinidumpModule(module_snapshot,
877                                                    expect_modules[index],
878                                                    module_paths[index],
879                                                    module_pdbs[index],
880                                                    uuids[index],
881                                                    ages[index]);
882     module_snapshots.push_back(module_snapshot);
883   }
884 
885   auto module_list_writer = std::make_unique<MinidumpModuleListWriter>();
886   module_list_writer->InitializeFromSnapshot(module_snapshots);
887 
888   MinidumpFileWriter minidump_file_writer;
889   ASSERT_TRUE(minidump_file_writer.AddStream(std::move(module_list_writer)));
890 
891   StringFile string_file;
892   ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
893 
894   const MINIDUMP_MODULE_LIST* module_list = nullptr;
895   ASSERT_NO_FATAL_FAILURE(
896       GetModuleListStream(string_file.string(), &module_list));
897 
898   ASSERT_EQ(module_list->NumberOfModules, 3u);
899 
900   for (size_t index = 0; index < module_list->NumberOfModules; ++index) {
901     SCOPED_TRACE(base::StringPrintf("index %" PRIuS, index));
902     ASSERT_NO_FATAL_FAILURE(ExpectModule(&expect_modules[index],
903                                          &module_list->Modules[index],
904                                          string_file.string(),
905                                          module_paths[index],
906                                          module_pdbs[index],
907                                          &uuids[index],
908                                          0,
909                                          ages[index],
910                                          nullptr,
911                                          0,
912                                          false));
913   }
914 }
915 
TEST(MinidumpModuleWriterDeathTest,NoModuleName)916 TEST(MinidumpModuleWriterDeathTest, NoModuleName) {
917   MinidumpFileWriter minidump_file_writer;
918   auto module_list_writer = std::make_unique<MinidumpModuleListWriter>();
919   auto module_writer = std::make_unique<MinidumpModuleWriter>();
920   module_list_writer->AddModule(std::move(module_writer));
921   ASSERT_TRUE(minidump_file_writer.AddStream(std::move(module_list_writer)));
922 
923   StringFile string_file;
924   ASSERT_DEATH_CHECK(minidump_file_writer.WriteEverything(&string_file),
925                      "name_");
926 }
927 
928 }  // namespace
929 }  // namespace test
930 }  // namespace crashpad
931