diff options
author | Chris Lattner <sabre@nondot.org> | 2007-12-17 21:06:11 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2007-12-17 21:06:11 +0000 |
commit | 9f9a619a9fb4a0bcf521f2f7c2caa82411b122db (patch) | |
tree | fb0011aa68513c3375550ba92aa891ad1c1f9bf5 | |
parent | 24cb52c9b0cee08146da3c71ecaa73da361a5d33 (diff) | |
download | bcm5719-llvm-9f9a619a9fb4a0bcf521f2f7c2caa82411b122db.tar.gz bcm5719-llvm-9f9a619a9fb4a0bcf521f2f7c2caa82411b122db.zip |
implement enough helper functions to successfully dump out the
contents of the header map. Look ma, no assumptions about input data
here (aka, corrupt header maps can't crash the compiler - crazy thought).
llvm-svn: 45122
-rw-r--r-- | clang/Lex/HeaderMap.cpp | 112 | ||||
-rw-r--r-- | clang/include/clang/Lex/HeaderMap.h | 11 |
2 files changed, 116 insertions, 7 deletions
diff --git a/clang/Lex/HeaderMap.cpp b/clang/Lex/HeaderMap.cpp index abd1f9ee0c8..177821e0cf6 100644 --- a/clang/Lex/HeaderMap.cpp +++ b/clang/Lex/HeaderMap.cpp @@ -19,9 +19,23 @@ #include "llvm/Support/MemoryBuffer.h" using namespace clang; +//===----------------------------------------------------------------------===// +// Data Structures and Manifest Constants +//===----------------------------------------------------------------------===// + enum { - HeaderMagicNumber = ('h' << 24) | ('m' << 16) | ('a' << 8) | 'p', - HeaderVersion = 1 + HMAP_HeaderMagicNumber = ('h' << 24) | ('m' << 16) | ('a' << 8) | 'p', + HMAP_HeaderVersion = 1, + + HMAP_EmptyBucketKey = 0 +}; + +namespace clang { +struct HMapBucket { + uint32_t Key; // Offset (into strings) of key. + + uint32_t Prefix; // Offset (into strings) of value prefix. + uint32_t Suffix; // Offset (into strings) of value suffix. }; struct HMapHeader { @@ -29,12 +43,17 @@ struct HMapHeader { uint16_t Version; // Version number -- currently 1. uint16_t Reserved; // Reserved for future use - zero for now. uint32_t StringsOffset; // Offset to start of string pool. - uint32_t Count; // Number of entries in the string table. - uint32_t Capacity; // Number of buckets (always a power of 2). + uint32_t NumEntries; // Number of entries in the string table. + uint32_t NumBuckets; // Number of buckets (always a power of 2). uint32_t MaxValueLength; // Length of longest result path (excluding nul). + // An array of 'NumBuckets' HMapBucket objects follows this header. // Strings follow the buckets, at StringsOffset. }; +} // end namespace clang. +//===----------------------------------------------------------------------===// +// Verification and Construction +//===----------------------------------------------------------------------===// /// HeaderMap::Create - This attempts to load the specified file as a header /// map. If it doesn't look like a HeaderMap, it gives up and returns null. @@ -57,10 +76,11 @@ const HeaderMap *HeaderMap::Create(const FileEntry *FE) { // Sniff it to see if it's a headermap by checking the magic number and // version. bool NeedsByteSwap; - if (Header->Magic == HeaderMagicNumber && Header->Version == HeaderVersion) + if (Header->Magic == HMAP_HeaderMagicNumber && + Header->Version == HMAP_HeaderVersion) NeedsByteSwap = false; - else if (Header->Magic == llvm::ByteSwap_32(HeaderMagicNumber) && - Header->Version == llvm::ByteSwap_16(HeaderVersion)) + else if (Header->Magic == llvm::ByteSwap_32(HMAP_HeaderMagicNumber) && + Header->Version == llvm::ByteSwap_16(HMAP_HeaderVersion)) NeedsByteSwap = true; // Mixed endianness headermap. else return 0; // Not a header map. @@ -75,12 +95,90 @@ HeaderMap::~HeaderMap() { delete FileBuffer; } +//===----------------------------------------------------------------------===// +// Utility Methods +//===----------------------------------------------------------------------===// + /// getFileName - Return the filename of the headermap. const char *HeaderMap::getFileName() const { return FileBuffer->getBufferIdentifier(); } +unsigned HeaderMap::getEndianAdjustedWord(unsigned X) const { + if (!NeedsBSwap) return X; + return llvm::ByteSwap_32(X); +} + +/// getHeader - Return a reference to the file header, in unbyte-swapped form. +/// This method cannot fail. +const HMapHeader &HeaderMap::getHeader() const { + // We know the file is at least as big as the header. Return it. + return *reinterpret_cast<const HMapHeader*>(FileBuffer->getBufferStart()); +} + +/// getBucket - Return the specified hash table bucket from the header map, +/// bswap'ing its fields as appropriate. If the bucket number is not valid, +/// this return a bucket with an empty key (0). +HMapBucket HeaderMap::getBucket(unsigned BucketNo) const { + HMapBucket Result; + Result.Key = HMAP_EmptyBucketKey; + + const HMapBucket *BucketArray = + reinterpret_cast<const HMapBucket*>(FileBuffer->getBufferStart() + + sizeof(HMapHeader)); + + const HMapBucket *BucketPtr = BucketArray+BucketNo; + if ((char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) + return Result; // Invalid buffer, corrupt hmap. + + // Otherwise, the bucket is valid. Load the values, bswapping as needed. + Result.Key = getEndianAdjustedWord(BucketPtr->Key); + Result.Prefix = getEndianAdjustedWord(BucketPtr->Prefix); + Result.Suffix = getEndianAdjustedWord(BucketPtr->Suffix); + return Result; +} + +/// getString - Look up the specified string in the string table. If the string +/// index is not valid, it returns an empty string. +const char *HeaderMap::getString(unsigned StrTabIdx) const { + // Add the start of the string table to the idx. + StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset); + + // Check for invalid index. + if (StrTabIdx >= FileBuffer->getBufferSize()) + return 0; + + // Otherwise, we have a valid pointer into the file. Just return it. We know + // that the "string" can not overrun the end of the file, because the buffer + // is nul terminated by virtue of being a MemoryBuffer. + return FileBuffer->getBufferStart()+StrTabIdx; +} + +//===----------------------------------------------------------------------===// +// The Main Drivers +//===----------------------------------------------------------------------===// + +/// dump - Print the contents of this headermap to stderr. +void HeaderMap::dump() const { + const HMapHeader &Hdr = getHeader(); + unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); + + fprintf(stderr, "Header Map %s:\n %d buckets, %d entries\n", + getFileName(), NumBuckets, + getEndianAdjustedWord(Hdr.NumEntries)); + + for (unsigned i = 0; i != NumBuckets; ++i) { + HMapBucket B = getBucket(i); + if (B.Key == HMAP_EmptyBucketKey) continue; + + const char *Key = getString(B.Key); + const char *Prefix = getString(B.Prefix); + const char *Suffix = getString(B.Suffix); + fprintf(stderr, " %d. %s -> '%s' '%s'\n", i, Key, Prefix, Suffix); + } +} + /// LookupFile - Check to see if the specified relative filename is located in /// this HeaderMap. If so, open it and return its FileEntry. const FileEntry *HeaderMap::LookupFile(const char *FilenameStart, diff --git a/clang/include/clang/Lex/HeaderMap.h b/clang/include/clang/Lex/HeaderMap.h index 973cf10a861..3bc0acf70fc 100644 --- a/clang/include/clang/Lex/HeaderMap.h +++ b/clang/include/clang/Lex/HeaderMap.h @@ -20,6 +20,8 @@ namespace llvm { namespace clang { class FileEntry; class FileManager; + struct HMapBucket; + struct HMapHeader; /// This class represents an Apple concept known as a 'header map'. To the /// #include file resolution process, it basically acts like a directory of @@ -49,6 +51,15 @@ public: /// getFileName - Return the filename of the headermap. const char *getFileName() const; + + /// dump - Print the contents of this headermap to stderr. + void dump() const; + +private: + unsigned getEndianAdjustedWord(unsigned X) const; + const HMapHeader &getHeader() const; + HMapBucket getBucket(unsigned BucketNo) const; + const char *getString(unsigned StrTabIdx) const; }; } // end namespace clang. |