blob: 7d532ee56d834bdc6bb8c8182c5c5bd54507cf06 [file] [log] [blame]
Eugene Zelenko570e39a2016-11-23 23:16:32 +00001//===- 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//===----------------------------------------------------------------------===//
Zachary Turnerc6d54da2016-09-09 17:46:17 +00009
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000010#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000011#include "llvm/ADT/ArrayRef.h"
12#include "llvm/ADT/STLExtras.h"
Zachary Turnerc6d54da2016-09-09 17:46:17 +000013#include "llvm/DebugInfo/CodeView/TypeIndex.h"
14#include "llvm/DebugInfo/CodeView/TypeRecord.h"
Zachary Turnerd2684b72017-02-25 00:33:34 +000015#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"
Zachary Turner620961d2016-09-14 23:00:02 +000019#include "llvm/DebugInfo/MSF/MSFBuilder.h"
Zachary Turnerc6d54da2016-09-09 17:46:17 +000020#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000021#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"
Zachary Turnerc6d54da2016-09-09 17:46:17 +000025#include "llvm/Support/Allocator.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000026#include "llvm/Support/Endian.h"
27#include "llvm/Support/Error.h"
28#include <algorithm>
29#include <cstdint>
Zachary Turnerc6d54da2016-09-09 17:46:17 +000030
31using namespace llvm;
32using namespace llvm::msf;
33using namespace llvm::pdb;
34using namespace llvm::support;
35
Zachary Turnerde9ba152016-09-15 18:22:31 +000036TpiStreamBuilder::TpiStreamBuilder(MSFBuilder &Msf, uint32_t StreamIdx)
Zachary Turneraf299ea2017-02-25 00:44:30 +000037 : Msf(Msf), Allocator(Msf.getAllocator()),
38 TypeRecordStream(llvm::support::little), Header(nullptr), Idx(StreamIdx) {
Zachary Turnerde9ba152016-09-15 18:22:31 +000039}
Zachary Turnerc6d54da2016-09-09 17:46:17 +000040
Eugene Zelenko570e39a2016-11-23 23:16:32 +000041TpiStreamBuilder::~TpiStreamBuilder() = default;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000042
43void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) {
44 VerHeader = Version;
45}
46
47void TpiStreamBuilder::addTypeRecord(const codeview::CVType &Record) {
48 TypeRecords.push_back(Record);
49 TypeRecordStream.setItems(TypeRecords);
50}
51
52Error TpiStreamBuilder::finalize() {
53 if (Header)
54 return Error::success();
55
56 TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>();
57
58 uint32_t Count = TypeRecords.size();
Zachary Turner620961d2016-09-14 23:00:02 +000059 uint32_t HashBufferSize = calculateHashBufferSize();
Zachary Turnerc6d54da2016-09-09 17:46:17 +000060
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
Zachary Turner620961d2016-09-14 23:00:02 +000067 H->HashStreamIndex = HashStreamIndex;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000068 H->HashAuxStreamIndex = kInvalidStreamIndex;
69 H->HashKeySize = sizeof(ulittle32_t);
70 H->NumHashBuckets = MinTpiHashBuckets;
71
Zachary Turner620961d2016-09-14 23:00:02 +000072 // 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;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000078 H->HashAdjBuffer.Length = 0;
Zachary Turner620961d2016-09-14 23:00:02 +000079 H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000080 H->IndexOffsetBuffer.Length = 0;
81
82 Header = H;
83 return Error::success();
84}
85
Zachary Turneraf299ea2017-02-25 00:44:30 +000086uint32_t TpiStreamBuilder::calculateSerializedLength() {
Zachary Turnera6cbfb52016-09-15 18:22:21 +000087 return sizeof(TpiStreamHeader) + TypeRecordStream.getLength();
Zachary Turner620961d2016-09-14 23:00:02 +000088}
89
90uint32_t TpiStreamBuilder::calculateHashBufferSize() const {
91 if (TypeRecords.empty() || !TypeRecords[0].Hash.hasValue())
92 return 0;
93 return TypeRecords.size() * sizeof(ulittle32_t);
94}
95
96Error TpiStreamBuilder::finalizeMsfLayout() {
97 uint32_t Length = calculateSerializedLength();
Zachary Turnerde9ba152016-09-15 18:22:31 +000098 if (auto EC = Msf.setStreamSize(Idx, Length))
Zachary Turner620961d2016-09-14 23:00:02 +000099 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);
Zachary Turneraf299ea2017-02-25 00:44:30 +0000117 HashValueStream =
118 llvm::make_unique<BinaryByteStream>(Bytes, llvm::support::little);
Zachary Turner620961d2016-09-14 23:00:02 +0000119 return Error::success();
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000120}
121
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000122Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout,
Zachary Turneraf299ea2017-02-25 00:44:30 +0000123 WritableBinaryStreamRef Buffer) {
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000124 if (auto EC = finalize())
125 return EC;
126
127 auto InfoS =
Zachary Turnerde9ba152016-09-15 18:22:31 +0000128 WritableMappedBlockStream::createIndexedStream(Layout, Buffer, Idx);
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000129
Zachary Turneraf299ea2017-02-25 00:44:30 +0000130 BinaryStreamWriter Writer(*InfoS);
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000131 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
Zachary Turner620961d2016-09-14 23:00:02 +0000138 if (HashStreamIndex != kInvalidStreamIndex) {
139 auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
140 HashStreamIndex);
Zachary Turneraf299ea2017-02-25 00:44:30 +0000141 BinaryStreamWriter HW(*HVS);
Zachary Turner620961d2016-09-14 23:00:02 +0000142 if (auto EC = HW.writeStreamRef(*HashValueStream))
143 return EC;
144 }
145
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000146 return Error::success();
147}