MSFBuilderTest.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. //===- MSFBuilderTest.cpp Tests manipulation of MSF stream metadata ------===//
  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/DebugInfo/MSF/MSFBuilder.h"
  9. #include "llvm/DebugInfo/MSF/MSFCommon.h"
  10. #include "llvm/Testing/Support/Error.h"
  11. #include "gmock/gmock-matchers.h"
  12. #include "gmock/gmock.h"
  13. #include "gtest/gtest.h"
  14. using namespace llvm;
  15. using namespace llvm::msf;
  16. using namespace testing;
  17. namespace {
  18. class MSFBuilderTest : public testing::Test {
  19. protected:
  20. void initializeSimpleSuperBlock(msf::SuperBlock &SB) {
  21. initializeSuperBlock(SB);
  22. SB.NumBlocks = 1000;
  23. SB.NumDirectoryBytes = 8192;
  24. }
  25. void initializeSuperBlock(msf::SuperBlock &SB) {
  26. ::memset(&SB, 0, sizeof(SB));
  27. ::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic));
  28. SB.FreeBlockMapBlock = 1;
  29. SB.BlockMapAddr = 1;
  30. SB.BlockSize = 4096;
  31. SB.NumDirectoryBytes = 0;
  32. SB.NumBlocks = 2; // one for the Super Block, one for the directory
  33. }
  34. BumpPtrAllocator Allocator;
  35. };
  36. } // namespace
  37. TEST_F(MSFBuilderTest, ValidateSuperBlockAccept) {
  38. // Test that a known good super block passes validation.
  39. SuperBlock SB;
  40. initializeSuperBlock(SB);
  41. EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Succeeded());
  42. }
  43. TEST_F(MSFBuilderTest, ValidateSuperBlockReject) {
  44. // Test that various known problems cause a super block to be rejected.
  45. SuperBlock SB;
  46. initializeSimpleSuperBlock(SB);
  47. // Mismatched magic
  48. SB.MagicBytes[0] = 8;
  49. EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
  50. initializeSimpleSuperBlock(SB);
  51. // Block 0 is reserved for super block, can't be occupied by the block map
  52. SB.BlockMapAddr = 0;
  53. EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
  54. initializeSimpleSuperBlock(SB);
  55. // Block sizes have to be powers of 2.
  56. SB.BlockSize = 3120;
  57. EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
  58. initializeSimpleSuperBlock(SB);
  59. // The directory itself has a maximum size.
  60. SB.NumDirectoryBytes = SB.BlockSize * SB.BlockSize / 4;
  61. EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Succeeded());
  62. SB.NumDirectoryBytes = SB.NumDirectoryBytes + 4;
  63. EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
  64. }
  65. TEST_F(MSFBuilderTest, TestUsedBlocksMarkedAsUsed) {
  66. // Test that when assigning a stream to a known list of blocks, the blocks
  67. // are correctly marked as used after adding, but no other incorrect blocks
  68. // are accidentally marked as used.
  69. std::vector<uint32_t> Blocks = {4, 5, 6, 7, 8, 9, 10, 11, 12};
  70. // Allocate some extra blocks at the end so we can verify that they're free
  71. // after the initialization.
  72. uint32_t NumBlocks = msf::getMinimumBlockCount() + Blocks.size() + 10;
  73. auto ExpectedMsf = MSFBuilder::create(Allocator, 4096, NumBlocks);
  74. ASSERT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  75. auto &Msf = *ExpectedMsf;
  76. EXPECT_THAT_EXPECTED(Msf.addStream(Blocks.size() * 4096, Blocks),
  77. Succeeded());
  78. for (auto B : Blocks) {
  79. EXPECT_FALSE(Msf.isBlockFree(B));
  80. }
  81. uint32_t FreeBlockStart = Blocks.back() + 1;
  82. for (uint32_t I = FreeBlockStart; I < NumBlocks; ++I) {
  83. EXPECT_TRUE(Msf.isBlockFree(I));
  84. }
  85. }
  86. TEST_F(MSFBuilderTest, TestAddStreamNoDirectoryBlockIncrease) {
  87. // Test that adding a new stream correctly updates the directory. This only
  88. // tests the case where the directory *DOES NOT* grow large enough that it
  89. // crosses a Block boundary.
  90. auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
  91. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  92. auto &Msf = *ExpectedMsf;
  93. auto ExpectedL1 = Msf.generateLayout();
  94. EXPECT_THAT_EXPECTED(ExpectedL1, Succeeded());
  95. MSFLayout &L1 = *ExpectedL1;
  96. auto OldDirBlocks = L1.DirectoryBlocks;
  97. EXPECT_EQ(1U, OldDirBlocks.size());
  98. auto ExpectedMsf2 = MSFBuilder::create(Allocator, 4096);
  99. EXPECT_THAT_EXPECTED(ExpectedMsf2, Succeeded());
  100. auto &Msf2 = *ExpectedMsf2;
  101. EXPECT_THAT_EXPECTED(Msf2.addStream(4000), Succeeded());
  102. EXPECT_EQ(1U, Msf2.getNumStreams());
  103. EXPECT_EQ(4000U, Msf2.getStreamSize(0));
  104. auto Blocks = Msf2.getStreamBlocks(0);
  105. EXPECT_EQ(1U, Blocks.size());
  106. auto ExpectedL2 = Msf2.generateLayout();
  107. EXPECT_THAT_EXPECTED(ExpectedL2, Succeeded());
  108. MSFLayout &L2 = *ExpectedL2;
  109. auto NewDirBlocks = L2.DirectoryBlocks;
  110. EXPECT_EQ(1U, NewDirBlocks.size());
  111. }
  112. TEST_F(MSFBuilderTest, TestAddStreamWithDirectoryBlockIncrease) {
  113. // Test that adding a new stream correctly updates the directory. This only
  114. // tests the case where the directory *DOES* grow large enough that it
  115. // crosses a Block boundary. This is because the newly added stream occupies
  116. // so many Blocks that need to be indexed in the directory that the directory
  117. // crosses a Block boundary.
  118. auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
  119. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  120. auto &Msf = *ExpectedMsf;
  121. EXPECT_THAT_EXPECTED(Msf.addStream(4096 * 4096 / sizeof(uint32_t)),
  122. Succeeded());
  123. auto ExpectedL1 = Msf.generateLayout();
  124. EXPECT_THAT_EXPECTED(ExpectedL1, Succeeded());
  125. MSFLayout &L1 = *ExpectedL1;
  126. auto DirBlocks = L1.DirectoryBlocks;
  127. EXPECT_EQ(2U, DirBlocks.size());
  128. }
  129. TEST_F(MSFBuilderTest, TestGrowStreamNoBlockIncrease) {
  130. // Test growing an existing stream by a value that does not affect the number
  131. // of blocks it occupies.
  132. auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
  133. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  134. auto &Msf = *ExpectedMsf;
  135. EXPECT_THAT_EXPECTED(Msf.addStream(1024), Succeeded());
  136. EXPECT_EQ(1024U, Msf.getStreamSize(0));
  137. auto OldStreamBlocks = Msf.getStreamBlocks(0);
  138. EXPECT_EQ(1U, OldStreamBlocks.size());
  139. EXPECT_THAT_ERROR(Msf.setStreamSize(0, 2048), Succeeded());
  140. EXPECT_EQ(2048U, Msf.getStreamSize(0));
  141. auto NewStreamBlocks = Msf.getStreamBlocks(0);
  142. EXPECT_EQ(1U, NewStreamBlocks.size());
  143. EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
  144. }
  145. TEST_F(MSFBuilderTest, TestGrowStreamWithBlockIncrease) {
  146. // Test that growing an existing stream to a value large enough that it causes
  147. // the need to allocate new Blocks to the stream correctly updates the
  148. // stream's
  149. // block list.
  150. auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
  151. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  152. auto &Msf = *ExpectedMsf;
  153. EXPECT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());
  154. EXPECT_EQ(2048U, Msf.getStreamSize(0));
  155. std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
  156. EXPECT_EQ(1U, OldStreamBlocks.size());
  157. EXPECT_THAT_ERROR(Msf.setStreamSize(0, 6144), Succeeded());
  158. EXPECT_EQ(6144U, Msf.getStreamSize(0));
  159. std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
  160. EXPECT_EQ(2U, NewStreamBlocks.size());
  161. EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
  162. EXPECT_NE(NewStreamBlocks[0], NewStreamBlocks[1]);
  163. }
  164. TEST_F(MSFBuilderTest, TestShrinkStreamNoBlockDecrease) {
  165. // Test that shrinking an existing stream by a value that does not affect the
  166. // number of Blocks it occupies makes no changes to stream's block list.
  167. auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
  168. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  169. auto &Msf = *ExpectedMsf;
  170. EXPECT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());
  171. EXPECT_EQ(2048U, Msf.getStreamSize(0));
  172. std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
  173. EXPECT_EQ(1U, OldStreamBlocks.size());
  174. EXPECT_THAT_ERROR(Msf.setStreamSize(0, 1024), Succeeded());
  175. EXPECT_EQ(1024U, Msf.getStreamSize(0));
  176. std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
  177. EXPECT_EQ(1U, NewStreamBlocks.size());
  178. EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
  179. }
  180. TEST_F(MSFBuilderTest, TestShrinkStreamWithBlockDecrease) {
  181. // Test that shrinking an existing stream to a value large enough that it
  182. // causes the need to deallocate new Blocks to the stream correctly updates
  183. // the stream's block list.
  184. auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
  185. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  186. auto &Msf = *ExpectedMsf;
  187. EXPECT_THAT_EXPECTED(Msf.addStream(6144), Succeeded());
  188. EXPECT_EQ(6144U, Msf.getStreamSize(0));
  189. std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
  190. EXPECT_EQ(2U, OldStreamBlocks.size());
  191. EXPECT_THAT_ERROR(Msf.setStreamSize(0, 2048), Succeeded());
  192. EXPECT_EQ(2048U, Msf.getStreamSize(0));
  193. std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
  194. EXPECT_EQ(1U, NewStreamBlocks.size());
  195. EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
  196. }
  197. TEST_F(MSFBuilderTest, TestRejectReusedStreamBlock) {
  198. // Test that attempting to add a stream and assigning a block that is already
  199. // in use by another stream fails.
  200. auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
  201. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  202. auto &Msf = *ExpectedMsf;
  203. EXPECT_THAT_EXPECTED(Msf.addStream(6144), Succeeded());
  204. std::vector<uint32_t> Blocks = {2, 3};
  205. EXPECT_THAT_EXPECTED(Msf.addStream(6144, Blocks), Failed());
  206. }
  207. TEST_F(MSFBuilderTest, TestBlockCountsWhenAddingStreams) {
  208. // Test that when adding multiple streams, the number of used and free Blocks
  209. // allocated to the MSF file are as expected.
  210. auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
  211. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  212. auto &Msf = *ExpectedMsf;
  213. // one for the super block, one for the directory block map
  214. uint32_t NumUsedBlocks = Msf.getNumUsedBlocks();
  215. EXPECT_EQ(msf::getMinimumBlockCount(), NumUsedBlocks);
  216. EXPECT_EQ(0U, Msf.getNumFreeBlocks());
  217. const uint32_t StreamSizes[] = {4000, 6193, 189723};
  218. for (int I = 0; I < 3; ++I) {
  219. EXPECT_THAT_EXPECTED(Msf.addStream(StreamSizes[I]), Succeeded());
  220. NumUsedBlocks += bytesToBlocks(StreamSizes[I], 4096);
  221. EXPECT_EQ(NumUsedBlocks, Msf.getNumUsedBlocks());
  222. EXPECT_EQ(0U, Msf.getNumFreeBlocks());
  223. }
  224. }
  225. TEST_F(MSFBuilderTest, BuildMsfLayout) {
  226. // Test that we can generate an MSFLayout structure from a valid layout
  227. // specification.
  228. auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
  229. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  230. auto &Msf = *ExpectedMsf;
  231. const uint32_t StreamSizes[] = {4000, 6193, 189723};
  232. uint32_t ExpectedNumBlocks = msf::getMinimumBlockCount();
  233. for (int I = 0; I < 3; ++I) {
  234. EXPECT_THAT_EXPECTED(Msf.addStream(StreamSizes[I]), Succeeded());
  235. ExpectedNumBlocks += bytesToBlocks(StreamSizes[I], 4096);
  236. }
  237. ++ExpectedNumBlocks; // The directory itself should use 1 block
  238. auto ExpectedLayout = Msf.generateLayout();
  239. EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
  240. MSFLayout &L = *ExpectedLayout;
  241. EXPECT_EQ(4096U, L.SB->BlockSize);
  242. EXPECT_EQ(ExpectedNumBlocks, L.SB->NumBlocks);
  243. EXPECT_EQ(1U, L.DirectoryBlocks.size());
  244. EXPECT_EQ(3U, L.StreamMap.size());
  245. EXPECT_EQ(3U, L.StreamSizes.size());
  246. for (int I = 0; I < 3; ++I) {
  247. EXPECT_EQ(StreamSizes[I], L.StreamSizes[I]);
  248. uint32_t ExpectedNumBlocks = bytesToBlocks(StreamSizes[I], 4096);
  249. EXPECT_EQ(ExpectedNumBlocks, L.StreamMap[I].size());
  250. }
  251. }
  252. TEST_F(MSFBuilderTest, UseDirectoryBlockHint) {
  253. Expected<MSFBuilder> ExpectedMsf = MSFBuilder::create(
  254. Allocator, 4096, msf::getMinimumBlockCount() + 1, false);
  255. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  256. auto &Msf = *ExpectedMsf;
  257. uint32_t B = msf::getFirstUnreservedBlock();
  258. EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1}), Succeeded());
  259. EXPECT_THAT_EXPECTED(Msf.addStream(2048, {B + 2}), Succeeded());
  260. auto ExpectedLayout = Msf.generateLayout();
  261. EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
  262. MSFLayout &L = *ExpectedLayout;
  263. EXPECT_EQ(msf::getMinimumBlockCount() + 2, L.SB->NumBlocks);
  264. EXPECT_EQ(1U, L.DirectoryBlocks.size());
  265. EXPECT_EQ(1U, L.StreamMap[0].size());
  266. EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
  267. EXPECT_EQ(B + 2, L.StreamMap[0].front());
  268. }
  269. TEST_F(MSFBuilderTest, DirectoryBlockHintInsufficient) {
  270. Expected<MSFBuilder> ExpectedMsf =
  271. MSFBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
  272. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  273. auto &Msf = *ExpectedMsf;
  274. uint32_t B = msf::getFirstUnreservedBlock();
  275. EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1}), Succeeded());
  276. uint32_t Size = 4096 * 4096 / 4;
  277. EXPECT_THAT_EXPECTED(Msf.addStream(Size), Succeeded());
  278. auto ExpectedLayout = Msf.generateLayout();
  279. EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
  280. MSFLayout &L = *ExpectedLayout;
  281. EXPECT_EQ(2U, L.DirectoryBlocks.size());
  282. EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
  283. }
  284. TEST_F(MSFBuilderTest, DirectoryBlockHintOverestimated) {
  285. Expected<MSFBuilder> ExpectedMsf =
  286. MSFBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
  287. EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  288. auto &Msf = *ExpectedMsf;
  289. uint32_t B = msf::getFirstUnreservedBlock();
  290. EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1, B + 2}), Succeeded());
  291. ASSERT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());
  292. auto ExpectedLayout = Msf.generateLayout();
  293. ASSERT_THAT_EXPECTED(ExpectedLayout, Succeeded());
  294. MSFLayout &L = *ExpectedLayout;
  295. EXPECT_EQ(1U, L.DirectoryBlocks.size());
  296. EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
  297. }
  298. TEST_F(MSFBuilderTest, StreamDoesntUseFpmBlocks) {
  299. Expected<MSFBuilder> ExpectedMsf = MSFBuilder::create(Allocator, 4096);
  300. ASSERT_THAT_EXPECTED(ExpectedMsf, Succeeded());
  301. auto &Msf = *ExpectedMsf;
  302. // A block is 4096 bytes, and every 4096 blocks we have 2 reserved FPM blocks.
  303. // By creating add a stream that spans 4096*4096*3 bytes, we ensure that we
  304. // cross over a couple of reserved FPM blocks, and that none of them are
  305. // allocated to the stream.
  306. constexpr uint32_t StreamSize = 4096 * 4096 * 3;
  307. Expected<uint32_t> SN = Msf.addStream(StreamSize);
  308. ASSERT_THAT_EXPECTED(SN, Succeeded());
  309. auto ExpectedLayout = Msf.generateLayout();
  310. ASSERT_THAT_EXPECTED(ExpectedLayout, Succeeded());
  311. MSFLayout &L = *ExpectedLayout;
  312. auto BlocksRef = L.StreamMap[*SN];
  313. std::vector<uint32_t> Blocks(BlocksRef.begin(), BlocksRef.end());
  314. EXPECT_EQ(StreamSize, L.StreamSizes[*SN]);
  315. for (uint32_t I = 0; I <= 3; ++I) {
  316. // Pages from both FPMs are always allocated.
  317. EXPECT_FALSE(L.FreePageMap.test(2 + I * 4096));
  318. EXPECT_FALSE(L.FreePageMap.test(1 + I * 4096));
  319. }
  320. for (uint32_t I = 1; I <= 3; ++I) {
  321. EXPECT_THAT(Blocks, Not(Contains(1 + I * 4096)));
  322. EXPECT_THAT(Blocks, Not(Contains(2 + I * 4096)));
  323. }
  324. }