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/FileManager.h" 00016 #include "llvm/ADT/OwningPtr.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 <cctype> 00022 #include <cstdio> 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 += tolower(*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 0; 00083 00084 OwningPtr<const llvm::MemoryBuffer> FileBuffer(FM.getBufferForFile(FE)); 00085 if (FileBuffer == 0) return 0; // 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 0; // Not a header map. 00102 00103 if (Header->Reserved != 0) return 0; 00104 00105 // Okay, everything looks good, create the header map. 00106 return new HeaderMap(FileBuffer.take(), NeedsByteSwap); 00107 } 00108 00109 HeaderMap::~HeaderMap() { 00110 delete FileBuffer; 00111 } 00112 00113 //===----------------------------------------------------------------------===// 00114 // Utility Methods 00115 //===----------------------------------------------------------------------===// 00116 00117 00118 /// getFileName - Return the filename of the headermap. 00119 const char *HeaderMap::getFileName() const { 00120 return FileBuffer->getBufferIdentifier(); 00121 } 00122 00123 unsigned HeaderMap::getEndianAdjustedWord(unsigned X) const { 00124 if (!NeedsBSwap) return X; 00125 return llvm::ByteSwap_32(X); 00126 } 00127 00128 /// getHeader - Return a reference to the file header, in unbyte-swapped form. 00129 /// This method cannot fail. 00130 const HMapHeader &HeaderMap::getHeader() const { 00131 // We know the file is at least as big as the header. Return it. 00132 return *reinterpret_cast<const HMapHeader*>(FileBuffer->getBufferStart()); 00133 } 00134 00135 /// getBucket - Return the specified hash table bucket from the header map, 00136 /// bswap'ing its fields as appropriate. If the bucket number is not valid, 00137 /// this return a bucket with an empty key (0). 00138 HMapBucket HeaderMap::getBucket(unsigned BucketNo) const { 00139 HMapBucket Result; 00140 Result.Key = HMAP_EmptyBucketKey; 00141 00142 const HMapBucket *BucketArray = 00143 reinterpret_cast<const HMapBucket*>(FileBuffer->getBufferStart() + 00144 sizeof(HMapHeader)); 00145 00146 const HMapBucket *BucketPtr = BucketArray+BucketNo; 00147 if ((char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) { 00148 Result.Prefix = 0; 00149 Result.Suffix = 0; 00150 return Result; // Invalid buffer, corrupt hmap. 00151 } 00152 00153 // Otherwise, the bucket is valid. Load the values, bswapping as needed. 00154 Result.Key = getEndianAdjustedWord(BucketPtr->Key); 00155 Result.Prefix = getEndianAdjustedWord(BucketPtr->Prefix); 00156 Result.Suffix = getEndianAdjustedWord(BucketPtr->Suffix); 00157 return Result; 00158 } 00159 00160 /// getString - Look up the specified string in the string table. If the string 00161 /// index is not valid, it returns an empty string. 00162 const char *HeaderMap::getString(unsigned StrTabIdx) const { 00163 // Add the start of the string table to the idx. 00164 StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset); 00165 00166 // Check for invalid index. 00167 if (StrTabIdx >= FileBuffer->getBufferSize()) 00168 return 0; 00169 00170 // Otherwise, we have a valid pointer into the file. Just return it. We know 00171 // that the "string" can not overrun the end of the file, because the buffer 00172 // is nul terminated by virtue of being a MemoryBuffer. 00173 return FileBuffer->getBufferStart()+StrTabIdx; 00174 } 00175 00176 //===----------------------------------------------------------------------===// 00177 // The Main Drivers 00178 //===----------------------------------------------------------------------===// 00179 00180 /// dump - Print the contents of this headermap to stderr. 00181 void HeaderMap::dump() const { 00182 const HMapHeader &Hdr = getHeader(); 00183 unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); 00184 00185 fprintf(stderr, "Header Map %s:\n %d buckets, %d entries\n", 00186 getFileName(), NumBuckets, 00187 getEndianAdjustedWord(Hdr.NumEntries)); 00188 00189 for (unsigned i = 0; i != NumBuckets; ++i) { 00190 HMapBucket B = getBucket(i); 00191 if (B.Key == HMAP_EmptyBucketKey) continue; 00192 00193 const char *Key = getString(B.Key); 00194 const char *Prefix = getString(B.Prefix); 00195 const char *Suffix = getString(B.Suffix); 00196 fprintf(stderr, " %d. %s -> '%s' '%s'\n", i, Key, Prefix, Suffix); 00197 } 00198 } 00199 00200 /// LookupFile - Check to see if the specified relative filename is located in 00201 /// this HeaderMap. If so, open it and return its FileEntry. 00202 const FileEntry *HeaderMap::LookupFile( 00203 StringRef Filename, FileManager &FM) const { 00204 const HMapHeader &Hdr = getHeader(); 00205 unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); 00206 00207 // If the number of buckets is not a power of two, the headermap is corrupt. 00208 // Don't probe infinitely. 00209 if (NumBuckets & (NumBuckets-1)) 00210 return 0; 00211 00212 // Linearly probe the hash table. 00213 for (unsigned Bucket = HashHMapKey(Filename);; ++Bucket) { 00214 HMapBucket B = getBucket(Bucket & (NumBuckets-1)); 00215 if (B.Key == HMAP_EmptyBucketKey) return 0; // Hash miss. 00216 00217 // See if the key matches. If not, probe on. 00218 if (!Filename.equals_lower(getString(B.Key))) 00219 continue; 00220 00221 // If so, we have a match in the hash table. Construct the destination 00222 // path. 00223 SmallString<1024> DestPath; 00224 DestPath += getString(B.Prefix); 00225 DestPath += getString(B.Suffix); 00226 return FM.getFile(DestPath.str()); 00227 } 00228 }