LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) { if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) { reportInvalidFile("Malformed metadata block"); return Failure; } bool versionChecked = false; while (true) { unsigned blockOrCode = 0; StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block", blockOrCode); switch(Res) { case Read_EndOfStream: llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock"); case Read_Failure: return Failure; case Read_Record: break; case Read_BlockBegin: if (Stream.SkipBlock()) { reportInvalidFile("Malformed metadata block"); return Failure; } case Read_BlockEnd: if (!versionChecked) { reportInvalidFile("Diagnostics file does not contain version" " information"); return Failure; } return Success; } RecordData Record; unsigned recordID = Stream.readRecord(blockOrCode, Record); if (recordID == serialized_diags::RECORD_VERSION) { if (Record.size() < 1) { reportInvalidFile("malformed VERSION identifier in diagnostics file"); return Failure; } if (Record[0] > MaxSupportedVersion) { reportInvalidFile("diagnosics file is a newer version than the one " "supported"); return Failure; } versionChecked = true; } } }
/// Populate \p extendedInfo with the data from the options block. /// /// Returns true on success. static bool readOptionsBlock(llvm::BitstreamCursor &cursor, SmallVectorImpl<uint64_t> &scratch, ExtendedValidationInfo &extendedInfo) { auto next = cursor.advance(); while (next.Kind != llvm::BitstreamEntry::EndBlock) { if (next.Kind == llvm::BitstreamEntry::Error) return false; if (next.Kind == llvm::BitstreamEntry::SubBlock) { // Unknown metadata sub-block, possibly for use by a future version of // the module format. if (cursor.SkipBlock()) return false; next = cursor.advance(); continue; } scratch.clear(); StringRef blobData; unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case options_block::SDK_PATH: extendedInfo.setSDKPath(blobData); break; case options_block::XCC: extendedInfo.addExtraClangImporterOption(blobData); break; case options_block::IS_SIB: bool IsSIB; options_block::IsSIBLayout::readRecord(scratch, IsSIB); extendedInfo.setIsSIB(IsSIB); break; case options_block::IS_TESTABLE: extendedInfo.setIsTestable(true); break; case options_block::IS_RESILIENT: extendedInfo.setIsResilient(true); break; default: // Unknown options record, possibly for use by a future version of the // module format. break; } next = cursor.advance(); } return true; }
bool ModuleFile::readCommentBlock(llvm::BitstreamCursor &cursor) { cursor.EnterSubBlock(COMMENT_BLOCK_ID); SmallVector<uint64_t, 4> scratch; StringRef blobData; while (true) { auto next = cursor.advance(); switch (next.Kind) { case llvm::BitstreamEntry::EndBlock: return true; case llvm::BitstreamEntry::Error: return false; case llvm::BitstreamEntry::SubBlock: // Unknown sub-block, which this version of the compiler won't use. if (cursor.SkipBlock()) return false; break; case llvm::BitstreamEntry::Record: scratch.clear(); unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case comment_block::DECL_COMMENTS: DeclCommentTable = readDeclCommentTable(scratch, blobData); break; case comment_block::GROUP_NAMES: GroupNamesMap = readGroupTable(scratch, blobData); break; default: // Unknown index kind, which this version of the compiler won't use. break; } break; } } }
std::error_code SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) { if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) return SDError::MalformedMetadataBlock; bool VersionChecked = false; while (true) { unsigned BlockOrCode = 0; llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode); if (!Res) Res.getError(); switch (Res.get()) { case Cursor::Record: break; case Cursor::BlockBegin: if (Stream.SkipBlock()) return SDError::MalformedMetadataBlock; case Cursor::BlockEnd: if (!VersionChecked) return SDError::MissingVersion; return std::error_code(); } SmallVector<uint64_t, 1> Record; unsigned RecordID = Stream.readRecord(BlockOrCode, Record); if (RecordID == RECORD_VERSION) { if (Record.size() < 1) return SDError::MissingVersion; if (Record[0] > VersionNumber) return SDError::VersionMismatch; VersionChecked = true; } } }
bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) { cursor.EnterSubBlock(INDEX_BLOCK_ID); SmallVector<uint64_t, 4> scratch; StringRef blobData; while (true) { auto next = cursor.advance(); switch (next.Kind) { case llvm::BitstreamEntry::EndBlock: return true; case llvm::BitstreamEntry::Error: return false; case llvm::BitstreamEntry::SubBlock: // Unknown sub-block, which this version of the compiler won't use. if (cursor.SkipBlock()) return false; break; case llvm::BitstreamEntry::Record: scratch.clear(); blobData = {}; unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case index_block::DECL_OFFSETS: assert(blobData.empty()); Decls.assign(scratch.begin(), scratch.end()); break; case index_block::DECL_CONTEXT_OFFSETS: assert(blobData.empty()); DeclContexts.assign(scratch.begin(), scratch.end()); break; case index_block::TYPE_OFFSETS: assert(blobData.empty()); Types.assign(scratch.begin(), scratch.end()); break; case index_block::IDENTIFIER_OFFSETS: assert(blobData.empty()); Identifiers.assign(scratch.begin(), scratch.end()); break; case index_block::TOP_LEVEL_DECLS: TopLevelDecls = readDeclTable(scratch, blobData); break; case index_block::OPERATORS: OperatorDecls = readDeclTable(scratch, blobData); break; case index_block::EXTENSIONS: ExtensionDecls = readDeclTable(scratch, blobData); break; case index_block::CLASS_MEMBERS: ClassMembersByName = readDeclTable(scratch, blobData); break; case index_block::OPERATOR_METHODS: OperatorMethodDecls = readDeclTable(scratch, blobData); break; case index_block::OBJC_METHODS: ObjCMethods = readObjCMethodTable(scratch, blobData); break; case index_block::ENTRY_POINT: assert(blobData.empty()); setEntryPointClassID(scratch.front()); break; case index_block::LOCAL_TYPE_DECLS: LocalTypeDecls = readLocalDeclTable(scratch, blobData); break; case index_block::LOCAL_DECL_CONTEXT_OFFSETS: assert(blobData.empty()); LocalDeclContexts.assign(scratch.begin(), scratch.end()); break; case index_block::NORMAL_CONFORMANCE_OFFSETS: assert(blobData.empty()); NormalConformances.assign(scratch.begin(), scratch.end()); break; default: // Unknown index kind, which this version of the compiler won't use. break; } break; } } }
static ValidationInfo validateControlBlock(llvm::BitstreamCursor &cursor, SmallVectorImpl<uint64_t> &scratch, ExtendedValidationInfo *extendedInfo) { // The control block is malformed until we've at least read a major version // number. ValidationInfo result; bool versionSeen = false; auto next = cursor.advance(); while (next.Kind != llvm::BitstreamEntry::EndBlock) { if (next.Kind == llvm::BitstreamEntry::Error) { result.status = Status::Malformed; return result; } if (next.Kind == llvm::BitstreamEntry::SubBlock) { if (next.ID == OPTIONS_BLOCK_ID && extendedInfo) { cursor.EnterSubBlock(OPTIONS_BLOCK_ID); if (!readOptionsBlock(cursor, scratch, *extendedInfo)) { result.status = Status::Malformed; return result; } } else { // Unknown metadata sub-block, possibly for use by a future version of // the module format. if (cursor.SkipBlock()) { result.status = Status::Malformed; return result; } } next = cursor.advance(); continue; } scratch.clear(); StringRef blobData; unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case control_block::METADATA: { if (versionSeen) { result.status = Status::Malformed; break; } uint16_t versionMajor = scratch[0]; if (versionMajor > VERSION_MAJOR) result.status = Status::FormatTooNew; else if (versionMajor < VERSION_MAJOR) result.status = Status::FormatTooOld; else result.status = Status::Valid; // Major version 0 does not have stable minor versions. if (versionMajor == 0) { uint16_t versionMinor = scratch[1]; if (versionMinor != VERSION_MINOR) { if (versionMinor < VERSION_MINOR) result.status = Status::FormatTooOld; else result.status = Status::FormatTooNew; } } versionSeen = true; break; } case control_block::MODULE_NAME: result.name = blobData; break; case control_block::TARGET: result.targetTriple = blobData; break; default: // Unknown metadata record, possibly for use by a future version of the // module format. break; } next = cursor.advance(); } return result; }
GlobalModuleIndex::GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> Buffer, llvm::BitstreamCursor Cursor) : Buffer(std::move(Buffer)), IdentifierIndex(), NumIdentifierLookups(), NumIdentifierLookupHits() { // Read the global index. bool InGlobalIndexBlock = false; bool Done = false; while (!Done) { llvm::BitstreamEntry Entry = Cursor.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: return; case llvm::BitstreamEntry::EndBlock: if (InGlobalIndexBlock) { InGlobalIndexBlock = false; Done = true; continue; } return; case llvm::BitstreamEntry::Record: // Entries in the global index block are handled below. if (InGlobalIndexBlock) break; return; case llvm::BitstreamEntry::SubBlock: if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) { if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID)) return; InGlobalIndexBlock = true; } else if (Cursor.SkipBlock()) { return; } continue; } SmallVector<uint64_t, 64> Record; StringRef Blob; switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) { case INDEX_METADATA: // Make sure that the version matches. if (Record.size() < 1 || Record[0] != CurrentVersion) return; break; case MODULE: { unsigned Idx = 0; unsigned ID = Record[Idx++]; // Make room for this module's information. if (ID == Modules.size()) Modules.push_back(ModuleInfo()); else Modules.resize(ID + 1); // Size/modification time for this module file at the time the // global index was built. Modules[ID].Size = Record[Idx++]; Modules[ID].ModTime = Record[Idx++]; // File name. unsigned NameLen = Record[Idx++]; Modules[ID].FileName.assign(Record.begin() + Idx, Record.begin() + Idx + NameLen); Idx += NameLen; // Dependencies unsigned NumDeps = Record[Idx++]; Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(), Record.begin() + Idx, Record.begin() + Idx + NumDeps); Idx += NumDeps; // Make sure we're at the end of the record. assert(Idx == Record.size() && "More module info?"); // Record this module as an unresolved module. // FIXME: this doesn't work correctly for module names containing path // separators. StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName); // Remove the -<hash of ModuleMapPath> ModuleName = ModuleName.rsplit('-').first; UnresolvedModules[ModuleName] = ID; break; } case IDENTIFIER_INDEX: // Wire up the identifier index. if (Record[0]) { IdentifierIndex = IdentifierIndexTable::Create( (const unsigned char *)Blob.data() + Record[0], (const unsigned char *)Blob.data() + sizeof(uint32_t), (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait()); } break; } } }
std::error_code SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) { if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) return SDError::MalformedDiagnosticBlock; std::error_code EC; if ((EC = visitStartOfDiagnostic())) return EC; SmallVector<uint64_t, 16> Record; while (true) { unsigned BlockOrCode = 0; llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode); if (!Res) Res.getError(); switch (Res.get()) { case Cursor::BlockBegin: // The only blocks we care about are subdiagnostics. if (BlockOrCode == serialized_diags::BLOCK_DIAG) { if ((EC = readDiagnosticBlock(Stream))) return EC; } else if (!Stream.SkipBlock()) return SDError::MalformedSubBlock; continue; case Cursor::BlockEnd: if ((EC = visitEndOfDiagnostic())) return EC; return std::error_code(); case Cursor::Record: break; } // Read the record. Record.clear(); StringRef Blob; unsigned RecID = Stream.readRecord(BlockOrCode, Record, &Blob); if (RecID < serialized_diags::RECORD_FIRST || RecID > serialized_diags::RECORD_LAST) continue; switch ((RecordIDs)RecID) { case RECORD_CATEGORY: // A category has ID and name size. if (Record.size() != 2) return SDError::MalformedDiagnosticRecord; if ((EC = visitCategoryRecord(Record[0], Blob))) return EC; continue; case RECORD_DIAG: // A diagnostic has severity, location (4), category, flag, and message // size. if (Record.size() != 8) return SDError::MalformedDiagnosticRecord; if ((EC = visitDiagnosticRecord( Record[0], Location(Record[1], Record[2], Record[3], Record[4]), Record[5], Record[6], Blob))) return EC; continue; case RECORD_DIAG_FLAG: // A diagnostic flag has ID and name size. if (Record.size() != 2) return SDError::MalformedDiagnosticRecord; if ((EC = visitDiagFlagRecord(Record[0], Blob))) return EC; continue; case RECORD_FILENAME: // A filename has ID, size, timestamp, and name size. The size and // timestamp are legacy fields that are always zero these days. if (Record.size() != 4) return SDError::MalformedDiagnosticRecord; if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob))) return EC; continue; case RECORD_FIXIT: // A fixit has two locations (4 each) and message size. if (Record.size() != 9) return SDError::MalformedDiagnosticRecord; if ((EC = visitFixitRecord( Location(Record[0], Record[1], Record[2], Record[3]), Location(Record[4], Record[5], Record[6], Record[7]), Blob))) return EC; continue; case RECORD_SOURCE_RANGE: // A source range is two locations (4 each). if (Record.size() != 8) return SDError::MalformedDiagnosticRecord; if ((EC = visitSourceRangeRecord( Location(Record[0], Record[1], Record[2], Record[3]), Location(Record[4], Record[5], Record[6], Record[7])))) return EC; continue; case RECORD_VERSION: // A version is just a number. if (Record.size() != 1) return SDError::MalformedDiagnosticRecord; if ((EC = visitVersionRecord(Record[0]))) return EC; continue; } } }
GlobalModuleIndex::GlobalModuleIndex(FileManager &FileMgr, llvm::MemoryBuffer *Buffer, llvm::BitstreamCursor Cursor) : Buffer(Buffer), IdentifierIndex(), NumIdentifierLookups(), NumIdentifierLookupHits() { typedef llvm::DenseMap<unsigned, LoadedModuleInfo> LoadedModulesMap; LoadedModulesMap LoadedModules; // Read the global index. unsigned LargestID = 0; bool InGlobalIndexBlock = false; bool Done = false; bool AnyOutOfDate = false; while (!Done) { llvm::BitstreamEntry Entry = Cursor.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: return; case llvm::BitstreamEntry::EndBlock: if (InGlobalIndexBlock) { InGlobalIndexBlock = false; Done = true; continue; } return; case llvm::BitstreamEntry::Record: // Entries in the global index block are handled below. if (InGlobalIndexBlock) break; return; case llvm::BitstreamEntry::SubBlock: if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) { if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID)) return; InGlobalIndexBlock = true; } else if (Cursor.SkipBlock()) { return; } continue; } SmallVector<uint64_t, 64> Record; StringRef Blob; switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) { case INDEX_METADATA: // Make sure that the version matches. if (Record.size() < 1 || Record[0] != CurrentVersion) return; break; case MODULE: { unsigned Idx = 0; unsigned ID = Record[Idx++]; if (ID > LargestID) LargestID = ID; off_t Size = Record[Idx++]; time_t ModTime = Record[Idx++]; // File name. unsigned NameLen = Record[Idx++]; llvm::SmallString<64> FileName(Record.begin() + Idx, Record.begin() + Idx + NameLen); Idx += NameLen; // Dependencies unsigned NumDeps = Record[Idx++]; llvm::SmallVector<unsigned, 2> Dependencies(Record.begin() + Idx, Record.begin() + Idx + NumDeps); // Find the file. If we can't find it, ignore it. const FileEntry *File = FileMgr.getFile(FileName); if (!File) { AnyOutOfDate = true; break; } // If the module file is newer than the index, ignore it. if (File->getSize() != Size || File->getModificationTime() != ModTime) { AnyOutOfDate = true; break; } // Record this module. The dependencies will be resolved later. LoadedModuleInfo &Info = LoadedModules[ID]; Info.File = File; Info.Dependencies.swap(Dependencies); break; } case IDENTIFIER_INDEX: // Wire up the identifier index. if (Record[0]) { IdentifierIndex = IdentifierIndexTable::Create( (const unsigned char *)Blob.data() + Record[0], (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait()); } break; } } // If there are any modules that have gone out-of-date, prune out any modules // that depend on them. if (AnyOutOfDate) { // First, build back links in the module dependency graph. SmallVector<unsigned, 4> Stack; for (LoadedModulesMap::iterator LM = LoadedModules.begin(), LMEnd = LoadedModules.end(); LM != LMEnd; ++LM) { unsigned ID = LM->first; // If this module is out-of-date, push it onto the stack. if (LM->second.File == 0) Stack.push_back(ID); for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) { unsigned DepID = LM->second.Dependencies[I]; LoadedModulesMap::iterator Known = LoadedModules.find(DepID); if (Known == LoadedModules.end() || !Known->second.File) { // The dependency was out-of-date, so mark us as out of date. // This is just an optimization. if (LM->second.File) Stack.push_back(ID); LM->second.File = 0; continue; } // Record this reverse dependency. Known->second.ImportedBy.push_back(ID); } } // Second, walk the back links from out-of-date modules to those modules // that depend on them, making those modules out-of-date as well. while (!Stack.empty()) { unsigned ID = Stack.back(); Stack.pop_back(); LoadedModuleInfo &Info = LoadedModules[ID]; for (unsigned I = 0, N = Info.ImportedBy.size(); I != N; ++I) { unsigned FromID = Info.ImportedBy[I]; if (LoadedModules[FromID].File) { LoadedModules[FromID].File = 0; Stack.push_back(FromID); } } } } // Allocate the vector containing information about all of the modules. Modules.resize(LargestID + 1); for (LoadedModulesMap::iterator LM = LoadedModules.begin(), LMEnd = LoadedModules.end(); LM != LMEnd; ++LM) { if (!LM->second.File) continue; Modules[LM->first].File = LM->second.File; // Resolve dependencies. Drop any we can't resolve due to out-of-date // module files. for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) { unsigned DepID = LM->second.Dependencies[I]; LoadedModulesMap::iterator Known = LoadedModules.find(DepID); if (Known == LoadedModules.end() || !Known->second.File) continue; Modules[LM->first].Dependencies.push_back(Known->second.File); } } }
LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream, CXDiagnosticSetImpl &Diags, CXLoadedDiagnosticSetImpl &TopDiags){ if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) { reportInvalidFile("malformed diagnostic block"); return Failure; } OwningPtr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic()); RecordData Record; while (true) { unsigned blockOrCode = 0; StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block", blockOrCode); switch (Res) { case Read_EndOfStream: llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock"); case Read_Failure: return Failure; case Read_BlockBegin: { // The only blocks we care about are subdiagnostics. if (blockOrCode != serialized_diags::BLOCK_DIAG) { if (!Stream.SkipBlock()) { reportInvalidFile("Invalid subblock in Diagnostics block"); return Failure; } } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(), TopDiags)) { return Failure; } continue; } case Read_BlockEnd: Diags.appendDiagnostic(D.take()); return Success; case Read_Record: break; } // Read the record. Record.clear(); StringRef Blob; unsigned recID = Stream.readRecord(blockOrCode, Record, &Blob); if (recID < serialized_diags::RECORD_FIRST || recID > serialized_diags::RECORD_LAST) continue; switch ((serialized_diags::RecordIDs)recID) { case serialized_diags::RECORD_VERSION: continue; case serialized_diags::RECORD_CATEGORY: if (readString(TopDiags, TopDiags.Categories, "category", Record, Blob, /* allowEmptyString */ true)) return Failure; continue; case serialized_diags::RECORD_DIAG_FLAG: if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record, Blob)) return Failure; continue; case serialized_diags::RECORD_FILENAME: { if (readString(TopDiags, TopDiags.FileNames, "filename", Record, Blob)) return Failure; if (Record.size() < 3) { reportInvalidFile("Invalid file entry"); return Failure; } const FileEntry *FE = TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]], /* size */ Record[1], /* time */ Record[2]); TopDiags.Files[Record[0]] = FE; continue; } case serialized_diags::RECORD_SOURCE_RANGE: { CXSourceRange SR; if (readRange(TopDiags, Record, 0, SR)) return Failure; D->Ranges.push_back(SR); continue; } case serialized_diags::RECORD_FIXIT: { CXSourceRange SR; if (readRange(TopDiags, Record, 0, SR)) return Failure; llvm::StringRef RetStr; if (readString(TopDiags, RetStr, "FIXIT", Record, Blob, /* allowEmptyString */ true)) return Failure; D->FixIts.push_back(std::make_pair(SR, createCXString(RetStr, false))); continue; } case serialized_diags::RECORD_DIAG: { D->severity = Record[0]; unsigned offset = 1; if (readLocation(TopDiags, Record, offset, D->DiagLoc)) return Failure; D->category = Record[offset++]; unsigned diagFlag = Record[offset++]; D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : ""; D->CategoryText = D->category ? TopDiags.Categories[D->category] : ""; D->Spelling = TopDiags.makeString(Blob); continue; } } } }