blob: c769321f18c13e20a72482cebd2c6c74d3d736cb [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
Eugene Zelenko570e39a2016-11-23 23:16:32 +000010#include "llvm/ADT/ArrayRef.h"
11#include "llvm/ADT/STLExtras.h"
Zachary Turnerc6d54da2016-09-09 17:46:17 +000012#include "llvm/DebugInfo/CodeView/TypeIndex.h"
13#include "llvm/DebugInfo/CodeView/TypeRecord.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000014#include "llvm/DebugInfo/MSF/ByteStream.h"
Zachary Turner620961d2016-09-14 23:00:02 +000015#include "llvm/DebugInfo/MSF/MSFBuilder.h"
Zachary Turnerc6d54da2016-09-09 17:46:17 +000016#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000017#include "llvm/DebugInfo/MSF/StreamArray.h"
18#include "llvm/DebugInfo/MSF/StreamReader.h"
Zachary Turnerc6d54da2016-09-09 17:46:17 +000019#include "llvm/DebugInfo/MSF/StreamWriter.h"
20#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
21#include "llvm/DebugInfo/PDB/Raw/RawError.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000022#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
Zachary Turnerc6d54da2016-09-09 17:46:17 +000023#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000024#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.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)
37 : Msf(Msf), Allocator(Msf.getAllocator()), Header(nullptr), Idx(StreamIdx) {
38}
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
85uint32_t TpiStreamBuilder::calculateSerializedLength() const {
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);
116 HashValueStream = llvm::make_unique<ByteStream>(Bytes);
117 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,
121 const msf::WritableStream &Buffer) {
122 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
128 StreamWriter Writer(*InfoS);
129 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);
139 StreamWriter HW(*HVS);
140 if (auto EC = HW.writeStreamRef(*HashValueStream))
141 return EC;
142 }
143
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000144 return Error::success();
145}