Line data Source code
1 : //
2 : // The LLVM Compiler Infrastructure
3 : //
4 : // This file is distributed under the University of Illinois Open Source
5 : // License. See LICENSE.TXT for details.
6 : //
7 : //===----------------------------------------------------------------------===//
8 :
9 : #include "llvm/DebugInfo/Msf/MsfBuilder.h"
10 : #include "llvm/DebugInfo/Msf/MsfError.h"
11 :
12 : using namespace llvm;
13 : using namespace llvm::msf;
14 : using namespace llvm::support;
15 :
16 : namespace {
17 : const uint32_t kSuperBlockBlock = 0;
18 : const uint32_t kFreePageMap0Block = 1;
19 : const uint32_t kFreePageMap1Block = 2;
20 : const uint32_t kNumReservedPages = 3;
21 :
22 : const uint32_t kDefaultBlockMapAddr = kNumReservedPages;
23 : }
24 :
25 1 : MsfBuilder::MsfBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow,
26 : BumpPtrAllocator &Allocator)
27 : : Allocator(Allocator), IsGrowable(CanGrow), BlockSize(BlockSize),
28 : MininumBlocks(MinBlockCount), BlockMapAddr(kDefaultBlockMapAddr),
29 3 : FreeBlocks(MinBlockCount, true) {
30 3 : FreeBlocks[kSuperBlockBlock] = false;
31 3 : FreeBlocks[kFreePageMap0Block] = false;
32 3 : FreeBlocks[kFreePageMap1Block] = false;
33 3 : FreeBlocks[BlockMapAddr] = false;
34 1 : }
35 :
36 1 : Expected<MsfBuilder> MsfBuilder::create(BumpPtrAllocator &Allocator,
37 : uint32_t BlockSize,
38 : uint32_t MinBlockCount, bool CanGrow) {
39 1 : if (!isValidBlockSize(BlockSize))
40 0 : return make_error<MsfError>(msf_error_code::invalid_format,
41 0 : "The requested block size is unsupported");
42 :
43 : return MsfBuilder(BlockSize,
44 3 : std::max(MinBlockCount, msf::getMinimumBlockCount()),
45 3 : CanGrow, Allocator);
46 : }
47 :
48 1 : Error MsfBuilder::setBlockMapAddr(uint32_t Addr) {
49 1 : if (Addr == BlockMapAddr)
50 : return Error::success();
51 :
52 1 : if (Addr >= FreeBlocks.size()) {
53 0 : if (!IsGrowable)
54 : return make_error<MsfError>(msf_error_code::insufficient_buffer,
55 0 : "Cannot grow the number of blocks");
56 0 : FreeBlocks.resize(Addr + 1);
57 : }
58 :
59 1 : if (!isBlockFree(Addr))
60 : return make_error<MsfError>(
61 : msf_error_code::block_in_use,
62 0 : "Requested block map address is already in use");
63 3 : FreeBlocks[BlockMapAddr] = true;
64 3 : FreeBlocks[Addr] = false;
65 1 : BlockMapAddr = Addr;
66 : return Error::success();
67 : }
68 :
69 1 : void MsfBuilder::setFreePageMap(uint32_t Fpm) { FreePageMap = Fpm; }
70 :
71 1 : void MsfBuilder::setUnknown1(uint32_t Unk1) { Unknown1 = Unk1; }
72 :
73 1 : Error MsfBuilder::setDirectoryBlocksHint(ArrayRef<uint32_t> DirBlocks) {
74 4 : for (auto B : DirectoryBlocks)
75 0 : FreeBlocks[B] = true;
76 3 : for (auto B : DirBlocks) {
77 1 : if (!isBlockFree(B)) {
78 : return make_error<MsfError>(msf_error_code::unspecified,
79 0 : "Attempt to reuse an allocated block");
80 : }
81 3 : FreeBlocks[B] = false;
82 : }
83 :
84 3 : DirectoryBlocks = DirBlocks;
85 : return Error::success();
86 : }
87 :
88 0 : Error MsfBuilder::allocateBlocks(uint32_t NumBlocks,
89 : MutableArrayRef<uint32_t> Blocks) {
90 0 : if (NumBlocks == 0)
91 : return Error::success();
92 :
93 0 : uint32_t NumFreeBlocks = FreeBlocks.count();
94 0 : if (NumFreeBlocks < NumBlocks) {
95 0 : if (!IsGrowable)
96 : return make_error<MsfError>(msf_error_code::insufficient_buffer,
97 0 : "There are no free Blocks in the file");
98 0 : uint32_t AllocBlocks = NumBlocks - NumFreeBlocks;
99 0 : FreeBlocks.resize(AllocBlocks + FreeBlocks.size(), true);
100 : }
101 :
102 0 : int I = 0;
103 0 : int Block = FreeBlocks.find_first();
104 0 : do {
105 : assert(Block != -1 && "We ran out of Blocks!");
106 :
107 0 : uint32_t NextBlock = static_cast<uint32_t>(Block);
108 0 : Blocks[I++] = NextBlock;
109 0 : FreeBlocks.reset(NextBlock);
110 0 : Block = FreeBlocks.find_next(Block);
111 : } while (--NumBlocks > 0);
112 : return Error::success();
113 : }
114 :
115 0 : uint32_t MsfBuilder::getNumUsedBlocks() const {
116 0 : return getTotalBlockCount() - getNumFreeBlocks();
117 : }
118 :
119 0 : uint32_t MsfBuilder::getNumFreeBlocks() const { return FreeBlocks.count(); }
120 :
121 0 : uint32_t MsfBuilder::getTotalBlockCount() const { return FreeBlocks.size(); }
122 :
123 4 : bool MsfBuilder::isBlockFree(uint32_t Idx) const { return FreeBlocks[Idx]; }
124 :
125 17 : Error MsfBuilder::addStream(uint32_t Size, ArrayRef<uint32_t> Blocks) {
126 : // Add a new stream mapped to the specified blocks. Verify that the specified
127 : // blocks are both necessary and sufficient for holding the requested number
128 : // of bytes, and verify that all requested blocks are free.
129 34 : uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize);
130 17 : if (ReqBlocks != Blocks.size())
131 : return make_error<MsfError>(
132 : msf_error_code::invalid_format,
133 0 : "Incorrect number of blocks for requested stream size");
134 50 : for (auto Block : Blocks) {
135 16 : if (Block >= FreeBlocks.size())
136 0 : FreeBlocks.resize(Block + 1, true);
137 :
138 32 : if (!FreeBlocks.test(Block))
139 : return make_error<MsfError>(
140 : msf_error_code::unspecified,
141 0 : "Attempt to re-use an already allocated block");
142 : }
143 : // Mark all the blocks occupied by the new stream as not free.
144 49 : for (auto Block : Blocks) {
145 32 : FreeBlocks.reset(Block);
146 : }
147 85 : StreamData.push_back(std::make_pair(Size, Blocks));
148 : return Error::success();
149 : }
150 :
151 0 : Error MsfBuilder::addStream(uint32_t Size) {
152 0 : uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize);
153 0 : std::vector<uint32_t> NewBlocks;
154 0 : NewBlocks.resize(ReqBlocks);
155 0 : if (auto EC = allocateBlocks(ReqBlocks, NewBlocks))
156 0 : return EC;
157 0 : StreamData.push_back(std::make_pair(Size, NewBlocks));
158 : return Error::success();
159 : }
160 :
161 1 : Error MsfBuilder::setStreamSize(uint32_t Idx, uint32_t Size) {
162 1 : uint32_t OldSize = getStreamSize(Idx);
163 1 : if (OldSize == Size)
164 : return Error::success();
165 :
166 0 : uint32_t NewBlocks = bytesToBlocks(Size, BlockSize);
167 0 : uint32_t OldBlocks = bytesToBlocks(OldSize, BlockSize);
168 :
169 0 : if (NewBlocks > OldBlocks) {
170 0 : uint32_t AddedBlocks = NewBlocks - OldBlocks;
171 : // If we're growing, we have to allocate new Blocks.
172 0 : std::vector<uint32_t> AddedBlockList;
173 0 : AddedBlockList.resize(AddedBlocks);
174 0 : if (auto EC = allocateBlocks(AddedBlocks, AddedBlockList))
175 0 : return EC;
176 0 : auto &CurrentBlocks = StreamData[Idx].second;
177 0 : CurrentBlocks.insert(CurrentBlocks.end(), AddedBlockList.begin(),
178 0 : AddedBlockList.end());
179 0 : } else if (OldBlocks > NewBlocks) {
180 : // For shrinking, free all the Blocks in the Block map, update the stream
181 : // data, then shrink the directory.
182 0 : uint32_t RemovedBlocks = OldBlocks - NewBlocks;
183 0 : auto CurrentBlocks = ArrayRef<uint32_t>(StreamData[Idx].second);
184 0 : auto RemovedBlockList = CurrentBlocks.drop_front(NewBlocks);
185 0 : for (auto P : RemovedBlockList)
186 0 : FreeBlocks[P] = true;
187 0 : StreamData[Idx].second = CurrentBlocks.drop_back(RemovedBlocks);
188 : }
189 :
190 0 : StreamData[Idx].first = Size;
191 : return Error::success();
192 : }
193 :
194 0 : uint32_t MsfBuilder::getNumStreams() const { return StreamData.size(); }
195 :
196 1 : uint32_t MsfBuilder::getStreamSize(uint32_t StreamIdx) const {
197 2 : return StreamData[StreamIdx].first;
198 : }
199 :
200 0 : ArrayRef<uint32_t> MsfBuilder::getStreamBlocks(uint32_t StreamIdx) const {
201 0 : return StreamData[StreamIdx].second;
202 : }
203 :
204 1 : uint32_t MsfBuilder::computeDirectoryByteSize() const {
205 : // The directory has the following layout, where each item is a ulittle32_t:
206 : // NumStreams
207 : // StreamSizes[NumStreams]
208 : // StreamBlocks[NumStreams][]
209 1 : uint32_t Size = sizeof(ulittle32_t); // NumStreams
210 2 : Size += StreamData.size() * sizeof(ulittle32_t); // StreamSizes
211 21 : for (const auto &D : StreamData) {
212 34 : uint32_t ExpectedNumBlocks = bytesToBlocks(D.first, BlockSize);
213 : assert(ExpectedNumBlocks == D.second.size() &&
214 : "Unexpected number of blocks");
215 17 : Size += ExpectedNumBlocks * sizeof(ulittle32_t);
216 : }
217 1 : return Size;
218 : }
219 :
220 1 : Expected<MsfLayout> MsfBuilder::build() {
221 2 : SuperBlock *SB = Allocator.Allocate<SuperBlock>();
222 2 : MsfLayout L;
223 1 : L.SB = SB;
224 :
225 1 : std::memcpy(SB->MagicBytes, Magic, sizeof(Magic));
226 2 : SB->BlockMapAddr = BlockMapAddr;
227 2 : SB->BlockSize = BlockSize;
228 2 : SB->NumDirectoryBytes = computeDirectoryByteSize();
229 2 : SB->FreeBlockMapBlock = FreePageMap;
230 2 : SB->Unknown1 = Unknown1;
231 :
232 3 : uint32_t NumDirectoryBlocks = bytesToBlocks(SB->NumDirectoryBytes, BlockSize);
233 2 : if (NumDirectoryBlocks > DirectoryBlocks.size()) {
234 : // Our hint wasn't enough to satisfy the entire directory. Allocate
235 : // remaining pages.
236 0 : std::vector<uint32_t> ExtraBlocks;
237 0 : uint32_t NumExtraBlocks = NumDirectoryBlocks - DirectoryBlocks.size();
238 0 : ExtraBlocks.resize(NumExtraBlocks);
239 0 : if (auto EC = allocateBlocks(NumExtraBlocks, ExtraBlocks))
240 0 : return std::move(EC);
241 0 : DirectoryBlocks.insert(DirectoryBlocks.end(), ExtraBlocks.begin(),
242 0 : ExtraBlocks.end());
243 1 : } else if (NumDirectoryBlocks < DirectoryBlocks.size()) {
244 0 : uint32_t NumUnnecessaryBlocks = DirectoryBlocks.size() - NumDirectoryBlocks;
245 0 : for (auto B :
246 0 : ArrayRef<uint32_t>(DirectoryBlocks).drop_back(NumUnnecessaryBlocks))
247 0 : FreeBlocks[B] = true;
248 0 : DirectoryBlocks.resize(NumDirectoryBlocks);
249 : }
250 :
251 : // Don't set the number of blocks in the file until after allocating Blocks
252 : // for the directory, since the allocation might cause the file to need to
253 : // grow.
254 2 : SB->NumBlocks = FreeBlocks.size();
255 :
256 2 : ulittle32_t *DirBlocks = Allocator.Allocate<ulittle32_t>(NumDirectoryBlocks);
257 2 : std::uninitialized_copy_n(DirectoryBlocks.begin(), NumDirectoryBlocks,
258 1 : DirBlocks);
259 1 : L.DirectoryBlocks = ArrayRef<ulittle32_t>(DirBlocks, NumDirectoryBlocks);
260 :
261 : // The stream sizes should be re-allocated as a stable pointer and the stream
262 : // map should have each of its entries allocated as a separate stable pointer.
263 2 : if (StreamData.size() > 0) {
264 2 : ulittle32_t *Sizes = Allocator.Allocate<ulittle32_t>(StreamData.size());
265 2 : L.StreamSizes = ArrayRef<ulittle32_t>(Sizes, StreamData.size());
266 1 : L.StreamMap.resize(StreamData.size());
267 36 : for (uint32_t I = 0; I < StreamData.size(); ++I) {
268 51 : Sizes[I] = StreamData[I].first;
269 : ulittle32_t *BlockList =
270 51 : Allocator.Allocate<ulittle32_t>(StreamData[I].second.size());
271 51 : std::uninitialized_copy_n(StreamData[I].second.begin(),
272 51 : StreamData[I].second.size(), BlockList);
273 34 : L.StreamMap[I] =
274 34 : ArrayRef<ulittle32_t>(BlockList, StreamData[I].second.size());
275 : }
276 : }
277 :
278 : return L;
279 : }
|