1//===- NameMap.cpp - PDB Name 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/Raw/NameMap.h" 11#include "llvm/ADT/SparseBitVector.h" 12#include "llvm/DebugInfo/CodeView/StreamReader.h" 13#include "llvm/DebugInfo/CodeView/StreamWriter.h" 14#include "llvm/DebugInfo/PDB/Raw/RawError.h" 15 16using namespace llvm; 17using namespace llvm::codeview; 18using namespace llvm::pdb; 19 20NameMap::NameMap() {} 21 22Error NameMap::load(codeview::StreamReader &Stream) { 23 24 // This is some sort of weird string-set/hash table encoded in the stream. 25 // It starts with the number of bytes in the table. 26 uint32_t NumberOfBytes; 27 if (auto EC = Stream.readInteger(NumberOfBytes)) 28 return joinErrors(std::move(EC), 29 make_error<RawError>(raw_error_code::corrupt_file, 30 "Expected name map length")); 31 if (Stream.bytesRemaining() < NumberOfBytes) 32 return make_error<RawError>(raw_error_code::corrupt_file, 33 "Invalid name map length"); 34 35 // Following that field is the starting offset of strings in the name table. 36 uint32_t StringsOffset = Stream.getOffset(); 37 Stream.setOffset(StringsOffset + NumberOfBytes); 38 39 // This appears to be equivalent to the total number of strings *actually* 40 // in the name table. 41 uint32_t HashSize; 42 if (auto EC = Stream.readInteger(HashSize)) 43 return joinErrors(std::move(EC), 44 make_error<RawError>(raw_error_code::corrupt_file, 45 "Expected name map hash size")); 46 47 // This appears to be an upper bound on the number of strings in the name 48 // table. 49 uint32_t MaxNumberOfStrings; 50 if (auto EC = Stream.readInteger(MaxNumberOfStrings)) 51 return joinErrors(std::move(EC), 52 make_error<RawError>(raw_error_code::corrupt_file, 53 "Expected name map max strings")); 54 55 if (MaxNumberOfStrings > (UINT32_MAX / sizeof(uint32_t))) 56 return make_error<RawError>(raw_error_code::corrupt_file, 57 "Implausible number of strings"); 58 59 const uint32_t MaxNumberOfWords = UINT32_MAX / (sizeof(uint32_t) * 8); 60 61 // This appears to be a hash table which uses bitfields to determine whether 62 // or not a bucket is 'present'. 63 uint32_t NumPresentWords; 64 if (auto EC = Stream.readInteger(NumPresentWords)) 65 return joinErrors(std::move(EC), 66 make_error<RawError>(raw_error_code::corrupt_file, 67 "Expected name map num words")); 68 69 if (NumPresentWords > MaxNumberOfWords) 70 return make_error<RawError>(raw_error_code::corrupt_file, 71 "Number of present words is too large"); 72 73 SparseBitVector<> Present; 74 for (uint32_t I = 0; I != NumPresentWords; ++I) { 75 uint32_t Word; 76 if (auto EC = Stream.readInteger(Word)) 77 return joinErrors(std::move(EC), 78 make_error<RawError>(raw_error_code::corrupt_file, 79 "Expected name map word")); 80 for (unsigned Idx = 0; Idx < 32; ++Idx) 81 if (Word & (1U << Idx)) 82 Present.set((I * 32) + Idx); 83 } 84 85 // This appears to be a hash table which uses bitfields to determine whether 86 // or not a bucket is 'deleted'. 87 uint32_t NumDeletedWords; 88 if (auto EC = Stream.readInteger(NumDeletedWords)) 89 return joinErrors( 90 std::move(EC), 91 make_error<RawError>(raw_error_code::corrupt_file, 92 "Expected name map num deleted words")); 93 94 if (NumDeletedWords > MaxNumberOfWords) 95 return make_error<RawError>(raw_error_code::corrupt_file, 96 "Number of deleted words is too large"); 97 98 SparseBitVector<> Deleted; 99 for (uint32_t I = 0; I != NumDeletedWords; ++I) { 100 uint32_t Word; 101 if (auto EC = Stream.readInteger(Word)) 102 return joinErrors(std::move(EC), 103 make_error<RawError>(raw_error_code::corrupt_file, 104 "Expected name map word")); 105 for (unsigned Idx = 0; Idx < 32; ++Idx) 106 if (Word & (1U << Idx)) 107 Deleted.set((I * 32) + Idx); 108 } 109 110 for (unsigned I : Present) { 111 // For all present entries, dump out their mapping. 112 (void)I; 113 114 // This appears to be an offset relative to the start of the strings. 115 // It tells us where the null-terminated string begins. 116 uint32_t NameOffset; 117 if (auto EC = Stream.readInteger(NameOffset)) 118 return joinErrors(std::move(EC), 119 make_error<RawError>(raw_error_code::corrupt_file, 120 "Expected name map name offset")); 121 122 // This appears to be a stream number into the stream directory. 123 uint32_t NameIndex; 124 if (auto EC = Stream.readInteger(NameIndex)) 125 return joinErrors(std::move(EC), 126 make_error<RawError>(raw_error_code::corrupt_file, 127 "Expected name map name index")); 128 129 // Compute the offset of the start of the string relative to the stream. 130 uint32_t StringOffset = StringsOffset + NameOffset; 131 uint32_t OldOffset = Stream.getOffset(); 132 // Pump out our c-string from the stream. 133 StringRef Str; 134 Stream.setOffset(StringOffset); 135 if (auto EC = Stream.readZeroString(Str)) 136 return joinErrors(std::move(EC), 137 make_error<RawError>(raw_error_code::corrupt_file, 138 "Expected name map name")); 139 140 Stream.setOffset(OldOffset); 141 // Add this to a string-map from name to stream number. 142 Mapping.insert({Str, NameIndex}); 143 } 144 145 return Error::success(); 146} 147 148Error NameMap::commit(codeview::StreamWriter &Writer) { 149 if (auto EC = Writer.writeInteger(0U)) // Number of bytes in table 150 return EC; 151 152 if (auto EC = Writer.writeInteger(0U)) // Hash Size 153 return EC; 154 155 if (auto EC = Writer.writeInteger(0U)) // Max Number of Strings 156 return EC; 157 158 if (auto EC = Writer.writeInteger(0U)) // Num Present Words 159 return EC; 160 161 if (auto EC = Writer.writeInteger(0U)) // Num Deleted Words 162 return EC; 163 return Error::success(); 164} 165 166iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const { 167 return llvm::make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), 168 Mapping.end()); 169} 170 171bool NameMap::tryGetValue(StringRef Name, uint32_t &Value) const { 172 auto Iter = Mapping.find(Name); 173 if (Iter == Mapping.end()) 174 return false; 175 Value = Iter->second; 176 return true; 177} 178