blob: 4cace5b002450eddc014172ffbf7fd28c13f5562 [file] [log] [blame]
Chris Lattner1587e6d2007-12-17 08:22:46 +00001//===--- HeaderMap.cpp - A file that acts like dir of symlinks ------------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner5b12ab82007-12-29 19:59:25 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Chris Lattner1587e6d2007-12-17 08:22:46 +00007//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the HeaderMap interface.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Lex/HeaderMap.h"
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +000015#include "clang/Lex/HeaderMapTypes.h"
Jordan Rose4938f272013-02-09 10:09:43 +000016#include "clang/Basic/CharInfo.h"
Chris Lattner4ffe46c2007-12-17 18:34:53 +000017#include "clang/Basic/FileManager.h"
Chris Lattner619e18c2007-12-17 21:38:04 +000018#include "llvm/ADT/SmallString.h"
Duncan P. N. Exon Smithb5ce11f2016-02-23 00:48:16 +000019#include "llvm/Support/Compiler.h"
Michael J. Spencer8aaf4992010-11-29 18:12:39 +000020#include "llvm/Support/DataTypes.h"
Chris Lattner4ffe46c2007-12-17 18:34:53 +000021#include "llvm/Support/MathExtras.h"
22#include "llvm/Support/MemoryBuffer.h"
Duncan P. N. Exon Smithdfe85302016-02-20 21:00:58 +000023#include "llvm/Support/SwapByteOrder.h"
Duncan P. N. Exon Smithbef47f02016-02-20 23:09:14 +000024#include "llvm/Support/Debug.h"
Duncan P. N. Exon Smith96a01fa2016-02-21 00:14:36 +000025#include <cstring>
Ahmed Charlesdfca6f92014-03-09 11:36:40 +000026#include <memory>
Chris Lattner1587e6d2007-12-17 08:22:46 +000027using namespace clang;
28
Chris Lattner619e18c2007-12-17 21:38:04 +000029/// HashHMapKey - This is the 'well known' hash function required by the file
30/// format, used to look up keys in the hash table. The hash table uses simple
31/// linear probing based on this function.
Chris Lattner0e62c1c2011-07-23 10:55:15 +000032static inline unsigned HashHMapKey(StringRef Str) {
Chris Lattner619e18c2007-12-17 21:38:04 +000033 unsigned Result = 0;
Chris Lattnerd081f8c2010-01-10 01:35:12 +000034 const char *S = Str.begin(), *End = Str.end();
Mike Stump11289f42009-09-09 15:08:12 +000035
Chris Lattner619e18c2007-12-17 21:38:04 +000036 for (; S != End; S++)
Jordan Rose4938f272013-02-09 10:09:43 +000037 Result += toLowercase(*S) * 13;
Chris Lattner619e18c2007-12-17 21:38:04 +000038 return Result;
39}
40
41
42
Chris Lattner9f9a6192007-12-17 21:06:11 +000043//===----------------------------------------------------------------------===//
44// Verification and Construction
45//===----------------------------------------------------------------------===//
Chris Lattner4ffe46c2007-12-17 18:34:53 +000046
47/// HeaderMap::Create - This attempts to load the specified file as a header
48/// map. If it doesn't look like a HeaderMap, it gives up and returns null.
49/// If it looks like a HeaderMap but is obviously corrupted, it puts a reason
50/// into the string error argument and returns null.
Chris Lattner5159f612010-11-23 08:35:12 +000051const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) {
Chris Lattner4ffe46c2007-12-17 18:34:53 +000052 // If the file is too small to be a header map, ignore it.
53 unsigned FileSize = FE->getSize();
Craig Topperd2d442c2014-05-17 23:10:59 +000054 if (FileSize <= sizeof(HMapHeader)) return nullptr;
Mike Stump11289f42009-09-09 15:08:12 +000055
Benjamin Kramera8857962014-10-26 22:44:13 +000056 auto FileBuffer = FM.getBufferForFile(FE);
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +000057 if (!FileBuffer || !*FileBuffer)
58 return nullptr;
59 bool NeedsByteSwap;
60 if (!checkHeader(**FileBuffer, NeedsByteSwap))
61 return nullptr;
62 return new HeaderMap(std::move(*FileBuffer), NeedsByteSwap);
63}
64
65bool HeaderMapImpl::checkHeader(const llvm::MemoryBuffer &File,
66 bool &NeedsByteSwap) {
67 if (File.getBufferSize() <= sizeof(HMapHeader))
68 return false;
69 const char *FileStart = File.getBufferStart();
Chris Lattner4ffe46c2007-12-17 18:34:53 +000070
71 // We know the file is at least as big as the header, check it now.
72 const HMapHeader *Header = reinterpret_cast<const HMapHeader*>(FileStart);
Mike Stump11289f42009-09-09 15:08:12 +000073
Chris Lattnerd39b8c02007-12-17 18:59:44 +000074 // Sniff it to see if it's a headermap by checking the magic number and
75 // version.
Mike Stump11289f42009-09-09 15:08:12 +000076 if (Header->Magic == HMAP_HeaderMagicNumber &&
Chris Lattner9f9a6192007-12-17 21:06:11 +000077 Header->Version == HMAP_HeaderVersion)
Chris Lattner4ffe46c2007-12-17 18:34:53 +000078 NeedsByteSwap = false;
Chris Lattner9f9a6192007-12-17 21:06:11 +000079 else if (Header->Magic == llvm::ByteSwap_32(HMAP_HeaderMagicNumber) &&
80 Header->Version == llvm::ByteSwap_16(HMAP_HeaderVersion))
Chris Lattner4ffe46c2007-12-17 18:34:53 +000081 NeedsByteSwap = true; // Mixed endianness headermap.
Mike Stump11289f42009-09-09 15:08:12 +000082 else
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +000083 return false; // Not a header map.
Mike Stump11289f42009-09-09 15:08:12 +000084
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +000085 if (Header->Reserved != 0)
86 return false;
Chris Lattner79764a62007-12-17 18:44:09 +000087
Duncan P. N. Exon Smith8d6a31c022016-02-20 21:24:31 +000088 // Check the number of buckets. It should be a power of two, and there
89 // should be enough space in the file for all of them.
Duncan P. N. Exon Smith3a7def02016-02-22 22:24:22 +000090 uint32_t NumBuckets = NeedsByteSwap
91 ? llvm::sys::getSwappedBytes(Header->NumBuckets)
92 : Header->NumBuckets;
93 if (!llvm::isPowerOf2_32(NumBuckets))
Duncan P. N. Exon Smithdfe85302016-02-20 21:00:58 +000094 return false;
Duncan P. N. Exon Smith8d6a31c022016-02-20 21:24:31 +000095 if (File.getBufferSize() <
96 sizeof(HMapHeader) + sizeof(HMapBucket) * NumBuckets)
97 return false;
Duncan P. N. Exon Smithdfe85302016-02-20 21:00:58 +000098
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +000099 // Okay, everything looks good.
100 return true;
Chris Lattner79764a62007-12-17 18:44:09 +0000101}
102
Chris Lattner9f9a6192007-12-17 21:06:11 +0000103//===----------------------------------------------------------------------===//
104// Utility Methods
105//===----------------------------------------------------------------------===//
106
Chris Lattner79764a62007-12-17 18:44:09 +0000107
108/// getFileName - Return the filename of the headermap.
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +0000109const char *HeaderMapImpl::getFileName() const {
Chris Lattner79764a62007-12-17 18:44:09 +0000110 return FileBuffer->getBufferIdentifier();
Chris Lattner1587e6d2007-12-17 08:22:46 +0000111}
112
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +0000113unsigned HeaderMapImpl::getEndianAdjustedWord(unsigned X) const {
Chris Lattner9f9a6192007-12-17 21:06:11 +0000114 if (!NeedsBSwap) return X;
115 return llvm::ByteSwap_32(X);
116}
117
118/// getHeader - Return a reference to the file header, in unbyte-swapped form.
119/// This method cannot fail.
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +0000120const HMapHeader &HeaderMapImpl::getHeader() const {
Chris Lattner9f9a6192007-12-17 21:06:11 +0000121 // We know the file is at least as big as the header. Return it.
122 return *reinterpret_cast<const HMapHeader*>(FileBuffer->getBufferStart());
123}
124
125/// getBucket - Return the specified hash table bucket from the header map,
126/// bswap'ing its fields as appropriate. If the bucket number is not valid,
127/// this return a bucket with an empty key (0).
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +0000128HMapBucket HeaderMapImpl::getBucket(unsigned BucketNo) const {
Duncan P. N. Exon Smith8d6a31c022016-02-20 21:24:31 +0000129 assert(FileBuffer->getBufferSize() >=
130 sizeof(HMapHeader) + sizeof(HMapBucket) * BucketNo &&
131 "Expected bucket to be in range");
132
Chris Lattner9f9a6192007-12-17 21:06:11 +0000133 HMapBucket Result;
134 Result.Key = HMAP_EmptyBucketKey;
Mike Stump11289f42009-09-09 15:08:12 +0000135
136 const HMapBucket *BucketArray =
Chris Lattner9f9a6192007-12-17 21:06:11 +0000137 reinterpret_cast<const HMapBucket*>(FileBuffer->getBufferStart() +
138 sizeof(HMapHeader));
Chris Lattner9f9a6192007-12-17 21:06:11 +0000139 const HMapBucket *BucketPtr = BucketArray+BucketNo;
Chris Lattner9f9a6192007-12-17 21:06:11 +0000140
Duncan P. N. Exon Smith8d6a31c022016-02-20 21:24:31 +0000141 // Load the values, bswapping as needed.
Chris Lattner9f9a6192007-12-17 21:06:11 +0000142 Result.Key = getEndianAdjustedWord(BucketPtr->Key);
143 Result.Prefix = getEndianAdjustedWord(BucketPtr->Prefix);
144 Result.Suffix = getEndianAdjustedWord(BucketPtr->Suffix);
145 return Result;
146}
147
Duncan P. N. Exon Smithb5ce11f2016-02-23 00:48:16 +0000148Optional<StringRef> HeaderMapImpl::getString(unsigned StrTabIdx) const {
Chris Lattner9f9a6192007-12-17 21:06:11 +0000149 // Add the start of the string table to the idx.
150 StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset);
Mike Stump11289f42009-09-09 15:08:12 +0000151
Chris Lattner9f9a6192007-12-17 21:06:11 +0000152 // Check for invalid index.
153 if (StrTabIdx >= FileBuffer->getBufferSize())
Duncan P. N. Exon Smithb5ce11f2016-02-23 00:48:16 +0000154 return None;
Mike Stump11289f42009-09-09 15:08:12 +0000155
Duncan P. N. Exon Smith96a01fa2016-02-21 00:14:36 +0000156 const char *Data = FileBuffer->getBufferStart() + StrTabIdx;
157 unsigned MaxLen = FileBuffer->getBufferSize() - StrTabIdx;
158 unsigned Len = strnlen(Data, MaxLen);
159
160 // Check whether the buffer is null-terminated.
161 if (Len == MaxLen && Data[Len - 1])
Duncan P. N. Exon Smithb5ce11f2016-02-23 00:48:16 +0000162 return None;
Duncan P. N. Exon Smith96a01fa2016-02-21 00:14:36 +0000163
164 return StringRef(Data, Len);
Chris Lattner9f9a6192007-12-17 21:06:11 +0000165}
166
167//===----------------------------------------------------------------------===//
168// The Main Drivers
169//===----------------------------------------------------------------------===//
170
171/// dump - Print the contents of this headermap to stderr.
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +0000172LLVM_DUMP_METHOD void HeaderMapImpl::dump() const {
Chris Lattner9f9a6192007-12-17 21:06:11 +0000173 const HMapHeader &Hdr = getHeader();
174 unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
Mike Stump11289f42009-09-09 15:08:12 +0000175
Duncan P. N. Exon Smithbef47f02016-02-20 23:09:14 +0000176 llvm::dbgs() << "Header Map " << getFileName() << ":\n " << NumBuckets
177 << ", " << getEndianAdjustedWord(Hdr.NumEntries) << "\n";
Mike Stump11289f42009-09-09 15:08:12 +0000178
Duncan P. N. Exon Smithb5ce11f2016-02-23 00:48:16 +0000179 auto getStringOrInvalid = [this](unsigned Id) -> StringRef {
180 if (Optional<StringRef> S = getString(Id))
181 return *S;
182 return "<invalid>";
183 };
184
Chris Lattner9f9a6192007-12-17 21:06:11 +0000185 for (unsigned i = 0; i != NumBuckets; ++i) {
186 HMapBucket B = getBucket(i);
187 if (B.Key == HMAP_EmptyBucketKey) continue;
Mike Stump11289f42009-09-09 15:08:12 +0000188
Duncan P. N. Exon Smithb5ce11f2016-02-23 00:48:16 +0000189 StringRef Key = getStringOrInvalid(B.Key);
190 StringRef Prefix = getStringOrInvalid(B.Prefix);
191 StringRef Suffix = getStringOrInvalid(B.Suffix);
Duncan P. N. Exon Smithbef47f02016-02-20 23:09:14 +0000192 llvm::dbgs() << " " << i << ". " << Key << " -> '" << Prefix << "' '"
193 << Suffix << "'\n";
Chris Lattner9f9a6192007-12-17 21:06:11 +0000194 }
195}
196
Chris Lattner1587e6d2007-12-17 08:22:46 +0000197/// LookupFile - Check to see if the specified relative filename is located in
198/// this HeaderMap. If so, open it and return its FileEntry.
Chandler Carruth3cc331a2011-03-16 18:34:36 +0000199const FileEntry *HeaderMap::LookupFile(
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000200 StringRef Filename, FileManager &FM) const {
Argyrios Kyrtzidis75fa9ed2014-02-14 14:58:28 +0000201
202 SmallString<1024> Path;
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +0000203 StringRef Dest = HeaderMapImpl::lookupFilename(Filename, Path);
Argyrios Kyrtzidis75fa9ed2014-02-14 14:58:28 +0000204 if (Dest.empty())
Craig Topperd2d442c2014-05-17 23:10:59 +0000205 return nullptr;
Argyrios Kyrtzidis75fa9ed2014-02-14 14:58:28 +0000206
207 return FM.getFile(Dest);
208}
209
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +0000210StringRef HeaderMapImpl::lookupFilename(StringRef Filename,
211 SmallVectorImpl<char> &DestPath) const {
Chris Lattner619e18c2007-12-17 21:38:04 +0000212 const HMapHeader &Hdr = getHeader();
213 unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
214
Duncan P. N. Exon Smithdfe85302016-02-20 21:00:58 +0000215 // Don't probe infinitely. This should be checked before constructing.
Duncan P. N. Exon Smith3a7def02016-02-22 22:24:22 +0000216 assert(llvm::isPowerOf2_32(NumBuckets) && "Expected power of 2");
Mike Stump11289f42009-09-09 15:08:12 +0000217
Chris Lattner619e18c2007-12-17 21:38:04 +0000218 // Linearly probe the hash table.
Chris Lattnerd081f8c2010-01-10 01:35:12 +0000219 for (unsigned Bucket = HashHMapKey(Filename);; ++Bucket) {
Chris Lattner619e18c2007-12-17 21:38:04 +0000220 HMapBucket B = getBucket(Bucket & (NumBuckets-1));
Argyrios Kyrtzidis75fa9ed2014-02-14 14:58:28 +0000221 if (B.Key == HMAP_EmptyBucketKey) return StringRef(); // Hash miss.
Mike Stump11289f42009-09-09 15:08:12 +0000222
Chris Lattner619e18c2007-12-17 21:38:04 +0000223 // See if the key matches. If not, probe on.
Duncan P. N. Exon Smithb5ce11f2016-02-23 00:48:16 +0000224 Optional<StringRef> Key = getString(B.Key);
225 if (LLVM_UNLIKELY(!Key))
226 continue;
227 if (!Filename.equals_lower(*Key))
Chris Lattner619e18c2007-12-17 21:38:04 +0000228 continue;
Mike Stump11289f42009-09-09 15:08:12 +0000229
Chris Lattner619e18c2007-12-17 21:38:04 +0000230 // If so, we have a match in the hash table. Construct the destination
231 // path.
Duncan P. N. Exon Smithb5ce11f2016-02-23 00:48:16 +0000232 Optional<StringRef> Prefix = getString(B.Prefix);
233 Optional<StringRef> Suffix = getString(B.Suffix);
234
Argyrios Kyrtzidis75fa9ed2014-02-14 14:58:28 +0000235 DestPath.clear();
Duncan P. N. Exon Smithb5ce11f2016-02-23 00:48:16 +0000236 if (LLVM_LIKELY(Prefix && Suffix)) {
237 DestPath.append(Prefix->begin(), Prefix->end());
238 DestPath.append(Suffix->begin(), Suffix->end());
239 }
Argyrios Kyrtzidis75fa9ed2014-02-14 14:58:28 +0000240 return StringRef(DestPath.begin(), DestPath.size());
Chris Lattner619e18c2007-12-17 21:38:04 +0000241 }
Chris Lattner1587e6d2007-12-17 08:22:46 +0000242}