xref: /llvm-project/llvm/unittests/Object/MinidumpTest.cpp (revision deba13409245aabf3fda8b82a873336ea5238d3a)
1581d79a4SPavel Labath //===- MinidumpTest.cpp - Tests for Minidump.cpp --------------------------===//
2581d79a4SPavel Labath //
3581d79a4SPavel Labath // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4581d79a4SPavel Labath // See https://llvm.org/LICENSE.txt for license information.
5581d79a4SPavel Labath // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6581d79a4SPavel Labath //
7581d79a4SPavel Labath //===----------------------------------------------------------------------===//
8581d79a4SPavel Labath 
9581d79a4SPavel Labath #include "llvm/Object/Minidump.h"
10581d79a4SPavel Labath #include "llvm/Support/MemoryBuffer.h"
11581d79a4SPavel Labath #include "llvm/Testing/Support/Error.h"
12581d79a4SPavel Labath #include "gtest/gtest.h"
13581d79a4SPavel Labath 
14581d79a4SPavel Labath using namespace llvm;
15581d79a4SPavel Labath using namespace llvm::object;
16581d79a4SPavel Labath using namespace minidump;
17581d79a4SPavel Labath 
18581d79a4SPavel Labath static Expected<std::unique_ptr<MinidumpFile>> create(ArrayRef<uint8_t> Data) {
19581d79a4SPavel Labath   return MinidumpFile::create(
20581d79a4SPavel Labath       MemoryBufferRef(toStringRef(Data), "Test buffer"));
21581d79a4SPavel Labath }
22581d79a4SPavel Labath 
23581d79a4SPavel Labath TEST(MinidumpFile, BasicInterface) {
24045b8544SPavel Labath   std::vector<uint8_t> Data{                        // Header
25045b8544SPavel Labath                             'M', 'D', 'M', 'P',     // Signature
26045b8544SPavel Labath                             0x93, 0xa7, 0, 0,       // Version
27581d79a4SPavel Labath                             1, 0, 0, 0,             // NumberOfStreams,
28581d79a4SPavel Labath                             0x20, 0, 0, 0,          // StreamDirectoryRVA
29581d79a4SPavel Labath                             0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
30581d79a4SPavel Labath                             8, 9, 0, 1, 2, 3, 4, 5, // Flags
31581d79a4SPavel Labath                                                     // Stream Directory
32581d79a4SPavel Labath                             3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
33581d79a4SPavel Labath                             0x2c, 0, 0, 0,                // RVA
34581d79a4SPavel Labath                                                           // Stream
35045b8544SPavel Labath                             'C', 'P', 'U', 'I', 'N', 'F', 'O'};
36045b8544SPavel Labath   // A very simple minidump file which contains just a single stream.
37045b8544SPavel Labath   auto ExpectedFile = create(Data);
38581d79a4SPavel Labath   ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
39581d79a4SPavel Labath   const MinidumpFile &File = **ExpectedFile;
40581d79a4SPavel Labath   const Header &H = File.header();
41581d79a4SPavel Labath   EXPECT_EQ(Header::MagicSignature, H.Signature);
42581d79a4SPavel Labath   EXPECT_EQ(Header::MagicVersion, H.Version);
43581d79a4SPavel Labath   EXPECT_EQ(1u, H.NumberOfStreams);
44581d79a4SPavel Labath   EXPECT_EQ(0x20u, H.StreamDirectoryRVA);
45581d79a4SPavel Labath   EXPECT_EQ(0x03020100u, H.Checksum);
46581d79a4SPavel Labath   EXPECT_EQ(0x07060504u, H.TimeDateStamp);
47581d79a4SPavel Labath   EXPECT_EQ(uint64_t(0x0504030201000908), H.Flags);
48581d79a4SPavel Labath 
49581d79a4SPavel Labath   ASSERT_EQ(1u, File.streams().size());
50581d79a4SPavel Labath   const Directory &Stream0 = File.streams()[0];
51581d79a4SPavel Labath   EXPECT_EQ(StreamType::LinuxCPUInfo, Stream0.Type);
52581d79a4SPavel Labath   EXPECT_EQ(7u, Stream0.Location.DataSize);
53581d79a4SPavel Labath   EXPECT_EQ(0x2cu, Stream0.Location.RVA);
54581d79a4SPavel Labath 
55581d79a4SPavel Labath   EXPECT_EQ("CPUINFO", toStringRef(File.getRawStream(Stream0)));
56581d79a4SPavel Labath   EXPECT_EQ("CPUINFO",
57581d79a4SPavel Labath             toStringRef(*File.getRawStream(StreamType::LinuxCPUInfo)));
58581d79a4SPavel Labath 
59581d79a4SPavel Labath   EXPECT_THAT_EXPECTED(File.getSystemInfo(), Failed<BinaryError>());
60581d79a4SPavel Labath }
61581d79a4SPavel Labath 
62581d79a4SPavel Labath // Use the input from the previous test, but corrupt it in various ways
63581d79a4SPavel Labath TEST(MinidumpFile, create_ErrorCases) {
64045b8544SPavel Labath   std::vector<uint8_t> FileTooShort{'M', 'D', 'M', 'P'};
65045b8544SPavel Labath   EXPECT_THAT_EXPECTED(create(FileTooShort), Failed<BinaryError>());
66581d79a4SPavel Labath 
67045b8544SPavel Labath   std::vector<uint8_t> WrongSignature{
68045b8544SPavel Labath       // Header
69581d79a4SPavel Labath       '!', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
70581d79a4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
71581d79a4SPavel Labath       0x20, 0, 0, 0,                        // StreamDirectoryRVA
72581d79a4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
73581d79a4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
74581d79a4SPavel Labath                                             // Stream Directory
75581d79a4SPavel Labath       3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,
76581d79a4SPavel Labath       0x2c, 0, 0, 0,                        // RVA
77581d79a4SPavel Labath                                             // Stream
78045b8544SPavel Labath       'C', 'P', 'U', 'I', 'N', 'F', 'O'};
79045b8544SPavel Labath   EXPECT_THAT_EXPECTED(create(WrongSignature), Failed<BinaryError>());
80581d79a4SPavel Labath 
81045b8544SPavel Labath   std::vector<uint8_t> WrongVersion{
82045b8544SPavel Labath       // Header
83581d79a4SPavel Labath       'M', 'D', 'M', 'P', 0x39, 0xa7, 0, 0, // Signature, Version
84581d79a4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
85581d79a4SPavel Labath       0x20, 0, 0, 0,                        // StreamDirectoryRVA
86581d79a4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
87581d79a4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
88581d79a4SPavel Labath                                             // Stream Directory
89581d79a4SPavel Labath       3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,
90581d79a4SPavel Labath       0x2c, 0, 0, 0,                        // RVA
91581d79a4SPavel Labath                                             // Stream
92045b8544SPavel Labath       'C', 'P', 'U', 'I', 'N', 'F', 'O'};
93045b8544SPavel Labath   EXPECT_THAT_EXPECTED(create(WrongVersion), Failed<BinaryError>());
94581d79a4SPavel Labath 
95045b8544SPavel Labath   std::vector<uint8_t> DirectoryAfterEOF{
96045b8544SPavel Labath       // Header
97581d79a4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
98581d79a4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
99581d79a4SPavel Labath       0x20, 1, 0, 0,                        // StreamDirectoryRVA
100581d79a4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
101581d79a4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
102581d79a4SPavel Labath                                             // Stream Directory
103581d79a4SPavel Labath       3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,
104581d79a4SPavel Labath       0x2c, 0, 0, 0,                        // RVA
105581d79a4SPavel Labath                                             // Stream
106045b8544SPavel Labath       'C', 'P', 'U', 'I', 'N', 'F', 'O'};
107045b8544SPavel Labath   EXPECT_THAT_EXPECTED(create(DirectoryAfterEOF), Failed<BinaryError>());
108581d79a4SPavel Labath 
109045b8544SPavel Labath   std::vector<uint8_t> TruncatedDirectory{
110045b8544SPavel Labath       // Header
111581d79a4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
112581d79a4SPavel Labath       1, 1, 0, 0,                           // NumberOfStreams,
113581d79a4SPavel Labath       0x20, 0, 0, 0,                        // StreamDirectoryRVA
114581d79a4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
115581d79a4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
116581d79a4SPavel Labath                                             // Stream Directory
117581d79a4SPavel Labath       3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,
118581d79a4SPavel Labath       0x2c, 0, 0, 0,                        // RVA
119581d79a4SPavel Labath                                             // Stream
120045b8544SPavel Labath       'C', 'P', 'U', 'I', 'N', 'F', 'O'};
121045b8544SPavel Labath   EXPECT_THAT_EXPECTED(create(TruncatedDirectory), Failed<BinaryError>());
122581d79a4SPavel Labath 
123045b8544SPavel Labath   std::vector<uint8_t> Stream0AfterEOF{
124045b8544SPavel Labath       // Header
125581d79a4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
126581d79a4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
127581d79a4SPavel Labath       0x20, 0, 0, 0,                        // StreamDirectoryRVA
128581d79a4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
129581d79a4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
130581d79a4SPavel Labath                                             // Stream Directory
131581d79a4SPavel Labath       3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,
132581d79a4SPavel Labath       0x2c, 1, 0, 0,                        // RVA
133581d79a4SPavel Labath                                             // Stream
134045b8544SPavel Labath       'C', 'P', 'U', 'I', 'N', 'F', 'O'};
135045b8544SPavel Labath   EXPECT_THAT_EXPECTED(create(Stream0AfterEOF), Failed<BinaryError>());
136581d79a4SPavel Labath 
137045b8544SPavel Labath   std::vector<uint8_t> Stream0Truncated{
138045b8544SPavel Labath       // Header
139581d79a4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
140581d79a4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
141581d79a4SPavel Labath       0x20, 0, 0, 0,                        // StreamDirectoryRVA
142581d79a4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
143581d79a4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
144581d79a4SPavel Labath                                             // Stream Directory
145581d79a4SPavel Labath       3, 0, 0x67, 0x47, 8, 0, 0, 0,         // Type, DataSize,
146581d79a4SPavel Labath       0x2c, 0, 0, 0,                        // RVA
147581d79a4SPavel Labath                                             // Stream
148045b8544SPavel Labath       'C', 'P', 'U', 'I', 'N', 'F', 'O'};
149045b8544SPavel Labath   EXPECT_THAT_EXPECTED(create(Stream0Truncated), Failed<BinaryError>());
150581d79a4SPavel Labath 
151045b8544SPavel Labath   std::vector<uint8_t> DuplicateStream{
152045b8544SPavel Labath       // Header
153581d79a4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
154581d79a4SPavel Labath       2, 0, 0, 0,                           // NumberOfStreams,
155581d79a4SPavel Labath       0x20, 0, 0, 0,                        // StreamDirectoryRVA
156581d79a4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
157581d79a4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
158581d79a4SPavel Labath                                             // Stream Directory
159581d79a4SPavel Labath       3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,
160581d79a4SPavel Labath       0x40, 0, 0, 0,                        // RVA
161581d79a4SPavel Labath                                             // Stream
162581d79a4SPavel Labath       3, 0, 0x67, 0x47, 7, 0, 0, 0,         // Type, DataSize,
163581d79a4SPavel Labath       0x40, 0, 0, 0,                        // RVA
164581d79a4SPavel Labath                                             // Stream
165045b8544SPavel Labath       'C', 'P', 'U', 'I', 'N', 'F', 'O'};
166045b8544SPavel Labath   EXPECT_THAT_EXPECTED(create(DuplicateStream), Failed<BinaryError>());
167581d79a4SPavel Labath 
168045b8544SPavel Labath   std::vector<uint8_t> DenseMapInfoConflict{
169045b8544SPavel Labath       // Header
170581d79a4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
171581d79a4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
172581d79a4SPavel Labath       0x20, 0, 0, 0,                        // StreamDirectoryRVA
173581d79a4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
174581d79a4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
175581d79a4SPavel Labath                                             // Stream Directory
176581d79a4SPavel Labath       0xff, 0xff, 0xff, 0xff, 7, 0, 0, 0,   // Type, DataSize,
177581d79a4SPavel Labath       0x2c, 0, 0, 0,                        // RVA
178581d79a4SPavel Labath                                             // Stream
179045b8544SPavel Labath       'C', 'P', 'U', 'I', 'N', 'F', 'O'};
180045b8544SPavel Labath   EXPECT_THAT_EXPECTED(create(DenseMapInfoConflict), Failed<BinaryError>());
181581d79a4SPavel Labath }
182581d79a4SPavel Labath 
183581d79a4SPavel Labath TEST(MinidumpFile, IngoresDummyStreams) {
184045b8544SPavel Labath   std::vector<uint8_t> TwoDummyStreams{
185581d79a4SPavel Labath       // Header
186581d79a4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
187581d79a4SPavel Labath       2, 0, 0, 0,                           // NumberOfStreams,
188581d79a4SPavel Labath       0x20, 0, 0, 0,                        // StreamDirectoryRVA
189581d79a4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
190581d79a4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
191581d79a4SPavel Labath                                             // Stream Directory
192581d79a4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Type, DataSize,
193581d79a4SPavel Labath       0x20, 0, 0, 0,                        // RVA
194581d79a4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Type, DataSize,
195581d79a4SPavel Labath       0x20, 0, 0, 0,                        // RVA
196045b8544SPavel Labath   };
197045b8544SPavel Labath   auto ExpectedFile = create(TwoDummyStreams);
198581d79a4SPavel Labath   ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
199581d79a4SPavel Labath   const MinidumpFile &File = **ExpectedFile;
200581d79a4SPavel Labath   ASSERT_EQ(2u, File.streams().size());
201581d79a4SPavel Labath   EXPECT_EQ(StreamType::Unused, File.streams()[0].Type);
202581d79a4SPavel Labath   EXPECT_EQ(StreamType::Unused, File.streams()[1].Type);
203b6a01caaSKazu Hirata   EXPECT_EQ(std::nullopt, File.getRawStream(StreamType::Unused));
204581d79a4SPavel Labath }
205581d79a4SPavel Labath 
206581d79a4SPavel Labath TEST(MinidumpFile, getSystemInfo) {
207045b8544SPavel Labath   std::vector<uint8_t> Data{
208581d79a4SPavel Labath       // Header
209581d79a4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
210581d79a4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
211581d79a4SPavel Labath       0x20, 0, 0, 0,                        // StreamDirectoryRVA
212581d79a4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
213581d79a4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
214581d79a4SPavel Labath                                             // Stream Directory
215581d79a4SPavel Labath       7, 0, 0, 0, 56, 0, 0, 0,              // Type, DataSize,
216581d79a4SPavel Labath       0x2c, 0, 0, 0,                        // RVA
217581d79a4SPavel Labath                                             // SystemInfo
218581d79a4SPavel Labath       0, 0, 1, 2,                           // ProcessorArch, ProcessorLevel
219581d79a4SPavel Labath       3, 4, 5, 6, // ProcessorRevision, NumberOfProcessors, ProductType
220581d79a4SPavel Labath       7, 8, 9, 0, 1, 2, 3, 4, // MajorVersion, MinorVersion
221581d79a4SPavel Labath       5, 6, 7, 8, 2, 0, 0, 0, // BuildNumber, PlatformId
222581d79a4SPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // CSDVersionRVA, SuiteMask, Reserved
223581d79a4SPavel Labath       'L', 'L', 'V', 'M', 'L', 'L', 'V', 'M', 'L', 'L', 'V', 'M', // VendorID
224581d79a4SPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // VersionInfo, FeatureInfo
225581d79a4SPavel Labath       9, 0, 1, 2,             // AMDExtendedFeatures
226045b8544SPavel Labath   };
227045b8544SPavel Labath   auto ExpectedFile = create(Data);
228581d79a4SPavel Labath   ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
229581d79a4SPavel Labath   const MinidumpFile &File = **ExpectedFile;
230581d79a4SPavel Labath 
231581d79a4SPavel Labath   auto ExpectedInfo = File.getSystemInfo();
232581d79a4SPavel Labath   ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());
233581d79a4SPavel Labath   const SystemInfo &Info = *ExpectedInfo;
234581d79a4SPavel Labath   EXPECT_EQ(ProcessorArchitecture::X86, Info.ProcessorArch);
235581d79a4SPavel Labath   EXPECT_EQ(0x0201, Info.ProcessorLevel);
236581d79a4SPavel Labath   EXPECT_EQ(0x0403, Info.ProcessorRevision);
237581d79a4SPavel Labath   EXPECT_EQ(5, Info.NumberOfProcessors);
238581d79a4SPavel Labath   EXPECT_EQ(6, Info.ProductType);
239581d79a4SPavel Labath   EXPECT_EQ(0x00090807u, Info.MajorVersion);
240581d79a4SPavel Labath   EXPECT_EQ(0x04030201u, Info.MinorVersion);
241581d79a4SPavel Labath   EXPECT_EQ(0x08070605u, Info.BuildNumber);
242581d79a4SPavel Labath   EXPECT_EQ(OSPlatform::Win32NT, Info.PlatformId);
243581d79a4SPavel Labath   EXPECT_EQ(0x04030201u, Info.CSDVersionRVA);
244581d79a4SPavel Labath   EXPECT_EQ(0x0605u, Info.SuiteMask);
245581d79a4SPavel Labath   EXPECT_EQ(0x0807u, Info.Reserved);
246581d79a4SPavel Labath   EXPECT_EQ("LLVMLLVMLLVM", llvm::StringRef(Info.CPU.X86.VendorID,
247581d79a4SPavel Labath                                             sizeof(Info.CPU.X86.VendorID)));
248581d79a4SPavel Labath   EXPECT_EQ(0x04030201u, Info.CPU.X86.VersionInfo);
249581d79a4SPavel Labath   EXPECT_EQ(0x08070605u, Info.CPU.X86.FeatureInfo);
250581d79a4SPavel Labath   EXPECT_EQ(0x02010009u, Info.CPU.X86.AMDExtendedFeatures);
251581d79a4SPavel Labath }
25251d9fa0aSPavel Labath 
25351d9fa0aSPavel Labath TEST(MinidumpFile, getString) {
25451d9fa0aSPavel Labath   std::vector<uint8_t> ManyStrings{
25551d9fa0aSPavel Labath       // Header
25651d9fa0aSPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
25751d9fa0aSPavel Labath       2, 0, 0, 0,                           // NumberOfStreams,
25851d9fa0aSPavel Labath       0x20, 0, 0, 0,                        // StreamDirectoryRVA
25951d9fa0aSPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
26051d9fa0aSPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
26151d9fa0aSPavel Labath                                             // Stream Directory
26251d9fa0aSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Type, DataSize,
26351d9fa0aSPavel Labath       0x20, 0, 0, 0,                        // RVA
26451d9fa0aSPavel Labath       1, 0, 0, 0, 0, 0,                     // String1 - odd length
26551d9fa0aSPavel Labath       0, 0, 1, 0, 0, 0,                     // String2 - too long
26651d9fa0aSPavel Labath       2, 0, 0, 0, 0, 0xd8,                  // String3 - invalid utf16
26751d9fa0aSPavel Labath       0, 0, 0, 0, 0, 0,                     // String4 - ""
26851d9fa0aSPavel Labath       2, 0, 0, 0, 'a', 0,                   // String5 - "a"
26951d9fa0aSPavel Labath       0,                                    // Mis-align next string
27051d9fa0aSPavel Labath       2, 0, 0, 0, 'a', 0,                   // String6 - "a"
27151d9fa0aSPavel Labath 
27251d9fa0aSPavel Labath   };
27351d9fa0aSPavel Labath   auto ExpectedFile = create(ManyStrings);
27451d9fa0aSPavel Labath   ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
27551d9fa0aSPavel Labath   const MinidumpFile &File = **ExpectedFile;
27651d9fa0aSPavel Labath   EXPECT_THAT_EXPECTED(File.getString(44), Failed<BinaryError>());
27751d9fa0aSPavel Labath   EXPECT_THAT_EXPECTED(File.getString(50), Failed<BinaryError>());
27851d9fa0aSPavel Labath   EXPECT_THAT_EXPECTED(File.getString(56), Failed<BinaryError>());
27951d9fa0aSPavel Labath   EXPECT_THAT_EXPECTED(File.getString(62), HasValue(""));
28051d9fa0aSPavel Labath   EXPECT_THAT_EXPECTED(File.getString(68), HasValue("a"));
28151d9fa0aSPavel Labath   EXPECT_THAT_EXPECTED(File.getString(75), HasValue("a"));
28251d9fa0aSPavel Labath 
28351d9fa0aSPavel Labath   // Check the case when the size field does not fit into the remaining data.
28451d9fa0aSPavel Labath   EXPECT_THAT_EXPECTED(File.getString(ManyStrings.size() - 2),
28551d9fa0aSPavel Labath                        Failed<BinaryError>());
28651d9fa0aSPavel Labath }
287aaff480cSPavel Labath 
288aaff480cSPavel Labath TEST(MinidumpFile, getModuleList) {
289aaff480cSPavel Labath   std::vector<uint8_t> OneModule{
290aaff480cSPavel Labath       // Header
291aaff480cSPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
292aaff480cSPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
293aaff480cSPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
294aaff480cSPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
295aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
296aaff480cSPavel Labath                                             // Stream Directory
297aaff480cSPavel Labath       4, 0, 0, 0, 112, 0, 0, 0,             // Type, DataSize,
298aaff480cSPavel Labath       44, 0, 0, 0,                          // RVA
299aaff480cSPavel Labath       // ModuleList
300aaff480cSPavel Labath       1, 0, 0, 0,             // NumberOfModules
301aaff480cSPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
302aaff480cSPavel Labath       9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
303aaff480cSPavel Labath       7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
304aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
305aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
306aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
307aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
308aaff480cSPavel Labath       0, 0, 0, 0,             // FileOS
309aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
310aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileDate
311aaff480cSPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
312aaff480cSPavel Labath       9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
313aaff480cSPavel Labath       7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
314aaff480cSPavel Labath       5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
315aaff480cSPavel Labath   };
316aaff480cSPavel Labath   // Same as before, but with a padded module list.
317aaff480cSPavel Labath   std::vector<uint8_t> PaddedModule{
318aaff480cSPavel Labath       // Header
319aaff480cSPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
320aaff480cSPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
321aaff480cSPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
322aaff480cSPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
323aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
324aaff480cSPavel Labath                                             // Stream Directory
325aaff480cSPavel Labath       4, 0, 0, 0, 116, 0, 0, 0,             // Type, DataSize,
326aaff480cSPavel Labath       44, 0, 0, 0,                          // RVA
327aaff480cSPavel Labath       // ModuleList
328aaff480cSPavel Labath       1, 0, 0, 0,             // NumberOfModules
329aaff480cSPavel Labath       0, 0, 0, 0,             // Padding
330aaff480cSPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
331aaff480cSPavel Labath       9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
332aaff480cSPavel Labath       7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
333aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
334aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
335aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
336aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
337aaff480cSPavel Labath       0, 0, 0, 0,             // FileOS
338aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
339aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileDate
340aaff480cSPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
341aaff480cSPavel Labath       9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
342aaff480cSPavel Labath       7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
343aaff480cSPavel Labath       5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
344aaff480cSPavel Labath   };
345aaff480cSPavel Labath 
346cfc4519eSPavel Labath   for (ArrayRef<uint8_t> Data : {OneModule, PaddedModule}) {
347aaff480cSPavel Labath     auto ExpectedFile = create(Data);
348aaff480cSPavel Labath     ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
349aaff480cSPavel Labath     const MinidumpFile &File = **ExpectedFile;
350aaff480cSPavel Labath     Expected<ArrayRef<Module>> ExpectedModule = File.getModuleList();
351aaff480cSPavel Labath     ASSERT_THAT_EXPECTED(ExpectedModule, Succeeded());
352aaff480cSPavel Labath     ASSERT_EQ(1u, ExpectedModule->size());
353aaff480cSPavel Labath     const Module &M = ExpectedModule.get()[0];
354aaff480cSPavel Labath     EXPECT_EQ(0x0807060504030201u, M.BaseOfImage);
355aaff480cSPavel Labath     EXPECT_EQ(0x02010009u, M.SizeOfImage);
356aaff480cSPavel Labath     EXPECT_EQ(0x06050403u, M.Checksum);
357aaff480cSPavel Labath     EXPECT_EQ(0x00090807u, M.TimeDateStamp);
358aaff480cSPavel Labath     EXPECT_EQ(0x04030201u, M.ModuleNameRVA);
359aaff480cSPavel Labath     EXPECT_EQ(0x04030201u, M.CvRecord.DataSize);
360aaff480cSPavel Labath     EXPECT_EQ(0x08070605u, M.CvRecord.RVA);
361aaff480cSPavel Labath     EXPECT_EQ(0x02010009u, M.MiscRecord.DataSize);
362aaff480cSPavel Labath     EXPECT_EQ(0x06050403u, M.MiscRecord.RVA);
363aaff480cSPavel Labath     EXPECT_EQ(0x0403020100090807u, M.Reserved0);
364aaff480cSPavel Labath     EXPECT_EQ(0x0201000908070605u, M.Reserved1);
365aaff480cSPavel Labath   }
366aaff480cSPavel Labath 
367aaff480cSPavel Labath   std::vector<uint8_t> StreamTooShort{
368aaff480cSPavel Labath       // Header
369aaff480cSPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
370aaff480cSPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
371aaff480cSPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
372aaff480cSPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
373aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
374aaff480cSPavel Labath                                             // Stream Directory
375aaff480cSPavel Labath       4, 0, 0, 0, 111, 0, 0, 0,             // Type, DataSize,
376aaff480cSPavel Labath       44, 0, 0, 0,                          // RVA
377aaff480cSPavel Labath       // ModuleList
378aaff480cSPavel Labath       1, 0, 0, 0,             // NumberOfModules
379aaff480cSPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
380aaff480cSPavel Labath       9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
381aaff480cSPavel Labath       7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
382aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
383aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
384aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
385aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
386aaff480cSPavel Labath       0, 0, 0, 0,             // FileOS
387aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
388aaff480cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // FileDate
389aaff480cSPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
390aaff480cSPavel Labath       9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
391aaff480cSPavel Labath       7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
392aaff480cSPavel Labath       5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
393aaff480cSPavel Labath   };
394aaff480cSPavel Labath   auto ExpectedFile = create(StreamTooShort);
395aaff480cSPavel Labath   ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
396aaff480cSPavel Labath   const MinidumpFile &File = **ExpectedFile;
397aaff480cSPavel Labath   EXPECT_THAT_EXPECTED(File.getModuleList(), Failed<BinaryError>());
398aaff480cSPavel Labath }
399cfc4519eSPavel Labath 
400cfc4519eSPavel Labath TEST(MinidumpFile, getThreadList) {
401cfc4519eSPavel Labath   std::vector<uint8_t> OneThread{
402cfc4519eSPavel Labath       // Header
403cfc4519eSPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
404cfc4519eSPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
405cfc4519eSPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
406cfc4519eSPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
407cfc4519eSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
408cfc4519eSPavel Labath                                             // Stream Directory
409cfc4519eSPavel Labath       3, 0, 0, 0, 52, 0, 0, 0,              // Type, DataSize,
410cfc4519eSPavel Labath       44, 0, 0, 0,                          // RVA
411cfc4519eSPavel Labath       // ThreadList
412cfc4519eSPavel Labath       1, 0, 0, 0,             // NumberOfThreads
413cfc4519eSPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // ThreadId, SuspendCount
414cfc4519eSPavel Labath       9, 0, 1, 2, 3, 4, 5, 6, // PriorityClass, Priority
415cfc4519eSPavel Labath       7, 8, 9, 0, 1, 2, 3, 4, // EnvironmentBlock
416cfc4519eSPavel Labath       // Stack
417cfc4519eSPavel Labath       5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
418cfc4519eSPavel Labath       3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
419cfc4519eSPavel Labath       // Context
420cfc4519eSPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // DataSize, RVA
421cfc4519eSPavel Labath   };
422cfc4519eSPavel Labath   // Same as before, but with a padded thread list.
423cfc4519eSPavel Labath   std::vector<uint8_t> PaddedThread{
424cfc4519eSPavel Labath       // Header
425cfc4519eSPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
426cfc4519eSPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
427cfc4519eSPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
428cfc4519eSPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
429cfc4519eSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
430cfc4519eSPavel Labath                                             // Stream Directory
431cfc4519eSPavel Labath       3, 0, 0, 0, 56, 0, 0, 0,              // Type, DataSize,
432cfc4519eSPavel Labath       44, 0, 0, 0,                          // RVA
433cfc4519eSPavel Labath       // ThreadList
434cfc4519eSPavel Labath       1, 0, 0, 0,             // NumberOfThreads
435cfc4519eSPavel Labath       0, 0, 0, 0,             // Padding
436cfc4519eSPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // ThreadId, SuspendCount
437cfc4519eSPavel Labath       9, 0, 1, 2, 3, 4, 5, 6, // PriorityClass, Priority
438cfc4519eSPavel Labath       7, 8, 9, 0, 1, 2, 3, 4, // EnvironmentBlock
439cfc4519eSPavel Labath       // Stack
440cfc4519eSPavel Labath       5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
441cfc4519eSPavel Labath       3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
442cfc4519eSPavel Labath       // Context
443cfc4519eSPavel Labath       1, 2, 3, 4, 5, 6, 7, 8, // DataSize, RVA
444cfc4519eSPavel Labath   };
445cfc4519eSPavel Labath 
446cfc4519eSPavel Labath   for (ArrayRef<uint8_t> Data : {OneThread, PaddedThread}) {
447cfc4519eSPavel Labath     auto ExpectedFile = create(Data);
448cfc4519eSPavel Labath     ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
449cfc4519eSPavel Labath     const MinidumpFile &File = **ExpectedFile;
450cfc4519eSPavel Labath     Expected<ArrayRef<Thread>> ExpectedThread = File.getThreadList();
451cfc4519eSPavel Labath     ASSERT_THAT_EXPECTED(ExpectedThread, Succeeded());
452cfc4519eSPavel Labath     ASSERT_EQ(1u, ExpectedThread->size());
453cfc4519eSPavel Labath     const Thread &T = ExpectedThread.get()[0];
454cfc4519eSPavel Labath     EXPECT_EQ(0x04030201u, T.ThreadId);
455cfc4519eSPavel Labath     EXPECT_EQ(0x08070605u, T.SuspendCount);
456cfc4519eSPavel Labath     EXPECT_EQ(0x02010009u, T.PriorityClass);
457cfc4519eSPavel Labath     EXPECT_EQ(0x06050403u, T.Priority);
458cfc4519eSPavel Labath     EXPECT_EQ(0x0403020100090807u, T.EnvironmentBlock);
459cfc4519eSPavel Labath     EXPECT_EQ(0x0201000908070605u, T.Stack.StartOfMemoryRange);
460cfc4519eSPavel Labath     EXPECT_EQ(0x06050403u, T.Stack.Memory.DataSize);
461cfc4519eSPavel Labath     EXPECT_EQ(0x00090807u, T.Stack.Memory.RVA);
462cfc4519eSPavel Labath     EXPECT_EQ(0x04030201u, T.Context.DataSize);
463cfc4519eSPavel Labath     EXPECT_EQ(0x08070605u, T.Context.RVA);
464cfc4519eSPavel Labath   }
465cfc4519eSPavel Labath }
4662d29e16cSPavel Labath 
4672d29e16cSPavel Labath TEST(MinidumpFile, getMemoryList) {
4682d29e16cSPavel Labath   std::vector<uint8_t> OneRange{
4692d29e16cSPavel Labath       // Header
4702d29e16cSPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
4712d29e16cSPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
4722d29e16cSPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
4732d29e16cSPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
4742d29e16cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
4752d29e16cSPavel Labath                                             // Stream Directory
4762d29e16cSPavel Labath       5, 0, 0, 0, 20, 0, 0, 0,              // Type, DataSize,
4772d29e16cSPavel Labath       44, 0, 0, 0,                          // RVA
4782d29e16cSPavel Labath       // MemoryDescriptor
4792d29e16cSPavel Labath       1, 0, 0, 0,             // NumberOfMemoryRanges
4802d29e16cSPavel Labath       5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
4812d29e16cSPavel Labath       3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
4822d29e16cSPavel Labath   };
4832d29e16cSPavel Labath   // Same as before, but with a padded memory list.
4842d29e16cSPavel Labath   std::vector<uint8_t> PaddedRange{
4852d29e16cSPavel Labath       // Header
4862d29e16cSPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
4872d29e16cSPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
4882d29e16cSPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
4892d29e16cSPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
4902d29e16cSPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
4912d29e16cSPavel Labath                                             // Stream Directory
4922d29e16cSPavel Labath       5, 0, 0, 0, 24, 0, 0, 0,              // Type, DataSize,
4932d29e16cSPavel Labath       44, 0, 0, 0,                          // RVA
4942d29e16cSPavel Labath       // MemoryDescriptor
4952d29e16cSPavel Labath       1, 0, 0, 0,             // NumberOfMemoryRanges
4962d29e16cSPavel Labath       0, 0, 0, 0,             // Padding
4972d29e16cSPavel Labath       5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
4982d29e16cSPavel Labath       3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
4992d29e16cSPavel Labath   };
5002d29e16cSPavel Labath 
5012d29e16cSPavel Labath   for (ArrayRef<uint8_t> Data : {OneRange, PaddedRange}) {
5022d29e16cSPavel Labath     auto ExpectedFile = create(Data);
5032d29e16cSPavel Labath     ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
5042d29e16cSPavel Labath     const MinidumpFile &File = **ExpectedFile;
5052d29e16cSPavel Labath     Expected<ArrayRef<MemoryDescriptor>> ExpectedRanges = File.getMemoryList();
5062d29e16cSPavel Labath     ASSERT_THAT_EXPECTED(ExpectedRanges, Succeeded());
5072d29e16cSPavel Labath     ASSERT_EQ(1u, ExpectedRanges->size());
5082d29e16cSPavel Labath     const MemoryDescriptor &MD = ExpectedRanges.get()[0];
5092d29e16cSPavel Labath     EXPECT_EQ(0x0201000908070605u, MD.StartOfMemoryRange);
5102d29e16cSPavel Labath     EXPECT_EQ(0x06050403u, MD.Memory.DataSize);
5112d29e16cSPavel Labath     EXPECT_EQ(0x00090807u, MD.Memory.RVA);
5122d29e16cSPavel Labath   }
5132d29e16cSPavel Labath }
5146e0b1ce4SPavel Labath 
5156e0b1ce4SPavel Labath TEST(MinidumpFile, getMemoryInfoList) {
5166e0b1ce4SPavel Labath   std::vector<uint8_t> OneEntry{
5176e0b1ce4SPavel Labath       // Header
5186e0b1ce4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
5196e0b1ce4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
5206e0b1ce4SPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
5216e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
5226e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
5236e0b1ce4SPavel Labath                                             // Stream Directory
5246e0b1ce4SPavel Labath       16, 0, 0, 0, 64, 0, 0, 0,             // Type, DataSize,
5256e0b1ce4SPavel Labath       44, 0, 0, 0,                          // RVA
5266e0b1ce4SPavel Labath       // MemoryInfoListHeader
5276e0b1ce4SPavel Labath       16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
5286e0b1ce4SPavel Labath       1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries
5296e0b1ce4SPavel Labath       // MemoryInfo
5306e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress
5316e0b1ce4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase
5326e0b1ce4SPavel Labath       16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0
5336e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize
5346e0b1ce4SPavel Labath       0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
5356e0b1ce4SPavel Labath       0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1
5366e0b1ce4SPavel Labath   };
5376e0b1ce4SPavel Labath 
5386e0b1ce4SPavel Labath   // Same as before, but the list header is larger.
5396e0b1ce4SPavel Labath   std::vector<uint8_t> BiggerHeader{
5406e0b1ce4SPavel Labath       // Header
5416e0b1ce4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
5426e0b1ce4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
5436e0b1ce4SPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
5446e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
5456e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
5466e0b1ce4SPavel Labath                                             // Stream Directory
5476e0b1ce4SPavel Labath       16, 0, 0, 0, 68, 0, 0, 0,             // Type, DataSize,
5486e0b1ce4SPavel Labath       44, 0, 0, 0,                          // RVA
5496e0b1ce4SPavel Labath       // MemoryInfoListHeader
5506e0b1ce4SPavel Labath       20, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
5516e0b1ce4SPavel Labath       1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries
5526e0b1ce4SPavel Labath       0, 0, 0, 0,               // ???
5536e0b1ce4SPavel Labath       // MemoryInfo
5546e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress
5556e0b1ce4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase
5566e0b1ce4SPavel Labath       16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0
5576e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize
5586e0b1ce4SPavel Labath       0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
5596e0b1ce4SPavel Labath       0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1
5606e0b1ce4SPavel Labath   };
5616e0b1ce4SPavel Labath 
5626e0b1ce4SPavel Labath   // Same as before, but the entry is larger.
5636e0b1ce4SPavel Labath   std::vector<uint8_t> BiggerEntry{
5646e0b1ce4SPavel Labath       // Header
5656e0b1ce4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
5666e0b1ce4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
5676e0b1ce4SPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
5686e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
5696e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
5706e0b1ce4SPavel Labath                                             // Stream Directory
5716e0b1ce4SPavel Labath       16, 0, 0, 0, 68, 0, 0, 0,             // Type, DataSize,
5726e0b1ce4SPavel Labath       44, 0, 0, 0,                          // RVA
5736e0b1ce4SPavel Labath       // MemoryInfoListHeader
5746e0b1ce4SPavel Labath       16, 0, 0, 0, 52, 0, 0, 0, // SizeOfHeader, SizeOfEntry
5756e0b1ce4SPavel Labath       1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries
5766e0b1ce4SPavel Labath       // MemoryInfo
5776e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress
5786e0b1ce4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase
5796e0b1ce4SPavel Labath       16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0
5806e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize
5816e0b1ce4SPavel Labath       0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
5826e0b1ce4SPavel Labath       0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1
5836e0b1ce4SPavel Labath       0, 0, 0, 0,               // ???
5846e0b1ce4SPavel Labath   };
5856e0b1ce4SPavel Labath 
5866e0b1ce4SPavel Labath   for (ArrayRef<uint8_t> Data : {OneEntry, BiggerHeader, BiggerEntry}) {
5876e0b1ce4SPavel Labath     auto ExpectedFile = create(Data);
5886e0b1ce4SPavel Labath     ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
5896e0b1ce4SPavel Labath     const MinidumpFile &File = **ExpectedFile;
5906e0b1ce4SPavel Labath     auto ExpectedInfo = File.getMemoryInfoList();
5916e0b1ce4SPavel Labath     ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());
592bff33bd5SMiloš Stojanović     ASSERT_EQ(1, std::distance(ExpectedInfo->begin(), ExpectedInfo->end()));
5936e0b1ce4SPavel Labath     const MemoryInfo &Info = *ExpectedInfo.get().begin();
5946e0b1ce4SPavel Labath     EXPECT_EQ(0x0706050403020100u, Info.BaseAddress);
5956e0b1ce4SPavel Labath     EXPECT_EQ(0x0504030201000908u, Info.AllocationBase);
5966e0b1ce4SPavel Labath     EXPECT_EQ(MemoryProtection::Execute, Info.AllocationProtect);
5976e0b1ce4SPavel Labath     EXPECT_EQ(0x09080706u, Info.Reserved0);
5986e0b1ce4SPavel Labath     EXPECT_EQ(0x0706050403020100u, Info.RegionSize);
5996e0b1ce4SPavel Labath     EXPECT_EQ(MemoryState::Commit, Info.State);
6006e0b1ce4SPavel Labath     EXPECT_EQ(MemoryProtection::ExecuteRead, Info.Protect);
6016e0b1ce4SPavel Labath     EXPECT_EQ(MemoryType::Private, Info.Type);
6026e0b1ce4SPavel Labath     EXPECT_EQ(0x01000908u, Info.Reserved1);
6036e0b1ce4SPavel Labath   }
6046e0b1ce4SPavel Labath 
6056e0b1ce4SPavel Labath   // Header does not fit into the stream.
6066e0b1ce4SPavel Labath   std::vector<uint8_t> HeaderTooBig{
6076e0b1ce4SPavel Labath       // Header
6086e0b1ce4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
6096e0b1ce4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
6106e0b1ce4SPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
6116e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
6126e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
6136e0b1ce4SPavel Labath                                             // Stream Directory
6146e0b1ce4SPavel Labath       16, 0, 0, 0, 15, 0, 0, 0,             // Type, DataSize,
6156e0b1ce4SPavel Labath       44, 0, 0, 0,                          // RVA
6166e0b1ce4SPavel Labath       // MemoryInfoListHeader
6176e0b1ce4SPavel Labath       16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
6186e0b1ce4SPavel Labath       1, 0, 0, 0, 0, 0, 0,      // ???
6196e0b1ce4SPavel Labath   };
6206e0b1ce4SPavel Labath   Expected<std::unique_ptr<MinidumpFile>> File = create(HeaderTooBig);
6216e0b1ce4SPavel Labath   ASSERT_THAT_EXPECTED(File, Succeeded());
6226e0b1ce4SPavel Labath   EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
6236e0b1ce4SPavel Labath 
6246e0b1ce4SPavel Labath   // Header fits into the stream, but it is too small to contain the required
6256e0b1ce4SPavel Labath   // entries.
6266e0b1ce4SPavel Labath   std::vector<uint8_t> HeaderTooSmall{
6276e0b1ce4SPavel Labath       // Header
6286e0b1ce4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
6296e0b1ce4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
6306e0b1ce4SPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
6316e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
6326e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
6336e0b1ce4SPavel Labath                                             // Stream Directory
6346e0b1ce4SPavel Labath       16, 0, 0, 0, 15, 0, 0, 0,             // Type, DataSize,
6356e0b1ce4SPavel Labath       44, 0, 0, 0,                          // RVA
6366e0b1ce4SPavel Labath       // MemoryInfoListHeader
6376e0b1ce4SPavel Labath       15, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
6386e0b1ce4SPavel Labath       1, 0, 0, 0, 0, 0, 0,      // ???
6396e0b1ce4SPavel Labath   };
6406e0b1ce4SPavel Labath   File = create(HeaderTooSmall);
6416e0b1ce4SPavel Labath   ASSERT_THAT_EXPECTED(File, Succeeded());
6426e0b1ce4SPavel Labath   EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
6436e0b1ce4SPavel Labath 
6446e0b1ce4SPavel Labath   std::vector<uint8_t> EntryTooBig{
6456e0b1ce4SPavel Labath       // Header
6466e0b1ce4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
6476e0b1ce4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
6486e0b1ce4SPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
6496e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
6506e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
6516e0b1ce4SPavel Labath                                             // Stream Directory
6526e0b1ce4SPavel Labath       16, 0, 0, 0, 64, 0, 0, 0,             // Type, DataSize,
6536e0b1ce4SPavel Labath       44, 0, 0, 0,                          // RVA
6546e0b1ce4SPavel Labath       // MemoryInfoListHeader
6556e0b1ce4SPavel Labath       16, 0, 0, 0, 49, 0, 0, 0, // SizeOfHeader, SizeOfEntry
6566e0b1ce4SPavel Labath       1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries
6576e0b1ce4SPavel Labath       // MemoryInfo
6586e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress
6596e0b1ce4SPavel Labath       8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase
6606e0b1ce4SPavel Labath       16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0
6616e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize
6626e0b1ce4SPavel Labath       0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
6636e0b1ce4SPavel Labath       0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1
6646e0b1ce4SPavel Labath   };
6656e0b1ce4SPavel Labath   File = create(EntryTooBig);
6666e0b1ce4SPavel Labath   ASSERT_THAT_EXPECTED(File, Succeeded());
6676e0b1ce4SPavel Labath   EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
6686e0b1ce4SPavel Labath 
6696e0b1ce4SPavel Labath   std::vector<uint8_t> ThreeEntries{
6706e0b1ce4SPavel Labath       // Header
6716e0b1ce4SPavel Labath       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
6726e0b1ce4SPavel Labath       1, 0, 0, 0,                           // NumberOfStreams,
6736e0b1ce4SPavel Labath       32, 0, 0, 0,                          // StreamDirectoryRVA
6746e0b1ce4SPavel Labath       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
6756e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0,               // Flags
6766e0b1ce4SPavel Labath                                             // Stream Directory
6776e0b1ce4SPavel Labath       16, 0, 0, 0, 160, 0, 0, 0,            // Type, DataSize,
6786e0b1ce4SPavel Labath       44, 0, 0, 0,                          // RVA
6796e0b1ce4SPavel Labath       // MemoryInfoListHeader
6806e0b1ce4SPavel Labath       16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
6816e0b1ce4SPavel Labath       3, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries
6826e0b1ce4SPavel Labath       // MemoryInfo
6836e0b1ce4SPavel Labath       0, 1, 2, 3, 0, 0, 0, 0, // BaseAddress
6846e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
6856e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
6866e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
6876e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
6886e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
6896e0b1ce4SPavel Labath       0, 0, 4, 5, 6, 7, 0, 0, // BaseAddress
6906e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
6916e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
6926e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
6936e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
6946e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
6956e0b1ce4SPavel Labath       0, 0, 0, 8, 9, 0, 1, 0, // BaseAddress
6966e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
6976e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
6986e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
6996e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
7006e0b1ce4SPavel Labath       0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
7016e0b1ce4SPavel Labath   };
7026e0b1ce4SPavel Labath   File = create(ThreeEntries);
7036e0b1ce4SPavel Labath   ASSERT_THAT_EXPECTED(File, Succeeded());
7046e0b1ce4SPavel Labath   auto ExpectedInfo = File.get()->getMemoryInfoList();
7056e0b1ce4SPavel Labath   ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());
7066e0b1ce4SPavel Labath   EXPECT_THAT(to_vector<3>(map_range(*ExpectedInfo,
7076e0b1ce4SPavel Labath                                      [](const MemoryInfo &Info) -> uint64_t {
7086e0b1ce4SPavel Labath                                        return Info.BaseAddress;
7096e0b1ce4SPavel Labath                                      })),
7106e0b1ce4SPavel Labath               testing::ElementsAre(0x0000000003020100u, 0x0000070605040000u,
7116e0b1ce4SPavel Labath                                    0x0001000908000000u));
7126e0b1ce4SPavel Labath }
713e4452473SJoseph Tremoulet 
714*deba1340SJacob Lalonde TEST(MinidumpFile, getExceptionStreams) {
715e4452473SJoseph Tremoulet   std::vector<uint8_t> Data{
716e4452473SJoseph Tremoulet       // Header
717e4452473SJoseph Tremoulet       'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
718e4452473SJoseph Tremoulet       1, 0, 0, 0,                           // NumberOfStreams,
719e4452473SJoseph Tremoulet       0x20, 0, 0, 0,                        // StreamDirectoryRVA
720e4452473SJoseph Tremoulet       0, 1, 2, 3, 4, 5, 6, 7,               // Checksum, TimeDateStamp
721e4452473SJoseph Tremoulet       8, 9, 0, 1, 2, 3, 4, 5,               // Flags
722e4452473SJoseph Tremoulet       // Stream Directory
723e4452473SJoseph Tremoulet       6, 0, 0, 0, 168, 0, 0, 0, // Type, DataSize,
724e4452473SJoseph Tremoulet       0x2c, 0, 0, 0,            // RVA
725e4452473SJoseph Tremoulet       // Exception Stream
726e4452473SJoseph Tremoulet       1, 2, 3, 4, // Thread ID
727e4452473SJoseph Tremoulet       0, 0, 0, 0, // Padding
728e4452473SJoseph Tremoulet       // Exception Record
729e4452473SJoseph Tremoulet       2, 3, 4, 2, 7, 8, 8, 9,  // Code, Flags
730e4452473SJoseph Tremoulet       3, 4, 5, 6, 7, 8, 9, 10, // Inner exception record address
731e4452473SJoseph Tremoulet       8, 7, 6, 5, 4, 3, 2, 1,  // Exception address
732e4452473SJoseph Tremoulet       4, 0, 0, 0, 0, 0, 0, 0,  // Parameter count, padding
733e4452473SJoseph Tremoulet       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, // Parameter 0
734e4452473SJoseph Tremoulet       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, // Parameter 1
735e4452473SJoseph Tremoulet       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Parameter 2
736e4452473SJoseph Tremoulet       0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, // Parameter 3
737e4452473SJoseph Tremoulet       0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // Parameter 4
738e4452473SJoseph Tremoulet       0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // Parameter 5
739e4452473SJoseph Tremoulet       0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // Parameter 6
740e4452473SJoseph Tremoulet       0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, // Parameter 7
741e4452473SJoseph Tremoulet       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, // Parameter 8
742e4452473SJoseph Tremoulet       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, // Parameter 9
743e4452473SJoseph Tremoulet       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, // Parameter 10
744e4452473SJoseph Tremoulet       0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, // Parameter 11
745e4452473SJoseph Tremoulet       0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, // Parameter 12
746e4452473SJoseph Tremoulet       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, // Parameter 13
747e4452473SJoseph Tremoulet       0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, // Parameter 14
748e4452473SJoseph Tremoulet       // Thread Context
749e4452473SJoseph Tremoulet       0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, // DataSize, RVA
750e4452473SJoseph Tremoulet   };
751e4452473SJoseph Tremoulet   auto ExpectedFile = create(Data);
752e4452473SJoseph Tremoulet   ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
753e4452473SJoseph Tremoulet   const MinidumpFile &File = **ExpectedFile;
754*deba1340SJacob Lalonde 
755*deba1340SJacob Lalonde   auto ExceptionStreams = File.getExceptionStreams();
756*deba1340SJacob Lalonde   ASSERT_NE(ExceptionStreams.begin(), ExceptionStreams.end());
757*deba1340SJacob Lalonde   auto ExceptionIterator = ExceptionStreams.begin();
758*deba1340SJacob Lalonde   Expected<const ExceptionStream &> ExpectedStream = *ExceptionIterator;
759e4452473SJoseph Tremoulet   ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded());
760e4452473SJoseph Tremoulet   EXPECT_EQ(0x04030201u, ExpectedStream->ThreadId);
761e4452473SJoseph Tremoulet   const minidump::Exception &Exception = ExpectedStream->ExceptionRecord;
762e4452473SJoseph Tremoulet   EXPECT_EQ(0x02040302u, Exception.ExceptionCode);
763e4452473SJoseph Tremoulet   EXPECT_EQ(0x09080807u, Exception.ExceptionFlags);
764e4452473SJoseph Tremoulet   EXPECT_EQ(0x0a09080706050403u, Exception.ExceptionRecord);
765e4452473SJoseph Tremoulet   EXPECT_EQ(0x0102030405060708u, Exception.ExceptionAddress);
766e4452473SJoseph Tremoulet   EXPECT_EQ(4u, Exception.NumberParameters);
767e4452473SJoseph Tremoulet   for (uint64_t index = 0; index < Exception.MaxParameters; ++index) {
768e4452473SJoseph Tremoulet     EXPECT_EQ(0x1716151413121110u + index * 0x1010101010101010u,
769e4452473SJoseph Tremoulet               Exception.ExceptionInformation[index]);
770e4452473SJoseph Tremoulet   }
771e4452473SJoseph Tremoulet   EXPECT_EQ(0x84838281, ExpectedStream->ThreadContext.DataSize);
772e4452473SJoseph Tremoulet   EXPECT_EQ(0x88878685, ExpectedStream->ThreadContext.RVA);
773*deba1340SJacob Lalonde   ++ExceptionIterator;
774*deba1340SJacob Lalonde   ASSERT_EQ(ExceptionIterator, ExceptionStreams.end());
775e4452473SJoseph Tremoulet }
776