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-exception |
6 | // |
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 | |
14 | using namespace llvm; |
15 | using namespace llvm::object; |
16 | using namespace minidump; |
17 | |
18 | static Expected<std::unique_ptr<MinidumpFile>> create(ArrayRef<uint8_t> Data) { |
19 | return MinidumpFile::create( |
20 | Source: MemoryBufferRef(toStringRef(Input: Data), "Test buffer" )); |
21 | } |
22 | |
23 | TEST(MinidumpFile, BasicInterface) { |
24 | std::vector<uint8_t> Data{ // Header |
25 | 'M', 'D', 'M', 'P', // Signature |
26 | 0x93, 0xa7, 0, 0, // Version |
27 | 1, 0, 0, 0, // NumberOfStreams, |
28 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
29 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
30 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
31 | // Stream Directory |
32 | 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize, |
33 | 0x2c, 0, 0, 0, // RVA |
34 | // Stream |
35 | '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 ways |
63 | TEST(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 | // Header |
69 | '!', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
70 | 1, 0, 0, 0, // NumberOfStreams, |
71 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
72 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
73 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
74 | // Stream Directory |
75 | 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize, |
76 | 0x2c, 0, 0, 0, // RVA |
77 | // Stream |
78 | 'C', 'P', 'U', 'I', 'N', 'F', 'O'}; |
79 | EXPECT_THAT_EXPECTED(create(WrongSignature), Failed<BinaryError>()); |
80 | |
81 | std::vector<uint8_t> WrongVersion{ |
82 | // Header |
83 | 'M', 'D', 'M', 'P', 0x39, 0xa7, 0, 0, // Signature, Version |
84 | 1, 0, 0, 0, // NumberOfStreams, |
85 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
86 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
87 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
88 | // Stream Directory |
89 | 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize, |
90 | 0x2c, 0, 0, 0, // RVA |
91 | // Stream |
92 | 'C', 'P', 'U', 'I', 'N', 'F', 'O'}; |
93 | EXPECT_THAT_EXPECTED(create(WrongVersion), Failed<BinaryError>()); |
94 | |
95 | std::vector<uint8_t> DirectoryAfterEOF{ |
96 | // Header |
97 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
98 | 1, 0, 0, 0, // NumberOfStreams, |
99 | 0x20, 1, 0, 0, // StreamDirectoryRVA |
100 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
101 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
102 | // Stream Directory |
103 | 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize, |
104 | 0x2c, 0, 0, 0, // RVA |
105 | // Stream |
106 | 'C', 'P', 'U', 'I', 'N', 'F', 'O'}; |
107 | EXPECT_THAT_EXPECTED(create(DirectoryAfterEOF), Failed<BinaryError>()); |
108 | |
109 | std::vector<uint8_t> TruncatedDirectory{ |
110 | // Header |
111 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
112 | 1, 1, 0, 0, // NumberOfStreams, |
113 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
114 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
115 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
116 | // Stream Directory |
117 | 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize, |
118 | 0x2c, 0, 0, 0, // RVA |
119 | // Stream |
120 | 'C', 'P', 'U', 'I', 'N', 'F', 'O'}; |
121 | EXPECT_THAT_EXPECTED(create(TruncatedDirectory), Failed<BinaryError>()); |
122 | |
123 | std::vector<uint8_t> Stream0AfterEOF{ |
124 | // Header |
125 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
126 | 1, 0, 0, 0, // NumberOfStreams, |
127 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
128 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
129 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
130 | // Stream Directory |
131 | 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize, |
132 | 0x2c, 1, 0, 0, // RVA |
133 | // Stream |
134 | 'C', 'P', 'U', 'I', 'N', 'F', 'O'}; |
135 | EXPECT_THAT_EXPECTED(create(Stream0AfterEOF), Failed<BinaryError>()); |
136 | |
137 | std::vector<uint8_t> Stream0Truncated{ |
138 | // Header |
139 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
140 | 1, 0, 0, 0, // NumberOfStreams, |
141 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
142 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
143 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
144 | // Stream Directory |
145 | 3, 0, 0x67, 0x47, 8, 0, 0, 0, // Type, DataSize, |
146 | 0x2c, 0, 0, 0, // RVA |
147 | // Stream |
148 | 'C', 'P', 'U', 'I', 'N', 'F', 'O'}; |
149 | EXPECT_THAT_EXPECTED(create(Stream0Truncated), Failed<BinaryError>()); |
150 | |
151 | std::vector<uint8_t> DuplicateStream{ |
152 | // Header |
153 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
154 | 2, 0, 0, 0, // NumberOfStreams, |
155 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
156 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
157 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
158 | // Stream Directory |
159 | 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize, |
160 | 0x40, 0, 0, 0, // RVA |
161 | // Stream |
162 | 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize, |
163 | 0x40, 0, 0, 0, // RVA |
164 | // Stream |
165 | 'C', 'P', 'U', 'I', 'N', 'F', 'O'}; |
166 | EXPECT_THAT_EXPECTED(create(DuplicateStream), Failed<BinaryError>()); |
167 | |
168 | std::vector<uint8_t> DenseMapInfoConflict{ |
169 | // Header |
170 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
171 | 1, 0, 0, 0, // NumberOfStreams, |
172 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
173 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
174 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
175 | // Stream Directory |
176 | 0xff, 0xff, 0xff, 0xff, 7, 0, 0, 0, // Type, DataSize, |
177 | 0x2c, 0, 0, 0, // RVA |
178 | // Stream |
179 | 'C', 'P', 'U', 'I', 'N', 'F', 'O'}; |
180 | EXPECT_THAT_EXPECTED(create(DenseMapInfoConflict), Failed<BinaryError>()); |
181 | } |
182 | |
183 | TEST(MinidumpFile, IngoresDummyStreams) { |
184 | std::vector<uint8_t> TwoDummyStreams{ |
185 | // Header |
186 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
187 | 2, 0, 0, 0, // NumberOfStreams, |
188 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
189 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
190 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
191 | // Stream Directory |
192 | 0, 0, 0, 0, 0, 0, 0, 0, // Type, DataSize, |
193 | 0x20, 0, 0, 0, // RVA |
194 | 0, 0, 0, 0, 0, 0, 0, 0, // Type, DataSize, |
195 | 0x20, 0, 0, 0, // RVA |
196 | }; |
197 | auto ExpectedFile = create(Data: 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 | |
206 | TEST(MinidumpFile, getSystemInfo) { |
207 | std::vector<uint8_t> Data{ |
208 | // Header |
209 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
210 | 1, 0, 0, 0, // NumberOfStreams, |
211 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
212 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
213 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
214 | // Stream Directory |
215 | 7, 0, 0, 0, 56, 0, 0, 0, // Type, DataSize, |
216 | 0x2c, 0, 0, 0, // RVA |
217 | // SystemInfo |
218 | 0, 0, 1, 2, // ProcessorArch, ProcessorLevel |
219 | 3, 4, 5, 6, // ProcessorRevision, NumberOfProcessors, ProductType |
220 | 7, 8, 9, 0, 1, 2, 3, 4, // MajorVersion, MinorVersion |
221 | 5, 6, 7, 8, 2, 0, 0, 0, // BuildNumber, PlatformId |
222 | 1, 2, 3, 4, 5, 6, 7, 8, // CSDVersionRVA, SuiteMask, Reserved |
223 | 'L', 'L', 'V', 'M', 'L', 'L', 'V', 'M', 'L', 'L', 'V', 'M', // VendorID |
224 | 1, 2, 3, 4, 5, 6, 7, 8, // VersionInfo, FeatureInfo |
225 | 9, 0, 1, 2, // AMDExtendedFeatures |
226 | }; |
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 | |
253 | TEST(MinidumpFile, getString) { |
254 | std::vector<uint8_t> ManyStrings{ |
255 | // Header |
256 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
257 | 2, 0, 0, 0, // NumberOfStreams, |
258 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
259 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
260 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
261 | // Stream Directory |
262 | 0, 0, 0, 0, 0, 0, 0, 0, // Type, DataSize, |
263 | 0x20, 0, 0, 0, // RVA |
264 | 1, 0, 0, 0, 0, 0, // String1 - odd length |
265 | 0, 0, 1, 0, 0, 0, // String2 - too long |
266 | 2, 0, 0, 0, 0, 0xd8, // String3 - invalid utf16 |
267 | 0, 0, 0, 0, 0, 0, // String4 - "" |
268 | 2, 0, 0, 0, 'a', 0, // String5 - "a" |
269 | 0, // Mis-align next string |
270 | 2, 0, 0, 0, 'a', 0, // String6 - "a" |
271 | |
272 | }; |
273 | auto ExpectedFile = create(Data: 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 | |
288 | TEST(MinidumpFile, getModuleList) { |
289 | std::vector<uint8_t> OneModule{ |
290 | // Header |
291 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
292 | 1, 0, 0, 0, // NumberOfStreams, |
293 | 32, 0, 0, 0, // StreamDirectoryRVA |
294 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
295 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
296 | // Stream Directory |
297 | 4, 0, 0, 0, 112, 0, 0, 0, // Type, DataSize, |
298 | 44, 0, 0, 0, // RVA |
299 | // ModuleList |
300 | 1, 0, 0, 0, // NumberOfModules |
301 | 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage |
302 | 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum |
303 | 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA |
304 | 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion |
305 | 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion |
306 | 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion |
307 | 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags |
308 | 0, 0, 0, 0, // FileOS |
309 | 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType |
310 | 0, 0, 0, 0, 0, 0, 0, 0, // FileDate |
311 | 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord |
312 | 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord |
313 | 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0 |
314 | 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1 |
315 | }; |
316 | // Same as before, but with a padded module list. |
317 | std::vector<uint8_t> PaddedModule{ |
318 | // Header |
319 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
320 | 1, 0, 0, 0, // NumberOfStreams, |
321 | 32, 0, 0, 0, // StreamDirectoryRVA |
322 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
323 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
324 | // Stream Directory |
325 | 4, 0, 0, 0, 116, 0, 0, 0, // Type, DataSize, |
326 | 44, 0, 0, 0, // RVA |
327 | // ModuleList |
328 | 1, 0, 0, 0, // NumberOfModules |
329 | 0, 0, 0, 0, // Padding |
330 | 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage |
331 | 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum |
332 | 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA |
333 | 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion |
334 | 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion |
335 | 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion |
336 | 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags |
337 | 0, 0, 0, 0, // FileOS |
338 | 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType |
339 | 0, 0, 0, 0, 0, 0, 0, 0, // FileDate |
340 | 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord |
341 | 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord |
342 | 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0 |
343 | 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1 |
344 | }; |
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 | // Header |
369 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
370 | 1, 0, 0, 0, // NumberOfStreams, |
371 | 32, 0, 0, 0, // StreamDirectoryRVA |
372 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
373 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
374 | // Stream Directory |
375 | 4, 0, 0, 0, 111, 0, 0, 0, // Type, DataSize, |
376 | 44, 0, 0, 0, // RVA |
377 | // ModuleList |
378 | 1, 0, 0, 0, // NumberOfModules |
379 | 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage |
380 | 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum |
381 | 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA |
382 | 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion |
383 | 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion |
384 | 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion |
385 | 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags |
386 | 0, 0, 0, 0, // FileOS |
387 | 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType |
388 | 0, 0, 0, 0, 0, 0, 0, 0, // FileDate |
389 | 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord |
390 | 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord |
391 | 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0 |
392 | 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1 |
393 | }; |
394 | auto ExpectedFile = create(Data: StreamTooShort); |
395 | ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded()); |
396 | const MinidumpFile &File = **ExpectedFile; |
397 | EXPECT_THAT_EXPECTED(File.getModuleList(), Failed<BinaryError>()); |
398 | } |
399 | |
400 | TEST(MinidumpFile, getThreadList) { |
401 | std::vector<uint8_t> OneThread{ |
402 | // Header |
403 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
404 | 1, 0, 0, 0, // NumberOfStreams, |
405 | 32, 0, 0, 0, // StreamDirectoryRVA |
406 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
407 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
408 | // Stream Directory |
409 | 3, 0, 0, 0, 52, 0, 0, 0, // Type, DataSize, |
410 | 44, 0, 0, 0, // RVA |
411 | // ThreadList |
412 | 1, 0, 0, 0, // NumberOfThreads |
413 | 1, 2, 3, 4, 5, 6, 7, 8, // ThreadId, SuspendCount |
414 | 9, 0, 1, 2, 3, 4, 5, 6, // PriorityClass, Priority |
415 | 7, 8, 9, 0, 1, 2, 3, 4, // EnvironmentBlock |
416 | // Stack |
417 | 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange |
418 | 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA |
419 | // Context |
420 | 1, 2, 3, 4, 5, 6, 7, 8, // DataSize, RVA |
421 | }; |
422 | // Same as before, but with a padded thread list. |
423 | std::vector<uint8_t> PaddedThread{ |
424 | // Header |
425 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
426 | 1, 0, 0, 0, // NumberOfStreams, |
427 | 32, 0, 0, 0, // StreamDirectoryRVA |
428 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
429 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
430 | // Stream Directory |
431 | 3, 0, 0, 0, 56, 0, 0, 0, // Type, DataSize, |
432 | 44, 0, 0, 0, // RVA |
433 | // ThreadList |
434 | 1, 0, 0, 0, // NumberOfThreads |
435 | 0, 0, 0, 0, // Padding |
436 | 1, 2, 3, 4, 5, 6, 7, 8, // ThreadId, SuspendCount |
437 | 9, 0, 1, 2, 3, 4, 5, 6, // PriorityClass, Priority |
438 | 7, 8, 9, 0, 1, 2, 3, 4, // EnvironmentBlock |
439 | // Stack |
440 | 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange |
441 | 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA |
442 | // Context |
443 | 1, 2, 3, 4, 5, 6, 7, 8, // DataSize, RVA |
444 | }; |
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 | |
467 | TEST(MinidumpFile, getMemoryList) { |
468 | std::vector<uint8_t> OneRange{ |
469 | // Header |
470 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
471 | 1, 0, 0, 0, // NumberOfStreams, |
472 | 32, 0, 0, 0, // StreamDirectoryRVA |
473 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
474 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
475 | // Stream Directory |
476 | 5, 0, 0, 0, 20, 0, 0, 0, // Type, DataSize, |
477 | 44, 0, 0, 0, // RVA |
478 | // MemoryDescriptor |
479 | 1, 0, 0, 0, // NumberOfMemoryRanges |
480 | 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange |
481 | 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA |
482 | }; |
483 | // Same as before, but with a padded memory list. |
484 | std::vector<uint8_t> PaddedRange{ |
485 | // Header |
486 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
487 | 1, 0, 0, 0, // NumberOfStreams, |
488 | 32, 0, 0, 0, // StreamDirectoryRVA |
489 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
490 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
491 | // Stream Directory |
492 | 5, 0, 0, 0, 24, 0, 0, 0, // Type, DataSize, |
493 | 44, 0, 0, 0, // RVA |
494 | // MemoryDescriptor |
495 | 1, 0, 0, 0, // NumberOfMemoryRanges |
496 | 0, 0, 0, 0, // Padding |
497 | 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange |
498 | 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA |
499 | }; |
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 | |
515 | TEST(MinidumpFile, getMemoryInfoList) { |
516 | std::vector<uint8_t> OneEntry{ |
517 | // Header |
518 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
519 | 1, 0, 0, 0, // NumberOfStreams, |
520 | 32, 0, 0, 0, // StreamDirectoryRVA |
521 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
522 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
523 | // Stream Directory |
524 | 16, 0, 0, 0, 64, 0, 0, 0, // Type, DataSize, |
525 | 44, 0, 0, 0, // RVA |
526 | // MemoryInfoListHeader |
527 | 16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry |
528 | 1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries |
529 | // MemoryInfo |
530 | 0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress |
531 | 8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase |
532 | 16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0 |
533 | 0, 1, 2, 3, 4, 5, 6, 7, // RegionSize |
534 | 0, 16, 0, 0, 32, 0, 0, 0, // State, Protect |
535 | 0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1 |
536 | }; |
537 | |
538 | // Same as before, but the list header is larger. |
539 | std::vector<uint8_t> { |
540 | // Header |
541 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
542 | 1, 0, 0, 0, // NumberOfStreams, |
543 | 32, 0, 0, 0, // StreamDirectoryRVA |
544 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
545 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
546 | // Stream Directory |
547 | 16, 0, 0, 0, 68, 0, 0, 0, // Type, DataSize, |
548 | 44, 0, 0, 0, // RVA |
549 | // MemoryInfoListHeader |
550 | 20, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry |
551 | 1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries |
552 | 0, 0, 0, 0, // ??? |
553 | // MemoryInfo |
554 | 0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress |
555 | 8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase |
556 | 16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0 |
557 | 0, 1, 2, 3, 4, 5, 6, 7, // RegionSize |
558 | 0, 16, 0, 0, 32, 0, 0, 0, // State, Protect |
559 | 0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1 |
560 | }; |
561 | |
562 | // Same as before, but the entry is larger. |
563 | std::vector<uint8_t> BiggerEntry{ |
564 | // Header |
565 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
566 | 1, 0, 0, 0, // NumberOfStreams, |
567 | 32, 0, 0, 0, // StreamDirectoryRVA |
568 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
569 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
570 | // Stream Directory |
571 | 16, 0, 0, 0, 68, 0, 0, 0, // Type, DataSize, |
572 | 44, 0, 0, 0, // RVA |
573 | // MemoryInfoListHeader |
574 | 16, 0, 0, 0, 52, 0, 0, 0, // SizeOfHeader, SizeOfEntry |
575 | 1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries |
576 | // MemoryInfo |
577 | 0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress |
578 | 8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase |
579 | 16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0 |
580 | 0, 1, 2, 3, 4, 5, 6, 7, // RegionSize |
581 | 0, 16, 0, 0, 32, 0, 0, 0, // State, Protect |
582 | 0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1 |
583 | 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> { |
607 | // Header |
608 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
609 | 1, 0, 0, 0, // NumberOfStreams, |
610 | 32, 0, 0, 0, // StreamDirectoryRVA |
611 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
612 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
613 | // Stream Directory |
614 | 16, 0, 0, 0, 15, 0, 0, 0, // Type, DataSize, |
615 | 44, 0, 0, 0, // RVA |
616 | // MemoryInfoListHeader |
617 | 16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry |
618 | 1, 0, 0, 0, 0, 0, 0, // ??? |
619 | }; |
620 | Expected<std::unique_ptr<MinidumpFile>> File = create(Data: 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 required |
625 | // entries. |
626 | std::vector<uint8_t> { |
627 | // Header |
628 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
629 | 1, 0, 0, 0, // NumberOfStreams, |
630 | 32, 0, 0, 0, // StreamDirectoryRVA |
631 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
632 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
633 | // Stream Directory |
634 | 16, 0, 0, 0, 15, 0, 0, 0, // Type, DataSize, |
635 | 44, 0, 0, 0, // RVA |
636 | // MemoryInfoListHeader |
637 | 15, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry |
638 | 1, 0, 0, 0, 0, 0, 0, // ??? |
639 | }; |
640 | File = create(Data: HeaderTooSmall); |
641 | ASSERT_THAT_EXPECTED(File, Succeeded()); |
642 | EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>()); |
643 | |
644 | std::vector<uint8_t> EntryTooBig{ |
645 | // Header |
646 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
647 | 1, 0, 0, 0, // NumberOfStreams, |
648 | 32, 0, 0, 0, // StreamDirectoryRVA |
649 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
650 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
651 | // Stream Directory |
652 | 16, 0, 0, 0, 64, 0, 0, 0, // Type, DataSize, |
653 | 44, 0, 0, 0, // RVA |
654 | // MemoryInfoListHeader |
655 | 16, 0, 0, 0, 49, 0, 0, 0, // SizeOfHeader, SizeOfEntry |
656 | 1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries |
657 | // MemoryInfo |
658 | 0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress |
659 | 8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase |
660 | 16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0 |
661 | 0, 1, 2, 3, 4, 5, 6, 7, // RegionSize |
662 | 0, 16, 0, 0, 32, 0, 0, 0, // State, Protect |
663 | 0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1 |
664 | }; |
665 | File = create(Data: EntryTooBig); |
666 | ASSERT_THAT_EXPECTED(File, Succeeded()); |
667 | EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>()); |
668 | |
669 | std::vector<uint8_t> ThreeEntries{ |
670 | // Header |
671 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
672 | 1, 0, 0, 0, // NumberOfStreams, |
673 | 32, 0, 0, 0, // StreamDirectoryRVA |
674 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
675 | 0, 0, 0, 0, 0, 0, 0, 0, // Flags |
676 | // Stream Directory |
677 | 16, 0, 0, 0, 160, 0, 0, 0, // Type, DataSize, |
678 | 44, 0, 0, 0, // RVA |
679 | // MemoryInfoListHeader |
680 | 16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry |
681 | 3, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries |
682 | // MemoryInfo |
683 | 0, 1, 2, 3, 0, 0, 0, 0, // BaseAddress |
684 | 0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase |
685 | 0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0 |
686 | 0, 0, 0, 0, 0, 0, 0, 0, // RegionSize |
687 | 0, 0, 0, 0, 0, 0, 0, 0, // State, Protect |
688 | 0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1 |
689 | 0, 0, 4, 5, 6, 7, 0, 0, // BaseAddress |
690 | 0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase |
691 | 0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0 |
692 | 0, 0, 0, 0, 0, 0, 0, 0, // RegionSize |
693 | 0, 0, 0, 0, 0, 0, 0, 0, // State, Protect |
694 | 0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1 |
695 | 0, 0, 0, 8, 9, 0, 1, 0, // BaseAddress |
696 | 0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase |
697 | 0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0 |
698 | 0, 0, 0, 0, 0, 0, 0, 0, // RegionSize |
699 | 0, 0, 0, 0, 0, 0, 0, 0, // State, Protect |
700 | 0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1 |
701 | }; |
702 | File = create(Data: 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 | |
714 | TEST(MinidumpFile, getExceptionStream) { |
715 | std::vector<uint8_t> Data{ |
716 | // Header |
717 | 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version |
718 | 1, 0, 0, 0, // NumberOfStreams, |
719 | 0x20, 0, 0, 0, // StreamDirectoryRVA |
720 | 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp |
721 | 8, 9, 0, 1, 2, 3, 4, 5, // Flags |
722 | // Stream Directory |
723 | 6, 0, 0, 0, 168, 0, 0, 0, // Type, DataSize, |
724 | 0x2c, 0, 0, 0, // RVA |
725 | // Exception Stream |
726 | 1, 2, 3, 4, // Thread ID |
727 | 0, 0, 0, 0, // Padding |
728 | // Exception Record |
729 | 2, 3, 4, 2, 7, 8, 8, 9, // Code, Flags |
730 | 3, 4, 5, 6, 7, 8, 9, 10, // Inner exception record address |
731 | 8, 7, 6, 5, 4, 3, 2, 1, // Exception address |
732 | 4, 0, 0, 0, 0, 0, 0, 0, // Parameter count, padding |
733 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, // Parameter 0 |
734 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, // Parameter 1 |
735 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Parameter 2 |
736 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, // Parameter 3 |
737 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // Parameter 4 |
738 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // Parameter 5 |
739 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // Parameter 6 |
740 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, // Parameter 7 |
741 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, // Parameter 8 |
742 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, // Parameter 9 |
743 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, // Parameter 10 |
744 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, // Parameter 11 |
745 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, // Parameter 12 |
746 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, // Parameter 13 |
747 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, // Parameter 14 |
748 | // Thread Context |
749 | 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, // DataSize, RVA |
750 | }; |
751 | auto ExpectedFile = create(Data); |
752 | ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded()); |
753 | const MinidumpFile &File = **ExpectedFile; |
754 | Expected<const minidump::ExceptionStream &> ExpectedStream = |
755 | File.getExceptionStream(); |
756 | ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded()); |
757 | EXPECT_EQ(0x04030201u, ExpectedStream->ThreadId); |
758 | const minidump::Exception &Exception = ExpectedStream->ExceptionRecord; |
759 | EXPECT_EQ(0x02040302u, Exception.ExceptionCode); |
760 | EXPECT_EQ(0x09080807u, Exception.ExceptionFlags); |
761 | EXPECT_EQ(0x0a09080706050403u, Exception.ExceptionRecord); |
762 | EXPECT_EQ(0x0102030405060708u, Exception.ExceptionAddress); |
763 | EXPECT_EQ(4u, Exception.NumberParameters); |
764 | for (uint64_t index = 0; index < Exception.MaxParameters; ++index) { |
765 | EXPECT_EQ(0x1716151413121110u + index * 0x1010101010101010u, |
766 | Exception.ExceptionInformation[index]); |
767 | } |
768 | EXPECT_EQ(0x84838281, ExpectedStream->ThreadContext.DataSize); |
769 | EXPECT_EQ(0x88878685, ExpectedStream->ThreadContext.RVA); |
770 | } |
771 | |