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