MinidumpTest.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  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. }