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