예제 #1
0
bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
  // Open the module file.
  OwningPtr<llvm::MemoryBuffer> Buffer;
  Buffer.reset(FileMgr.getBufferForFile(File));
  if (!Buffer) {
    return true;
  }

  // Initialize the input stream
  llvm::BitstreamReader InStreamFile;
  llvm::BitstreamCursor InStream;
  InStreamFile.init((const unsigned char *)Buffer->getBufferStart(),
                  (const unsigned char *)Buffer->getBufferEnd());
  InStream.init(InStreamFile);

  // Sniff for the signature.
  if (InStream.Read(8) != 'C' ||
      InStream.Read(8) != 'P' ||
      InStream.Read(8) != 'C' ||
      InStream.Read(8) != 'H') {
    return true;
  }

  // Record this module file and assign it a unique ID (if it doesn't have
  // one already).
  unsigned ID = getModuleFileInfo(File).ID;

  // Search for the blocks and records we care about.
  enum { Other, ControlBlock, ASTBlock } State = Other;
  bool Done = false;
  while (!Done) {
    llvm::BitstreamEntry Entry = InStream.advance();
    switch (Entry.Kind) {
    case llvm::BitstreamEntry::Error:
      Done = true;
      continue;

    case llvm::BitstreamEntry::Record:
      // In the 'other' state, just skip the record. We don't care.
      if (State == Other) {
        InStream.skipRecord(Entry.ID);
        continue;
      }

      // Handle potentially-interesting records below.
      break;

    case llvm::BitstreamEntry::SubBlock:
      if (Entry.ID == CONTROL_BLOCK_ID) {
        if (InStream.EnterSubBlock(CONTROL_BLOCK_ID))
          return true;

        // Found the control block.
        State = ControlBlock;
        continue;
      }

      if (Entry.ID == AST_BLOCK_ID) {
        if (InStream.EnterSubBlock(AST_BLOCK_ID))
          return true;

        // Found the AST block.
        State = ASTBlock;
        continue;
      }

      if (InStream.SkipBlock())
        return true;

      continue;

    case llvm::BitstreamEntry::EndBlock:
      State = Other;
      continue;
    }

    // Read the given record.
    SmallVector<uint64_t, 64> Record;
    StringRef Blob;
    unsigned Code = InStream.readRecord(Entry.ID, Record, &Blob);

    // Handle module dependencies.
    if (State == ControlBlock && Code == IMPORTS) {
      // Load each of the imported PCH files.
      unsigned Idx = 0, N = Record.size();
      while (Idx < N) {
        // Read information about the AST file.

        // Skip the imported kind
        ++Idx;

        // Skip the import location
        ++Idx;

        // Retrieve the imported file name.
        unsigned Length = Record[Idx++];
        SmallString<128> ImportedFile(Record.begin() + Idx,
                                      Record.begin() + Idx + Length);
        Idx += Length;

        // Find the imported module file.
        const FileEntry *DependsOnFile = FileMgr.getFile(ImportedFile);
        if (!DependsOnFile)
          return true;

        // Record the dependency.
        unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID;
        getModuleFileInfo(File).Dependencies.push_back(DependsOnID);
      }

      continue;
    }

    // Handle the identifier table
    if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) {
      typedef OnDiskChainedHashTable<InterestingASTIdentifierLookupTrait>
        InterestingIdentifierTable;
      llvm::OwningPtr<InterestingIdentifierTable>
        Table(InterestingIdentifierTable::Create(
                (const unsigned char *)Blob.data() + Record[0],
                (const unsigned char *)Blob.data()));
      for (InterestingIdentifierTable::data_iterator D = Table->data_begin(),
                                                     DEnd = Table->data_end();
           D != DEnd; ++D) {
        std::pair<StringRef, bool> Ident = *D;
        if (Ident.second)
          InterestingIdentifiers[Ident.first].push_back(ID);
        else
          (void)InterestingIdentifiers[Ident.first];
      }
    }

    // FIXME: Handle the selector table.
    
    // We don't care about this record.
  }

  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");
    }
  }
}
예제 #3
0
CXDiagnosticSet DiagLoader::load(const char *file) {
  // Open the diagnostics file.
  std::string ErrStr;
  FileSystemOptions FO;
  FileManager FileMgr(FO);

  OwningPtr<llvm::MemoryBuffer> Buffer;
  Buffer.reset(FileMgr.getBufferForFile(file));

  if (!Buffer) {
    reportBad(CXLoadDiag_CannotLoad, ErrStr);
    return 0;
  }

  llvm::BitstreamReader StreamFile;
  StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
                  (const unsigned char *)Buffer->getBufferEnd());

  llvm::BitstreamCursor Stream;
  Stream.init(StreamFile);

  // Sniff for the signature.
  if (Stream.Read(8) != 'D' ||
      Stream.Read(8) != 'I' ||
      Stream.Read(8) != 'A' ||
      Stream.Read(8) != 'G') {
    reportBad(CXLoadDiag_InvalidFile,
              "Bad header in diagnostics file");
    return 0;
  }

  OwningPtr<CXLoadedDiagnosticSetImpl> Diags(new CXLoadedDiagnosticSetImpl());

  while (true) {
    unsigned BlockID = 0;
    StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level", 
                                               BlockID, true);
    switch (Res) {
      case Read_EndOfStream:
        return (CXDiagnosticSet) Diags.take();
      case Read_Failure:
        return 0;
      case Read_Record:
        llvm_unreachable("Top-level does not have records");
      case Read_BlockEnd:
        continue;
      case Read_BlockBegin:
        break;
    }
    
    switch (BlockID) {
      case serialized_diags::BLOCK_META:
        if (readMetaBlock(Stream))
          return 0;
        break;
      case serialized_diags::BLOCK_DIAG:
        if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get()))
          return 0;
        break;
      default:
        if (!Stream.SkipBlock()) {
          reportInvalidFile("Malformed block at top-level of diagnostics file");
          return 0;
        }
        break;
    }
  }
}
예제 #4
0
error_code MemoryBuffer::getOpenFile(int FD, const char *Filename,
                                     OwningPtr<MemoryBuffer> &result,
                                     uint64_t FileSize, uint64_t MapSize,
                                     int64_t Offset,
                                     bool RequiresNullTerminator) {
  static int PageSize = sys::Process::GetPageSize();

  // Default is to map the full file.
  if (MapSize == uint64_t(-1)) {
    // If we don't know the file size, use fstat to find out.  fstat on an open
    // file descriptor is cheaper than stat on a random path.
    if (FileSize == uint64_t(-1)) {
      struct stat FileInfo;
      // TODO: This should use fstat64 when available.
      if (fstat(FD, &FileInfo) == -1) {
        return error_code(errno, posix_category());
      }
      FileSize = FileInfo.st_size;
    }
    MapSize = FileSize;
  }

  if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator,
                    PageSize)) {
    off_t RealMapOffset = Offset & ~(PageSize - 1);
    off_t Delta = Offset - RealMapOffset;
    size_t RealMapSize = MapSize + Delta;

    if (const char *Pages = sys::Path::MapInFilePages(FD,
                                                      RealMapSize,
                                                      RealMapOffset)) {
      result.reset(GetNamedBuffer<MemoryBufferMMapFile>(
          StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator));

      if (RequiresNullTerminator && result->getBufferEnd()[0] != '\0') {
        // There could be a racing issue that resulted in the file being larger
        // than the FileSize passed by the caller. We already have an assertion
        // for this in MemoryBuffer::init() but have a runtime guarantee that
        // the buffer will be null-terminated here, so do a copy that adds a
        // null-terminator.
        result.reset(MemoryBuffer::getMemBufferCopy(result->getBuffer(),
                                                    Filename));
      }
      return error_code::success();
    }
  }

  MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename);
  if (!Buf) {
    // Failed to create a buffer. The only way it can fail is if
    // new(std::nothrow) returns 0.
    return make_error_code(errc::not_enough_memory);
  }

  OwningPtr<MemoryBuffer> SB(Buf);
  char *BufPtr = const_cast<char*>(SB->getBufferStart());

  size_t BytesLeft = MapSize;
#ifndef HAVE_PREAD
  if (lseek(FD, Offset, SEEK_SET) == -1)
    return error_code(errno, posix_category());
#endif

  while (BytesLeft) {
#ifdef HAVE_PREAD
    ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset);
#else
    ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
#endif
    if (NumRead == -1) {
      if (errno == EINTR)
        continue;
      // Error while reading.
      return error_code(errno, posix_category());
    }
    if (NumRead == 0) {
      assert(0 && "We got inaccurate FileSize value or fstat reported an "
                   "invalid file size.");
      *BufPtr = '\0'; // null-terminate at the actual size.
      break;
    }
    BytesLeft -= NumRead;
    BufPtr += NumRead;
  }

  result.swap(SB);
  return error_code::success();
}