Line data Source code
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/ADT/ArrayRef.h"
11 : #include "llvm/ADT/STLExtras.h"
12 : #include "llvm/DebugInfo/CodeView/TypeIndex.h"
13 : #include "llvm/DebugInfo/CodeView/TypeRecord.h"
14 : #include "llvm/DebugInfo/MSF/ByteStream.h"
15 : #include "llvm/DebugInfo/MSF/MSFBuilder.h"
16 : #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
17 : #include "llvm/DebugInfo/MSF/StreamArray.h"
18 : #include "llvm/DebugInfo/MSF/StreamReader.h"
19 : #include "llvm/DebugInfo/MSF/StreamWriter.h"
20 : #include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
21 : #include "llvm/DebugInfo/PDB/Raw/RawError.h"
22 : #include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
23 : #include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
24 : #include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.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 6 : TpiStreamBuilder::TpiStreamBuilder(MSFBuilder &Msf, uint32_t StreamIdx)
37 30 : : Msf(Msf), Allocator(Msf.getAllocator()), Header(nullptr), Idx(StreamIdx) {
38 6 : }
39 :
40 : TpiStreamBuilder::~TpiStreamBuilder() = default;
41 :
42 6 : void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) {
43 12 : VerHeader = Version;
44 6 : }
45 :
46 167 : void TpiStreamBuilder::addTypeRecord(const codeview::CVType &Record) {
47 167 : TypeRecords.push_back(Record);
48 334 : TypeRecordStream.setItems(TypeRecords);
49 167 : }
50 :
51 6 : Error TpiStreamBuilder::finalize() {
52 6 : if (Header)
53 0 : return Error::success();
54 :
55 12 : TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>();
56 :
57 12 : uint32_t Count = TypeRecords.size();
58 6 : uint32_t HashBufferSize = calculateHashBufferSize();
59 :
60 18 : H->Version = *VerHeader;
61 12 : H->HeaderSize = sizeof(TpiStreamHeader);
62 12 : H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex;
63 18 : H->TypeIndexEnd = H->TypeIndexBegin + Count;
64 18 : H->TypeRecordBytes = TypeRecordStream.getLength();
65 :
66 12 : H->HashStreamIndex = HashStreamIndex;
67 12 : H->HashAuxStreamIndex = kInvalidStreamIndex;
68 12 : H->HashKeySize = sizeof(ulittle32_t);
69 12 : 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 12 : H->HashValueBuffer.Off = 0;
75 12 : H->HashValueBuffer.Length = HashBufferSize;
76 24 : H->HashAdjBuffer.Off = H->HashValueBuffer.Off + H->HashValueBuffer.Length;
77 12 : H->HashAdjBuffer.Length = 0;
78 24 : H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length;
79 12 : H->IndexOffsetBuffer.Length = 0;
80 :
81 6 : Header = H;
82 18 : return Error::success();
83 : }
84 :
85 6 : uint32_t TpiStreamBuilder::calculateSerializedLength() const {
86 12 : return sizeof(TpiStreamHeader) + TypeRecordStream.getLength();
87 : }
88 :
89 12 : uint32_t TpiStreamBuilder::calculateHashBufferSize() const {
90 24 : if (TypeRecords.empty() || !TypeRecords[0].Hash.hasValue())
91 : return 0;
92 0 : return TypeRecords.size() * sizeof(ulittle32_t);
93 : }
94 :
95 6 : Error TpiStreamBuilder::finalizeMsfLayout() {
96 6 : uint32_t Length = calculateSerializedLength();
97 18 : if (auto EC = Msf.setStreamSize(Idx, Length))
98 0 : return EC;
99 :
100 6 : uint32_t HashBufferSize = calculateHashBufferSize();
101 :
102 6 : if (HashBufferSize == 0)
103 18 : return Error::success();
104 :
105 0 : auto ExpectedIndex = Msf.addStream(HashBufferSize);
106 0 : if (!ExpectedIndex)
107 0 : return ExpectedIndex.takeError();
108 0 : HashStreamIndex = *ExpectedIndex;
109 0 : ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeRecords.size());
110 0 : MutableArrayRef<ulittle32_t> HashBuffer(H, TypeRecords.size());
111 0 : for (uint32_t I = 0; I < TypeRecords.size(); ++I) {
112 0 : HashBuffer[I] = *TypeRecords[I].Hash % MinTpiHashBuckets;
113 : }
114 0 : ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(HashBuffer.data()),
115 0 : HashBufferSize);
116 0 : HashValueStream = llvm::make_unique<ByteStream>(Bytes);
117 0 : return Error::success();
118 : }
119 :
120 6 : Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout,
121 : const msf::WritableStream &Buffer) {
122 18 : if (auto EC = finalize())
123 0 : return EC;
124 :
125 : auto InfoS =
126 6 : WritableMappedBlockStream::createIndexedStream(Layout, Buffer, Idx);
127 :
128 12 : StreamWriter Writer(*InfoS);
129 24 : if (auto EC = Writer.writeObject(*Header))
130 0 : return EC;
131 :
132 18 : auto RecordArray = VarStreamArray<codeview::CVType>(TypeRecordStream);
133 24 : if (auto EC = Writer.writeArray(RecordArray))
134 0 : return EC;
135 :
136 6 : if (HashStreamIndex != kInvalidStreamIndex) {
137 : auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
138 0 : HashStreamIndex);
139 0 : StreamWriter HW(*HVS);
140 0 : if (auto EC = HW.writeStreamRef(*HashValueStream))
141 0 : return EC;
142 : }
143 :
144 18 : return Error::success();
145 : }
|