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 assert(Item != Mapping.end()); 90 if (auto EC = Writer.writeCString(Item->getKey())) 91 return EC; 92 } 93 94 // And finally the Offset Index map. 95 if (auto EC = FinalizedHashTable.commit(Writer)) 96 return EC; 97 98 return Error::success(); 99 } 100 101 uint32_t NamedStreamMap::finalize() { 102 if (FinalizedInfo.hasValue()) 103 return FinalizedInfo->SerializedLength; 104 105 // Build the finalized hash table. 106 FinalizedHashTable.clear(); 107 FinalizedInfo.emplace(); 108 109 for (const auto &Name : OrderedStreamNames) { 110 auto Item = Mapping.find(Name); 111 assert(Item != Mapping.end()); 112 FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item->getValue()); 113 FinalizedInfo->StringDataBytes += Item->getKeyLength() + 1; 114 } 115 116 // Number of bytes of string data. 117 FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t); 118 // Followed by that many actual bytes of string data. 119 FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes; 120 // Followed by the mapping from Offset to Index. 121 FinalizedInfo->SerializedLength += 122 FinalizedHashTable.calculateSerializedLength(); 123 return FinalizedInfo->SerializedLength; 124 } 125 126 iterator_range<StringMapConstIterator<uint32_t>> 127 NamedStreamMap::entries() const { 128 return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), 129 Mapping.end()); 130 } 131 132 uint32_t NamedStreamMap::size() const { return Mapping.size(); } 133 134 bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const { 135 auto Iter = Mapping.find(Stream); 136 if (Iter == Mapping.end()) 137 return false; 138 StreamNo = Iter->second; 139 return true; 140 } 141 142 void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { 143 FinalizedInfo.reset(); 144 Mapping[Stream] = StreamNo; 145 } 146 147 void NamedStreamMap::remove(StringRef Stream) { 148 FinalizedInfo.reset(); 149 Mapping.erase(Stream); 150 } 151