MinidumpTest.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  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. #include "llvm/Object/Minidump.h"
  9. #include "llvm/Support/MemoryBuffer.h"
  10. #include "llvm/Testing/Support/Error.h"
  11. #include "gtest/gtest.h"
  12. using namespace llvm;
  13. using namespace llvm::object;
  14. using namespace minidump;
  15. static Expected<std::unique_ptr<MinidumpFile>> create(ArrayRef<uint8_t> Data) {
  16. return MinidumpFile::create(
  17. MemoryBufferRef(toStringRef(Data), "Test buffer"));
  18. }
  19. TEST(MinidumpFile, BasicInterface) {
  20. std::vector<uint8_t> Data{ // Header
  21. 'M', 'D', 'M', 'P', // Signature
  22. 0x93, 0xa7, 0, 0, // Version
  23. 1, 0, 0, 0, // NumberOfStreams,
  24. 0x20, 0, 0, 0, // StreamDirectoryRVA
  25. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  26. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  27. // Stream Directory
  28. 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
  29. 0x2c, 0, 0, 0, // RVA
  30. // Stream
  31. 'C', 'P', 'U', 'I', 'N', 'F', 'O'};
  32. // A very simple minidump file which contains just a single stream.
  33. auto ExpectedFile = create(Data);
  34. ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  35. const MinidumpFile &File = **ExpectedFile;
  36. const Header &H = File.header();
  37. EXPECT_EQ(Header::MagicSignature, H.Signature);
  38. EXPECT_EQ(Header::MagicVersion, H.Version);
  39. EXPECT_EQ(1u, H.NumberOfStreams);
  40. EXPECT_EQ(0x20u, H.StreamDirectoryRVA);
  41. EXPECT_EQ(0x03020100u, H.Checksum);
  42. EXPECT_EQ(0x07060504u, H.TimeDateStamp);
  43. EXPECT_EQ(uint64_t(0x0504030201000908), H.Flags);
  44. ASSERT_EQ(1u, File.streams().size());
  45. const Directory &Stream0 = File.streams()[0];
  46. EXPECT_EQ(StreamType::LinuxCPUInfo, Stream0.Type);
  47. EXPECT_EQ(7u, Stream0.Location.DataSize);
  48. EXPECT_EQ(0x2cu, Stream0.Location.RVA);
  49. EXPECT_EQ("CPUINFO", toStringRef(File.getRawStream(Stream0)));
  50. EXPECT_EQ("CPUINFO",
  51. toStringRef(*File.getRawStream(StreamType::LinuxCPUInfo)));
  52. EXPECT_THAT_EXPECTED(File.getSystemInfo(), Failed<BinaryError>());
  53. }
  54. // Use the input from the previous test, but corrupt it in various ways
  55. TEST(MinidumpFile, create_ErrorCases) {
  56. std::vector<uint8_t> FileTooShort{'M', 'D', 'M', 'P'};
  57. EXPECT_THAT_EXPECTED(create(FileTooShort), Failed<BinaryError>());
  58. std::vector<uint8_t> WrongSignature{
  59. // Header
  60. '!', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  61. 1, 0, 0, 0, // NumberOfStreams,
  62. 0x20, 0, 0, 0, // StreamDirectoryRVA
  63. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  64. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  65. // Stream Directory
  66. 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
  67. 0x2c, 0, 0, 0, // RVA
  68. // Stream
  69. 'C', 'P', 'U', 'I', 'N', 'F', 'O'};
  70. EXPECT_THAT_EXPECTED(create(WrongSignature), Failed<BinaryError>());
  71. std::vector<uint8_t> WrongVersion{
  72. // Header
  73. 'M', 'D', 'M', 'P', 0x39, 0xa7, 0, 0, // Signature, Version
  74. 1, 0, 0, 0, // NumberOfStreams,
  75. 0x20, 0, 0, 0, // StreamDirectoryRVA
  76. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  77. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  78. // Stream Directory
  79. 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
  80. 0x2c, 0, 0, 0, // RVA
  81. // Stream
  82. 'C', 'P', 'U', 'I', 'N', 'F', 'O'};
  83. EXPECT_THAT_EXPECTED(create(WrongVersion), Failed<BinaryError>());
  84. std::vector<uint8_t> DirectoryAfterEOF{
  85. // Header
  86. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  87. 1, 0, 0, 0, // NumberOfStreams,
  88. 0x20, 1, 0, 0, // StreamDirectoryRVA
  89. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  90. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  91. // Stream Directory
  92. 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
  93. 0x2c, 0, 0, 0, // RVA
  94. // Stream
  95. 'C', 'P', 'U', 'I', 'N', 'F', 'O'};
  96. EXPECT_THAT_EXPECTED(create(DirectoryAfterEOF), Failed<BinaryError>());
  97. std::vector<uint8_t> TruncatedDirectory{
  98. // Header
  99. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  100. 1, 1, 0, 0, // NumberOfStreams,
  101. 0x20, 0, 0, 0, // StreamDirectoryRVA
  102. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  103. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  104. // Stream Directory
  105. 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
  106. 0x2c, 0, 0, 0, // RVA
  107. // Stream
  108. 'C', 'P', 'U', 'I', 'N', 'F', 'O'};
  109. EXPECT_THAT_EXPECTED(create(TruncatedDirectory), Failed<BinaryError>());
  110. std::vector<uint8_t> Stream0AfterEOF{
  111. // Header
  112. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  113. 1, 0, 0, 0, // NumberOfStreams,
  114. 0x20, 0, 0, 0, // StreamDirectoryRVA
  115. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  116. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  117. // Stream Directory
  118. 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
  119. 0x2c, 1, 0, 0, // RVA
  120. // Stream
  121. 'C', 'P', 'U', 'I', 'N', 'F', 'O'};
  122. EXPECT_THAT_EXPECTED(create(Stream0AfterEOF), Failed<BinaryError>());
  123. std::vector<uint8_t> Stream0Truncated{
  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, 8, 0, 0, 0, // Type, DataSize,
  132. 0x2c, 0, 0, 0, // RVA
  133. // Stream
  134. 'C', 'P', 'U', 'I', 'N', 'F', 'O'};
  135. EXPECT_THAT_EXPECTED(create(Stream0Truncated), Failed<BinaryError>());
  136. std::vector<uint8_t> DuplicateStream{
  137. // Header
  138. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  139. 2, 0, 0, 0, // NumberOfStreams,
  140. 0x20, 0, 0, 0, // StreamDirectoryRVA
  141. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  142. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  143. // Stream Directory
  144. 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
  145. 0x40, 0, 0, 0, // RVA
  146. // Stream
  147. 3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
  148. 0x40, 0, 0, 0, // RVA
  149. // Stream
  150. 'C', 'P', 'U', 'I', 'N', 'F', 'O'};
  151. EXPECT_THAT_EXPECTED(create(DuplicateStream), Failed<BinaryError>());
  152. std::vector<uint8_t> DenseMapInfoConflict{
  153. // Header
  154. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  155. 1, 0, 0, 0, // NumberOfStreams,
  156. 0x20, 0, 0, 0, // StreamDirectoryRVA
  157. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  158. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  159. // Stream Directory
  160. 0xff, 0xff, 0xff, 0xff, 7, 0, 0, 0, // Type, DataSize,
  161. 0x2c, 0, 0, 0, // RVA
  162. // Stream
  163. 'C', 'P', 'U', 'I', 'N', 'F', 'O'};
  164. EXPECT_THAT_EXPECTED(create(DenseMapInfoConflict), Failed<BinaryError>());
  165. }
  166. TEST(MinidumpFile, IngoresDummyStreams) {
  167. std::vector<uint8_t> TwoDummyStreams{
  168. // Header
  169. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  170. 2, 0, 0, 0, // NumberOfStreams,
  171. 0x20, 0, 0, 0, // StreamDirectoryRVA
  172. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  173. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  174. // Stream Directory
  175. 0, 0, 0, 0, 0, 0, 0, 0, // Type, DataSize,
  176. 0x20, 0, 0, 0, // RVA
  177. 0, 0, 0, 0, 0, 0, 0, 0, // Type, DataSize,
  178. 0x20, 0, 0, 0, // RVA
  179. };
  180. auto ExpectedFile = create(TwoDummyStreams);
  181. ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  182. const MinidumpFile &File = **ExpectedFile;
  183. ASSERT_EQ(2u, File.streams().size());
  184. EXPECT_EQ(StreamType::Unused, File.streams()[0].Type);
  185. EXPECT_EQ(StreamType::Unused, File.streams()[1].Type);
  186. EXPECT_EQ(None, File.getRawStream(StreamType::Unused));
  187. }
  188. TEST(MinidumpFile, getSystemInfo) {
  189. std::vector<uint8_t> Data{
  190. // Header
  191. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  192. 1, 0, 0, 0, // NumberOfStreams,
  193. 0x20, 0, 0, 0, // StreamDirectoryRVA
  194. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  195. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  196. // Stream Directory
  197. 7, 0, 0, 0, 56, 0, 0, 0, // Type, DataSize,
  198. 0x2c, 0, 0, 0, // RVA
  199. // SystemInfo
  200. 0, 0, 1, 2, // ProcessorArch, ProcessorLevel
  201. 3, 4, 5, 6, // ProcessorRevision, NumberOfProcessors, ProductType
  202. 7, 8, 9, 0, 1, 2, 3, 4, // MajorVersion, MinorVersion
  203. 5, 6, 7, 8, 2, 0, 0, 0, // BuildNumber, PlatformId
  204. 1, 2, 3, 4, 5, 6, 7, 8, // CSDVersionRVA, SuiteMask, Reserved
  205. 'L', 'L', 'V', 'M', 'L', 'L', 'V', 'M', 'L', 'L', 'V', 'M', // VendorID
  206. 1, 2, 3, 4, 5, 6, 7, 8, // VersionInfo, FeatureInfo
  207. 9, 0, 1, 2, // AMDExtendedFeatures
  208. };
  209. auto ExpectedFile = create(Data);
  210. ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  211. const MinidumpFile &File = **ExpectedFile;
  212. auto ExpectedInfo = File.getSystemInfo();
  213. ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());
  214. const SystemInfo &Info = *ExpectedInfo;
  215. EXPECT_EQ(ProcessorArchitecture::X86, Info.ProcessorArch);
  216. EXPECT_EQ(0x0201, Info.ProcessorLevel);
  217. EXPECT_EQ(0x0403, Info.ProcessorRevision);
  218. EXPECT_EQ(5, Info.NumberOfProcessors);
  219. EXPECT_EQ(6, Info.ProductType);
  220. EXPECT_EQ(0x00090807u, Info.MajorVersion);
  221. EXPECT_EQ(0x04030201u, Info.MinorVersion);
  222. EXPECT_EQ(0x08070605u, Info.BuildNumber);
  223. EXPECT_EQ(OSPlatform::Win32NT, Info.PlatformId);
  224. EXPECT_EQ(0x04030201u, Info.CSDVersionRVA);
  225. EXPECT_EQ(0x0605u, Info.SuiteMask);
  226. EXPECT_EQ(0x0807u, Info.Reserved);
  227. EXPECT_EQ("LLVMLLVMLLVM", llvm::StringRef(Info.CPU.X86.VendorID,
  228. sizeof(Info.CPU.X86.VendorID)));
  229. EXPECT_EQ(0x04030201u, Info.CPU.X86.VersionInfo);
  230. EXPECT_EQ(0x08070605u, Info.CPU.X86.FeatureInfo);
  231. EXPECT_EQ(0x02010009u, Info.CPU.X86.AMDExtendedFeatures);
  232. }
  233. TEST(MinidumpFile, getString) {
  234. std::vector<uint8_t> ManyStrings{
  235. // Header
  236. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  237. 2, 0, 0, 0, // NumberOfStreams,
  238. 0x20, 0, 0, 0, // StreamDirectoryRVA
  239. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  240. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  241. // Stream Directory
  242. 0, 0, 0, 0, 0, 0, 0, 0, // Type, DataSize,
  243. 0x20, 0, 0, 0, // RVA
  244. 1, 0, 0, 0, 0, 0, // String1 - odd length
  245. 0, 0, 1, 0, 0, 0, // String2 - too long
  246. 2, 0, 0, 0, 0, 0xd8, // String3 - invalid utf16
  247. 0, 0, 0, 0, 0, 0, // String4 - ""
  248. 2, 0, 0, 0, 'a', 0, // String5 - "a"
  249. 0, // Mis-align next string
  250. 2, 0, 0, 0, 'a', 0, // String6 - "a"
  251. };
  252. auto ExpectedFile = create(ManyStrings);
  253. ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  254. const MinidumpFile &File = **ExpectedFile;
  255. EXPECT_THAT_EXPECTED(File.getString(44), Failed<BinaryError>());
  256. EXPECT_THAT_EXPECTED(File.getString(50), Failed<BinaryError>());
  257. EXPECT_THAT_EXPECTED(File.getString(56), Failed<BinaryError>());
  258. EXPECT_THAT_EXPECTED(File.getString(62), HasValue(""));
  259. EXPECT_THAT_EXPECTED(File.getString(68), HasValue("a"));
  260. EXPECT_THAT_EXPECTED(File.getString(75), HasValue("a"));
  261. // Check the case when the size field does not fit into the remaining data.
  262. EXPECT_THAT_EXPECTED(File.getString(ManyStrings.size() - 2),
  263. Failed<BinaryError>());
  264. }
  265. TEST(MinidumpFile, getModuleList) {
  266. std::vector<uint8_t> OneModule{
  267. // Header
  268. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  269. 1, 0, 0, 0, // NumberOfStreams,
  270. 32, 0, 0, 0, // StreamDirectoryRVA
  271. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  272. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  273. // Stream Directory
  274. 4, 0, 0, 0, 112, 0, 0, 0, // Type, DataSize,
  275. 44, 0, 0, 0, // RVA
  276. // ModuleList
  277. 1, 0, 0, 0, // NumberOfModules
  278. 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
  279. 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
  280. 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
  281. 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
  282. 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
  283. 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
  284. 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
  285. 0, 0, 0, 0, // FileOS
  286. 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
  287. 0, 0, 0, 0, 0, 0, 0, 0, // FileDate
  288. 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
  289. 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
  290. 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
  291. 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
  292. };
  293. // Same as before, but with a padded module list.
  294. std::vector<uint8_t> PaddedModule{
  295. // Header
  296. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  297. 1, 0, 0, 0, // NumberOfStreams,
  298. 32, 0, 0, 0, // StreamDirectoryRVA
  299. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  300. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  301. // Stream Directory
  302. 4, 0, 0, 0, 116, 0, 0, 0, // Type, DataSize,
  303. 44, 0, 0, 0, // RVA
  304. // ModuleList
  305. 1, 0, 0, 0, // NumberOfModules
  306. 0, 0, 0, 0, // Padding
  307. 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
  308. 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
  309. 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
  310. 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
  311. 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
  312. 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
  313. 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
  314. 0, 0, 0, 0, // FileOS
  315. 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
  316. 0, 0, 0, 0, 0, 0, 0, 0, // FileDate
  317. 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
  318. 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
  319. 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
  320. 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
  321. };
  322. for (ArrayRef<uint8_t> Data : {OneModule, PaddedModule}) {
  323. auto ExpectedFile = create(Data);
  324. ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  325. const MinidumpFile &File = **ExpectedFile;
  326. Expected<ArrayRef<Module>> ExpectedModule = File.getModuleList();
  327. ASSERT_THAT_EXPECTED(ExpectedModule, Succeeded());
  328. ASSERT_EQ(1u, ExpectedModule->size());
  329. const Module &M = ExpectedModule.get()[0];
  330. EXPECT_EQ(0x0807060504030201u, M.BaseOfImage);
  331. EXPECT_EQ(0x02010009u, M.SizeOfImage);
  332. EXPECT_EQ(0x06050403u, M.Checksum);
  333. EXPECT_EQ(0x00090807u, M.TimeDateStamp);
  334. EXPECT_EQ(0x04030201u, M.ModuleNameRVA);
  335. EXPECT_EQ(0x04030201u, M.CvRecord.DataSize);
  336. EXPECT_EQ(0x08070605u, M.CvRecord.RVA);
  337. EXPECT_EQ(0x02010009u, M.MiscRecord.DataSize);
  338. EXPECT_EQ(0x06050403u, M.MiscRecord.RVA);
  339. EXPECT_EQ(0x0403020100090807u, M.Reserved0);
  340. EXPECT_EQ(0x0201000908070605u, M.Reserved1);
  341. }
  342. std::vector<uint8_t> StreamTooShort{
  343. // Header
  344. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  345. 1, 0, 0, 0, // NumberOfStreams,
  346. 32, 0, 0, 0, // StreamDirectoryRVA
  347. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  348. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  349. // Stream Directory
  350. 4, 0, 0, 0, 111, 0, 0, 0, // Type, DataSize,
  351. 44, 0, 0, 0, // RVA
  352. // ModuleList
  353. 1, 0, 0, 0, // NumberOfModules
  354. 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
  355. 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
  356. 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
  357. 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
  358. 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
  359. 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
  360. 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
  361. 0, 0, 0, 0, // FileOS
  362. 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
  363. 0, 0, 0, 0, 0, 0, 0, 0, // FileDate
  364. 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
  365. 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
  366. 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
  367. 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
  368. };
  369. auto ExpectedFile = create(StreamTooShort);
  370. ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  371. const MinidumpFile &File = **ExpectedFile;
  372. EXPECT_THAT_EXPECTED(File.getModuleList(), Failed<BinaryError>());
  373. }
  374. TEST(MinidumpFile, getThreadList) {
  375. std::vector<uint8_t> OneThread{
  376. // Header
  377. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  378. 1, 0, 0, 0, // NumberOfStreams,
  379. 32, 0, 0, 0, // StreamDirectoryRVA
  380. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  381. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  382. // Stream Directory
  383. 3, 0, 0, 0, 52, 0, 0, 0, // Type, DataSize,
  384. 44, 0, 0, 0, // RVA
  385. // ThreadList
  386. 1, 0, 0, 0, // NumberOfThreads
  387. 1, 2, 3, 4, 5, 6, 7, 8, // ThreadId, SuspendCount
  388. 9, 0, 1, 2, 3, 4, 5, 6, // PriorityClass, Priority
  389. 7, 8, 9, 0, 1, 2, 3, 4, // EnvironmentBlock
  390. // Stack
  391. 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
  392. 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
  393. // Context
  394. 1, 2, 3, 4, 5, 6, 7, 8, // DataSize, RVA
  395. };
  396. // Same as before, but with a padded thread list.
  397. std::vector<uint8_t> PaddedThread{
  398. // Header
  399. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  400. 1, 0, 0, 0, // NumberOfStreams,
  401. 32, 0, 0, 0, // StreamDirectoryRVA
  402. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  403. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  404. // Stream Directory
  405. 3, 0, 0, 0, 56, 0, 0, 0, // Type, DataSize,
  406. 44, 0, 0, 0, // RVA
  407. // ThreadList
  408. 1, 0, 0, 0, // NumberOfThreads
  409. 0, 0, 0, 0, // Padding
  410. 1, 2, 3, 4, 5, 6, 7, 8, // ThreadId, SuspendCount
  411. 9, 0, 1, 2, 3, 4, 5, 6, // PriorityClass, Priority
  412. 7, 8, 9, 0, 1, 2, 3, 4, // EnvironmentBlock
  413. // Stack
  414. 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
  415. 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
  416. // Context
  417. 1, 2, 3, 4, 5, 6, 7, 8, // DataSize, RVA
  418. };
  419. for (ArrayRef<uint8_t> Data : {OneThread, PaddedThread}) {
  420. auto ExpectedFile = create(Data);
  421. ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  422. const MinidumpFile &File = **ExpectedFile;
  423. Expected<ArrayRef<Thread>> ExpectedThread = File.getThreadList();
  424. ASSERT_THAT_EXPECTED(ExpectedThread, Succeeded());
  425. ASSERT_EQ(1u, ExpectedThread->size());
  426. const Thread &T = ExpectedThread.get()[0];
  427. EXPECT_EQ(0x04030201u, T.ThreadId);
  428. EXPECT_EQ(0x08070605u, T.SuspendCount);
  429. EXPECT_EQ(0x02010009u, T.PriorityClass);
  430. EXPECT_EQ(0x06050403u, T.Priority);
  431. EXPECT_EQ(0x0403020100090807u, T.EnvironmentBlock);
  432. EXPECT_EQ(0x0201000908070605u, T.Stack.StartOfMemoryRange);
  433. EXPECT_EQ(0x06050403u, T.Stack.Memory.DataSize);
  434. EXPECT_EQ(0x00090807u, T.Stack.Memory.RVA);
  435. EXPECT_EQ(0x04030201u, T.Context.DataSize);
  436. EXPECT_EQ(0x08070605u, T.Context.RVA);
  437. }
  438. }
  439. TEST(MinidumpFile, getMemoryList) {
  440. std::vector<uint8_t> OneRange{
  441. // Header
  442. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  443. 1, 0, 0, 0, // NumberOfStreams,
  444. 32, 0, 0, 0, // StreamDirectoryRVA
  445. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  446. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  447. // Stream Directory
  448. 5, 0, 0, 0, 20, 0, 0, 0, // Type, DataSize,
  449. 44, 0, 0, 0, // RVA
  450. // MemoryDescriptor
  451. 1, 0, 0, 0, // NumberOfMemoryRanges
  452. 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
  453. 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
  454. };
  455. // Same as before, but with a padded memory list.
  456. std::vector<uint8_t> PaddedRange{
  457. // Header
  458. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  459. 1, 0, 0, 0, // NumberOfStreams,
  460. 32, 0, 0, 0, // StreamDirectoryRVA
  461. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  462. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  463. // Stream Directory
  464. 5, 0, 0, 0, 24, 0, 0, 0, // Type, DataSize,
  465. 44, 0, 0, 0, // RVA
  466. // MemoryDescriptor
  467. 1, 0, 0, 0, // NumberOfMemoryRanges
  468. 0, 0, 0, 0, // Padding
  469. 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
  470. 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
  471. };
  472. for (ArrayRef<uint8_t> Data : {OneRange, PaddedRange}) {
  473. auto ExpectedFile = create(Data);
  474. ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  475. const MinidumpFile &File = **ExpectedFile;
  476. Expected<ArrayRef<MemoryDescriptor>> ExpectedRanges = File.getMemoryList();
  477. ASSERT_THAT_EXPECTED(ExpectedRanges, Succeeded());
  478. ASSERT_EQ(1u, ExpectedRanges->size());
  479. const MemoryDescriptor &MD = ExpectedRanges.get()[0];
  480. EXPECT_EQ(0x0201000908070605u, MD.StartOfMemoryRange);
  481. EXPECT_EQ(0x06050403u, MD.Memory.DataSize);
  482. EXPECT_EQ(0x00090807u, MD.Memory.RVA);
  483. }
  484. }
  485. TEST(MinidumpFile, getMemoryInfoList) {
  486. std::vector<uint8_t> OneEntry{
  487. // Header
  488. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  489. 1, 0, 0, 0, // NumberOfStreams,
  490. 32, 0, 0, 0, // StreamDirectoryRVA
  491. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  492. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  493. // Stream Directory
  494. 16, 0, 0, 0, 64, 0, 0, 0, // Type, DataSize,
  495. 44, 0, 0, 0, // RVA
  496. // MemoryInfoListHeader
  497. 16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
  498. 1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries
  499. // MemoryInfo
  500. 0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress
  501. 8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase
  502. 16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0
  503. 0, 1, 2, 3, 4, 5, 6, 7, // RegionSize
  504. 0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
  505. 0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1
  506. };
  507. // Same as before, but the list header is larger.
  508. std::vector<uint8_t> BiggerHeader{
  509. // Header
  510. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  511. 1, 0, 0, 0, // NumberOfStreams,
  512. 32, 0, 0, 0, // StreamDirectoryRVA
  513. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  514. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  515. // Stream Directory
  516. 16, 0, 0, 0, 68, 0, 0, 0, // Type, DataSize,
  517. 44, 0, 0, 0, // RVA
  518. // MemoryInfoListHeader
  519. 20, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
  520. 1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries
  521. 0, 0, 0, 0, // ???
  522. // MemoryInfo
  523. 0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress
  524. 8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase
  525. 16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0
  526. 0, 1, 2, 3, 4, 5, 6, 7, // RegionSize
  527. 0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
  528. 0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1
  529. };
  530. // Same as before, but the entry is larger.
  531. std::vector<uint8_t> BiggerEntry{
  532. // Header
  533. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  534. 1, 0, 0, 0, // NumberOfStreams,
  535. 32, 0, 0, 0, // StreamDirectoryRVA
  536. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  537. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  538. // Stream Directory
  539. 16, 0, 0, 0, 68, 0, 0, 0, // Type, DataSize,
  540. 44, 0, 0, 0, // RVA
  541. // MemoryInfoListHeader
  542. 16, 0, 0, 0, 52, 0, 0, 0, // SizeOfHeader, SizeOfEntry
  543. 1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries
  544. // MemoryInfo
  545. 0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress
  546. 8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase
  547. 16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0
  548. 0, 1, 2, 3, 4, 5, 6, 7, // RegionSize
  549. 0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
  550. 0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1
  551. 0, 0, 0, 0, // ???
  552. };
  553. for (ArrayRef<uint8_t> Data : {OneEntry, BiggerHeader, BiggerEntry}) {
  554. auto ExpectedFile = create(Data);
  555. ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  556. const MinidumpFile &File = **ExpectedFile;
  557. auto ExpectedInfo = File.getMemoryInfoList();
  558. ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());
  559. ASSERT_EQ(1u, std::distance(ExpectedInfo->begin(), ExpectedInfo->end()));
  560. const MemoryInfo &Info = *ExpectedInfo.get().begin();
  561. EXPECT_EQ(0x0706050403020100u, Info.BaseAddress);
  562. EXPECT_EQ(0x0504030201000908u, Info.AllocationBase);
  563. EXPECT_EQ(MemoryProtection::Execute, Info.AllocationProtect);
  564. EXPECT_EQ(0x09080706u, Info.Reserved0);
  565. EXPECT_EQ(0x0706050403020100u, Info.RegionSize);
  566. EXPECT_EQ(MemoryState::Commit, Info.State);
  567. EXPECT_EQ(MemoryProtection::ExecuteRead, Info.Protect);
  568. EXPECT_EQ(MemoryType::Private, Info.Type);
  569. EXPECT_EQ(0x01000908u, Info.Reserved1);
  570. }
  571. // Header does not fit into the stream.
  572. std::vector<uint8_t> HeaderTooBig{
  573. // Header
  574. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  575. 1, 0, 0, 0, // NumberOfStreams,
  576. 32, 0, 0, 0, // StreamDirectoryRVA
  577. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  578. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  579. // Stream Directory
  580. 16, 0, 0, 0, 15, 0, 0, 0, // Type, DataSize,
  581. 44, 0, 0, 0, // RVA
  582. // MemoryInfoListHeader
  583. 16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
  584. 1, 0, 0, 0, 0, 0, 0, // ???
  585. };
  586. Expected<std::unique_ptr<MinidumpFile>> File = create(HeaderTooBig);
  587. ASSERT_THAT_EXPECTED(File, Succeeded());
  588. EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
  589. // Header fits into the stream, but it is too small to contain the required
  590. // entries.
  591. std::vector<uint8_t> HeaderTooSmall{
  592. // Header
  593. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  594. 1, 0, 0, 0, // NumberOfStreams,
  595. 32, 0, 0, 0, // StreamDirectoryRVA
  596. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  597. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  598. // Stream Directory
  599. 16, 0, 0, 0, 15, 0, 0, 0, // Type, DataSize,
  600. 44, 0, 0, 0, // RVA
  601. // MemoryInfoListHeader
  602. 15, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
  603. 1, 0, 0, 0, 0, 0, 0, // ???
  604. };
  605. File = create(HeaderTooSmall);
  606. ASSERT_THAT_EXPECTED(File, Succeeded());
  607. EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
  608. std::vector<uint8_t> EntryTooBig{
  609. // Header
  610. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  611. 1, 0, 0, 0, // NumberOfStreams,
  612. 32, 0, 0, 0, // StreamDirectoryRVA
  613. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  614. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  615. // Stream Directory
  616. 16, 0, 0, 0, 64, 0, 0, 0, // Type, DataSize,
  617. 44, 0, 0, 0, // RVA
  618. // MemoryInfoListHeader
  619. 16, 0, 0, 0, 49, 0, 0, 0, // SizeOfHeader, SizeOfEntry
  620. 1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries
  621. // MemoryInfo
  622. 0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress
  623. 8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase
  624. 16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0
  625. 0, 1, 2, 3, 4, 5, 6, 7, // RegionSize
  626. 0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
  627. 0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1
  628. };
  629. File = create(EntryTooBig);
  630. ASSERT_THAT_EXPECTED(File, Succeeded());
  631. EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
  632. std::vector<uint8_t> ThreeEntries{
  633. // Header
  634. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  635. 1, 0, 0, 0, // NumberOfStreams,
  636. 32, 0, 0, 0, // StreamDirectoryRVA
  637. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  638. 0, 0, 0, 0, 0, 0, 0, 0, // Flags
  639. // Stream Directory
  640. 16, 0, 0, 0, 160, 0, 0, 0, // Type, DataSize,
  641. 44, 0, 0, 0, // RVA
  642. // MemoryInfoListHeader
  643. 16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
  644. 3, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries
  645. // MemoryInfo
  646. 0, 1, 2, 3, 0, 0, 0, 0, // BaseAddress
  647. 0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
  648. 0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
  649. 0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
  650. 0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
  651. 0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
  652. 0, 0, 4, 5, 6, 7, 0, 0, // BaseAddress
  653. 0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
  654. 0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
  655. 0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
  656. 0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
  657. 0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
  658. 0, 0, 0, 8, 9, 0, 1, 0, // BaseAddress
  659. 0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
  660. 0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
  661. 0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
  662. 0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
  663. 0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
  664. };
  665. File = create(ThreeEntries);
  666. ASSERT_THAT_EXPECTED(File, Succeeded());
  667. auto ExpectedInfo = File.get()->getMemoryInfoList();
  668. ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());
  669. EXPECT_THAT(to_vector<3>(map_range(*ExpectedInfo,
  670. [](const MemoryInfo &Info) -> uint64_t {
  671. return Info.BaseAddress;
  672. })),
  673. testing::ElementsAre(0x0000000003020100u, 0x0000070605040000u,
  674. 0x0001000908000000u));
  675. }
  676. TEST(MinidumpFile, getExceptionStream) {
  677. std::vector<uint8_t> Data{
  678. // Header
  679. 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
  680. 1, 0, 0, 0, // NumberOfStreams,
  681. 0x20, 0, 0, 0, // StreamDirectoryRVA
  682. 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
  683. 8, 9, 0, 1, 2, 3, 4, 5, // Flags
  684. // Stream Directory
  685. 6, 0, 0, 0, 168, 0, 0, 0, // Type, DataSize,
  686. 0x2c, 0, 0, 0, // RVA
  687. // Exception Stream
  688. 1, 2, 3, 4, // Thread ID
  689. 0, 0, 0, 0, // Padding
  690. // Exception Record
  691. 2, 3, 4, 2, 7, 8, 8, 9, // Code, Flags
  692. 3, 4, 5, 6, 7, 8, 9, 10, // Inner exception record address
  693. 8, 7, 6, 5, 4, 3, 2, 1, // Exception address
  694. 4, 0, 0, 0, 0, 0, 0, 0, // Parameter count, padding
  695. 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, // Parameter 0
  696. 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, // Parameter 1
  697. 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Parameter 2
  698. 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, // Parameter 3
  699. 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // Parameter 4
  700. 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // Parameter 5
  701. 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // Parameter 6
  702. 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, // Parameter 7
  703. 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, // Parameter 8
  704. 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, // Parameter 9
  705. 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, // Parameter 10
  706. 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, // Parameter 11
  707. 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, // Parameter 12
  708. 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, // Parameter 13
  709. 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, // Parameter 14
  710. // Thread Context
  711. 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, // DataSize, RVA
  712. };
  713. auto ExpectedFile = create(Data);
  714. ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  715. const MinidumpFile &File = **ExpectedFile;
  716. Expected<const minidump::ExceptionStream &> ExpectedStream =
  717. File.getExceptionStream();
  718. ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded());
  719. EXPECT_EQ(0x04030201u, ExpectedStream->ThreadId);
  720. const minidump::Exception &Exception = ExpectedStream->ExceptionRecord;
  721. EXPECT_EQ(0x02040302u, Exception.ExceptionCode);
  722. EXPECT_EQ(0x09080807u, Exception.ExceptionFlags);
  723. EXPECT_EQ(0x0a09080706050403u, Exception.ExceptionRecord);
  724. EXPECT_EQ(0x0102030405060708u, Exception.ExceptionAddress);
  725. EXPECT_EQ(4u, Exception.NumberParameters);
  726. for (uint64_t index = 0; index < Exception.MaxParameters; ++index) {
  727. EXPECT_EQ(0x1716151413121110u + index * 0x1010101010101010u,
  728. Exception.ExceptionInformation[index]);
  729. }
  730. EXPECT_EQ(0x84838281, ExpectedStream->ThreadContext.DataSize);
  731. EXPECT_EQ(0x88878685, ExpectedStream->ThreadContext.RVA);
  732. }