blob: 40992e9a96e514ad168ba86d71b5380a56872478 [file] [log] [blame]
Zachary Turner2f09b502016-04-29 17:28:47 +00001//===- NameMap.cpp - PDB Name Map -------------------------------*- C++ -*-===//
Zachary Turnerf34e0162016-04-26 16:20:00 +00002//
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
Zachary Turner2f09b502016-04-29 17:28:47 +000010#include "llvm/DebugInfo/PDB/Raw/NameMap.h"
David Majnemer36b7b082016-06-04 22:47:39 +000011#include "llvm/ADT/SparseBitVector.h"
Zachary Turnera3225b02016-07-29 20:56:36 +000012#include "llvm/DebugInfo/MSF/StreamReader.h"
13#include "llvm/DebugInfo/MSF/StreamWriter.h"
Zachary Turner819e77d2016-05-06 20:51:57 +000014#include "llvm/DebugInfo/PDB/Raw/RawError.h"
Zachary Turnerf34e0162016-04-26 16:20:00 +000015
16using namespace llvm;
Zachary Turnerbac69d32016-07-22 19:56:05 +000017using namespace llvm::msf;
Zachary Turner2f09b502016-04-29 17:28:47 +000018using namespace llvm::pdb;
Zachary Turnerf34e0162016-04-26 16:20:00 +000019
Zachary Turner2f09b502016-04-29 17:28:47 +000020NameMap::NameMap() {}
Zachary Turnerf34e0162016-04-26 16:20:00 +000021
Zachary Turnerbac69d32016-07-22 19:56:05 +000022Error NameMap::load(StreamReader &Stream) {
Zachary Turner6ba65de2016-04-29 17:22:58 +000023
Zachary Turnerf34e0162016-04-26 16:20:00 +000024 // 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;
David Majnemer836937e2016-05-27 16:16:56 +000027 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"));
Zachary Turner819e77d2016-05-06 20:51:57 +000031 if (Stream.bytesRemaining() < NumberOfBytes)
32 return make_error<RawError>(raw_error_code::corrupt_file,
33 "Invalid name map length");
Zachary Turnerf34e0162016-04-26 16:20:00 +000034
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;
David Majnemer836937e2016-05-27 16:16:56 +000042 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"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000046
47 // This appears to be an upper bound on the number of strings in the name
48 // table.
49 uint32_t MaxNumberOfStrings;
David Majnemer836937e2016-05-27 16:16:56 +000050 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"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000054
David Majnemer328b6d32016-05-28 18:03:37 +000055 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);
David Majnemer869631f2016-05-28 05:59:25 +000060
Zachary Turnerf34e0162016-04-26 16:20:00 +000061 // This appears to be a hash table which uses bitfields to determine whether
62 // or not a bucket is 'present'.
63 uint32_t NumPresentWords;
David Majnemer836937e2016-05-27 16:16:56 +000064 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"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000068
David Majnemer869631f2016-05-28 05:59:25 +000069 if (NumPresentWords > MaxNumberOfWords)
70 return make_error<RawError>(raw_error_code::corrupt_file,
71 "Number of present words is too large");
72
David Majnemer36b7b082016-06-04 22:47:39 +000073 SparseBitVector<> Present;
Zachary Turnerf34e0162016-04-26 16:20:00 +000074 for (uint32_t I = 0; I != NumPresentWords; ++I) {
75 uint32_t Word;
David Majnemer836937e2016-05-27 16:16:56 +000076 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"));
David Majnemer36b7b082016-06-04 22:47:39 +000080 for (unsigned Idx = 0; Idx < 32; ++Idx)
81 if (Word & (1U << Idx))
82 Present.set((I * 32) + Idx);
Zachary Turnerf34e0162016-04-26 16:20:00 +000083 }
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;
David Majnemer836937e2016-05-27 16:16:56 +000088 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"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000093
David Majnemer869631f2016-05-28 05:59:25 +000094 if (NumDeletedWords > MaxNumberOfWords)
95 return make_error<RawError>(raw_error_code::corrupt_file,
96 "Number of deleted words is too large");
97
David Majnemer36b7b082016-06-04 22:47:39 +000098 SparseBitVector<> Deleted;
Zachary Turnerf34e0162016-04-26 16:20:00 +000099 for (uint32_t I = 0; I != NumDeletedWords; ++I) {
100 uint32_t Word;
David Majnemer836937e2016-05-27 16:16:56 +0000101 if (auto EC = Stream.readInteger(Word))
102 return joinErrors(std::move(EC),
103 make_error<RawError>(raw_error_code::corrupt_file,
David Majnemer36b7b082016-06-04 22:47:39 +0000104 "Expected name map word"));
105 for (unsigned Idx = 0; Idx < 32; ++Idx)
106 if (Word & (1U << Idx))
107 Deleted.set((I * 32) + Idx);
Zachary Turnerf34e0162016-04-26 16:20:00 +0000108 }
109
David Majnemer36b7b082016-06-04 22:47:39 +0000110 for (unsigned I : Present) {
Zachary Turnerf34e0162016-04-26 16:20:00 +0000111 // For all present entries, dump out their mapping.
David Majnemer36b7b082016-06-04 22:47:39 +0000112 (void)I;
Zachary Turnerf34e0162016-04-26 16:20:00 +0000113
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;
David Majnemer836937e2016-05-27 16:16:56 +0000117 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"));
Zachary Turnerf34e0162016-04-26 16:20:00 +0000121
122 // This appears to be a stream number into the stream directory.
123 uint32_t NameIndex;
David Majnemer836937e2016-05-27 16:16:56 +0000124 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"));
Zachary Turnerf34e0162016-04-26 16:20:00 +0000128
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.
Zachary Turner8dbe3622016-05-27 01:54:44 +0000133 StringRef Str;
Zachary Turnerf34e0162016-04-26 16:20:00 +0000134 Stream.setOffset(StringOffset);
David Majnemer836937e2016-05-27 16:16:56 +0000135 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"));
Zachary Turnerf34e0162016-04-26 16:20:00 +0000139
140 Stream.setOffset(OldOffset);
141 // Add this to a string-map from name to stream number.
142 Mapping.insert({Str, NameIndex});
143 }
144
Zachary Turner819e77d2016-05-06 20:51:57 +0000145 return Error::success();
Zachary Turnerf34e0162016-04-26 16:20:00 +0000146}
147
Zachary Turner85ed80b2016-05-25 03:43:17 +0000148iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const {
149 return llvm::make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
150 Mapping.end());
151}
152
Zachary Turner2f09b502016-04-29 17:28:47 +0000153bool NameMap::tryGetValue(StringRef Name, uint32_t &Value) const {
Zachary Turnerf34e0162016-04-26 16:20:00 +0000154 auto Iter = Mapping.find(Name);
155 if (Iter == Mapping.end())
156 return false;
157 Value = Iter->second;
158 return true;
159}