 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
0.0% |
0 / 38 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
0.0% |
0 / 38 |
| |
|
Line Coverage: |
0.0% |
0 / 73 |
| |
 |
|
 |
1 : //===--- HeaderMap.cpp - A file that acts like dir of symlinks ------------===//
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 : // This file implements the HeaderMap interface.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #include "clang/Lex/HeaderMap.h"
15 : #include "clang/Basic/FileManager.h"
16 : #include "llvm/ADT/OwningPtr.h"
17 : #include "llvm/ADT/SmallString.h"
18 : #include "llvm/System/DataTypes.h"
19 : #include "llvm/Support/MathExtras.h"
20 : #include "llvm/Support/MemoryBuffer.h"
21 : #include <cstdio>
22 : using namespace clang;
23 :
24 : //===----------------------------------------------------------------------===//
25 : // Data Structures and Manifest Constants
26 : //===----------------------------------------------------------------------===//
27 :
28 : enum {
29 : HMAP_HeaderMagicNumber = ('h' << 24) | ('m' << 16) | ('a' << 8) | 'p',
30 : HMAP_HeaderVersion = 1,
31 :
32 : HMAP_EmptyBucketKey = 0
33 : };
34 :
35 : namespace clang {
36 : struct HMapBucket {
37 : uint32_t Key; // Offset (into strings) of key.
38 :
39 : uint32_t Prefix; // Offset (into strings) of value prefix.
40 : uint32_t Suffix; // Offset (into strings) of value suffix.
41 : };
42 :
43 : struct HMapHeader {
44 : uint32_t Magic; // Magic word, also indicates byte order.
45 : uint16_t Version; // Version number -- currently 1.
46 : uint16_t Reserved; // Reserved for future use - zero for now.
47 : uint32_t StringsOffset; // Offset to start of string pool.
48 : uint32_t NumEntries; // Number of entries in the string table.
49 : uint32_t NumBuckets; // Number of buckets (always a power of 2).
50 : uint32_t MaxValueLength; // Length of longest result path (excluding nul).
51 : // An array of 'NumBuckets' HMapBucket objects follows this header.
52 : // Strings follow the buckets, at StringsOffset.
53 : };
54 : } // end namespace clang.
55 :
56 : /// HashHMapKey - This is the 'well known' hash function required by the file
57 : /// format, used to look up keys in the hash table. The hash table uses simple
58 : /// linear probing based on this function.
59 0: static inline unsigned HashHMapKey(llvm::StringRef Str) {
60 0: unsigned Result = 0;
61 0: const char *S = Str.begin(), *End = Str.end();
62 :
0: branch 0 not taken
0: branch 1 not taken
63 0: for (; S != End; S++)
64 0: Result += tolower(*S) * 13;
65 0: return Result;
66 : }
67 :
68 :
69 :
70 : //===----------------------------------------------------------------------===//
71 : // Verification and Construction
72 : //===----------------------------------------------------------------------===//
73 :
74 : /// HeaderMap::Create - This attempts to load the specified file as a header
75 : /// map. If it doesn't look like a HeaderMap, it gives up and returns null.
76 : /// If it looks like a HeaderMap but is obviously corrupted, it puts a reason
77 : /// into the string error argument and returns null.
78 0: const HeaderMap *HeaderMap::Create(const FileEntry *FE) {
79 : // If the file is too small to be a header map, ignore it.
80 0: unsigned FileSize = FE->getSize();
0: branch 0 not taken
0: branch 1 not taken
81 0: if (FileSize <= sizeof(HMapHeader)) return 0;
82 :
83 : llvm::OwningPtr<const llvm::MemoryBuffer> FileBuffer(
84 0: llvm::MemoryBuffer::getFile(FE->getName(), 0, FE->getSize()));
0: branch 1 not taken
0: branch 2 not taken
85 0: if (FileBuffer == 0) return 0; // Unreadable file?
86 0: const char *FileStart = FileBuffer->getBufferStart();
87 :
88 : // We know the file is at least as big as the header, check it now.
89 0: const HMapHeader *Header = reinterpret_cast<const HMapHeader*>(FileStart);
90 :
91 : // Sniff it to see if it's a headermap by checking the magic number and
92 : // version.
93 : bool NeedsByteSwap;
0: branch 0 not taken
0: branch 1 not taken
0: branch 2 not taken
0: branch 3 not taken
94 0: if (Header->Magic == HMAP_HeaderMagicNumber &&
95 : Header->Version == HMAP_HeaderVersion)
96 0: NeedsByteSwap = false;
0: branch 1 not taken
0: branch 2 not taken
0: branch 4 not taken
0: branch 5 not taken
0: branch 6 not taken
0: branch 7 not taken
97 0: else if (Header->Magic == llvm::ByteSwap_32(HMAP_HeaderMagicNumber) &&
98 : Header->Version == llvm::ByteSwap_16(HMAP_HeaderVersion))
99 0: NeedsByteSwap = true; // Mixed endianness headermap.
100 : else
101 0: return 0; // Not a header map.
102 :
0: branch 0 not taken
0: branch 1 not taken
103 0: if (Header->Reserved != 0) return 0;
104 :
105 : // Okay, everything looks good, create the header map.
106 0: return new HeaderMap(FileBuffer.take(), NeedsByteSwap);
107 : }
108 :
109 0: HeaderMap::~HeaderMap() {
0: branch 0 not taken
0: branch 1 not taken
0: branch 3 not taken
0: branch 4 not taken
110 0: delete FileBuffer;
111 0: }
112 :
113 : //===----------------------------------------------------------------------===//
114 : // Utility Methods
115 : //===----------------------------------------------------------------------===//
116 :
117 :
118 : /// getFileName - Return the filename of the headermap.
119 0: const char *HeaderMap::getFileName() const {
120 0: return FileBuffer->getBufferIdentifier();
121 : }
122 :
123 0: unsigned HeaderMap::getEndianAdjustedWord(unsigned X) const {
0: branch 0 not taken
0: branch 1 not taken
124 0: if (!NeedsBSwap) return X;
125 0: return llvm::ByteSwap_32(X);
126 : }
127 :
128 : /// getHeader - Return a reference to the file header, in unbyte-swapped form.
129 : /// This method cannot fail.
130 0: const HMapHeader &HeaderMap::getHeader() const {
131 : // We know the file is at least as big as the header. Return it.
132 0: return *reinterpret_cast<const HMapHeader*>(FileBuffer->getBufferStart());
133 : }
134 :
135 : /// getBucket - Return the specified hash table bucket from the header map,
136 : /// bswap'ing its fields as appropriate. If the bucket number is not valid,
137 : /// this return a bucket with an empty key (0).
138 0: HMapBucket HeaderMap::getBucket(unsigned BucketNo) const {
139 : HMapBucket Result;
140 0: Result.Key = HMAP_EmptyBucketKey;
141 :
142 : const HMapBucket *BucketArray =
143 : reinterpret_cast<const HMapBucket*>(FileBuffer->getBufferStart() +
144 0: sizeof(HMapHeader));
145 :
146 0: const HMapBucket *BucketPtr = BucketArray+BucketNo;
0: branch 1 not taken
0: branch 2 not taken
147 0: if ((char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) {
148 0: Result.Prefix = 0;
149 0: Result.Suffix = 0;
150 0: return Result; // Invalid buffer, corrupt hmap.
151 : }
152 :
153 : // Otherwise, the bucket is valid. Load the values, bswapping as needed.
154 0: Result.Key = getEndianAdjustedWord(BucketPtr->Key);
155 0: Result.Prefix = getEndianAdjustedWord(BucketPtr->Prefix);
156 0: Result.Suffix = getEndianAdjustedWord(BucketPtr->Suffix);
157 0: return Result;
158 : }
159 :
160 : /// getString - Look up the specified string in the string table. If the string
161 : /// index is not valid, it returns an empty string.
162 0: const char *HeaderMap::getString(unsigned StrTabIdx) const {
163 : // Add the start of the string table to the idx.
164 0: StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset);
165 :
166 : // Check for invalid index.
0: branch 1 not taken
0: branch 2 not taken
167 0: if (StrTabIdx >= FileBuffer->getBufferSize())
168 0: return 0;
169 :
170 : // Otherwise, we have a valid pointer into the file. Just return it. We know
171 : // that the "string" can not overrun the end of the file, because the buffer
172 : // is nul terminated by virtue of being a MemoryBuffer.
173 0: return FileBuffer->getBufferStart()+StrTabIdx;
174 : }
175 :
176 : //===----------------------------------------------------------------------===//
177 : // The Main Drivers
178 : //===----------------------------------------------------------------------===//
179 :
180 : /// dump - Print the contents of this headermap to stderr.
181 0: void HeaderMap::dump() const {
182 0: const HMapHeader &Hdr = getHeader();
183 0: unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
184 :
185 : fprintf(stderr, "Header Map %s:\n %d buckets, %d entries\n",
186 : getFileName(), NumBuckets,
187 0: getEndianAdjustedWord(Hdr.NumEntries));
188 :
0: branch 0 not taken
0: branch 1 not taken
189 0: for (unsigned i = 0; i != NumBuckets; ++i) {
190 0: HMapBucket B = getBucket(i);
0: branch 0 not taken
0: branch 1 not taken
191 0: if (B.Key == HMAP_EmptyBucketKey) continue;
192 :
193 0: const char *Key = getString(B.Key);
194 0: const char *Prefix = getString(B.Prefix);
195 0: const char *Suffix = getString(B.Suffix);
196 0: fprintf(stderr, " %d. %s -> '%s' '%s'\n", i, Key, Prefix, Suffix);
197 : }
198 0: }
199 :
200 : /// LookupFile - Check to see if the specified relative filename is located in
201 : /// this HeaderMap. If so, open it and return its FileEntry.
202 : const FileEntry *HeaderMap::LookupFile(llvm::StringRef Filename,
203 0: FileManager &FM) const {
204 0: const HMapHeader &Hdr = getHeader();
205 0: unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
206 :
207 : // If the number of buckets is not a power of two, the headermap is corrupt.
208 : // Don't probe infinitely.
0: branch 0 not taken
0: branch 1 not taken
209 0: if (NumBuckets & (NumBuckets-1))
210 0: return 0;
211 :
212 : // Linearly probe the hash table.
213 0: for (unsigned Bucket = HashHMapKey(Filename);; ++Bucket) {
214 0: HMapBucket B = getBucket(Bucket & (NumBuckets-1));
0: branch 0 not taken
0: branch 1 not taken
215 0: if (B.Key == HMAP_EmptyBucketKey) return 0; // Hash miss.
216 :
217 : // See if the key matches. If not, probe on.
0: branch 3 not taken
0: branch 4 not taken
218 0: if (!Filename.equals_lower(getString(B.Key)))
219 0: continue;
220 :
221 : // If so, we have a match in the hash table. Construct the destination
222 : // path.
223 0: llvm::SmallString<1024> DestPath;
224 0: DestPath += getString(B.Prefix);
225 0: DestPath += getString(B.Suffix);
226 0: return FM.getFile(DestPath.begin(), DestPath.end());
227 : }
228 : }
Generated: 2010-02-10 01:31 by zcov