• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
NameMap()20 NameMap::NameMap() {}
21 
load(codeview::StreamReader & Stream)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 
commit(codeview::StreamWriter & Writer)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 
entries() const166 iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const {
167   return llvm::make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
168                                                             Mapping.end());
169 }
170 
tryGetValue(StringRef Name,uint32_t & Value) const171 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