1 //===- TpiStreamBuilder.cpp - -------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" 11 #include "llvm/ADT/ArrayRef.h" 12 #include "llvm/ADT/STLExtras.h" 13 #include "llvm/DebugInfo/CodeView/TypeIndex.h" 14 #include "llvm/DebugInfo/CodeView/TypeRecord.h" 15 #include "llvm/DebugInfo/MSF/MSFBuilder.h" 16 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 17 #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 18 #include "llvm/DebugInfo/PDB/Native/RawError.h" 19 #include "llvm/DebugInfo/PDB/Native/RawTypes.h" 20 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 21 #include "llvm/Support/Allocator.h" 22 #include "llvm/Support/BinaryByteStream.h" 23 #include "llvm/Support/BinaryStreamArray.h" 24 #include "llvm/Support/BinaryStreamReader.h" 25 #include "llvm/Support/BinaryStreamWriter.h" 26 #include "llvm/Support/Endian.h" 27 #include "llvm/Support/Error.h" 28 #include <algorithm> 29 #include <cstdint> 30 31 using namespace llvm; 32 using namespace llvm::msf; 33 using namespace llvm::pdb; 34 using namespace llvm::support; 35 36 TpiStreamBuilder::TpiStreamBuilder(MSFBuilder &Msf, uint32_t StreamIdx) 37 : Msf(Msf), Allocator(Msf.getAllocator()), Header(nullptr), Idx(StreamIdx) { 38 } 39 40 TpiStreamBuilder::~TpiStreamBuilder() = default; 41 42 void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) { 43 VerHeader = Version; 44 } 45 46 void TpiStreamBuilder::addTypeRecord(ArrayRef<uint8_t> Record, 47 Optional<uint32_t> Hash) { 48 TypeRecordBytes += Record.size(); 49 TypeRecords.push_back(Record); 50 if (Hash) 51 TypeHashes.push_back(*Hash); 52 } 53 54 Error TpiStreamBuilder::finalize() { 55 if (Header) 56 return Error::success(); 57 58 TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>(); 59 60 uint32_t Count = TypeRecords.size(); 61 uint32_t HashBufferSize = calculateHashBufferSize(); 62 63 H->Version = *VerHeader; 64 H->HeaderSize = sizeof(TpiStreamHeader); 65 H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex; 66 H->TypeIndexEnd = H->TypeIndexBegin + Count; 67 H->TypeRecordBytes = TypeRecordBytes; 68 69 H->HashStreamIndex = HashStreamIndex; 70 H->HashAuxStreamIndex = kInvalidStreamIndex; 71 H->HashKeySize = sizeof(ulittle32_t); 72 H->NumHashBuckets = MinTpiHashBuckets; 73 74 // Recall that hash values go into a completely different stream identified by 75 // the `HashStreamIndex` field of the `TpiStreamHeader`. Therefore, the data 76 // begins at offset 0 of this independent stream. 77 H->HashValueBuffer.Off = 0; 78 H->HashValueBuffer.Length = HashBufferSize; 79 H->HashAdjBuffer.Off = H->HashValueBuffer.Off + H->HashValueBuffer.Length; 80 H->HashAdjBuffer.Length = 0; 81 H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length; 82 H->IndexOffsetBuffer.Length = 0; 83 84 Header = H; 85 return Error::success(); 86 } 87 88 uint32_t TpiStreamBuilder::calculateSerializedLength() { 89 return sizeof(TpiStreamHeader) + TypeRecordBytes; 90 } 91 92 uint32_t TpiStreamBuilder::calculateHashBufferSize() const { 93 assert(TypeHashes.size() == TypeHashes.size() && 94 "either all or no type records should have hashes"); 95 return TypeHashes.size() * sizeof(ulittle32_t); 96 } 97 98 Error TpiStreamBuilder::finalizeMsfLayout() { 99 uint32_t Length = calculateSerializedLength(); 100 if (auto EC = Msf.setStreamSize(Idx, Length)) 101 return EC; 102 103 uint32_t HashBufferSize = calculateHashBufferSize(); 104 105 if (HashBufferSize == 0) 106 return Error::success(); 107 108 auto ExpectedIndex = Msf.addStream(HashBufferSize); 109 if (!ExpectedIndex) 110 return ExpectedIndex.takeError(); 111 HashStreamIndex = *ExpectedIndex; 112 ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeHashes.size()); 113 MutableArrayRef<ulittle32_t> HashBuffer(H, TypeHashes.size()); 114 for (uint32_t I = 0; I < TypeHashes.size(); ++I) { 115 HashBuffer[I] = TypeHashes[I] % MinTpiHashBuckets; 116 } 117 ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(HashBuffer.data()), 118 HashBufferSize); 119 HashValueStream = 120 llvm::make_unique<BinaryByteStream>(Bytes, llvm::support::little); 121 return Error::success(); 122 } 123 124 Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout, 125 WritableBinaryStreamRef Buffer) { 126 if (auto EC = finalize()) 127 return EC; 128 129 auto InfoS = 130 WritableMappedBlockStream::createIndexedStream(Layout, Buffer, Idx); 131 132 BinaryStreamWriter Writer(*InfoS); 133 if (auto EC = Writer.writeObject(*Header)) 134 return EC; 135 136 for (auto Rec : TypeRecords) 137 if (auto EC = Writer.writeBytes(Rec)) 138 return EC; 139 140 if (HashStreamIndex != kInvalidStreamIndex) { 141 auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, 142 HashStreamIndex); 143 BinaryStreamWriter HW(*HVS); 144 if (auto EC = HW.writeStreamRef(*HashValueStream)) 145 return EC; 146 } 147 148 return Error::success(); 149 } 150