Zachary Turner | e204a6c | 2017-05-02 18:00:13 +0000 | [diff] [blame] | 1 | //===- PDBStringTableBuilder.cpp - PDB String Table -------------*- C++ -*-===// |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 2 | // |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame^] | 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
Zachary Turner | e204a6c | 2017-05-02 18:00:13 +0000 | [diff] [blame] | 9 | #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 10 | |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 11 | #include "llvm/ADT/ArrayRef.h" |
Adrian McCarthy | 6b6b8c4 | 2017-01-25 22:38:55 +0000 | [diff] [blame] | 12 | #include "llvm/DebugInfo/PDB/Native/Hash.h" |
| 13 | #include "llvm/DebugInfo/PDB/Native/RawTypes.h" |
Zachary Turner | d9dc282 | 2017-03-02 20:52:51 +0000 | [diff] [blame] | 14 | #include "llvm/Support/BinaryStreamWriter.h" |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 15 | #include "llvm/Support/Endian.h" |
| 16 | |
Zachary Turner | a6fb536 | 2018-03-23 18:43:39 +0000 | [diff] [blame] | 17 | #include <map> |
| 18 | |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 19 | using namespace llvm; |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 20 | using namespace llvm::msf; |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 21 | using namespace llvm::support; |
| 22 | using namespace llvm::support::endian; |
| 23 | using namespace llvm::pdb; |
| 24 | |
Zachary Turner | f228276 | 2018-03-23 19:57:25 +0000 | [diff] [blame] | 25 | StringTableHashTraits::StringTableHashTraits(PDBStringTableBuilder &Table) |
| 26 | : Table(&Table) {} |
| 27 | |
| 28 | uint32_t StringTableHashTraits::hashLookupKey(StringRef S) const { |
| 29 | return Table->getIdForString(S); |
| 30 | } |
| 31 | |
| 32 | StringRef StringTableHashTraits::storageKeyToLookupKey(uint32_t Offset) const { |
| 33 | return Table->getStringForId(Offset); |
| 34 | } |
| 35 | |
| 36 | uint32_t StringTableHashTraits::lookupKeyToStorageKey(StringRef S) { |
| 37 | return Table->insert(S); |
| 38 | } |
| 39 | |
Zachary Turner | e204a6c | 2017-05-02 18:00:13 +0000 | [diff] [blame] | 40 | uint32_t PDBStringTableBuilder::insert(StringRef S) { |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 41 | return Strings.insert(S); |
Zachary Turner | 8a2ebfb | 2017-05-01 23:27:42 +0000 | [diff] [blame] | 42 | } |
| 43 | |
Zachary Turner | 71d36ad | 2018-03-22 17:37:28 +0000 | [diff] [blame] | 44 | uint32_t PDBStringTableBuilder::getIdForString(StringRef S) const { |
| 45 | return Strings.getIdForString(S); |
| 46 | } |
| 47 | |
| 48 | StringRef PDBStringTableBuilder::getStringForId(uint32_t Id) const { |
| 49 | return Strings.getStringForId(Id); |
| 50 | } |
| 51 | |
Zachary Turner | a6fb536 | 2018-03-23 18:43:39 +0000 | [diff] [blame] | 52 | // This is a precomputed list of Buckets given the specified number of |
| 53 | // strings. Matching the reference algorithm exactly is not strictly |
| 54 | // necessary for correctness, but it helps when comparing LLD's PDBs with |
| 55 | // Microsoft's PDBs so as to eliminate superfluous differences. |
| 56 | static std::map<uint32_t, uint32_t> StringsToBuckets = { |
| 57 | {1, 2}, |
| 58 | {2, 4}, |
| 59 | {4, 7}, |
| 60 | {6, 11}, |
| 61 | {9, 17}, |
| 62 | {13, 26}, |
| 63 | {20, 40}, |
| 64 | {31, 61}, |
| 65 | {46, 92}, |
| 66 | {70, 139}, |
| 67 | {105, 209}, |
| 68 | {157, 314}, |
| 69 | {236, 472}, |
| 70 | {355, 709}, |
| 71 | {532, 1064}, |
| 72 | {799, 1597}, |
| 73 | {1198, 2396}, |
| 74 | {1798, 3595}, |
| 75 | {2697, 5393}, |
| 76 | {4045, 8090}, |
| 77 | {6068, 12136}, |
| 78 | {9103, 18205}, |
| 79 | {13654, 27308}, |
| 80 | {20482, 40963}, |
| 81 | {30723, 61445}, |
| 82 | {46084, 92168}, |
| 83 | {69127, 138253}, |
| 84 | {103690, 207380}, |
| 85 | {155536, 311071}, |
| 86 | {233304, 466607}, |
| 87 | {349956, 699911}, |
| 88 | {524934, 1049867}, |
| 89 | {787401, 1574801}, |
| 90 | {1181101, 2362202}, |
| 91 | {1771652, 3543304}, |
| 92 | {2657479, 5314957}, |
| 93 | {3986218, 7972436}, |
| 94 | {5979328, 11958655}, |
| 95 | {8968992, 17937983}, |
| 96 | {13453488, 26906975}, |
| 97 | {20180232, 40360463}, |
| 98 | {30270348, 60540695}, |
| 99 | {45405522, 90811043}, |
| 100 | {68108283, 136216565}, |
| 101 | {102162424, 204324848}, |
| 102 | {153243637, 306487273}, |
| 103 | {229865455, 459730910}, |
| 104 | {344798183, 689596366}, |
| 105 | {517197275, 1034394550}, |
| 106 | {775795913, 1551591826}}; |
| 107 | |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 108 | static uint32_t computeBucketCount(uint32_t NumStrings) { |
Zachary Turner | a6fb536 | 2018-03-23 18:43:39 +0000 | [diff] [blame] | 109 | auto Entry = StringsToBuckets.lower_bound(NumStrings); |
| 110 | assert(Entry != StringsToBuckets.end()); |
| 111 | return Entry->second; |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 112 | } |
| 113 | |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 114 | uint32_t PDBStringTableBuilder::calculateHashTableSize() const { |
| 115 | uint32_t Size = sizeof(uint32_t); // Hash table begins with 4-byte size field. |
| 116 | Size += sizeof(uint32_t) * computeBucketCount(Strings.size()); |
Daniel Jasper | dff096f | 2017-05-03 07:29:25 +0000 | [diff] [blame] | 117 | |
Zachary Turner | 7dba20b | 2017-05-02 23:36:17 +0000 | [diff] [blame] | 118 | return Size; |
| 119 | } |
| 120 | |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 121 | uint32_t PDBStringTableBuilder::calculateSerializedSize() const { |
| 122 | uint32_t Size = 0; |
| 123 | Size += sizeof(PDBStringTableHeader); |
| 124 | Size += Strings.calculateSerializedSize(); |
| 125 | Size += calculateHashTableSize(); |
| 126 | Size += sizeof(uint32_t); // The /names stream ends with the string count. |
| 127 | return Size; |
| 128 | } |
| 129 | |
Zachary Turner | a8cfc29 | 2017-06-14 15:59:27 +0000 | [diff] [blame] | 130 | void PDBStringTableBuilder::setStrings( |
| 131 | const codeview::DebugStringTableSubsection &Strings) { |
| 132 | this->Strings = Strings; |
| 133 | } |
| 134 | |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 135 | Error PDBStringTableBuilder::writeHeader(BinaryStreamWriter &Writer) const { |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 136 | // Write a header |
Zachary Turner | e204a6c | 2017-05-02 18:00:13 +0000 | [diff] [blame] | 137 | PDBStringTableHeader H; |
| 138 | H.Signature = PDBStringTableSignature; |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 139 | H.HashVersion = 1; |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 140 | H.ByteSize = Strings.calculateSerializedSize(); |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 141 | if (auto EC = Writer.writeObject(H)) |
| 142 | return EC; |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 143 | assert(Writer.bytesRemaining() == 0); |
| 144 | return Error::success(); |
| 145 | } |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 146 | |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 147 | Error PDBStringTableBuilder::writeStrings(BinaryStreamWriter &Writer) const { |
| 148 | if (auto EC = Strings.commit(Writer)) |
| 149 | return EC; |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 150 | |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 151 | assert(Writer.bytesRemaining() == 0); |
| 152 | return Error::success(); |
| 153 | } |
| 154 | |
| 155 | Error PDBStringTableBuilder::writeHashTable(BinaryStreamWriter &Writer) const { |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 156 | // Write a hash table. |
| 157 | uint32_t BucketCount = computeBucketCount(Strings.size()); |
Zachary Turner | 695ed56 | 2017-02-28 00:04:07 +0000 | [diff] [blame] | 158 | if (auto EC = Writer.writeInteger(BucketCount)) |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 159 | return EC; |
| 160 | std::vector<ulittle32_t> Buckets(BucketCount); |
| 161 | |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 162 | for (auto &Pair : Strings) { |
| 163 | StringRef S = Pair.getKey(); |
| 164 | uint32_t Offset = Pair.getValue(); |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 165 | uint32_t Hash = hashStringV1(S); |
| 166 | |
| 167 | for (uint32_t I = 0; I != BucketCount; ++I) { |
| 168 | uint32_t Slot = (Hash + I) % BucketCount; |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 169 | if (Buckets[Slot] != 0) |
| 170 | continue; |
| 171 | Buckets[Slot] = Offset; |
| 172 | break; |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets))) |
| 177 | return EC; |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 178 | |
| 179 | assert(Writer.bytesRemaining() == 0); |
| 180 | return Error::success(); |
| 181 | } |
| 182 | |
| 183 | Error PDBStringTableBuilder::writeEpilogue(BinaryStreamWriter &Writer) const { |
| 184 | if (auto EC = Writer.writeInteger<uint32_t>(Strings.size())) |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 185 | return EC; |
Zachary Turner | c504ae3 | 2017-05-03 15:58:37 +0000 | [diff] [blame] | 186 | assert(Writer.bytesRemaining() == 0); |
| 187 | return Error::success(); |
| 188 | } |
| 189 | |
| 190 | Error PDBStringTableBuilder::commit(BinaryStreamWriter &Writer) const { |
| 191 | BinaryStreamWriter SectionWriter; |
| 192 | |
| 193 | std::tie(SectionWriter, Writer) = Writer.split(sizeof(PDBStringTableHeader)); |
| 194 | if (auto EC = writeHeader(SectionWriter)) |
| 195 | return EC; |
| 196 | |
| 197 | std::tie(SectionWriter, Writer) = |
| 198 | Writer.split(Strings.calculateSerializedSize()); |
| 199 | if (auto EC = writeStrings(SectionWriter)) |
| 200 | return EC; |
| 201 | |
| 202 | std::tie(SectionWriter, Writer) = Writer.split(calculateHashTableSize()); |
| 203 | if (auto EC = writeHashTable(SectionWriter)) |
| 204 | return EC; |
| 205 | |
| 206 | std::tie(SectionWriter, Writer) = Writer.split(sizeof(uint32_t)); |
| 207 | if (auto EC = writeEpilogue(SectionWriter)) |
| 208 | return EC; |
| 209 | |
Rui Ueyama | dcd3293 | 2017-01-15 00:36:02 +0000 | [diff] [blame] | 210 | return Error::success(); |
| 211 | } |