zcov: / lib/Lex/HeaderMap.cpp


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


Programs: 2 Runs 3018


       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