llvm.org GIT mirror llvm / 288180a
Make codeview::StringTable. Previously we had knowledge of how to serialize and deserialize a string table inside of DebugInfo/PDB, but the string table that it serializes contains a piece that is actually considered CodeView and can appear outside of a PDB. We already have logic in llvm-readobj and MCCodeView to read and write this format, so it doesn't make sense to duplicate the logic in DebugInfoPDB as well. This patch makes codeview::StringTable (for writing) and codeview::StringTableRef (for reading), updates DebugInfoPDB to use these classes for its own writing, and updates llvm-readobj to additionally use StringTableRef for reading. It's a bit more difficult to get MCCodeView to use this for writing, but it's a logical next step. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301986 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
19 changed file(s) with 482 addition(s) and 116 deletion(s). Raw diff Collapse all Expand all
0 //===- StringTable.h - CodeView String Table Reader/Writer ------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_STRINGTABLE_H
10 #define LLVM_DEBUGINFO_CODEVIEW_STRINGTABLE_H
11
12 #include "llvm/ADT/StringMap.h"
13 #include "llvm/ADT/StringRef.h"
14
15 #include "llvm/Support/BinaryStreamRef.h"
16 #include "llvm/Support/Error.h"
17
18 #include
19
20 namespace llvm {
21
22 class BinaryStreamReader;
23 class BinaryStreamRef;
24 class BinaryStreamWriter;
25
26 namespace codeview {
27
28 /// Represents a read-only view of a CodeView string table. This is a very
29 /// simple flat buffer consisting of null-terminated strings, where strings
30 /// are retrieved by their offset in the buffer. StringTableRef does not own
31 /// the underlying storage for the buffer.
32 class StringTableRef {
33 public:
34 StringTableRef();
35
36 Error initialize(BinaryStreamReader &Stream);
37
38 StringRef getString(uint32_t Offset) const;
39
40 private:
41 BinaryStreamRef Stream;
42 };
43
44 /// Represents a read-write view of a CodeView string table. StringTable owns
45 /// the underlying storage for the table, and is capable of serializing the
46 /// string table into a format understood by StringTableRef.
47 class StringTable {
48 public:
49 // If string S does not exist in the string table, insert it.
50 // Returns the ID for S.
51 uint32_t insert(StringRef S);
52
53 uint32_t calculateSerializedSize() const;
54 Error commit(BinaryStreamWriter &Writer) const;
55
56 uint32_t size() const;
57
58 StringMap::const_iterator begin() const { return Strings.begin(); }
59
60 StringMap::const_iterator end() const { return Strings.end(); }
61
62 private:
63 StringMap Strings;
64 uint32_t StringSize = 1;
65 };
66 }
67 }
68
69 #endif
129129 std::unique_ptr Publics;
130130 std::unique_ptr Symbols;
131131 std::unique_ptr DirectoryStream;
132 std::unique_ptr PDBStringTableStream;
132 std::unique_ptr StringTableStream;
133133 std::unique_ptr Strings;
134134 };
135135 }
4949
5050 Error commit(StringRef Filename);
5151
52 Expected getNamedStreamIndex(StringRef Name) const;
53 Error addNamedStream(StringRef Name, uint32_t Size);
54
5255 private:
53 Error addNamedStream(StringRef Name, uint32_t Size);
5456 Expected finalizeMsfLayout();
5557
5658 BumpPtrAllocator &Allocator;
1212
1313 #include "llvm/ADT/ArrayRef.h"
1414 #include "llvm/ADT/StringRef.h"
15 #include "llvm/DebugInfo/CodeView/StringTable.h"
1516 #include "llvm/Support/BinaryStreamArray.h"
1617 #include "llvm/Support/BinaryStreamRef.h"
1718 #include "llvm/Support/Endian.h"
2223 namespace llvm {
2324 class BinaryStreamReader;
2425
26 namespace msf {
27 class MappedBlockStream;
28 }
29
2530 namespace pdb {
31
32 struct PDBStringTableHeader;
2633
2734 class PDBStringTable {
2835 public:
29 PDBStringTable();
30
31 Error load(BinaryStreamReader &Stream);
36 Error reload(BinaryStreamReader &Reader);
3237
3338 uint32_t getByteSize() const;
34
35 uint32_t getNameCount() const { return NameCount; }
36 uint32_t getHashVersion() const { return HashVersion; }
37 uint32_t getSignature() const { return Signature; }
39 uint32_t getNameCount() const;
40 uint32_t getHashVersion() const;
41 uint32_t getSignature() const;
3842
3943 StringRef getStringForID(uint32_t ID) const;
4044 uint32_t getIDForString(StringRef Str) const;
4246 FixedStreamArray name_ids() const;
4347
4448 private:
45 BinaryStreamRef NamesBuffer;
49 Error readHeader(BinaryStreamReader &Reader);
50 Error readStrings(BinaryStreamReader &Reader);
51 Error readHashTable(BinaryStreamReader &Reader);
52 Error readEpilogue(BinaryStreamReader &Reader);
53
54 const PDBStringTableHeader *Header = nullptr;
55 codeview::StringTableRef Strings;
4656 FixedStreamArray IDs;
4757 uint32_t ByteSize = 0;
48 uint32_t Signature = 0;
49 uint32_t HashVersion = 0;
5058 uint32_t NameCount = 0;
5159 };
5260
1515
1616 #include "llvm/ADT/DenseMap.h"
1717 #include "llvm/ADT/StringRef.h"
18 #include "llvm/DebugInfo/CodeView/StringTable.h"
1819 #include "llvm/Support/Error.h"
1920 #include
2021
2122 namespace llvm {
2223 class BinaryStreamWriter;
24 class WritableBinaryStreamRef;
25
26 namespace msf {
27 struct MSFLayout;
28 }
2329
2430 namespace pdb {
31
32 class PDBFileBuilder;
2533
2634 class PDBStringTableBuilder {
2735 public:
2836 // If string S does not exist in the string table, insert it.
2937 // Returns the ID for S.
3038 uint32_t insert(StringRef S);
31 uint32_t getStringIndex(StringRef S);
3239
33 uint32_t finalize();
40 uint32_t calculateSerializedSize() const;
3441 Error commit(BinaryStreamWriter &Writer) const;
3542
3643 private:
37 DenseMap Strings;
38 uint32_t StringSize = 1;
44 uint32_t calculateHashTableSize() const;
45 Error writeHeader(BinaryStreamWriter &Writer) const;
46 Error writeStrings(BinaryStreamWriter &Writer) const;
47 Error writeHashTable(BinaryStreamWriter &Writer) const;
48 Error writeEpilogue(BinaryStreamWriter &Writer) const;
49
50 codeview::StringTable Strings;
3951 };
4052
4153 } // end namespace pdb
307307
308308 /// The header preceeding the /names stream.
309309 struct PDBStringTableHeader {
310 support::ulittle32_t Signature;
311 support::ulittle32_t HashVersion;
312 support::ulittle32_t ByteSize;
310 support::ulittle32_t Signature; // PDBStringTableSignature
311 support::ulittle32_t HashVersion; // 1 or 2
312 support::ulittle32_t ByteSize; // Number of bytes of names buffer.
313313 };
314314
315315 const uint32_t PDBStringTableSignature = 0xEFFEEFFE;
3030 /// are overridable.
3131 class BinaryStreamReader {
3232 public:
33 BinaryStreamReader() = default;
3334 explicit BinaryStreamReader(BinaryStreamRef Stream);
3435 virtual ~BinaryStreamReader() {}
3536
226227 /// \returns the next byte in the stream.
227228 uint8_t peek() const;
228229
230 std::pair
231 split(uint32_t Offset) const;
232
229233 private:
230234 BinaryStreamRef Stream;
231235 uint32_t Offset;
1919 #include "llvm/Support/Error.h"
2020 #include
2121 #include
22 #include
2223
2324 namespace llvm {
2425
2930 /// although no methods are overridable.
3031 class BinaryStreamWriter {
3132 public:
32 // FIXME: We should be able to slice and drop_front etc on Writers / Readers.
33
3433 BinaryStreamWriter() = default;
3534 explicit BinaryStreamWriter(WritableBinaryStreamRef Stream);
3635 virtual ~BinaryStreamWriter() {}
151150 return writeStreamRef(Array.getUnderlyingStream());
152151 }
153152
153 /// Splits the Writer into two Writers at a given offset.
154 std::pair split(uint32_t Off) const;
155
154156 void setOffset(uint32_t Off) { Offset = Off; }
155157 uint32_t getOffset() const { return Offset; }
156158 uint32_t getLength() const { return Stream.getLength(); }
1414 ModuleDebugLineFragment.cpp
1515 ModuleDebugUnknownFragment.cpp
1616 RecordSerialization.cpp
17 StringTable.cpp
1718 SymbolRecordMapping.cpp
1819 SymbolDumper.cpp
1920 SymbolSerializer.cpp
0 //===- StringTable.cpp - CodeView String Table Reader/Writer ----*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/StringTable.h"
10
11 #include "llvm/Support/BinaryStream.h"
12 #include "llvm/Support/BinaryStreamReader.h"
13 #include "llvm/Support/BinaryStreamWriter.h"
14
15 using namespace llvm;
16 using namespace llvm::codeview;
17
18 StringTableRef::StringTableRef() {}
19
20 Error StringTableRef::initialize(BinaryStreamReader &Reader) {
21 return Reader.readStreamRef(Stream, Reader.bytesRemaining());
22 }
23
24 StringRef StringTableRef::getString(uint32_t Offset) const {
25 BinaryStreamReader Reader(Stream);
26 Reader.setOffset(Offset);
27 StringRef Result;
28 Error EC = Reader.readCString(Result);
29 assert(!EC);
30 consumeError(std::move(EC));
31 return Result;
32 }
33
34 uint32_t StringTable::insert(StringRef S) {
35 auto P = Strings.insert({S, StringSize});
36
37 // If a given string didn't exist in the string table, we want to increment
38 // the string table size.
39 if (P.second)
40 StringSize += S.size() + 1; // +1 for '\0'
41 return P.first->second;
42 }
43
44 uint32_t StringTable::calculateSerializedSize() const { return StringSize; }
45
46 Error StringTable::commit(BinaryStreamWriter &Writer) const {
47 assert(Writer.bytesRemaining() == StringSize);
48 uint32_t MaxOffset = 1;
49
50 for (auto &Pair : Strings) {
51 StringRef S = Pair.getKey();
52 uint32_t Offset = Pair.getValue();
53 Writer.setOffset(Offset);
54 if (auto EC = Writer.writeCString(S))
55 return EC;
56 MaxOffset = std::max(MaxOffset, Offset + S.size() + 1);
57 }
58
59 Writer.setOffset(MaxOffset);
60 assert(Writer.bytesRemaining() == 0);
61 return Error::success();
62 }
63
64 uint32_t StringTable::size() const { return Strings.size(); }
145145
146146 if (ECSubstream.getLength() > 0) {
147147 BinaryStreamReader ECReader(ECSubstream);
148 if (auto EC = ECNames.load(ECReader))
148 if (auto EC = ECNames.reload(ECReader))
149149 return EC;
150150 }
151151
337337 }
338338
339339 Expected PDBFile::getStringTable() {
340 if (!Strings || !PDBStringTableStream) {
340 if (!Strings) {
341341 auto IS = getPDBInfoStream();
342342 if (!IS)
343343 return IS.takeError();
349349 if (!NS)
350350 return NS.takeError();
351351
352 auto N = llvm::make_unique();
352353 BinaryStreamReader Reader(**NS);
353 auto N = llvm::make_unique();
354 if (auto EC = N->load(Reader))
355 return std::move(EC);
354 if (auto EC = N->reload(Reader))
355 return std::move(EC);
356 assert(Reader.bytesRemaining() == 0);
357 StringTableStream = std::move(*NS);
356358 Strings = std::move(N);
357 PDBStringTableStream = std::move(*NS);
358359 }
359360 return *Strings;
360361 }
7979 }
8080
8181 Expected PDBFileBuilder::finalizeMsfLayout() {
82 uint32_t PDBStringTableSize = Strings.finalize();
82 uint32_t StringsLen = Strings.calculateSerializedSize();
8383
84 if (auto EC = addNamedStream("/names", PDBStringTableSize))
84 if (auto EC = addNamedStream("/names", StringsLen))
8585 return std::move(EC);
8686 if (auto EC = addNamedStream("/LinkInfo", 0))
8787 return std::move(EC);
106106 }
107107
108108 return Msf->build();
109 }
110
111 Expected PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
112 uint32_t SN = 0;
113 if (!NamedStreams.get(Name, SN))
114 return llvm::make_error(raw_error_code::no_stream);
115 return SN;
109116 }
110117
111118 Error PDBFileBuilder::commit(StringRef Filename) {
145152 return EC;
146153 }
147154
148 uint32_t PDBStringTableStreamNo = 0;
149 if (!NamedStreams.get("/names", PDBStringTableStreamNo))
150 return llvm::make_error(raw_error_code::no_stream);
155 auto ExpectedSN = getNamedStreamIndex("/names");
156 if (!ExpectedSN)
157 return ExpectedSN.takeError();
151158
152 auto NS = WritableMappedBlockStream::createIndexedStream(
153 Layout, Buffer, PDBStringTableStreamNo);
159 auto NS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
160 *ExpectedSN);
154161 BinaryStreamWriter NSWriter(*NS);
155162 if (auto EC = Strings.commit(NSWriter))
156163 return EC;
None //===- PDBStringTable.cpp - PDB String Table -----------------------*- C++
1 //-*-===//
0 //===- PDBStringTable.cpp - PDB String Table ---------------------*- C++-*-===//
21 //
32 // The LLVM Compiler Infrastructure
43 //
109 #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
1110
1211 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
1313 #include "llvm/DebugInfo/PDB/Native/Hash.h"
1414 #include "llvm/DebugInfo/PDB/Native/RawError.h"
1515 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
2020 using namespace llvm::support;
2121 using namespace llvm::pdb;
2222
23 PDBStringTable::PDBStringTable() {}
23 uint32_t PDBStringTable::getByteSize() const { return ByteSize; }
24 uint32_t PDBStringTable::getNameCount() const { return NameCount; }
25 uint32_t PDBStringTable::getHashVersion() const { return Header->HashVersion; }
26 uint32_t PDBStringTable::getSignature() const { return Header->Signature; }
2427
25 Error PDBStringTable::load(BinaryStreamReader &Stream) {
26 ByteSize = Stream.getLength();
27
28 const PDBStringTableHeader *H;
29 if (auto EC = Stream.readObject(H))
28 Error PDBStringTable::readHeader(BinaryStreamReader &Reader) {
29 if (auto EC = Reader.readObject(Header))
3030 return EC;
3131
32 if (H->Signature != PDBStringTableSignature)
32 if (Header->Signature != PDBStringTableSignature)
3333 return make_error(raw_error_code::corrupt_file,
3434 "Invalid hash table signature");
35 if (H->HashVersion != 1 && H->HashVersion != 2)
35 if (Header->HashVersion != 1 && Header->HashVersion != 2)
3636 return make_error(raw_error_code::corrupt_file,
3737 "Unsupported hash version");
3838
39 Signature = H->Signature;
40 HashVersion = H->HashVersion;
41 if (auto EC = Stream.readStreamRef(NamesBuffer, H->ByteSize))
39 assert(Reader.bytesRemaining() == 0);
40 return Error::success();
41 }
42
43 Error PDBStringTable::readStrings(BinaryStreamReader &Reader) {
44 if (auto EC = Strings.initialize(Reader)) {
4245 return joinErrors(std::move(EC),
4346 make_error(raw_error_code::corrupt_file,
4447 "Invalid hash table byte length"));
48 }
4549
50 assert(Reader.bytesRemaining() == 0);
51 return Error::success();
52 }
53
54 Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) {
4655 const support::ulittle32_t *HashCount;
47 if (auto EC = Stream.readObject(HashCount))
56 if (auto EC = Reader.readObject(HashCount))
4857 return EC;
4958
50 if (auto EC = Stream.readArray(IDs, *HashCount))
59 if (auto EC = Reader.readArray(IDs, *HashCount)) {
5160 return joinErrors(std::move(EC),
5261 make_error(raw_error_code::corrupt_file,
5362 "Could not read bucket array"));
54
55 if (Stream.bytesRemaining() < sizeof(support::ulittle32_t))
56 return make_error(raw_error_code::corrupt_file,
57 "Missing name count");
58
59 if (auto EC = Stream.readInteger(NameCount))
60 return EC;
61
62 if (Stream.bytesRemaining() > 0)
63 return make_error(raw_error_code::stream_too_long,
64 "Unexpected bytes found in string table");
63 }
6564
6665 return Error::success();
6766 }
6867
69 uint32_t PDBStringTable::getByteSize() const { return ByteSize; }
68 Error PDBStringTable::readEpilogue(BinaryStreamReader &Reader) {
69 if (auto EC = Reader.readInteger(NameCount))
70 return EC;
71
72 assert(Reader.bytesRemaining() == 0);
73 return Error::success();
74 }
75
76 Error PDBStringTable::reload(BinaryStreamReader &Reader) {
77
78 BinaryStreamReader SectionReader;
79
80 std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader));
81 if (auto EC = readHeader(SectionReader))
82 return EC;
83
84 std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize);
85 if (auto EC = readStrings(SectionReader))
86 return EC;
87
88 // We don't know how long the hash table is until we parse it, so let the
89 // function responsible for doing that figure it out.
90 if (auto EC = readHashTable(Reader))
91 return EC;
92
93 std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t));
94 if (auto EC = readEpilogue(SectionReader))
95 return EC;
96
97 assert(Reader.bytesRemaining() == 0);
98 return Error::success();
99 }
70100
71101 StringRef PDBStringTable::getStringForID(uint32_t ID) const {
72 if (ID == IDs[0])
73 return StringRef();
74
75 // NamesBuffer is a buffer of null terminated strings back to back. ID is
76 // the starting offset of the string we're looking for. So just seek into
77 // the desired offset and a read a null terminated stream from that offset.
78 StringRef Result;
79 BinaryStreamReader NameReader(NamesBuffer);
80 NameReader.setOffset(ID);
81 if (auto EC = NameReader.readCString(Result))
82 consumeError(std::move(EC));
83 return Result;
102 return Strings.getString(ID);
84103 }
85104
86105 uint32_t PDBStringTable::getIDForString(StringRef Str) const {
87 uint32_t Hash = (HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
106 uint32_t Hash =
107 (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
88108 size_t Count = IDs.size();
89109 uint32_t Start = Hash % Count;
90110 for (size_t I = 0; I < Count; ++I) {
77 //===----------------------------------------------------------------------===//
88
99 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
10
1011 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
1113 #include "llvm/DebugInfo/PDB/Native/Hash.h"
14 #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
1215 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
1316 #include "llvm/Support/BinaryStreamWriter.h"
1417 #include "llvm/Support/Endian.h"
1518
1619 using namespace llvm;
20 using namespace llvm::msf;
1721 using namespace llvm::support;
1822 using namespace llvm::support::endian;
1923 using namespace llvm::pdb;
2024
2125 uint32_t PDBStringTableBuilder::insert(StringRef S) {
22 auto P = Strings.insert({S, StringSize});
23
24 // If a given string didn't exist in the string table, we want to increment
25 // the string table size.
26 if (P.second)
27 StringSize += S.size() + 1; // +1 for '\0'
28 return P.first->second;
29 }
30
31 uint32_t PDBStringTableBuilder::getStringIndex(StringRef S) {
32 auto Iter = Strings.find(S);
33 assert(Iter != Strings.end());
34 return Iter->second;
26 return Strings.insert(S);
3527 }
3628
3729 static uint32_t computeBucketCount(uint32_t NumStrings) {
4335 return (NumStrings + 1) * 1.25;
4436 }
4537
46 uint32_t PDBStringTableBuilder::finalize() {
47 uint32_t Size = 0;
48 Size += sizeof(PDBStringTableHeader);
49 Size += StringSize;
50 Size += sizeof(uint32_t); // Hash table begins with 4-byte size field.
38 uint32_t PDBStringTableBuilder::calculateHashTableSize() const {
39 uint32_t Size = sizeof(uint32_t); // Hash table begins with 4-byte size field.
40 Size += sizeof(uint32_t) * computeBucketCount(Strings.size());
5141
52 uint32_t BucketCount = computeBucketCount(Strings.size());
53 Size += BucketCount * sizeof(uint32_t);
54
55 Size +=
56 sizeof(uint32_t); // The /names stream ends with the number of strings.
5742 return Size;
5843 }
5944
60 Error PDBStringTableBuilder::commit(BinaryStreamWriter &Writer) const {
45 uint32_t PDBStringTableBuilder::calculateSerializedSize() const {
46 uint32_t Size = 0;
47 Size += sizeof(PDBStringTableHeader);
48 Size += Strings.calculateSerializedSize();
49 Size += calculateHashTableSize();
50 Size += sizeof(uint32_t); // The /names stream ends with the string count.
51 return Size;
52 }
53
54 Error PDBStringTableBuilder::writeHeader(BinaryStreamWriter &Writer) const {
6155 // Write a header
6256 PDBStringTableHeader H;
6357 H.Signature = PDBStringTableSignature;
6458 H.HashVersion = 1;
65 H.ByteSize = StringSize;
59 H.ByteSize = Strings.calculateSerializedSize();
6660 if (auto EC = Writer.writeObject(H))
6761 return EC;
62 assert(Writer.bytesRemaining() == 0);
63 return Error::success();
64 }
6865
69 // Write a string table.
70 uint32_t StringStart = Writer.getOffset();
71 for (auto Pair : Strings) {
72 StringRef S = Pair.first;
73 uint32_t Offset = Pair.second;
74 Writer.setOffset(StringStart + Offset);
75 if (auto EC = Writer.writeCString(S))
76 return EC;
77 }
78 Writer.setOffset(StringStart + StringSize);
66 Error PDBStringTableBuilder::writeStrings(BinaryStreamWriter &Writer) const {
67 if (auto EC = Strings.commit(Writer))
68 return EC;
7969
70 assert(Writer.bytesRemaining() == 0);
71 return Error::success();
72 }
73
74 Error PDBStringTableBuilder::writeHashTable(BinaryStreamWriter &Writer) const {
8075 // Write a hash table.
8176 uint32_t BucketCount = computeBucketCount(Strings.size());
8277 if (auto EC = Writer.writeInteger(BucketCount))
8378 return EC;
8479 std::vector Buckets(BucketCount);
8580
86 for (auto Pair : Strings) {
87 StringRef S = Pair.first;
88 uint32_t Offset = Pair.second;
81 for (auto &Pair : Strings) {
82 StringRef S = Pair.getKey();
83 uint32_t Offset = Pair.getValue();
8984 uint32_t Hash = hashStringV1(S);
9085
9186 for (uint32_t I = 0; I != BucketCount; ++I) {
10196
10297 if (auto EC = Writer.writeArray(ArrayRef(Buckets)))
10398 return EC;
104 if (auto EC = Writer.writeInteger(static_cast(Strings.size())))
105 return EC;
99
100 assert(Writer.bytesRemaining() == 0);
106101 return Error::success();
107102 }
103
104 Error PDBStringTableBuilder::writeEpilogue(BinaryStreamWriter &Writer) const {
105 if (auto EC = Writer.writeInteger(Strings.size()))
106 return EC;
107 assert(Writer.bytesRemaining() == 0);
108 return Error::success();
109 }
110
111 Error PDBStringTableBuilder::commit(BinaryStreamWriter &Writer) const {
112 BinaryStreamWriter SectionWriter;
113
114 std::tie(SectionWriter, Writer) = Writer.split(sizeof(PDBStringTableHeader));
115 if (auto EC = writeHeader(SectionWriter))
116 return EC;
117
118 std::tie(SectionWriter, Writer) =
119 Writer.split(Strings.calculateSerializedSize());
120 if (auto EC = writeStrings(SectionWriter))
121 return EC;
122
123 std::tie(SectionWriter, Writer) = Writer.split(calculateHashTableSize());
124 if (auto EC = writeHashTable(SectionWriter))
125 return EC;
126
127 std::tie(SectionWriter, Writer) = Writer.split(sizeof(uint32_t));
128 if (auto EC = writeEpilogue(SectionWriter))
129 return EC;
130
131 return Error::success();
132 }
0 //===- StringTableStreamBuilder.cpp - PDB String Table ----------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/PDB/Native/StringTableStreamBuilder.h"
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/DebugInfo/PDB/Native/Hash.h"
12 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
13 #include "llvm/Support/BinaryStreamWriter.h"
14 #include "llvm/Support/Endian.h"
15
16 using namespace llvm;
17 using namespace llvm::support;
18 using namespace llvm::support::endian;
19 using namespace llvm::pdb;
20
21 uint32_t StringTableStreamBuilder::insert(StringRef S) {
22 return Strings.insert(S);
23 }
24
25 static uint32_t computeBucketCount(uint32_t NumStrings) {
26 // The /names stream is basically an on-disk open-addressing hash table.
27 // Hash collisions are resolved by linear probing. We cannot make
28 // utilization 100% because it will make the linear probing extremely
29 // slow. But lower utilization wastes disk space. As a reasonable
30 // load factor, we choose 80%. We need +1 because slot 0 is reserved.
31 return (NumStrings + 1) * 1.25;
32 }
33
34 uint32_t StringTableStreamBuilder::hashTableSize() const {
35 uint32_t Size = sizeof(uint32_t); // Hash table begins with 4-byte size field.
36
37 Size += computeBucketCount(Strings.size()) * sizeof(uint32_t);
38 return Size;
39 }
40
41 uint32_t StringTableStreamBuilder::calculateSerializedSize() const {
42 uint32_t Size = 0;
43 Size += sizeof(StringTableHeader);
44 Size += Strings.calculateSerializedSize();
45 Size += hashTableSize();
46 Size += sizeof(uint32_t); // The table ends with the number of strings.
47 return Size;
48 }
49
50 Error StringTableStreamBuilder::writeHeader(BinaryStreamWriter &Writer) const {
51 // Write a header
52 StringTableHeader H;
53 H.Signature = StringTableSignature;
54 H.HashVersion = 1;
55 H.ByteSize = Strings.calculateSerializedSize();
56 if (auto EC = Writer.writeObject(H))
57 return EC;
58
59 assert(Writer.bytesRemaining() == 0);
60 return Error::success();
61 }
62
63 Error StringTableStreamBuilder::writeStrings(BinaryStreamWriter &Writer) const {
64 if (auto EC = Strings.commit(Writer))
65 return EC;
66
67 assert(Writer.bytesRemaining() == 0);
68 return Error::success();
69 }
70
71 Error StringTableStreamBuilder::writeHashTable(
72 BinaryStreamWriter &Writer) const {
73 // Write a hash table.
74 uint32_t BucketCount = computeBucketCount(Strings.size());
75 if (auto EC = Writer.writeInteger(BucketCount))
76 return EC;
77
78 std::vector Buckets(BucketCount);
79
80 for (auto &Pair : Strings) {
81 StringRef S = Pair.getKey();
82 uint32_t Offset = Pair.getValue();
83 uint32_t Hash = hashStringV1(S);
84
85 for (uint32_t I = 0; I != BucketCount; ++I) {
86 uint32_t Slot = (Hash + I) % BucketCount;
87 if (Slot == 0)
88 continue; // Skip reserved slot
89 if (Buckets[Slot] != 0)
90 continue;
91 Buckets[Slot] = Offset;
92 break;
93 }
94 }
95
96 if (auto EC = Writer.writeArray(makeArrayRef(Buckets)))
97 return EC;
98 assert(Writer.bytesRemaining() == 0);
99 return Error::success();
100 }
101
102 Error StringTableStreamBuilder::commit(BinaryStreamWriter &Writer) const {
103 BinaryStreamWriter Section;
104
105 std::tie(Section, Writer) = Writer.split(sizeof(StringTableHeader));
106 if (auto EC = writeHeader(Section))
107 return EC;
108
109 std::tie(Section, Writer) = Writer.split(Strings.calculateSerializedSize());
110 if (auto EC = writeStrings(Section))
111 return EC;
112
113 std::tie(Section, Writer) = Writer.split(hashTableSize());
114 if (auto EC = writeHashTable(Section))
115 return EC;
116
117 if (auto EC = Writer.writeInteger(Strings.size()))
118 return EC;
119
120 assert(Writer.bytesRemaining() == 0);
121 return Error::success();
122 }
9292 llvm::consumeError(std::move(EC));
9393 return Buffer[0];
9494 }
95
96 std::pair
97 BinaryStreamReader::split(uint32_t Off) const {
98 assert(getLength() >= Off);
99
100 BinaryStreamRef First = Stream.drop_front(Offset);
101
102 BinaryStreamRef Second = First.drop_front(Off);
103 First = First.keep_front(Off);
104 BinaryStreamReader W1{First};
105 BinaryStreamReader W2{Second};
106 return std::make_pair(W1, W2);
107 }
5858 return Error::success();
5959 }
6060
61 std::pair
62 BinaryStreamWriter::split(uint32_t Off) const {
63 assert(getLength() >= Off);
64
65 WritableBinaryStreamRef First = Stream.drop_front(Offset);
66
67 WritableBinaryStreamRef Second = First.drop_front(Off);
68 First = First.keep_front(Off);
69 BinaryStreamWriter W1{First};
70 BinaryStreamWriter W2{Second};
71 return std::make_pair(W1, W2);
72 }
73
6174 Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
6275 uint32_t NewOffset = alignTo(Offset, Align);
6376 if (NewOffset > getLength())
3232 EXPECT_EQ(1U, Builder.insert("foo"));
3333 EXPECT_EQ(9U, Builder.insert("baz"));
3434
35 std::vector Buffer(Builder.finalize());
35 std::vector Buffer(Builder.calculateSerializedSize());
3636 MutableBinaryByteStream OutStream(Buffer, little);
3737 BinaryStreamWriter Writer(OutStream);
3838 EXPECT_NO_ERROR(Builder.commit(Writer));
4141 BinaryByteStream InStream(Buffer, little);
4242 BinaryStreamReader Reader(InStream);
4343 PDBStringTable Table;
44 EXPECT_NO_ERROR(Table.load(Reader));
44 EXPECT_NO_ERROR(Table.reload(Reader));
4545
4646 EXPECT_EQ(3U, Table.getNameCount());
4747 EXPECT_EQ(1U, Table.getHashVersion());