clang API Documentation
00001 //===--- HeaderMap.cpp - A file that acts like dir of symlinks ------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements the HeaderMap interface. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "clang/Lex/HeaderMap.h" 00015 #include "clang/Basic/CharInfo.h" 00016 #include "clang/Basic/FileManager.h" 00017 #include "llvm/ADT/SmallString.h" 00018 #include "llvm/Support/DataTypes.h" 00019 #include "llvm/Support/MathExtras.h" 00020 #include "llvm/Support/MemoryBuffer.h" 00021 #include <cstdio> 00022 #include <memory> 00023 using namespace clang; 00024 00025 //===----------------------------------------------------------------------===// 00026 // Data Structures and Manifest Constants 00027 //===----------------------------------------------------------------------===// 00028 00029 enum { 00030 HMAP_HeaderMagicNumber = ('h' << 24) | ('m' << 16) | ('a' << 8) | 'p', 00031 HMAP_HeaderVersion = 1, 00032 00033 HMAP_EmptyBucketKey = 0 00034 }; 00035 00036 namespace clang { 00037 struct HMapBucket { 00038 uint32_t Key; // Offset (into strings) of key. 00039 00040 uint32_t Prefix; // Offset (into strings) of value prefix. 00041 uint32_t Suffix; // Offset (into strings) of value suffix. 00042 }; 00043 00044 struct HMapHeader { 00045 uint32_t Magic; // Magic word, also indicates byte order. 00046 uint16_t Version; // Version number -- currently 1. 00047 uint16_t Reserved; // Reserved for future use - zero for now. 00048 uint32_t StringsOffset; // Offset to start of string pool. 00049 uint32_t NumEntries; // Number of entries in the string table. 00050 uint32_t NumBuckets; // Number of buckets (always a power of 2). 00051 uint32_t MaxValueLength; // Length of longest result path (excluding nul). 00052 // An array of 'NumBuckets' HMapBucket objects follows this header. 00053 // Strings follow the buckets, at StringsOffset. 00054 }; 00055 } // end namespace clang. 00056 00057 /// HashHMapKey - This is the 'well known' hash function required by the file 00058 /// format, used to look up keys in the hash table. The hash table uses simple 00059 /// linear probing based on this function. 00060 static inline unsigned HashHMapKey(StringRef Str) { 00061 unsigned Result = 0; 00062 const char *S = Str.begin(), *End = Str.end(); 00063 00064 for (; S != End; S++) 00065 Result += toLowercase(*S) * 13; 00066 return Result; 00067 } 00068 00069 00070 00071 //===----------------------------------------------------------------------===// 00072 // Verification and Construction 00073 //===----------------------------------------------------------------------===// 00074 00075 /// HeaderMap::Create - This attempts to load the specified file as a header 00076 /// map. If it doesn't look like a HeaderMap, it gives up and returns null. 00077 /// If it looks like a HeaderMap but is obviously corrupted, it puts a reason 00078 /// into the string error argument and returns null. 00079 const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) { 00080 // If the file is too small to be a header map, ignore it. 00081 unsigned FileSize = FE->getSize(); 00082 if (FileSize <= sizeof(HMapHeader)) return nullptr; 00083 00084 auto FileBuffer = FM.getBufferForFile(FE); 00085 if (!FileBuffer) return nullptr; // Unreadable file? 00086 const char *FileStart = (*FileBuffer)->getBufferStart(); 00087 00088 // We know the file is at least as big as the header, check it now. 00089 const HMapHeader *Header = reinterpret_cast<const HMapHeader*>(FileStart); 00090 00091 // Sniff it to see if it's a headermap by checking the magic number and 00092 // version. 00093 bool NeedsByteSwap; 00094 if (Header->Magic == HMAP_HeaderMagicNumber && 00095 Header->Version == HMAP_HeaderVersion) 00096 NeedsByteSwap = false; 00097 else if (Header->Magic == llvm::ByteSwap_32(HMAP_HeaderMagicNumber) && 00098 Header->Version == llvm::ByteSwap_16(HMAP_HeaderVersion)) 00099 NeedsByteSwap = true; // Mixed endianness headermap. 00100 else 00101 return nullptr; // Not a header map. 00102 00103 if (Header->Reserved != 0) return nullptr; 00104 00105 // Okay, everything looks good, create the header map. 00106 return new HeaderMap(std::move(*FileBuffer), NeedsByteSwap); 00107 } 00108 00109 //===----------------------------------------------------------------------===// 00110 // Utility Methods 00111 //===----------------------------------------------------------------------===// 00112 00113 00114 /// getFileName - Return the filename of the headermap. 00115 const char *HeaderMap::getFileName() const { 00116 return FileBuffer->getBufferIdentifier(); 00117 } 00118 00119 unsigned HeaderMap::getEndianAdjustedWord(unsigned X) const { 00120 if (!NeedsBSwap) return X; 00121 return llvm::ByteSwap_32(X); 00122 } 00123 00124 /// getHeader - Return a reference to the file header, in unbyte-swapped form. 00125 /// This method cannot fail. 00126 const HMapHeader &HeaderMap::getHeader() const { 00127 // We know the file is at least as big as the header. Return it. 00128 return *reinterpret_cast<const HMapHeader*>(FileBuffer->getBufferStart()); 00129 } 00130 00131 /// getBucket - Return the specified hash table bucket from the header map, 00132 /// bswap'ing its fields as appropriate. If the bucket number is not valid, 00133 /// this return a bucket with an empty key (0). 00134 HMapBucket HeaderMap::getBucket(unsigned BucketNo) const { 00135 HMapBucket Result; 00136 Result.Key = HMAP_EmptyBucketKey; 00137 00138 const HMapBucket *BucketArray = 00139 reinterpret_cast<const HMapBucket*>(FileBuffer->getBufferStart() + 00140 sizeof(HMapHeader)); 00141 00142 const HMapBucket *BucketPtr = BucketArray+BucketNo; 00143 if ((const char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) { 00144 Result.Prefix = 0; 00145 Result.Suffix = 0; 00146 return Result; // Invalid buffer, corrupt hmap. 00147 } 00148 00149 // Otherwise, the bucket is valid. Load the values, bswapping as needed. 00150 Result.Key = getEndianAdjustedWord(BucketPtr->Key); 00151 Result.Prefix = getEndianAdjustedWord(BucketPtr->Prefix); 00152 Result.Suffix = getEndianAdjustedWord(BucketPtr->Suffix); 00153 return Result; 00154 } 00155 00156 /// getString - Look up the specified string in the string table. If the string 00157 /// index is not valid, it returns an empty string. 00158 const char *HeaderMap::getString(unsigned StrTabIdx) const { 00159 // Add the start of the string table to the idx. 00160 StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset); 00161 00162 // Check for invalid index. 00163 if (StrTabIdx >= FileBuffer->getBufferSize()) 00164 return nullptr; 00165 00166 // Otherwise, we have a valid pointer into the file. Just return it. We know 00167 // that the "string" can not overrun the end of the file, because the buffer 00168 // is nul terminated by virtue of being a MemoryBuffer. 00169 return FileBuffer->getBufferStart()+StrTabIdx; 00170 } 00171 00172 //===----------------------------------------------------------------------===// 00173 // The Main Drivers 00174 //===----------------------------------------------------------------------===// 00175 00176 /// dump - Print the contents of this headermap to stderr. 00177 void HeaderMap::dump() const { 00178 const HMapHeader &Hdr = getHeader(); 00179 unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); 00180 00181 fprintf(stderr, "Header Map %s:\n %d buckets, %d entries\n", 00182 getFileName(), NumBuckets, 00183 getEndianAdjustedWord(Hdr.NumEntries)); 00184 00185 for (unsigned i = 0; i != NumBuckets; ++i) { 00186 HMapBucket B = getBucket(i); 00187 if (B.Key == HMAP_EmptyBucketKey) continue; 00188 00189 const char *Key = getString(B.Key); 00190 const char *Prefix = getString(B.Prefix); 00191 const char *Suffix = getString(B.Suffix); 00192 fprintf(stderr, " %d. %s -> '%s' '%s'\n", i, Key, Prefix, Suffix); 00193 } 00194 } 00195 00196 /// LookupFile - Check to see if the specified relative filename is located in 00197 /// this HeaderMap. If so, open it and return its FileEntry. 00198 const FileEntry *HeaderMap::LookupFile( 00199 StringRef Filename, FileManager &FM) const { 00200 00201 SmallString<1024> Path; 00202 StringRef Dest = lookupFilename(Filename, Path); 00203 if (Dest.empty()) 00204 return nullptr; 00205 00206 return FM.getFile(Dest); 00207 } 00208 00209 StringRef HeaderMap::lookupFilename(StringRef Filename, 00210 SmallVectorImpl<char> &DestPath) const { 00211 const HMapHeader &Hdr = getHeader(); 00212 unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); 00213 00214 // If the number of buckets is not a power of two, the headermap is corrupt. 00215 // Don't probe infinitely. 00216 if (NumBuckets & (NumBuckets-1)) 00217 return StringRef(); 00218 00219 // Linearly probe the hash table. 00220 for (unsigned Bucket = HashHMapKey(Filename);; ++Bucket) { 00221 HMapBucket B = getBucket(Bucket & (NumBuckets-1)); 00222 if (B.Key == HMAP_EmptyBucketKey) return StringRef(); // Hash miss. 00223 00224 // See if the key matches. If not, probe on. 00225 if (!Filename.equals_lower(getString(B.Key))) 00226 continue; 00227 00228 // If so, we have a match in the hash table. Construct the destination 00229 // path. 00230 StringRef Prefix = getString(B.Prefix); 00231 StringRef Suffix = getString(B.Suffix); 00232 DestPath.clear(); 00233 DestPath.append(Prefix.begin(), Prefix.end()); 00234 DestPath.append(Suffix.begin(), Suffix.end()); 00235 return StringRef(DestPath.begin(), DestPath.size()); 00236 } 00237 }