MinidumpTest.cpp 14 KB

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