blob: 49412b1f95accb0ae545928db44f2b0ee3321077 [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)
NAKAMURA Takumi05a75e42017-02-25 17:04:23 +000037 : Msf(Msf), Allocator(Msf.getAllocator()), Header(nullptr), Idx(StreamIdx) {
Zachary Turnerde9ba152016-09-15 18:22:31 +000038}
Zachary Turnerc6d54da2016-09-09 17:46:17 +000039
Eugene Zelenko570e39a2016-11-23 23:16:32 +000040TpiStreamBuilder::~TpiStreamBuilder() = default;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000041
42void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) {
43 VerHeader = Version;
44}
45
46void TpiStreamBuilder::addTypeRecord(const codeview::CVType &Record) {
47 TypeRecords.push_back(Record);
48 TypeRecordStream.setItems(TypeRecords);
49}
50
51Error TpiStreamBuilder::finalize() {
52 if (Header)
53 return Error::success();
54
55 TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>();
56
57 uint32_t Count = TypeRecords.size();
Zachary Turner620961d2016-09-14 23:00:02 +000058 uint32_t HashBufferSize = calculateHashBufferSize();
Zachary Turnerc6d54da2016-09-09 17:46:17 +000059
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
Zachary Turner620961d2016-09-14 23:00:02 +000066 H->HashStreamIndex = HashStreamIndex;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000067 H->HashAuxStreamIndex = kInvalidStreamIndex;
68 H->HashKeySize = sizeof(ulittle32_t);
69 H->NumHashBuckets = MinTpiHashBuckets;
70
Zachary Turner620961d2016-09-14 23:00:02 +000071 // 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;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000077 H->HashAdjBuffer.Length = 0;
Zachary Turner620961d2016-09-14 23:00:02 +000078 H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length;
Zachary Turnerc6d54da2016-09-09 17:46:17 +000079 H->IndexOffsetBuffer.Length = 0;
80
81 Header = H;
82 return Error::success();
83}
84
Zachary Turner120faca2017-02-27 22:11:43 +000085uint32_t TpiStreamBuilder::calculateSerializedLength() {
Zachary Turnera6cbfb52016-09-15 18:22:21 +000086 return sizeof(TpiStreamHeader) + TypeRecordStream.getLength();
Zachary Turner620961d2016-09-14 23:00:02 +000087}
88
89uint32_t TpiStreamBuilder::calculateHashBufferSize() const {
90 if (TypeRecords.empty() || !TypeRecords[0].Hash.hasValue())
91 return 0;
92 return TypeRecords.size() * sizeof(ulittle32_t);
93}
94
95Error TpiStreamBuilder::finalizeMsfLayout() {
96 uint32_t Length = calculateSerializedLength();
Zachary Turnerde9ba152016-09-15 18:22:31 +000097 if (auto EC = Msf.setStreamSize(Idx, Length))
Zachary Turner620961d2016-09-14 23:00:02 +000098 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);
Zachary Turner120faca2017-02-27 22:11:43 +0000116 HashValueStream = llvm::make_unique<BinaryByteStream>(Bytes);
Zachary Turner620961d2016-09-14 23:00:02 +0000117 return Error::success();
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000118}
119
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000120Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout,
Zachary Turner120faca2017-02-27 22:11:43 +0000121 WritableBinaryStreamRef Buffer) {
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000122 if (auto EC = finalize())
123 return EC;
124
125 auto InfoS =
Zachary Turnerde9ba152016-09-15 18:22:31 +0000126 WritableMappedBlockStream::createIndexedStream(Layout, Buffer, Idx);
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000127
Zachary Turner120faca2017-02-27 22:11:43 +0000128 BinaryStreamWriter Writer(*InfoS);
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000129 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
Zachary Turner620961d2016-09-14 23:00:02 +0000136 if (HashStreamIndex != kInvalidStreamIndex) {
137 auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
138 HashStreamIndex);
Zachary Turner120faca2017-02-27 22:11:43 +0000139 BinaryStreamWriter HW(*HVS);
Zachary Turner620961d2016-09-14 23:00:02 +0000140 if (auto EC = HW.writeStreamRef(*HashValueStream))
141 return EC;
142 }
143
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000144 return Error::success();
145}