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