brintos

brintos / llvm-project-archived public Read only

0
0
Text · 36.1 KiB · 44a9661 Raw
776 lines · cpp
1//===- MinidumpTest.cpp - Tests for Minidump.cpp --------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Object/Minidump.h"10#include "llvm/Support/MemoryBuffer.h"11#include "llvm/Testing/Support/Error.h"12#include "gtest/gtest.h"13 14using namespace llvm;15using namespace llvm::object;16using namespace minidump;17 18static Expected<std::unique_ptr<MinidumpFile>> create(ArrayRef<uint8_t> Data) {19  return MinidumpFile::create(20      MemoryBufferRef(toStringRef(Data), "Test buffer"));21}22 23TEST(MinidumpFile, BasicInterface) {24  std::vector<uint8_t> Data{                        // Header25                            'M', 'D', 'M', 'P',     // Signature26                            0x93, 0xa7, 0, 0,       // Version27                            1, 0, 0, 0,             // NumberOfStreams,28                            0x20, 0, 0, 0,          // StreamDirectoryRVA29                            0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp30                            8, 9, 0, 1, 2, 3, 4, 5, // Flags31                                                    // Stream Directory32                            3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,33                            0x2c, 0, 0, 0,                // RVA34                                                          // Stream35                            'C', 'P', 'U', 'I', 'N', 'F', 'O'};36  // A very simple minidump file which contains just a single stream.37  auto ExpectedFile = create(Data);38  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());39  const MinidumpFile &File = **ExpectedFile;40  const Header &H = File.header();41  EXPECT_EQ(Header::MagicSignature, H.Signature);42  EXPECT_EQ(Header::MagicVersion, H.Version);43  EXPECT_EQ(1u, H.NumberOfStreams);44  EXPECT_EQ(0x20u, H.StreamDirectoryRVA);45  EXPECT_EQ(0x03020100u, H.Checksum);46  EXPECT_EQ(0x07060504u, H.TimeDateStamp);47  EXPECT_EQ(uint64_t(0x0504030201000908), H.Flags);48 49  ASSERT_EQ(1u, File.streams().size());50  const Directory &Stream0 = File.streams()[0];51  EXPECT_EQ(StreamType::LinuxCPUInfo, Stream0.Type);52  EXPECT_EQ(7u, Stream0.Location.DataSize);53  EXPECT_EQ(0x2cu, Stream0.Location.RVA);54 55  EXPECT_EQ("CPUINFO", toStringRef(File.getRawStream(Stream0)));56  EXPECT_EQ("CPUINFO",57            toStringRef(*File.getRawStream(StreamType::LinuxCPUInfo)));58 59  EXPECT_THAT_EXPECTED(File.getSystemInfo(), Failed<BinaryError>());60}61 62// Use the input from the previous test, but corrupt it in various ways63TEST(MinidumpFile, create_ErrorCases) {64  std::vector<uint8_t> FileTooShort{'M', 'D', 'M', 'P'};65  EXPECT_THAT_EXPECTED(create(FileTooShort), Failed<BinaryError>());66 67  std::vector<uint8_t> WrongSignature{68      // Header69      '!', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version70      1, 0, 0, 0,                           // NumberOfStreams,71      0x20, 0, 0, 0,                        // StreamDirectoryRVA72      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp73      8, 9, 0, 1, 2, 3, 4, 5,               // Flags74                                            // Stream Directory75      3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,76      0x2c, 0, 0, 0,                        // RVA77                                            // Stream78      'C', 'P', 'U', 'I', 'N', 'F', 'O'};79  EXPECT_THAT_EXPECTED(create(WrongSignature), Failed<BinaryError>());80 81  std::vector<uint8_t> WrongVersion{82      // Header83      'M', 'D', 'M', 'P', 0x39, 0xa7, 0, 0, // Signature, Version84      1, 0, 0, 0,                           // NumberOfStreams,85      0x20, 0, 0, 0,                        // StreamDirectoryRVA86      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp87      8, 9, 0, 1, 2, 3, 4, 5,               // Flags88                                            // Stream Directory89      3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,90      0x2c, 0, 0, 0,                        // RVA91                                            // Stream92      'C', 'P', 'U', 'I', 'N', 'F', 'O'};93  EXPECT_THAT_EXPECTED(create(WrongVersion), Failed<BinaryError>());94 95  std::vector<uint8_t> DirectoryAfterEOF{96      // Header97      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version98      1, 0, 0, 0,                           // NumberOfStreams,99      0x20, 1, 0, 0,                        // StreamDirectoryRVA100      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp101      8, 9, 0, 1, 2, 3, 4, 5,               // Flags102                                            // Stream Directory103      3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,104      0x2c, 0, 0, 0,                        // RVA105                                            // Stream106      'C', 'P', 'U', 'I', 'N', 'F', 'O'};107  EXPECT_THAT_EXPECTED(create(DirectoryAfterEOF), Failed<BinaryError>());108 109  std::vector<uint8_t> TruncatedDirectory{110      // Header111      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version112      1, 1, 0, 0,                           // NumberOfStreams,113      0x20, 0, 0, 0,                        // StreamDirectoryRVA114      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp115      8, 9, 0, 1, 2, 3, 4, 5,               // Flags116                                            // Stream Directory117      3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,118      0x2c, 0, 0, 0,                        // RVA119                                            // Stream120      'C', 'P', 'U', 'I', 'N', 'F', 'O'};121  EXPECT_THAT_EXPECTED(create(TruncatedDirectory), Failed<BinaryError>());122 123  std::vector<uint8_t> Stream0AfterEOF{124      // Header125      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version126      1, 0, 0, 0,                           // NumberOfStreams,127      0x20, 0, 0, 0,                        // StreamDirectoryRVA128      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp129      8, 9, 0, 1, 2, 3, 4, 5,               // Flags130                                            // Stream Directory131      3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,132      0x2c, 1, 0, 0,                        // RVA133                                            // Stream134      'C', 'P', 'U', 'I', 'N', 'F', 'O'};135  EXPECT_THAT_EXPECTED(create(Stream0AfterEOF), Failed<BinaryError>());136 137  std::vector<uint8_t> Stream0Truncated{138      // Header139      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version140      1, 0, 0, 0,                           // NumberOfStreams,141      0x20, 0, 0, 0,                        // StreamDirectoryRVA142      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp143      8, 9, 0, 1, 2, 3, 4, 5,               // Flags144                                            // Stream Directory145      3, 0, 0x67, 0x47, 8, 0, 0, 0,         // Type, DataSize,146      0x2c, 0, 0, 0,                        // RVA147                                            // Stream148      'C', 'P', 'U', 'I', 'N', 'F', 'O'};149  EXPECT_THAT_EXPECTED(create(Stream0Truncated), Failed<BinaryError>());150 151  std::vector<uint8_t> DuplicateStream{152      // Header153      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version154      2, 0, 0, 0,                           // NumberOfStreams,155      0x20, 0, 0, 0,                        // StreamDirectoryRVA156      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp157      8, 9, 0, 1, 2, 3, 4, 5,               // Flags158                                            // Stream Directory159      3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,160      0x40, 0, 0, 0,                        // RVA161                                            // Stream162      3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,163      0x40, 0, 0, 0,                        // RVA164                                            // Stream165      'C', 'P', 'U', 'I', 'N', 'F', 'O'};166  EXPECT_THAT_EXPECTED(create(DuplicateStream), Failed<BinaryError>());167 168  std::vector<uint8_t> DenseMapInfoConflict{169      // Header170      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version171      1, 0, 0, 0,                           // NumberOfStreams,172      0x20, 0, 0, 0,                        // StreamDirectoryRVA173      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp174      8, 9, 0, 1, 2, 3, 4, 5,               // Flags175                                            // Stream Directory176      0xff, 0xff, 0xff, 0xff, 7, 0, 0, 0,   // Type, DataSize,177      0x2c, 0, 0, 0,                        // RVA178                                            // Stream179      'C', 'P', 'U', 'I', 'N', 'F', 'O'};180  EXPECT_THAT_EXPECTED(create(DenseMapInfoConflict), Failed<BinaryError>());181}182 183TEST(MinidumpFile, IngoresDummyStreams) {184  std::vector<uint8_t> TwoDummyStreams{185      // Header186      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version187      2, 0, 0, 0,                           // NumberOfStreams,188      0x20, 0, 0, 0,                        // StreamDirectoryRVA189      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp190      8, 9, 0, 1, 2, 3, 4, 5,               // Flags191                                            // Stream Directory192      0, 0, 0, 0, 0, 0, 0, 0,               // Type, DataSize,193      0x20, 0, 0, 0,                        // RVA194      0, 0, 0, 0, 0, 0, 0, 0,               // Type, DataSize,195      0x20, 0, 0, 0,                        // RVA196  };197  auto ExpectedFile = create(TwoDummyStreams);198  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());199  const MinidumpFile &File = **ExpectedFile;200  ASSERT_EQ(2u, File.streams().size());201  EXPECT_EQ(StreamType::Unused, File.streams()[0].Type);202  EXPECT_EQ(StreamType::Unused, File.streams()[1].Type);203  EXPECT_EQ(std::nullopt, File.getRawStream(StreamType::Unused));204}205 206TEST(MinidumpFile, getSystemInfo) {207  std::vector<uint8_t> Data{208      // Header209      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version210      1, 0, 0, 0,                           // NumberOfStreams,211      0x20, 0, 0, 0,                        // StreamDirectoryRVA212      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp213      8, 9, 0, 1, 2, 3, 4, 5,               // Flags214                                            // Stream Directory215      7, 0, 0, 0, 56, 0, 0, 0,              // Type, DataSize,216      0x2c, 0, 0, 0,                        // RVA217                                            // SystemInfo218      0, 0, 1, 2,                           // ProcessorArch, ProcessorLevel219      3, 4, 5, 6, // ProcessorRevision, NumberOfProcessors, ProductType220      7, 8, 9, 0, 1, 2, 3, 4, // MajorVersion, MinorVersion221      5, 6, 7, 8, 2, 0, 0, 0, // BuildNumber, PlatformId222      1, 2, 3, 4, 5, 6, 7, 8, // CSDVersionRVA, SuiteMask, Reserved223      'L', 'L', 'V', 'M', 'L', 'L', 'V', 'M', 'L', 'L', 'V', 'M', // VendorID224      1, 2, 3, 4, 5, 6, 7, 8, // VersionInfo, FeatureInfo225      9, 0, 1, 2,             // AMDExtendedFeatures226  };227  auto ExpectedFile = create(Data);228  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());229  const MinidumpFile &File = **ExpectedFile;230 231  auto ExpectedInfo = File.getSystemInfo();232  ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());233  const SystemInfo &Info = *ExpectedInfo;234  EXPECT_EQ(ProcessorArchitecture::X86, Info.ProcessorArch);235  EXPECT_EQ(0x0201, Info.ProcessorLevel);236  EXPECT_EQ(0x0403, Info.ProcessorRevision);237  EXPECT_EQ(5, Info.NumberOfProcessors);238  EXPECT_EQ(6, Info.ProductType);239  EXPECT_EQ(0x00090807u, Info.MajorVersion);240  EXPECT_EQ(0x04030201u, Info.MinorVersion);241  EXPECT_EQ(0x08070605u, Info.BuildNumber);242  EXPECT_EQ(OSPlatform::Win32NT, Info.PlatformId);243  EXPECT_EQ(0x04030201u, Info.CSDVersionRVA);244  EXPECT_EQ(0x0605u, Info.SuiteMask);245  EXPECT_EQ(0x0807u, Info.Reserved);246  EXPECT_EQ("LLVMLLVMLLVM", llvm::StringRef(Info.CPU.X86.VendorID,247                                            sizeof(Info.CPU.X86.VendorID)));248  EXPECT_EQ(0x04030201u, Info.CPU.X86.VersionInfo);249  EXPECT_EQ(0x08070605u, Info.CPU.X86.FeatureInfo);250  EXPECT_EQ(0x02010009u, Info.CPU.X86.AMDExtendedFeatures);251}252 253TEST(MinidumpFile, getString) {254  std::vector<uint8_t> ManyStrings{255      // Header256      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version257      2, 0, 0, 0,                           // NumberOfStreams,258      0x20, 0, 0, 0,                        // StreamDirectoryRVA259      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp260      8, 9, 0, 1, 2, 3, 4, 5,               // Flags261                                            // Stream Directory262      0, 0, 0, 0, 0, 0, 0, 0,               // Type, DataSize,263      0x20, 0, 0, 0,                        // RVA264      1, 0, 0, 0, 0, 0,                     // String1 - odd length265      0, 0, 1, 0, 0, 0,                     // String2 - too long266      2, 0, 0, 0, 0, 0xd8,                  // String3 - invalid utf16267      0, 0, 0, 0, 0, 0,                     // String4 - ""268      2, 0, 0, 0, 'a', 0,                   // String5 - "a"269      0,                                    // Mis-align next string270      2, 0, 0, 0, 'a', 0,                   // String6 - "a"271 272  };273  auto ExpectedFile = create(ManyStrings);274  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());275  const MinidumpFile &File = **ExpectedFile;276  EXPECT_THAT_EXPECTED(File.getString(44), Failed<BinaryError>());277  EXPECT_THAT_EXPECTED(File.getString(50), Failed<BinaryError>());278  EXPECT_THAT_EXPECTED(File.getString(56), Failed<BinaryError>());279  EXPECT_THAT_EXPECTED(File.getString(62), HasValue(""));280  EXPECT_THAT_EXPECTED(File.getString(68), HasValue("a"));281  EXPECT_THAT_EXPECTED(File.getString(75), HasValue("a"));282 283  // Check the case when the size field does not fit into the remaining data.284  EXPECT_THAT_EXPECTED(File.getString(ManyStrings.size() - 2),285                       Failed<BinaryError>());286}287 288TEST(MinidumpFile, getModuleList) {289  std::vector<uint8_t> OneModule{290      // Header291      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version292      1, 0, 0, 0,                           // NumberOfStreams,293      32, 0, 0, 0,                          // StreamDirectoryRVA294      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp295      0, 0, 0, 0, 0, 0, 0, 0,               // Flags296                                            // Stream Directory297      4, 0, 0, 0, 112, 0, 0, 0,             // Type, DataSize,298      44, 0, 0, 0,                          // RVA299      // ModuleList300      1, 0, 0, 0,             // NumberOfModules301      1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage302      9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum303      7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA304      0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion305      0, 0, 0, 0, 0, 0, 0, 0, // FileVersion306      0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion307      0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags308      0, 0, 0, 0,             // FileOS309      0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType310      0, 0, 0, 0, 0, 0, 0, 0, // FileDate311      1, 2, 3, 4, 5, 6, 7, 8, // CvRecord312      9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord313      7, 8, 9, 0, 1, 2, 3, 4, // Reserved0314      5, 6, 7, 8, 9, 0, 1, 2, // Reserved1315  };316  // Same as before, but with a padded module list.317  std::vector<uint8_t> PaddedModule{318      // Header319      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version320      1, 0, 0, 0,                           // NumberOfStreams,321      32, 0, 0, 0,                          // StreamDirectoryRVA322      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp323      0, 0, 0, 0, 0, 0, 0, 0,               // Flags324                                            // Stream Directory325      4, 0, 0, 0, 116, 0, 0, 0,             // Type, DataSize,326      44, 0, 0, 0,                          // RVA327      // ModuleList328      1, 0, 0, 0,             // NumberOfModules329      0, 0, 0, 0,             // Padding330      1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage331      9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum332      7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA333      0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion334      0, 0, 0, 0, 0, 0, 0, 0, // FileVersion335      0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion336      0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags337      0, 0, 0, 0,             // FileOS338      0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType339      0, 0, 0, 0, 0, 0, 0, 0, // FileDate340      1, 2, 3, 4, 5, 6, 7, 8, // CvRecord341      9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord342      7, 8, 9, 0, 1, 2, 3, 4, // Reserved0343      5, 6, 7, 8, 9, 0, 1, 2, // Reserved1344  };345 346  for (ArrayRef<uint8_t> Data : {OneModule, PaddedModule}) {347    auto ExpectedFile = create(Data);348    ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());349    const MinidumpFile &File = **ExpectedFile;350    Expected<ArrayRef<Module>> ExpectedModule = File.getModuleList();351    ASSERT_THAT_EXPECTED(ExpectedModule, Succeeded());352    ASSERT_EQ(1u, ExpectedModule->size());353    const Module &M = ExpectedModule.get()[0];354    EXPECT_EQ(0x0807060504030201u, M.BaseOfImage);355    EXPECT_EQ(0x02010009u, M.SizeOfImage);356    EXPECT_EQ(0x06050403u, M.Checksum);357    EXPECT_EQ(0x00090807u, M.TimeDateStamp);358    EXPECT_EQ(0x04030201u, M.ModuleNameRVA);359    EXPECT_EQ(0x04030201u, M.CvRecord.DataSize);360    EXPECT_EQ(0x08070605u, M.CvRecord.RVA);361    EXPECT_EQ(0x02010009u, M.MiscRecord.DataSize);362    EXPECT_EQ(0x06050403u, M.MiscRecord.RVA);363    EXPECT_EQ(0x0403020100090807u, M.Reserved0);364    EXPECT_EQ(0x0201000908070605u, M.Reserved1);365  }366 367  std::vector<uint8_t> StreamTooShort{368      // Header369      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version370      1, 0, 0, 0,                           // NumberOfStreams,371      32, 0, 0, 0,                          // StreamDirectoryRVA372      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp373      0, 0, 0, 0, 0, 0, 0, 0,               // Flags374                                            // Stream Directory375      4, 0, 0, 0, 111, 0, 0, 0,             // Type, DataSize,376      44, 0, 0, 0,                          // RVA377      // ModuleList378      1, 0, 0, 0,             // NumberOfModules379      1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage380      9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum381      7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA382      0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion383      0, 0, 0, 0, 0, 0, 0, 0, // FileVersion384      0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion385      0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags386      0, 0, 0, 0,             // FileOS387      0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType388      0, 0, 0, 0, 0, 0, 0, 0, // FileDate389      1, 2, 3, 4, 5, 6, 7, 8, // CvRecord390      9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord391      7, 8, 9, 0, 1, 2, 3, 4, // Reserved0392      5, 6, 7, 8, 9, 0, 1, 2, // Reserved1393  };394  auto ExpectedFile = create(StreamTooShort);395  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());396  const MinidumpFile &File = **ExpectedFile;397  EXPECT_THAT_EXPECTED(File.getModuleList(), Failed<BinaryError>());398}399 400TEST(MinidumpFile, getThreadList) {401  std::vector<uint8_t> OneThread{402      // Header403      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version404      1, 0, 0, 0,                           // NumberOfStreams,405      32, 0, 0, 0,                          // StreamDirectoryRVA406      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp407      0, 0, 0, 0, 0, 0, 0, 0,               // Flags408                                            // Stream Directory409      3, 0, 0, 0, 52, 0, 0, 0,              // Type, DataSize,410      44, 0, 0, 0,                          // RVA411      // ThreadList412      1, 0, 0, 0,             // NumberOfThreads413      1, 2, 3, 4, 5, 6, 7, 8, // ThreadId, SuspendCount414      9, 0, 1, 2, 3, 4, 5, 6, // PriorityClass, Priority415      7, 8, 9, 0, 1, 2, 3, 4, // EnvironmentBlock416      // Stack417      5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange418      3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA419      // Context420      1, 2, 3, 4, 5, 6, 7, 8, // DataSize, RVA421  };422  // Same as before, but with a padded thread list.423  std::vector<uint8_t> PaddedThread{424      // Header425      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version426      1, 0, 0, 0,                           // NumberOfStreams,427      32, 0, 0, 0,                          // StreamDirectoryRVA428      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp429      0, 0, 0, 0, 0, 0, 0, 0,               // Flags430                                            // Stream Directory431      3, 0, 0, 0, 56, 0, 0, 0,              // Type, DataSize,432      44, 0, 0, 0,                          // RVA433      // ThreadList434      1, 0, 0, 0,             // NumberOfThreads435      0, 0, 0, 0,             // Padding436      1, 2, 3, 4, 5, 6, 7, 8, // ThreadId, SuspendCount437      9, 0, 1, 2, 3, 4, 5, 6, // PriorityClass, Priority438      7, 8, 9, 0, 1, 2, 3, 4, // EnvironmentBlock439      // Stack440      5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange441      3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA442      // Context443      1, 2, 3, 4, 5, 6, 7, 8, // DataSize, RVA444  };445 446  for (ArrayRef<uint8_t> Data : {OneThread, PaddedThread}) {447    auto ExpectedFile = create(Data);448    ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());449    const MinidumpFile &File = **ExpectedFile;450    Expected<ArrayRef<Thread>> ExpectedThread = File.getThreadList();451    ASSERT_THAT_EXPECTED(ExpectedThread, Succeeded());452    ASSERT_EQ(1u, ExpectedThread->size());453    const Thread &T = ExpectedThread.get()[0];454    EXPECT_EQ(0x04030201u, T.ThreadId);455    EXPECT_EQ(0x08070605u, T.SuspendCount);456    EXPECT_EQ(0x02010009u, T.PriorityClass);457    EXPECT_EQ(0x06050403u, T.Priority);458    EXPECT_EQ(0x0403020100090807u, T.EnvironmentBlock);459    EXPECT_EQ(0x0201000908070605u, T.Stack.StartOfMemoryRange);460    EXPECT_EQ(0x06050403u, T.Stack.Memory.DataSize);461    EXPECT_EQ(0x00090807u, T.Stack.Memory.RVA);462    EXPECT_EQ(0x04030201u, T.Context.DataSize);463    EXPECT_EQ(0x08070605u, T.Context.RVA);464  }465}466 467TEST(MinidumpFile, getMemoryList) {468  std::vector<uint8_t> OneRange{469      // Header470      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version471      1, 0, 0, 0,                           // NumberOfStreams,472      32, 0, 0, 0,                          // StreamDirectoryRVA473      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp474      0, 0, 0, 0, 0, 0, 0, 0,               // Flags475                                            // Stream Directory476      5, 0, 0, 0, 20, 0, 0, 0,              // Type, DataSize,477      44, 0, 0, 0,                          // RVA478      // MemoryDescriptor479      1, 0, 0, 0,             // NumberOfMemoryRanges480      5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange481      3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA482  };483  // Same as before, but with a padded memory list.484  std::vector<uint8_t> PaddedRange{485      // Header486      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version487      1, 0, 0, 0,                           // NumberOfStreams,488      32, 0, 0, 0,                          // StreamDirectoryRVA489      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp490      0, 0, 0, 0, 0, 0, 0, 0,               // Flags491                                            // Stream Directory492      5, 0, 0, 0, 24, 0, 0, 0,              // Type, DataSize,493      44, 0, 0, 0,                          // RVA494      // MemoryDescriptor495      1, 0, 0, 0,             // NumberOfMemoryRanges496      0, 0, 0, 0,             // Padding497      5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange498      3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA499  };500 501  for (ArrayRef<uint8_t> Data : {OneRange, PaddedRange}) {502    auto ExpectedFile = create(Data);503    ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());504    const MinidumpFile &File = **ExpectedFile;505    Expected<ArrayRef<MemoryDescriptor>> ExpectedRanges = File.getMemoryList();506    ASSERT_THAT_EXPECTED(ExpectedRanges, Succeeded());507    ASSERT_EQ(1u, ExpectedRanges->size());508    const MemoryDescriptor &MD = ExpectedRanges.get()[0];509    EXPECT_EQ(0x0201000908070605u, MD.StartOfMemoryRange);510    EXPECT_EQ(0x06050403u, MD.Memory.DataSize);511    EXPECT_EQ(0x00090807u, MD.Memory.RVA);512  }513}514 515TEST(MinidumpFile, getMemoryInfoList) {516  std::vector<uint8_t> OneEntry{517      // Header518      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version519      1, 0, 0, 0,                           // NumberOfStreams,520      32, 0, 0, 0,                          // StreamDirectoryRVA521      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp522      0, 0, 0, 0, 0, 0, 0, 0,               // Flags523                                            // Stream Directory524      16, 0, 0, 0, 64, 0, 0, 0,             // Type, DataSize,525      44, 0, 0, 0,                          // RVA526      // MemoryInfoListHeader527      16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry528      1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries529      // MemoryInfo530      0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress531      8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase532      16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0533      0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize534      0, 16, 0, 0, 32, 0, 0, 0, // State, Protect535      0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1536  };537 538  // Same as before, but the list header is larger.539  std::vector<uint8_t> BiggerHeader{540      // Header541      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version542      1, 0, 0, 0,                           // NumberOfStreams,543      32, 0, 0, 0,                          // StreamDirectoryRVA544      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp545      0, 0, 0, 0, 0, 0, 0, 0,               // Flags546                                            // Stream Directory547      16, 0, 0, 0, 68, 0, 0, 0,             // Type, DataSize,548      44, 0, 0, 0,                          // RVA549      // MemoryInfoListHeader550      20, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry551      1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries552      0, 0, 0, 0,               // ???553      // MemoryInfo554      0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress555      8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase556      16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0557      0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize558      0, 16, 0, 0, 32, 0, 0, 0, // State, Protect559      0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1560  };561 562  // Same as before, but the entry is larger.563  std::vector<uint8_t> BiggerEntry{564      // Header565      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version566      1, 0, 0, 0,                           // NumberOfStreams,567      32, 0, 0, 0,                          // StreamDirectoryRVA568      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp569      0, 0, 0, 0, 0, 0, 0, 0,               // Flags570                                            // Stream Directory571      16, 0, 0, 0, 68, 0, 0, 0,             // Type, DataSize,572      44, 0, 0, 0,                          // RVA573      // MemoryInfoListHeader574      16, 0, 0, 0, 52, 0, 0, 0, // SizeOfHeader, SizeOfEntry575      1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries576      // MemoryInfo577      0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress578      8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase579      16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0580      0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize581      0, 16, 0, 0, 32, 0, 0, 0, // State, Protect582      0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1583      0, 0, 0, 0,               // ???584  };585 586  for (ArrayRef<uint8_t> Data : {OneEntry, BiggerHeader, BiggerEntry}) {587    auto ExpectedFile = create(Data);588    ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());589    const MinidumpFile &File = **ExpectedFile;590    auto ExpectedInfo = File.getMemoryInfoList();591    ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());592    ASSERT_EQ(1, std::distance(ExpectedInfo->begin(), ExpectedInfo->end()));593    const MemoryInfo &Info = *ExpectedInfo.get().begin();594    EXPECT_EQ(0x0706050403020100u, Info.BaseAddress);595    EXPECT_EQ(0x0504030201000908u, Info.AllocationBase);596    EXPECT_EQ(MemoryProtection::Execute, Info.AllocationProtect);597    EXPECT_EQ(0x09080706u, Info.Reserved0);598    EXPECT_EQ(0x0706050403020100u, Info.RegionSize);599    EXPECT_EQ(MemoryState::Commit, Info.State);600    EXPECT_EQ(MemoryProtection::ExecuteRead, Info.Protect);601    EXPECT_EQ(MemoryType::Private, Info.Type);602    EXPECT_EQ(0x01000908u, Info.Reserved1);603  }604 605  // Header does not fit into the stream.606  std::vector<uint8_t> HeaderTooBig{607      // Header608      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version609      1, 0, 0, 0,                           // NumberOfStreams,610      32, 0, 0, 0,                          // StreamDirectoryRVA611      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp612      0, 0, 0, 0, 0, 0, 0, 0,               // Flags613                                            // Stream Directory614      16, 0, 0, 0, 15, 0, 0, 0,             // Type, DataSize,615      44, 0, 0, 0,                          // RVA616      // MemoryInfoListHeader617      16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry618      1, 0, 0, 0, 0, 0, 0,      // ???619  };620  Expected<std::unique_ptr<MinidumpFile>> File = create(HeaderTooBig);621  ASSERT_THAT_EXPECTED(File, Succeeded());622  EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());623 624  // Header fits into the stream, but it is too small to contain the required625  // entries.626  std::vector<uint8_t> HeaderTooSmall{627      // Header628      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version629      1, 0, 0, 0,                           // NumberOfStreams,630      32, 0, 0, 0,                          // StreamDirectoryRVA631      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp632      0, 0, 0, 0, 0, 0, 0, 0,               // Flags633                                            // Stream Directory634      16, 0, 0, 0, 15, 0, 0, 0,             // Type, DataSize,635      44, 0, 0, 0,                          // RVA636      // MemoryInfoListHeader637      15, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry638      1, 0, 0, 0, 0, 0, 0,      // ???639  };640  File = create(HeaderTooSmall);641  ASSERT_THAT_EXPECTED(File, Succeeded());642  EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());643 644  std::vector<uint8_t> EntryTooBig{645      // Header646      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version647      1, 0, 0, 0,                           // NumberOfStreams,648      32, 0, 0, 0,                          // StreamDirectoryRVA649      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp650      0, 0, 0, 0, 0, 0, 0, 0,               // Flags651                                            // Stream Directory652      16, 0, 0, 0, 64, 0, 0, 0,             // Type, DataSize,653      44, 0, 0, 0,                          // RVA654      // MemoryInfoListHeader655      16, 0, 0, 0, 49, 0, 0, 0, // SizeOfHeader, SizeOfEntry656      1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries657      // MemoryInfo658      0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress659      8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase660      16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0661      0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize662      0, 16, 0, 0, 32, 0, 0, 0, // State, Protect663      0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1664  };665  File = create(EntryTooBig);666  ASSERT_THAT_EXPECTED(File, Succeeded());667  EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());668 669  std::vector<uint8_t> ThreeEntries{670      // Header671      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version672      1, 0, 0, 0,                           // NumberOfStreams,673      32, 0, 0, 0,                          // StreamDirectoryRVA674      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp675      0, 0, 0, 0, 0, 0, 0, 0,               // Flags676                                            // Stream Directory677      16, 0, 0, 0, 160, 0, 0, 0,            // Type, DataSize,678      44, 0, 0, 0,                          // RVA679      // MemoryInfoListHeader680      16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry681      3, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries682      // MemoryInfo683      0, 1, 2, 3, 0, 0, 0, 0, // BaseAddress684      0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase685      0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0686      0, 0, 0, 0, 0, 0, 0, 0, // RegionSize687      0, 0, 0, 0, 0, 0, 0, 0, // State, Protect688      0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1689      0, 0, 4, 5, 6, 7, 0, 0, // BaseAddress690      0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase691      0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0692      0, 0, 0, 0, 0, 0, 0, 0, // RegionSize693      0, 0, 0, 0, 0, 0, 0, 0, // State, Protect694      0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1695      0, 0, 0, 8, 9, 0, 1, 0, // BaseAddress696      0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase697      0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0698      0, 0, 0, 0, 0, 0, 0, 0, // RegionSize699      0, 0, 0, 0, 0, 0, 0, 0, // State, Protect700      0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1701  };702  File = create(ThreeEntries);703  ASSERT_THAT_EXPECTED(File, Succeeded());704  auto ExpectedInfo = File.get()->getMemoryInfoList();705  ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());706  EXPECT_THAT(to_vector<3>(map_range(*ExpectedInfo,707                                     [](const MemoryInfo &Info) -> uint64_t {708                                       return Info.BaseAddress;709                                     })),710              testing::ElementsAre(0x0000000003020100u, 0x0000070605040000u,711                                   0x0001000908000000u));712}713 714TEST(MinidumpFile, getExceptionStreams) {715  std::vector<uint8_t> Data{716      // Header717      'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version718      1, 0, 0, 0,                           // NumberOfStreams,719      0x20, 0, 0, 0,                        // StreamDirectoryRVA720      0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp721      8, 9, 0, 1, 2, 3, 4, 5,               // Flags722      // Stream Directory723      6, 0, 0, 0, 168, 0, 0, 0, // Type, DataSize,724      0x2c, 0, 0, 0,            // RVA725      // Exception Stream726      1, 2, 3, 4, // Thread ID727      0, 0, 0, 0, // Padding728      // Exception Record729      2, 3, 4, 2, 7, 8, 8, 9,  // Code, Flags730      3, 4, 5, 6, 7, 8, 9, 10, // Inner exception record address731      8, 7, 6, 5, 4, 3, 2, 1,  // Exception address732      4, 0, 0, 0, 0, 0, 0, 0,  // Parameter count, padding733      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, // Parameter 0734      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, // Parameter 1735      0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Parameter 2736      0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, // Parameter 3737      0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // Parameter 4738      0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // Parameter 5739      0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // Parameter 6740      0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, // Parameter 7741      0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, // Parameter 8742      0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, // Parameter 9743      0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, // Parameter 10744      0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, // Parameter 11745      0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, // Parameter 12746      0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, // Parameter 13747      0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, // Parameter 14748      // Thread Context749      0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, // DataSize, RVA750  };751  auto ExpectedFile = create(Data);752  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());753  const MinidumpFile &File = **ExpectedFile;754 755  auto ExceptionStreams = File.getExceptionStreams();756  ASSERT_NE(ExceptionStreams.begin(), ExceptionStreams.end());757  auto ExceptionIterator = ExceptionStreams.begin();758  Expected<const ExceptionStream &> ExpectedStream = *ExceptionIterator;759  ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded());760  EXPECT_EQ(0x04030201u, ExpectedStream->ThreadId);761  const minidump::Exception &Exception = ExpectedStream->ExceptionRecord;762  EXPECT_EQ(0x02040302u, Exception.ExceptionCode);763  EXPECT_EQ(0x09080807u, Exception.ExceptionFlags);764  EXPECT_EQ(0x0a09080706050403u, Exception.ExceptionRecord);765  EXPECT_EQ(0x0102030405060708u, Exception.ExceptionAddress);766  EXPECT_EQ(4u, Exception.NumberParameters);767  for (uint64_t index = 0; index < Exception.MaxParameters; ++index) {768    EXPECT_EQ(0x1716151413121110u + index * 0x1010101010101010u,769              Exception.ExceptionInformation[index]);770  }771  EXPECT_EQ(0x84838281, ExpectedStream->ThreadContext.DataSize);772  EXPECT_EQ(0x88878685, ExpectedStream->ThreadContext.RVA);773  ++ExceptionIterator;774  ASSERT_EQ(ExceptionIterator, ExceptionStreams.end());775}776