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 NamedStreamMap::NamedStreamMap() = default; 27 28 Error NamedStreamMap::load(BinaryStreamReader &Stream) { 29 Mapping.clear(); 30 FinalizedHashTable.clear(); 31 FinalizedInfo.reset(); 32 33 uint32_t StringBufferSize; 34 if (auto EC = Stream.readInteger(StringBufferSize)) 35 return joinErrors(std::move(EC), 36 make_error<RawError>(raw_error_code::corrupt_file, 37 "Expected string buffer size")); 38 39 BinaryStreamRef StringsBuffer; 40 if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize)) 41 return EC; 42 43 HashTable OffsetIndexMap; 44 if (auto EC = OffsetIndexMap.load(Stream)) 45 return EC; 46 47 uint32_t NameOffset; 48 uint32_t NameIndex; 49 for (const auto &Entry : OffsetIndexMap) { 50 std::tie(NameOffset, NameIndex) = Entry; 51 52 // Compute the offset of the start of the string relative to the stream. 53 BinaryStreamReader NameReader(StringsBuffer); 54 NameReader.setOffset(NameOffset); 55 // Pump out our c-string from the stream. 56 StringRef Str; 57 if (auto EC = NameReader.readCString(Str)) 58 return joinErrors(std::move(EC), 59 make_error<RawError>(raw_error_code::corrupt_file, 60 "Expected name map name")); 61 62 // Add this to a string-map from name to stream number. 63 Mapping.insert({Str, NameIndex}); 64 } 65 66 return Error::success(); 67 } 68 69 Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const { 70 assert(FinalizedInfo.hasValue()); 71 72 // The first field is the number of bytes of string data. 73 if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes)) 74 return EC; 75 76 // Now all of the string data itself. 77 for (const auto &Item : Mapping) { 78 if (auto EC = Writer.writeCString(Item.getKey())) 79 return EC; 80 } 81 82 // And finally the Offset Index map. 83 if (auto EC = FinalizedHashTable.commit(Writer)) 84 return EC; 85 86 return Error::success(); 87 } 88 89 uint32_t NamedStreamMap::finalize() { 90 if (FinalizedInfo.hasValue()) 91 return FinalizedInfo->SerializedLength; 92 93 // Build the finalized hash table. 94 FinalizedHashTable.clear(); 95 FinalizedInfo.emplace(); 96 for (const auto &Item : Mapping) { 97 FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item.getValue()); 98 FinalizedInfo->StringDataBytes += Item.getKeyLength() + 1; 99 } 100 101 // Number of bytes of string data. 102 FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t); 103 // Followed by that many actual bytes of string data. 104 FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes; 105 // Followed by the mapping from Offset to Index. 106 FinalizedInfo->SerializedLength += 107 FinalizedHashTable.calculateSerializedLength(); 108 return FinalizedInfo->SerializedLength; 109 } 110 111 iterator_range<StringMapConstIterator<uint32_t>> 112 NamedStreamMap::entries() const { 113 return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), 114 Mapping.end()); 115 } 116 117 bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const { 118 auto Iter = Mapping.find(Stream); 119 if (Iter == Mapping.end()) 120 return false; 121 StreamNo = Iter->second; 122 return true; 123 } 124 125 void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { 126 FinalizedInfo.reset(); 127 Mapping[Stream] = StreamNo; 128 } 129 130 void NamedStreamMap::remove(StringRef Stream) { 131 FinalizedInfo.reset(); 132 Mapping.erase(Stream); 133 } 134