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;
}
예제 #2
0
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;
}
예제 #3
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;
}
예제 #4
0
// 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;
}
예제 #5
0
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;
}
예제 #6
0
// 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;
}
예제 #7
0
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;
}
예제 #8
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;
}
예제 #9
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;
}
예제 #10
0
// 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");
    }
  }
}