bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input, DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { SrcMgr::CharacteristicKind Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; if (Input.isBuffer()) { SourceMgr.createMainFileIDForMemBuffer(Input.getBuffer(), Kind); assert(!SourceMgr.getMainFileID().isInvalid() && "Couldn't establish MainFileID!"); return true; } StringRef InputFile = Input.getFile(); // Figure out where to get and map in the main file. if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); if (!File) { Diags.Report(diag::err_fe_error_reading) << InputFile; return false; } // The natural SourceManager infrastructure can't currently handle named // pipes, but we would at least like to accept them for the main // file. Detect them here, read them with the more generic MemoryBuffer // function, and simply override their contents as we do for STDIN. if (File->isNamedPipe()) { OwningPtr<llvm::MemoryBuffer> MB; if (llvm::error_code ec = llvm::MemoryBuffer::getFile(InputFile, MB)) { Diags.Report(diag::err_cannot_open_file) << InputFile << ec.message(); return false; } // Create a new virtual file that will have the correct size. File = FileMgr.getVirtualFile(InputFile, MB->getBufferSize(), 0); SourceMgr.overrideFileContents(File, MB.take()); } SourceMgr.createMainFileID(File, Kind); } else { OwningPtr<llvm::MemoryBuffer> SB; if (llvm::MemoryBuffer::getSTDIN(SB)) { // FIXME: Give ec.message() in this diag. Diags.Report(diag::err_fe_error_reading_stdin); return false; } const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(), SB->getBufferSize(), 0); SourceMgr.createMainFileID(File, Kind); SourceMgr.overrideFileContents(File, SB.take()); } assert(!SourceMgr.getMainFileID().isInvalid() && "Couldn't establish MainFileID!"); return true; }
int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); if (OutputFilename == "-") { errs() << argv[0] << ": error: Can't update standard output\n"; return 1; } // Get the input data. OwningPtr<MemoryBuffer> In; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), In)) { errs() << argv[0] << ": error: Unable to get input '" << InputFilename << "': " << ec.message() << '\n'; return 1; } // Get the output data. OwningPtr<MemoryBuffer> Out; MemoryBuffer::getFile(OutputFilename.c_str(), Out); // If the output exists and the contents match, we are done. if (Out && In->getBufferSize() == Out->getBufferSize() && memcmp(In->getBufferStart(), Out->getBufferStart(), Out->getBufferSize()) == 0) { if (!Quiet) errs() << argv[0] << ": Not updating '" << OutputFilename << "', contents match input.\n"; return 0; } // Otherwise, overwrite the output. if (!Quiet) errs() << argv[0] << ": Updating '" << OutputFilename << "', contents changed.\n"; std::string ErrorStr; tool_output_file OutStream(OutputFilename.c_str(), ErrorStr, raw_fd_ostream::F_Binary); if (!ErrorStr.empty()) { errs() << argv[0] << ": Unable to write output '" << OutputFilename << "': " << ErrorStr << '\n'; return 1; } OutStream.os().write(In->getBufferStart(), In->getBufferSize()); // Declare success. OutStream.keep(); return 0; }
bool CompilerInstance::InitializeSourceManager(StringRef InputFile, SrcMgr::CharacteristicKind Kind, DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { // Figure out where to get and map in the main file. if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); if (!File) { Diags.Report(diag::err_fe_error_reading) << InputFile; return false; } SourceMgr.createMainFileID(File, Kind); } else { OwningPtr<llvm::MemoryBuffer> SB; if (llvm::MemoryBuffer::getSTDIN(SB)) { // FIXME: Give ec.message() in this diag. Diags.Report(diag::err_fe_error_reading_stdin); return false; } const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(), SB->getBufferSize(), 0); SourceMgr.createMainFileID(File, Kind); SourceMgr.overrideFileContents(File, SB.take()); } assert(!SourceMgr.getMainFileID().isInvalid() && "Couldn't establish MainFileID!"); return true; }
// Returns true on error. static bool format(std::string FileName) { FileManager Files((FileSystemOptions())); DiagnosticsEngine Diagnostics( IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), new DiagnosticOptions); SourceManager Sources(Diagnostics, Files); OwningPtr<MemoryBuffer> Code; if (error_code ec = MemoryBuffer::getFileOrSTDIN(FileName, Code)) { llvm::errs() << ec.message() << "\n"; return true; } if (Code->getBufferSize() == 0) return true; // Empty files are formatted correctly. FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files); std::vector<CharSourceRange> Ranges; if (fillRanges(Sources, ID, Code.get(), Ranges)) return true; FormatStyle FormatStyle = getStyle(Style, FileName); Lexer Lex(ID, Sources.getBuffer(ID), Sources, getFormattingLangOpts(FormatStyle.Standard)); tooling::Replacements Replaces = reformat(FormatStyle, Lex, Sources, Ranges); if (OutputXML) { llvm::outs() << "<?xml version='1.0'?>\n<replacements xml:space='preserve'>\n"; for (tooling::Replacements::const_iterator I = Replaces.begin(), E = Replaces.end(); I != E; ++I) { llvm::outs() << "<replacement " << "offset='" << I->getOffset() << "' " << "length='" << I->getLength() << "'>" << I->getReplacementText() << "</replacement>\n"; } llvm::outs() << "</replacements>\n"; } else { Rewriter Rewrite(Sources, LangOptions()); tooling::applyAllReplacements(Replaces, Rewrite); if (Inplace) { if (Replaces.size() == 0) return false; // Nothing changed, don't touch the file. std::string ErrorInfo; llvm::raw_fd_ostream FileStream(FileName.c_str(), ErrorInfo, llvm::sys::fs::F_Binary); if (!ErrorInfo.empty()) { llvm::errs() << "Error while writing file: " << ErrorInfo << "\n"; return true; } Rewrite.getEditBuffer(ID).write(FileStream); FileStream.flush(); } else { if (Cursor.getNumOccurrences() != 0) outs() << "{ \"Cursor\": " << tooling::shiftedCodePosition( Replaces, Cursor) << " }\n"; Rewrite.getEditBuffer(ID).write(outs()); } } return false; }
Module* createModuleFromFile(const std::string & fileName) { std::string errorMessage; //create memory buffer for file OwningPtr<MemoryBuffer> fileBuffer; error_code e = MemoryBuffer::getFile(fileName.c_str(), fileBuffer); if (e) { errs() << "Error reading file '" << fileName << "': " << e.message() << "\n"; return NULL; } if (!fileBuffer) { errs() << "Error reading file '" << fileName << "'.\n"; return NULL; } if (fileBuffer->getBufferSize() & 3) { errs() << "Error: Bitcode stream should be " << "a multiple of 4 bytes in length\n"; return NULL; } //parse file Module* mod = ParseBitcodeFile(fileBuffer.get(), getGlobalContext(), &errorMessage); if (errorMessage != "") { errs() << "Error reading bitcode file: " << errorMessage << "\n"; return NULL; } if (!mod) { errs() << "Error reading bitcode file.\n"; return NULL; } return mod; }
// Returns true on error. static bool format(std::string FileName) { FileManager Files((FileSystemOptions())); DiagnosticsEngine Diagnostics( IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), new DiagnosticOptions); SourceManager Sources(Diagnostics, Files); OwningPtr<MemoryBuffer> Code; if (error_code ec = MemoryBuffer::getFileOrSTDIN(FileName, Code)) { llvm::errs() << ec.message() << "\n"; return true; } FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files); Lexer Lex(ID, Sources.getBuffer(ID), Sources, getFormattingLangOpts()); if (Offsets.empty()) Offsets.push_back(0); if (Offsets.size() != Lengths.size() && !(Offsets.size() == 1 && Lengths.empty())) { llvm::errs() << "error: number of -offset and -length arguments must match.\n"; return true; } std::vector<CharSourceRange> Ranges; for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { if (Offsets[i] >= Code->getBufferSize()) { llvm::errs() << "error: offset " << Offsets[i] << " is outside the file\n"; return true; } SourceLocation Start = Sources.getLocForStartOfFile(ID).getLocWithOffset(Offsets[i]); SourceLocation End; if (i < Lengths.size()) { if (Offsets[i] + Lengths[i] > Code->getBufferSize()) { llvm::errs() << "error: invalid length " << Lengths[i] << ", offset + length (" << Offsets[i] + Lengths[i] << ") is outside the file.\n"; return true; } End = Start.getLocWithOffset(Lengths[i]); } else { End = Sources.getLocForEndOfFile(ID); } Ranges.push_back(CharSourceRange::getCharRange(Start, End)); } tooling::Replacements Replaces = reformat(getStyle(), Lex, Sources, Ranges); if (OutputXML) { llvm::outs() << "<?xml version='1.0'?>\n<replacements xml:space='preserve'>\n"; for (tooling::Replacements::const_iterator I = Replaces.begin(), E = Replaces.end(); I != E; ++I) { llvm::outs() << "<replacement " << "offset='" << I->getOffset() << "' " << "length='" << I->getLength() << "'>" << I->getReplacementText() << "</replacement>\n"; } llvm::outs() << "</replacements>\n"; } else { Rewriter Rewrite(Sources, LangOptions()); tooling::applyAllReplacements(Replaces, Rewrite); if (Inplace) { if (Replaces.size() == 0) return false; // Nothing changed, don't touch the file. std::string ErrorInfo; llvm::raw_fd_ostream FileStream(FileName.c_str(), ErrorInfo, llvm::raw_fd_ostream::F_Binary); if (!ErrorInfo.empty()) { llvm::errs() << "Error while writing file: " << ErrorInfo << "\n"; return true; } Rewrite.getEditBuffer(ID).write(FileStream); FileStream.flush(); } else { Rewrite.getEditBuffer(ID).write(outs()); } } return false; }
int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); SourceMgr SM; // Read the expected strings from the check file. std::vector<CheckString> CheckStrings; if (ReadCheckFile(SM, CheckStrings)) return 2; // Open the file to check and add it to SourceMgr. OwningPtr<MemoryBuffer> File; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), File)) { errs() << "Could not open input file '" << InputFilename << "': " << ec.message() << '\n'; return 2; } if (File->getBufferSize() == 0) { errs() << "FileCheck error: '" << InputFilename << "' is empty.\n"; return 2; } // Remove duplicate spaces in the input file if requested. // Remove DOS style line endings. MemoryBuffer *F = CanonicalizeInputFile(File.take(), NoCanonicalizeWhiteSpace); SM.AddNewSourceBuffer(F, SMLoc()); /// VariableTable - This holds all the current filecheck variables. StringMap<StringRef> VariableTable; // Check that we have all of the expected strings, in order, in the input // file. StringRef Buffer = F->getBuffer(); const char *LastMatch = Buffer.data(); for (unsigned StrNo = 0, e = CheckStrings.size(); StrNo != e; ++StrNo) { const CheckString &CheckStr = CheckStrings[StrNo]; StringRef SearchFrom = Buffer; // Find StrNo in the file. size_t MatchLen = 0; size_t MatchPos = CheckStr.Pat.Match(Buffer, MatchLen, VariableTable); Buffer = Buffer.substr(MatchPos); // If we didn't find a match, reject the input. if (MatchPos == StringRef::npos) { PrintCheckFailed(SM, CheckStr, SearchFrom, VariableTable); return 1; } StringRef SkippedRegion(LastMatch, Buffer.data()-LastMatch); // If this check is a "CHECK-NEXT", verify that the previous match was on // the previous line (i.e. that there is one newline between them). if (CheckStr.IsCheckNext) { // Count the number of newlines between the previous match and this one. assert(LastMatch != F->getBufferStart() && "CHECK-NEXT can't be the first check in a file"); unsigned NumNewLines = CountNumNewlinesBetween(SkippedRegion); if (NumNewLines == 0) { SM.PrintMessage(CheckStr.Loc, SourceMgr::DK_Error, CheckPrefix+"-NEXT: is on the same line as previous match"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, "'next' match was here"); SM.PrintMessage(SMLoc::getFromPointer(LastMatch), SourceMgr::DK_Note, "previous match was here"); return 1; } if (NumNewLines != 1) { SM.PrintMessage(CheckStr.Loc, SourceMgr::DK_Error, CheckPrefix+ "-NEXT: is not on the line after the previous match"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, "'next' match was here"); SM.PrintMessage(SMLoc::getFromPointer(LastMatch), SourceMgr::DK_Note, "previous match was here"); return 1; } } // If this match had "not strings", verify that they don't exist in the // skipped region. for (unsigned ChunkNo = 0, e = CheckStr.NotStrings.size(); ChunkNo != e; ++ChunkNo) { size_t MatchLen = 0; size_t Pos = CheckStr.NotStrings[ChunkNo].second.Match(SkippedRegion, MatchLen, VariableTable); if (Pos == StringRef::npos) continue; SM.PrintMessage(SMLoc::getFromPointer(LastMatch+Pos), SourceMgr::DK_Error, CheckPrefix+"-NOT: string occurred!"); SM.PrintMessage(CheckStr.NotStrings[ChunkNo].first, SourceMgr::DK_Note, CheckPrefix+"-NOT: pattern specified here"); return 1; } // Otherwise, everything is good. Step over the matched text and remember // the position after the match as the end of the last match. Buffer = Buffer.substr(MatchLen); LastMatch = Buffer.data(); } return 0; }
/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename. static int AnalyzeBitcode() { // Read the input file. OwningPtr<MemoryBuffer> MemBuf; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), MemBuf)) return Error("Error reading '" + InputFilename + "': " + ec.message()); if (MemBuf->getBufferSize() & 3) return Error("Bitcode stream should be a multiple of 4 bytes in length"); const unsigned char *BufPtr = (const unsigned char *)MemBuf->getBufferStart(); const unsigned char *EndBufPtr = BufPtr+MemBuf->getBufferSize(); // If we have a wrapper header, parse it and ignore the non-bc file contents. // The magic number is 0x0B17C0DE stored in little endian. if (isBitcodeWrapper(BufPtr, EndBufPtr)) if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr, true)) return Error("Invalid bitcode wrapper header"); BitstreamReader StreamFile(BufPtr, EndBufPtr); BitstreamCursor Stream(StreamFile); StreamFile.CollectBlockInfoNames(); // Read the stream signature. char Signature[6]; Signature[0] = Stream.Read(8); Signature[1] = Stream.Read(8); Signature[2] = Stream.Read(4); Signature[3] = Stream.Read(4); Signature[4] = Stream.Read(4); Signature[5] = Stream.Read(4); // Autodetect the file contents, if it is one we know. CurStreamType = UnknownBitstream; if (Signature[0] == 'B' && Signature[1] == 'C' && Signature[2] == 0x0 && Signature[3] == 0xC && Signature[4] == 0xE && Signature[5] == 0xD) CurStreamType = LLVMIRBitstream; unsigned NumTopBlocks = 0; // Parse the top-level structure. We only allow blocks at the top-level. while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code != bitc::ENTER_SUBBLOCK) return Error("Invalid record at top-level"); unsigned BlockID = Stream.ReadSubBlockID(); if (ParseBlock(Stream, BlockID, 0)) return true; ++NumTopBlocks; } if (Dump) outs() << "\n\n"; uint64_t BufferSizeBits = (EndBufPtr-BufPtr)*CHAR_BIT; // Print a summary of the read file. outs() << "Summary of " << InputFilename << ":\n"; outs() << " Total size: "; PrintSize(BufferSizeBits); outs() << "\n"; outs() << " Stream type: "; switch (CurStreamType) { case UnknownBitstream: outs() << "unknown\n"; break; case LLVMIRBitstream: outs() << "LLVM IR\n"; break; } outs() << " # Toplevel Blocks: " << NumTopBlocks << "\n"; outs() << "\n"; // Emit per-block stats. outs() << "Per-block Summary:\n"; for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(), E = BlockIDStats.end(); I != E; ++I) { outs() << " Block ID #" << I->first; if (const char *BlockName = GetBlockName(I->first, StreamFile)) outs() << " (" << BlockName << ")"; outs() << ":\n"; const PerBlockIDStats &Stats = I->second; outs() << " Num Instances: " << Stats.NumInstances << "\n"; outs() << " Total Size: "; PrintSize(Stats.NumBits); outs() << "\n"; double pct = (Stats.NumBits * 100.0) / BufferSizeBits; outs() << " Percent of file: " << format("%2.4f%%", pct) << "\n"; if (Stats.NumInstances > 1) { outs() << " Average Size: "; PrintSize(Stats.NumBits/(double)Stats.NumInstances); outs() << "\n"; outs() << " Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/" << Stats.NumSubBlocks/(double)Stats.NumInstances << "\n"; outs() << " Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/" << Stats.NumAbbrevs/(double)Stats.NumInstances << "\n"; outs() << " Tot/Avg Records: " << Stats.NumRecords << "/" << Stats.NumRecords/(double)Stats.NumInstances << "\n"; } else { outs() << " Num SubBlocks: " << Stats.NumSubBlocks << "\n"; outs() << " Num Abbrevs: " << Stats.NumAbbrevs << "\n"; outs() << " Num Records: " << Stats.NumRecords << "\n"; } if (Stats.NumRecords) { double pct = (Stats.NumAbbreviatedRecords * 100.0) / Stats.NumRecords; outs() << " Percent Abbrevs: " << format("%2.4f%%", pct) << "\n"; } outs() << "\n"; // Print a histogram of the codes we see. if (!NoHistogram && !Stats.CodeFreq.empty()) { std::vector<std::pair<unsigned, unsigned> > FreqPairs; // <freq,code> for (unsigned i = 0, e = Stats.CodeFreq.size(); i != e; ++i) if (unsigned Freq = Stats.CodeFreq[i].NumInstances) FreqPairs.push_back(std::make_pair(Freq, i)); std::stable_sort(FreqPairs.begin(), FreqPairs.end()); std::reverse(FreqPairs.begin(), FreqPairs.end()); outs() << "\tRecord Histogram:\n"; outs() << "\t\t Count # Bits %% Abv Record Kind\n"; for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) { const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second]; outs() << format("\t\t%7d %9lu", RecStats.NumInstances, (unsigned long)RecStats.TotalBits); if (RecStats.NumAbbrev) outs() << format("%7.2f ", (double)RecStats.NumAbbrev/RecStats.NumInstances*100); else outs() << " "; if (const char *CodeName = GetCodeName(FreqPairs[i].second, I->first, StreamFile)) outs() << CodeName << "\n"; else outs() << "UnknownCode" << FreqPairs[i].second << "\n"; } outs() << "\n"; } } return 0; }
/// LinkInFile - opens a bitcode file and links in all objects which /// provide symbols that are currently undefined. /// /// Inputs: /// File - The pathname of the bitcode file. /// /// Outputs: /// ErrorMessage - A C++ string detailing what error occurred, if any. /// /// Return Value: /// TRUE - An error occurred. /// FALSE - No errors. /// bool Linker::LinkInFile(const sys::Path &File, bool &is_native) { is_native = false; // Check for a file of name "-", which means "read standard input" if (File.str() == "-") { std::auto_ptr<Module> M; OwningPtr<MemoryBuffer> Buffer; error_code ec; if (!(ec = MemoryBuffer::getSTDIN(Buffer))) { if (!Buffer->getBufferSize()) { Error = "standard input is empty"; } else { M.reset(ParseBitcodeFile(Buffer.get(), Context, &Error)); if (M.get()) if (!LinkInModule(M.get(), &Error)) return false; } } return error("Cannot link stdin: " + ec.message()); } // Determine what variety of file it is. std::string Magic; if (!File.getMagicNumber(Magic, 64)) return error("Cannot find linker input '" + File.str() + "'"); switch (sys::IdentifyFileType(Magic.c_str(), 64)) { default: llvm_unreachable("Bad file type identification"); case sys::Unknown_FileType: return warning("Ignoring file '" + File.str() + "' because does not contain bitcode."); case sys::Archive_FileType: // A user may specify an ar archive without -l, perhaps because it // is not installed as a library. Detect that and link the archive. if (LinkInArchive(File, is_native)) return true; break; case sys::Bitcode_FileType: { verbose("Linking bitcode file '" + File.str() + "'"); std::auto_ptr<Module> M(LoadObject(File)); if (M.get() == 0) return error("Cannot load file '" + File.str() + "': " + Error); if (LinkInModule(M.get(), &Error)) return error("Cannot link file '" + File.str() + "': " + Error); verbose("Linked in file '" + File.str() + "'"); break; } case sys::ELF_Relocatable_FileType: case sys::ELF_SharedObject_FileType: case sys::Mach_O_Object_FileType: case sys::Mach_O_FixedVirtualMemorySharedLib_FileType: case sys::Mach_O_DynamicallyLinkedSharedLib_FileType: case sys::Mach_O_DynamicallyLinkedSharedLibStub_FileType: case sys::COFF_FileType: is_native = true; break; } return false; }
// Write the entire archive to the file specified when the archive was created. // This writes to a temporary file first. Options are for creating a symbol // table, flattening the file names (no directories, 15 chars max) and // compressing each archive member. bool Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, std::string* ErrMsg) { // Make sure they haven't opened up the file, not loaded it, // but are now trying to write it which would wipe out the file. if (members.empty() && mapfile && mapfile->getBufferSize() > 8) { if (ErrMsg) *ErrMsg = "Can't write an archive not opened for writing"; return true; } // Create a temporary file to store the archive in sys::Path TmpArchive = archPath; if (TmpArchive.createTemporaryFileOnDisk(ErrMsg)) return true; // Make sure the temporary gets removed if we crash sys::RemoveFileOnSignal(TmpArchive); // Create archive file for output. std::ios::openmode io_mode = std::ios::out | std::ios::trunc | std::ios::binary; std::ofstream ArchiveFile(TmpArchive.c_str(), io_mode); // Check for errors opening or creating archive file. if (!ArchiveFile.is_open() || ArchiveFile.bad()) { TmpArchive.eraseFromDisk(); if (ErrMsg) *ErrMsg = "Error opening archive file: " + archPath.str(); return true; } // If we're creating a symbol table, reset it now if (CreateSymbolTable) { symTabSize = 0; symTab.clear(); } // Write magic string to archive. ArchiveFile << ARFILE_MAGIC; // Loop over all member files, and write them out. Note that this also // builds the symbol table, symTab. for (MembersList::iterator I = begin(), E = end(); I != E; ++I) { if (writeMember(*I, ArchiveFile, CreateSymbolTable, TruncateNames, ErrMsg)) { TmpArchive.eraseFromDisk(); ArchiveFile.close(); return true; } } // Close archive file. ArchiveFile.close(); // Write the symbol table if (CreateSymbolTable) { // At this point we have written a file that is a legal archive but it // doesn't have a symbol table in it. To aid in faster reading and to // ensure compatibility with other archivers we need to put the symbol // table first in the file. Unfortunately, this means mapping the file // we just wrote back in and copying it to the destination file. sys::Path FinalFilePath = archPath; // Map in the archive we just wrote. { OwningPtr<MemoryBuffer> arch; if (error_code ec = MemoryBuffer::getFile(TmpArchive.c_str(), arch)) { if (ErrMsg) *ErrMsg = ec.message(); return true; } const char* base = arch->getBufferStart(); // Open another temporary file in order to avoid invalidating the // mmapped data if (FinalFilePath.createTemporaryFileOnDisk(ErrMsg)) return true; sys::RemoveFileOnSignal(FinalFilePath); std::ofstream FinalFile(FinalFilePath.c_str(), io_mode); if (!FinalFile.is_open() || FinalFile.bad()) { TmpArchive.eraseFromDisk(); if (ErrMsg) *ErrMsg = "Error opening archive file: " + FinalFilePath.str(); return true; } // Write the file magic number FinalFile << ARFILE_MAGIC; // If there is a foreign symbol table, put it into the file now. Most // ar(1) implementations require the symbol table to be first but llvm-ar // can deal with it being after a foreign symbol table. This ensures // compatibility with other ar(1) implementations as well as allowing the // archive to store both native .o and LLVM .bc files, both indexed. if (foreignST) { if (writeMember(*foreignST, FinalFile, false, false, ErrMsg)) { FinalFile.close(); TmpArchive.eraseFromDisk(); return true; } } // Put out the LLVM symbol table now. writeSymbolTable(FinalFile); // Copy the temporary file contents being sure to skip the file's magic // number. FinalFile.write(base + sizeof(ARFILE_MAGIC)-1, arch->getBufferSize()-sizeof(ARFILE_MAGIC)+1); // Close up shop FinalFile.close(); } // free arch. // Move the final file over top of TmpArchive if (FinalFilePath.renamePathOnDisk(TmpArchive, ErrMsg)) return true; } // Before we replace the actual archive, we need to forget all the // members, since they point to data in that old archive. We need to do // this because we cannot replace an open file on Windows. cleanUpMemory(); if (TmpArchive.renamePathOnDisk(archPath, ErrMsg)) return true; // Set correct read and write permissions after temporary file is moved // to final destination path. if (archPath.makeReadableOnDisk(ErrMsg)) return true; if (archPath.makeWriteableOnDisk(ErrMsg)) return true; return false; }
void BenchmarkIRParsing() { outs() << "Benchmarking IR parsing...\n"; OwningPtr<MemoryBuffer> FileBuf; error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), FileBuf); if (ec) { report_fatal_error("Could not open input file: " + ec.message()); } size_t BufSize = FileBuf->getBufferSize(); const uint8_t *BufPtr = reinterpret_cast<const uint8_t*>(FileBuf->getBufferStart()); const uint8_t *EndBufPtr = reinterpret_cast<const uint8_t*>(FileBuf->getBufferEnd()); // Since MemoryBuffer may use mmap, make sure to first touch all bytes in the // input buffer to make sure it's actually in memory. volatile uint8_t *Slot = new uint8_t; for (const uint8_t *S = BufPtr; S != EndBufPtr; ++S) { *Slot = *S; } delete Slot; outs() << "Read bitcode into buffer. Size=" << BufSize << "\n"; // Trivial copy into a new buffer with a cascading XOR that simulates // "touching" every byte in the buffer in a simple way. { TimingOperationBlock T("Simple XOR copy", BufSize); volatile uint8_t *OutBuf = new uint8_t[BufSize]; OutBuf[0] = 1; size_t N = 1; // Run over the input buffer from start to end-1; run over the output buffer // from 1 to end. for (const uint8_t *S = BufPtr; S != EndBufPtr - 1; ++S, ++N) { OutBuf[N] = OutBuf[N - 1] ^ *S; } delete[] OutBuf; } // Bitcode parsing without any additional operations. This is the minimum // required to actually extract information from PNaCl bitcode. { TimingOperationBlock T("Bitcode block parsing", BufSize); NaClBitcodeHeader Header; if (Header.Read(BufPtr, EndBufPtr)) { report_fatal_error("Invalid PNaCl bitcode header"); } if (!Header.IsSupported()) { errs() << "Warning: " << Header.Unsupported() << "\n"; } if (!Header.IsReadable()) { report_fatal_error("Bitcode file is not readable"); } NaClBitstreamReader StreamFile(BufPtr, EndBufPtr); NaClBitstreamCursor Stream(StreamFile); StreamFile.CollectBlockInfoNames(); DummyBitcodeParser Parser(Stream); while (!Stream.AtEndOfStream()) { if (Parser.Parse()) { report_fatal_error("Parsing failed"); } } } // Actual LLVM IR parsing and formation from the bitcode { TimingOperationBlock T("LLVM IR parsing", BufSize); SMDiagnostic Err; Module *M = NaClParseIRFile(InputFilename, PNaClFormat, Err, getGlobalContext()); if (!M) { report_fatal_error("Unable to NaClParseIRFile"); } } }