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