Home | History | Annotate | Download | only in Raw
      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 
     16 using namespace llvm;
     17 using namespace llvm::codeview;
     18 using namespace llvm::pdb;
     19 
     20 NameMap::NameMap() {}
     21 
     22 Error 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 
    148 Error 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 
    166 iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const {
    167   return llvm::make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
    168                                                             Mapping.end());
    169 }
    170 
    171 bool 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