1 //===- NamedStreamMap.cpp - PDB Named Stream Map ----------------*- C++ -*-===// 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 //===----------------------------------------------------------------------===// 9 10 #include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" 11 12 #include "llvm/ADT/SparseBitVector.h" 13 #include "llvm/ADT/StringMap.h" 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/ADT/iterator_range.h" 16 #include "llvm/DebugInfo/PDB/Native/HashTable.h" 17 #include "llvm/DebugInfo/PDB/Native/RawError.h" 18 #include "llvm/Support/BinaryStreamReader.h" 19 #include "llvm/Support/Error.h" 20 #include <algorithm> 21 #include <cstdint> 22 23 using namespace llvm; 24 using namespace llvm::pdb; 25 26 // FIXME: This shouldn't be necessary, but if we insert the strings in any 27 // other order, cvdump cannot read the generated name map. This suggests that 28 // we may be using the wrong hash function. A closer inspection of the cvdump 29 // source code may reveal something, but for now this at least makes us work, 30 // even if only by accident. 31 static constexpr const char *OrderedStreamNames[] = {"/LinkInfo", "/names", 32 "/src/headerblock"}; 33 34 NamedStreamMap::NamedStreamMap() = default; 35 36 Error NamedStreamMap::load(BinaryStreamReader &Stream) { 37 Mapping.clear(); 38 FinalizedHashTable.clear(); 39 FinalizedInfo.reset(); 40 41 uint32_t StringBufferSize; 42 if (auto EC = Stream.readInteger(StringBufferSize)) 43 return joinErrors(std::move(EC), 44 make_error<RawError>(raw_error_code::corrupt_file, 45 "Expected string buffer size")); 46 47 BinaryStreamRef StringsBuffer; 48 if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize)) 49 return EC; 50 51 HashTable OffsetIndexMap; 52 if (auto EC = OffsetIndexMap.load(Stream)) 53 return EC; 54 55 uint32_t NameOffset; 56 uint32_t NameIndex; 57 for (const auto &Entry : OffsetIndexMap) { 58 std::tie(NameOffset, NameIndex) = Entry; 59 60 // Compute the offset of the start of the string relative to the stream. 61 BinaryStreamReader NameReader(StringsBuffer); 62 NameReader.setOffset(NameOffset); 63 // Pump out our c-string from the stream. 64 StringRef Str; 65 if (auto EC = NameReader.readCString(Str)) 66 return joinErrors(std::move(EC), 67 make_error<RawError>(raw_error_code::corrupt_file, 68 "Expected name map name")); 69 70 // Add this to a string-map from name to stream number. 71 Mapping.insert({Str, NameIndex}); 72 } 73 74 return Error::success(); 75 } 76 77 Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const { 78 assert(FinalizedInfo.hasValue()); 79 80 // The first field is the number of bytes of string data. 81 if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes)) 82 return EC; 83 84 for (const auto &Name : OrderedStreamNames) { 85 auto Item = Mapping.find(Name); 86 assert(Item != Mapping.end()); 87 if (auto EC = Writer.writeCString(Item->getKey())) 88 return EC; 89 } 90 91 // And finally the Offset Index map. 92 if (auto EC = FinalizedHashTable.commit(Writer)) 93 return EC; 94 95 return Error::success(); 96 } 97 98 uint32_t NamedStreamMap::finalize() { 99 if (FinalizedInfo.hasValue()) 100 return FinalizedInfo->SerializedLength; 101 102 // Build the finalized hash table. 103 FinalizedHashTable.clear(); 104 FinalizedInfo.emplace(); 105 106 for (const auto &Name : OrderedStreamNames) { 107 auto Item = Mapping.find(Name); 108 assert(Item != Mapping.end()); 109 FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item->getValue()); 110 FinalizedInfo->StringDataBytes += Item->getKeyLength() + 1; 111 } 112 113 // Number of bytes of string data. 114 FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t); 115 // Followed by that many actual bytes of string data. 116 FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes; 117 // Followed by the mapping from Offset to Index. 118 FinalizedInfo->SerializedLength += 119 FinalizedHashTable.calculateSerializedLength(); 120 return FinalizedInfo->SerializedLength; 121 } 122 123 iterator_range<StringMapConstIterator<uint32_t>> 124 NamedStreamMap::entries() const { 125 return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), 126 Mapping.end()); 127 } 128 129 uint32_t NamedStreamMap::size() const { return Mapping.size(); } 130 131 bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const { 132 auto Iter = Mapping.find(Stream); 133 if (Iter == Mapping.end()) 134 return false; 135 StreamNo = Iter->second; 136 return true; 137 } 138 139 void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { 140 FinalizedInfo.reset(); 141 Mapping[Stream] = StreamNo; 142 } 143 144 void NamedStreamMap::remove(StringRef Stream) { 145 FinalizedInfo.reset(); 146 Mapping.erase(Stream); 147 } 148