blob: 733efe882a2438dbd591bee2423442de5f0d5aeb [file] [log] [blame]
Zachary Turnerc6d54da2016-09-09 17:46:17 +00001#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
2
3#include "llvm/DebugInfo/CodeView/TypeIndex.h"
4#include "llvm/DebugInfo/CodeView/TypeRecord.h"
Zachary Turner620961d2016-09-14 23:00:02 +00005#include "llvm/DebugInfo/MSF/MSFBuilder.h"
Zachary Turnerc6d54da2016-09-09 17:46:17 +00006#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
7#include "llvm/DebugInfo/MSF/StreamWriter.h"
8#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
9#include "llvm/DebugInfo/PDB/Raw/RawError.h"
10#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
11#include "llvm/Support/Allocator.h"
12
13using namespace llvm;
14using namespace llvm::msf;
15using namespace llvm::pdb;
16using namespace llvm::support;
17
Zachary Turnerde9ba152016-09-15 18:22:31 +000018TpiStreamBuilder::TpiStreamBuilder(MSFBuilder &Msf, uint32_t StreamIdx)
19 : Msf(Msf), Allocator(Msf.getAllocator()), Header(nullptr), Idx(StreamIdx) {
20}
Zachary Turnerc6d54da2016-09-09 17:46:17 +000021
22TpiStreamBuilder::~TpiStreamBuilder() {}
23
24void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) {
25 VerHeader = Version;
26}
27
28void TpiStreamBuilder::addTypeRecord(const codeview::CVType &Record) {
29 TypeRecords.push_back(Record);
30 TypeRecordStream.setItems(TypeRecords);
31}
32
33Error TpiStreamBuilder::finalize() {
34 if (Header)
35 return Error::success();
36
37 TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>();
38
39 uint32_t Count = TypeRecords.size();
Zachary Turner620961d2016-09-14 23:00:02 +000040 uint32_t HashBufferSize = calculateHashBufferSize();
Zachary Turnerc6d54da2016-09-09 17:46:17 +000041
42 H->Version = *VerHeader;
43 H->HeaderSize = sizeof(TpiStreamHeader);
44 H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex;
45 H->TypeIndexEnd = H->TypeIndexBegin + Count;
46 H->TypeRecordBytes = TypeRecordStream.getLength();
47
Zachary Turner620961d2016-09-14 23:00:02 +000048 H->HashStreamIndex = HashStreamIndex;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000049 H->HashAuxStreamIndex = kInvalidStreamIndex;
50 H->HashKeySize = sizeof(ulittle32_t);
51 H->NumHashBuckets = MinTpiHashBuckets;
52
Zachary Turner620961d2016-09-14 23:00:02 +000053 // Recall that hash values go into a completely different stream identified by
54 // the `HashStreamIndex` field of the `TpiStreamHeader`. Therefore, the data
55 // begins at offset 0 of this independent stream.
56 H->HashValueBuffer.Off = 0;
57 H->HashValueBuffer.Length = HashBufferSize;
58 H->HashAdjBuffer.Off = H->HashValueBuffer.Off + H->HashValueBuffer.Length;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000059 H->HashAdjBuffer.Length = 0;
Zachary Turner620961d2016-09-14 23:00:02 +000060 H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000061 H->IndexOffsetBuffer.Length = 0;
62
63 Header = H;
64 return Error::success();
65}
66
67uint32_t TpiStreamBuilder::calculateSerializedLength() const {
Zachary Turnera6cbfb52016-09-15 18:22:21 +000068 return sizeof(TpiStreamHeader) + TypeRecordStream.getLength();
Zachary Turner620961d2016-09-14 23:00:02 +000069}
70
71uint32_t TpiStreamBuilder::calculateHashBufferSize() const {
72 if (TypeRecords.empty() || !TypeRecords[0].Hash.hasValue())
73 return 0;
74 return TypeRecords.size() * sizeof(ulittle32_t);
75}
76
77Error TpiStreamBuilder::finalizeMsfLayout() {
78 uint32_t Length = calculateSerializedLength();
Zachary Turnerde9ba152016-09-15 18:22:31 +000079 if (auto EC = Msf.setStreamSize(Idx, Length))
Zachary Turner620961d2016-09-14 23:00:02 +000080 return EC;
81
82 uint32_t HashBufferSize = calculateHashBufferSize();
83
84 if (HashBufferSize == 0)
85 return Error::success();
86
87 auto ExpectedIndex = Msf.addStream(HashBufferSize);
88 if (!ExpectedIndex)
89 return ExpectedIndex.takeError();
90 HashStreamIndex = *ExpectedIndex;
91 ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeRecords.size());
92 MutableArrayRef<ulittle32_t> HashBuffer(H, TypeRecords.size());
93 for (uint32_t I = 0; I < TypeRecords.size(); ++I) {
94 HashBuffer[I] = *TypeRecords[I].Hash % MinTpiHashBuckets;
95 }
96 ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(HashBuffer.data()),
97 HashBufferSize);
98 HashValueStream = llvm::make_unique<ByteStream>(Bytes);
99 return Error::success();
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000100}
101
102Expected<std::unique_ptr<TpiStream>>
103TpiStreamBuilder::build(PDBFile &File, const msf::WritableStream &Buffer) {
104 if (!VerHeader.hasValue())
105 return make_error<RawError>(raw_error_code::unspecified,
106 "Missing TPI Stream Version");
107 if (auto EC = finalize())
108 return std::move(EC);
109
Zachary Turnerde9ba152016-09-15 18:22:31 +0000110 auto StreamData =
111 MappedBlockStream::createIndexedStream(File.getMsfLayout(), Buffer, Idx);
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000112 auto Tpi = llvm::make_unique<TpiStream>(File, std::move(StreamData));
113 Tpi->Header = Header;
114 Tpi->TypeRecords = VarStreamArray<codeview::CVType>(TypeRecordStream);
Zachary Turner620961d2016-09-14 23:00:02 +0000115 if (HashValueStream) {
116 Tpi->HashStream = std::move(HashValueStream);
117 StreamReader HSR(*Tpi->HashStream);
118 if (auto EC = HSR.readArray(Tpi->HashValues, TypeRecords.size()))
119 return std::move(EC);
120 }
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000121 return std::move(Tpi);
122}
123
124Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout,
125 const msf::WritableStream &Buffer) {
126 if (auto EC = finalize())
127 return EC;
128
129 auto InfoS =
Zachary Turnerde9ba152016-09-15 18:22:31 +0000130 WritableMappedBlockStream::createIndexedStream(Layout, Buffer, Idx);
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000131
132 StreamWriter Writer(*InfoS);
133 if (auto EC = Writer.writeObject(*Header))
134 return EC;
135
136 auto RecordArray = VarStreamArray<codeview::CVType>(TypeRecordStream);
137 if (auto EC = Writer.writeArray(RecordArray))
138 return EC;
139
Zachary Turner620961d2016-09-14 23:00:02 +0000140 if (HashStreamIndex != kInvalidStreamIndex) {
141 auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
142 HashStreamIndex);
143 StreamWriter HW(*HVS);
144 if (auto EC = HW.writeStreamRef(*HashValueStream))
145 return EC;
146 }
147
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000148 return Error::success();
149}