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/MSF/BinaryStreamReader.h" 17 #include "llvm/DebugInfo/PDB/Native/HashTable.h" 18 #include "llvm/DebugInfo/PDB/Native/RawError.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, llvm::support::little)) 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 llvm::support::little)) 75 return EC; 76 77 // Now all of the string data itself. 78 for (const auto &Item : Mapping) { 79 if (auto EC = Writer.writeCString(Item.getKey())) 80 return EC; 81 } 82 83 // And finally the Offset Index map. 84 if (auto EC = FinalizedHashTable.commit(Writer)) 85 return EC; 86 87 return Error::success(); 88 } 89 90 uint32_t NamedStreamMap::finalize() { 91 if (FinalizedInfo.hasValue()) 92 return FinalizedInfo->SerializedLength; 93 94 // Build the finalized hash table. 95 FinalizedHashTable.clear(); 96 FinalizedInfo.emplace(); 97 for (const auto &Item : Mapping) { 98 FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item.getValue()); 99 FinalizedInfo->StringDataBytes += Item.getKeyLength() + 1; 100 } 101 102 // Number of bytes of string data. 103 FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t); 104 // Followed by that many actual bytes of string data. 105 FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes; 106 // Followed by the mapping from Offset to Index. 107 FinalizedInfo->SerializedLength += 108 FinalizedHashTable.calculateSerializedLength(); 109 return FinalizedInfo->SerializedLength; 110 } 111 112 iterator_range<StringMapConstIterator<uint32_t>> 113 NamedStreamMap::entries() const { 114 return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), 115 Mapping.end()); 116 } 117 118 bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const { 119 auto Iter = Mapping.find(Stream); 120 if (Iter == Mapping.end()) 121 return false; 122 StreamNo = Iter->second; 123 return true; 124 } 125 126 void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { 127 FinalizedInfo.reset(); 128 Mapping[Stream] = StreamNo; 129 } 130 131 void NamedStreamMap::remove(StringRef Stream) { 132 FinalizedInfo.reset(); 133 Mapping.erase(Stream); 134 } 135