blob: aa059387f6b0efa5bc49c8508c56756a848deae0 [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 Turner620961d2016-09-14 23:00:02 +000018TpiStreamBuilder::TpiStreamBuilder(MSFBuilder &Msf)
19 : Msf(Msf), Allocator(Msf.getAllocator()), Header(nullptr) {}
Zachary Turnerc6d54da2016-09-09 17:46:17 +000020
21TpiStreamBuilder::~TpiStreamBuilder() {}
22
23void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) {
24 VerHeader = Version;
25}
26
27void TpiStreamBuilder::addTypeRecord(const codeview::CVType &Record) {
28 TypeRecords.push_back(Record);
29 TypeRecordStream.setItems(TypeRecords);
30}
31
32Error TpiStreamBuilder::finalize() {
33 if (Header)
34 return Error::success();
35
36 TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>();
37
38 uint32_t Count = TypeRecords.size();
Zachary Turner620961d2016-09-14 23:00:02 +000039 uint32_t HashBufferSize = calculateHashBufferSize();
Zachary Turnerc6d54da2016-09-09 17:46:17 +000040
41 H->Version = *VerHeader;
42 H->HeaderSize = sizeof(TpiStreamHeader);
43 H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex;
44 H->TypeIndexEnd = H->TypeIndexBegin + Count;
45 H->TypeRecordBytes = TypeRecordStream.getLength();
46
Zachary Turner620961d2016-09-14 23:00:02 +000047 H->HashStreamIndex = HashStreamIndex;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000048 H->HashAuxStreamIndex = kInvalidStreamIndex;
49 H->HashKeySize = sizeof(ulittle32_t);
50 H->NumHashBuckets = MinTpiHashBuckets;
51
Zachary Turner620961d2016-09-14 23:00:02 +000052 // Recall that hash values go into a completely different stream identified by
53 // the `HashStreamIndex` field of the `TpiStreamHeader`. Therefore, the data
54 // begins at offset 0 of this independent stream.
55 H->HashValueBuffer.Off = 0;
56 H->HashValueBuffer.Length = HashBufferSize;
57 H->HashAdjBuffer.Off = H->HashValueBuffer.Off + H->HashValueBuffer.Length;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000058 H->HashAdjBuffer.Length = 0;
Zachary Turner620961d2016-09-14 23:00:02 +000059 H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000060 H->IndexOffsetBuffer.Length = 0;
61
62 Header = H;
63 return Error::success();
64}
65
66uint32_t TpiStreamBuilder::calculateSerializedLength() const {
Zachary Turnera6cbfb52016-09-15 18:22:21 +000067 return sizeof(TpiStreamHeader) + TypeRecordStream.getLength();
Zachary Turner620961d2016-09-14 23:00:02 +000068}
69
70uint32_t TpiStreamBuilder::calculateHashBufferSize() const {
71 if (TypeRecords.empty() || !TypeRecords[0].Hash.hasValue())
72 return 0;
73 return TypeRecords.size() * sizeof(ulittle32_t);
74}
75
76Error TpiStreamBuilder::finalizeMsfLayout() {
77 uint32_t Length = calculateSerializedLength();
78 if (auto EC = Msf.setStreamSize(StreamTPI, Length))
79 return EC;
80
81 uint32_t HashBufferSize = calculateHashBufferSize();
82
83 if (HashBufferSize == 0)
84 return Error::success();
85
86 auto ExpectedIndex = Msf.addStream(HashBufferSize);
87 if (!ExpectedIndex)
88 return ExpectedIndex.takeError();
89 HashStreamIndex = *ExpectedIndex;
90 ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeRecords.size());
91 MutableArrayRef<ulittle32_t> HashBuffer(H, TypeRecords.size());
92 for (uint32_t I = 0; I < TypeRecords.size(); ++I) {
93 HashBuffer[I] = *TypeRecords[I].Hash % MinTpiHashBuckets;
94 }
95 ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(HashBuffer.data()),
96 HashBufferSize);
97 HashValueStream = llvm::make_unique<ByteStream>(Bytes);
98 return Error::success();
Zachary Turnerc6d54da2016-09-09 17:46:17 +000099}
100
101Expected<std::unique_ptr<TpiStream>>
102TpiStreamBuilder::build(PDBFile &File, const msf::WritableStream &Buffer) {
103 if (!VerHeader.hasValue())
104 return make_error<RawError>(raw_error_code::unspecified,
105 "Missing TPI Stream Version");
106 if (auto EC = finalize())
107 return std::move(EC);
108
109 auto StreamData = MappedBlockStream::createIndexedStream(File.getMsfLayout(),
110 Buffer, StreamTPI);
111 auto Tpi = llvm::make_unique<TpiStream>(File, std::move(StreamData));
112 Tpi->Header = Header;
113 Tpi->TypeRecords = VarStreamArray<codeview::CVType>(TypeRecordStream);
Zachary Turner620961d2016-09-14 23:00:02 +0000114 if (HashValueStream) {
115 Tpi->HashStream = std::move(HashValueStream);
116 StreamReader HSR(*Tpi->HashStream);
117 if (auto EC = HSR.readArray(Tpi->HashValues, TypeRecords.size()))
118 return std::move(EC);
119 }
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000120 return std::move(Tpi);
121}
122
123Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout,
124 const msf::WritableStream &Buffer) {
125 if (auto EC = finalize())
126 return EC;
127
128 auto InfoS =
129 WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamTPI);
130
131 StreamWriter Writer(*InfoS);
132 if (auto EC = Writer.writeObject(*Header))
133 return EC;
134
135 auto RecordArray = VarStreamArray<codeview::CVType>(TypeRecordStream);
136 if (auto EC = Writer.writeArray(RecordArray))
137 return EC;
138
Zachary Turner620961d2016-09-14 23:00:02 +0000139 if (HashStreamIndex != kInvalidStreamIndex) {
140 auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
141 HashStreamIndex);
142 StreamWriter HW(*HVS);
143 if (auto EC = HW.writeStreamRef(*HashValueStream))
144 return EC;
145 }
146
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000147 return Error::success();
148}