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/BinaryByteStream.h" 16 #include "llvm/DebugInfo/MSF/BinaryStreamArray.h" 17 #include "llvm/DebugInfo/MSF/BinaryStreamReader.h" 18 #include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" 19 #include "llvm/DebugInfo/MSF/MSFBuilder.h" 20 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 21 #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 22 #include "llvm/DebugInfo/PDB/Native/RawError.h" 23 #include "llvm/DebugInfo/PDB/Native/RawTypes.h" 24 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 25 #include "llvm/Support/Allocator.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()), 38 TypeRecordStream(llvm::support::little), Header(nullptr), Idx(StreamIdx) { 39 } 40 41 TpiStreamBuilder::~TpiStreamBuilder() = default; 42 43 void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) { 44 VerHeader = Version; 45 } 46 47 void TpiStreamBuilder::addTypeRecord(const codeview::CVType &Record) { 48 TypeRecords.push_back(Record); 49 TypeRecordStream.setItems(TypeRecords); 50 } 51 52 Error TpiStreamBuilder::finalize() { 53 if (Header) 54 return Error::success(); 55 56 TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>(); 57 58 uint32_t Count = TypeRecords.size(); 59 uint32_t HashBufferSize = calculateHashBufferSize(); 60 61 H->Version = *VerHeader; 62 H->HeaderSize = sizeof(TpiStreamHeader); 63 H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex; 64 H->TypeIndexEnd = H->TypeIndexBegin + Count; 65 H->TypeRecordBytes = TypeRecordStream.getLength(); 66 67 H->HashStreamIndex = HashStreamIndex; 68 H->HashAuxStreamIndex = kInvalidStreamIndex; 69 H->HashKeySize = sizeof(ulittle32_t); 70 H->NumHashBuckets = MinTpiHashBuckets; 71 72 // Recall that hash values go into a completely different stream identified by 73 // the `HashStreamIndex` field of the `TpiStreamHeader`. Therefore, the data 74 // begins at offset 0 of this independent stream. 75 H->HashValueBuffer.Off = 0; 76 H->HashValueBuffer.Length = HashBufferSize; 77 H->HashAdjBuffer.Off = H->HashValueBuffer.Off + H->HashValueBuffer.Length; 78 H->HashAdjBuffer.Length = 0; 79 H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length; 80 H->IndexOffsetBuffer.Length = 0; 81 82 Header = H; 83 return Error::success(); 84 } 85 86 uint32_t TpiStreamBuilder::calculateSerializedLength() { 87 return sizeof(TpiStreamHeader) + TypeRecordStream.getLength(); 88 } 89 90 uint32_t TpiStreamBuilder::calculateHashBufferSize() const { 91 if (TypeRecords.empty() || !TypeRecords[0].Hash.hasValue()) 92 return 0; 93 return TypeRecords.size() * sizeof(ulittle32_t); 94 } 95 96 Error TpiStreamBuilder::finalizeMsfLayout() { 97 uint32_t Length = calculateSerializedLength(); 98 if (auto EC = Msf.setStreamSize(Idx, Length)) 99 return EC; 100 101 uint32_t HashBufferSize = calculateHashBufferSize(); 102 103 if (HashBufferSize == 0) 104 return Error::success(); 105 106 auto ExpectedIndex = Msf.addStream(HashBufferSize); 107 if (!ExpectedIndex) 108 return ExpectedIndex.takeError(); 109 HashStreamIndex = *ExpectedIndex; 110 ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeRecords.size()); 111 MutableArrayRef<ulittle32_t> HashBuffer(H, TypeRecords.size()); 112 for (uint32_t I = 0; I < TypeRecords.size(); ++I) { 113 HashBuffer[I] = *TypeRecords[I].Hash % MinTpiHashBuckets; 114 } 115 ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(HashBuffer.data()), 116 HashBufferSize); 117 HashValueStream = 118 llvm::make_unique<BinaryByteStream>(Bytes, llvm::support::little); 119 return Error::success(); 120 } 121 122 Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout, 123 WritableBinaryStreamRef Buffer) { 124 if (auto EC = finalize()) 125 return EC; 126 127 auto InfoS = 128 WritableMappedBlockStream::createIndexedStream(Layout, Buffer, Idx); 129 130 BinaryStreamWriter Writer(*InfoS); 131 if (auto EC = Writer.writeObject(*Header)) 132 return EC; 133 134 auto RecordArray = VarStreamArray<codeview::CVType>(TypeRecordStream); 135 if (auto EC = Writer.writeArray(RecordArray)) 136 return EC; 137 138 if (HashStreamIndex != kInvalidStreamIndex) { 139 auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, 140 HashStreamIndex); 141 BinaryStreamWriter HW(*HVS); 142 if (auto EC = HW.writeStreamRef(*HashValueStream)) 143 return EC; 144 } 145 146 return Error::success(); 147 } 148