// Write one member out to the file. bool Archive::writeMember( const ArchiveMember& member, raw_fd_ostream& ARFile, std::string* ErrMsg ) { uint64_t filepos = ARFile.tell(); filepos -= 8; // Get the data and its size either from the // member's in-memory data or directly from the file. size_t fSize = member.getSize(); const char *data = (const char*)member.getData(); MemoryBuffer *mFile = 0; if (!data) { ErrorOr<std::unique_ptr<MemoryBuffer> > FileOrErr = MemoryBuffer::getFile(member.getPath()); if (!FileOrErr) { if (ErrMsg) *ErrMsg = FileOrErr.getError().message(); return true; } mFile = FileOrErr.get().release(); data = mFile->getBufferStart(); fSize = mFile->getBufferSize(); } int hdrSize = fSize; // Compute the fields of the header ArchiveMemberHeader Hdr; bool writeLongName = fillHeader(member,Hdr,hdrSize); // Write header to archive file ARFile.write((char*)&Hdr, sizeof(Hdr)); // Write the long filename if its long if (writeLongName) { StringRef Name = sys::path::filename(member.getPath()); ARFile.write(Name.data(), Name.size()); } // Write the (possibly compressed) member's content to the file. ARFile.write(data,fSize); // Make sure the member is an even length if ((ARFile.tell() & 1) == 1) ARFile << ARFILE_PAD; // Close the mapped file if it was opened delete mFile; return false; }
static void printWithSpacePadding(raw_fd_ostream &OS, T Data, unsigned Size, bool MayTruncate = false) { uint64_t OldPos = OS.tell(); OS << Data; unsigned SizeSoFar = OS.tell() - OldPos; if (Size > SizeSoFar) { OS.indent(Size - SizeSoFar); } else if (Size < SizeSoFar) { assert(MayTruncate && "Data doesn't fit in Size"); // Some of the data this is used for (like UID) can be larger than the // space available in the archive format. Truncate in that case. OS.seek(OldPos + Size); } }
static void printBSDMemberHeader(raw_fd_ostream &Out, StringRef Name, const sys::TimeValue &ModTime, unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { uint64_t PosAfterHeader = Out.tell() + 60 + Name.size(); // Pad so that even 64 bit object files are aligned. unsigned Pad = OffsetToAlignment(PosAfterHeader, 8); unsigned NameWithPadding = Name.size() + Pad; printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16); printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, NameWithPadding + Size); Out << Name; assert(PosAfterHeader == Out.tell()); while (Pad--) Out.write(uint8_t(0)); }
void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final { // If the current section has size one, that means that the content we are // interested in is the file itself. Otherwise it is the content of the // section. // // TODO: Instead of copying the input file as is, deactivate the section // that is no longer needed. StringRef Content; CurrentSection->getContents(Content); if (Content.size() < 2) OS.write(Input.getBufferStart(), Input.getBufferSize()); else OS.write(Content.data(), Content.size()); }
/// Write 8-byte integers to a buffer in little-endian format. static void Write8byteIntegerToBuffer(raw_fd_ostream &OS, uint64_t Val) { for (unsigned i = 0; i < 8; ++i) { char Char = (char)(Val & 0xffu); OS.write(&Char, 1); Val >>= 8; } }
void InstrProfWriter::write(raw_fd_ostream &OS) { // Write the hash table. auto TableStart = writeImpl(OS); // Go back and fill in the hash table start. using namespace support; OS.seek(TableStart.first); endian::Writer<little>(OS).write<uint64_t>(TableStart.second); }
void InstrProfWriter::write(raw_fd_ostream &OS) { // Write the hash table. auto TableStart = writeImpl(OS); // Go back and fill in the hash table start. using namespace support; OS.seek(TableStart.first); // Now patch the HashOffset field previously reserved. endian::Writer<little>(OS).write<uint64_t>(TableStart.second); }
static void writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, MutableArrayRef<std::unique_ptr<MemoryBuffer>> Buffers, std::vector<std::pair<unsigned, unsigned>> &MemberOffsetRefs) { unsigned StartOffset = 0; unsigned MemberNum = 0; std::string NameBuf; raw_string_ostream NameOS(NameBuf); unsigned NumSyms = 0; LLVMContext &Context = getGlobalContext(); for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), E = Members.end(); I != E; ++I, ++MemberNum) { std::unique_ptr<MemoryBuffer> &MemberBuffer = Buffers[MemberNum]; ErrorOr<std::unique_ptr<object::SymbolicFile>> ObjOrErr = object::SymbolicFile::createSymbolicFile( MemberBuffer, sys::fs::file_magic::unknown, &Context); if (!ObjOrErr) continue; // FIXME: check only for "not an object file" errors. object::SymbolicFile &Obj = *ObjOrErr.get(); if (!StartOffset) { printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); StartOffset = Out.tell(); print32BE(Out, 0); } for (const object::BasicSymbolRef &S : Obj.symbols()) { uint32_t Symflags = S.getFlags(); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; failIfError(S.printName(NameOS)); NameOS << '\0'; ++NumSyms; MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); print32BE(Out, 0); } MemberBuffer.reset(Obj.releaseBuffer()); } Out << NameOS.str(); if (StartOffset == 0) return; if (Out.tell() % 2) Out << '\0'; unsigned Pos = Out.tell(); Out.seek(StartOffset - 12); printWithSpacePadding(Out, Pos - StartOffset, 10); Out.seek(StartOffset); print32BE(Out, NumSyms); Out.seek(Pos); }
static void writeStringTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, std::vector<unsigned> &StringMapIndexes) { unsigned StartOffset = 0; for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), E = Members.end(); I != E; ++I) { StringRef Name = I->getName(); if (Name.size() < 16) continue; if (StartOffset == 0) { printWithSpacePadding(Out, "//", 58); Out << "`\n"; StartOffset = Out.tell(); } StringMapIndexes.push_back(Out.tell() - StartOffset); Out << Name << "/\n"; } if (StartOffset == 0) return; if (Out.tell() % 2) Out << '\n'; int Pos = Out.tell(); Out.seek(StartOffset - 12); printWithSpacePadding(Out, Pos - StartOffset, 10); Out.seek(Pos); }
static void writeStringTable(raw_fd_ostream &Out, StringRef ArcName, ArrayRef<NewArchiveMember> Members, std::vector<unsigned> &StringMapIndexes, bool Thin) { unsigned StartOffset = 0; for (const NewArchiveMember &M : Members) { StringRef Path = M.Buf->getBufferIdentifier(); StringRef Name = sys::path::filename(Path); if (!useStringTable(Thin, Name)) continue; if (StartOffset == 0) { printWithSpacePadding(Out, "//", 58); Out << "`\n"; StartOffset = Out.tell(); } StringMapIndexes.push_back(Out.tell() - StartOffset); if (Thin) Out << computeRelativePath(ArcName, Path); else Out << Name; Out << "/\n"; } if (StartOffset == 0) return; if (Out.tell() % 2) Out << '\n'; int Pos = Out.tell(); Out.seek(StartOffset - 12); printWithSpacePadding(Out, Pos - StartOffset, 10); Out.seek(Pos); }
// Returns the offset of the first reference to a member offset. static ErrorOr<unsigned> writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, ArrayRef<NewArchiveMember> Members, std::vector<unsigned> &MemberOffsetRefs, bool Deterministic) { unsigned HeaderStartOffset = 0; unsigned BodyStartOffset = 0; SmallString<128> NameBuf; raw_svector_ostream NameOS(NameBuf); LLVMContext Context; for (unsigned MemberNum = 0, N = Members.size(); MemberNum < N; ++MemberNum) { MemoryBufferRef MemberBuffer = Members[MemberNum].Buf->getMemBufferRef(); Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = object::SymbolicFile::createSymbolicFile( MemberBuffer, sys::fs::file_magic::unknown, &Context); if (!ObjOrErr) { // FIXME: check only for "not an object file" errors. consumeError(ObjOrErr.takeError()); continue; } object::SymbolicFile &Obj = *ObjOrErr.get(); if (!HeaderStartOffset) { HeaderStartOffset = Out.tell(); if (Kind == object::Archive::K_GNU) printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0); else printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0); BodyStartOffset = Out.tell(); print32(Out, Kind, 0); // number of entries or bytes } for (const object::BasicSymbolRef &S : Obj.symbols()) { uint32_t Symflags = S.getFlags(); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; unsigned NameOffset = NameOS.tell(); if (auto EC = S.printName(NameOS)) return EC; NameOS << '\0'; MemberOffsetRefs.push_back(MemberNum); if (Kind == object::Archive::K_BSD) print32(Out, Kind, NameOffset); print32(Out, Kind, 0); // member offset } } if (HeaderStartOffset == 0) return 0; StringRef StringTable = NameOS.str(); if (Kind == object::Archive::K_BSD) print32(Out, Kind, StringTable.size()); // byte count of the string table Out << StringTable; // ld64 requires the next member header to start at an offset that is // 4 bytes aligned. unsigned Pad = OffsetToAlignment(Out.tell(), 4); while (Pad--) Out.write(uint8_t(0)); // Patch up the size of the symbol table now that we know how big it is. unsigned Pos = Out.tell(); const unsigned MemberHeaderSize = 60; Out.seek(HeaderStartOffset + 48); // offset of the size field. printWithSpacePadding(Out, Pos - MemberHeaderSize - HeaderStartOffset, 10); // Patch up the number of symbols. Out.seek(BodyStartOffset); unsigned NumSyms = MemberOffsetRefs.size(); if (Kind == object::Archive::K_GNU) print32(Out, Kind, NumSyms); else print32(Out, Kind, NumSyms * 8); Out.seek(Pos); return BodyStartOffset + 4; }
// Headers in tar files must be aligned to 512 byte boundaries. // This function forwards the current file position to the next boundary. static void pad(raw_fd_ostream &OS) { uint64_t Pos = OS.tell(); OS.seek(alignTo(Pos, BlockSize)); }
static void writeSymbolTable( raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) { unsigned StartOffset = 0; unsigned MemberNum = 0; std::vector<StringRef> SymNames; std::vector<object::ObjectFile *> DeleteIt; for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), E = Members.end(); I != E; ++I, ++MemberNum) { object::ObjectFile *Obj; if (I->isNewMember()) { const char *Filename = I->getNew(); Obj = object::ObjectFile::createObjectFile(Filename); } else { object::Archive::child_iterator OldMember = I->getOld(); OwningPtr<object::Binary> Binary; error_code EC = OldMember->getAsBinary(Binary); if (EC) { // FIXME: check only for "not an object file" errors. Obj = NULL; } else { Obj = dyn_cast<object::ObjectFile>(Binary.get()); if (Obj) Binary.take(); } } if (!Obj) continue; DeleteIt.push_back(Obj); if (!StartOffset) { printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); StartOffset = Out.tell(); print32BE(Out, 0); } error_code Err; for (object::symbol_iterator I = Obj->begin_symbols(), E = Obj->end_symbols(); I != E; I.increment(Err), failIfError(Err)) { uint32_t Symflags; failIfError(I->getFlags(Symflags)); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; StringRef Name; failIfError(I->getName(Name)); SymNames.push_back(Name); MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); print32BE(Out, 0); } } for (std::vector<StringRef>::iterator I = SymNames.begin(), E = SymNames.end(); I != E; ++I) { Out << *I; Out << '\0'; } for (std::vector<object::ObjectFile *>::iterator I = DeleteIt.begin(), E = DeleteIt.end(); I != E; ++I) { object::ObjectFile *O = *I; delete O; } if (StartOffset == 0) return; if (Out.tell() % 2) Out << '\0'; unsigned Pos = Out.tell(); Out.seek(StartOffset - 12); printWithSpacePadding(Out, Pos - StartOffset, 10); Out.seek(StartOffset); print32BE(Out, SymNames.size()); Out.seek(Pos); }
static void writeSymbolTable( raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, ArrayRef<MemoryBuffer *> Buffers, std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) { unsigned StartOffset = 0; unsigned MemberNum = 0; std::string NameBuf; raw_string_ostream NameOS(NameBuf); unsigned NumSyms = 0; std::vector<object::SymbolicFile *> DeleteIt; LLVMContext &Context = getGlobalContext(); for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), E = Members.end(); I != E; ++I, ++MemberNum) { MemoryBuffer *MemberBuffer = Buffers[MemberNum]; ErrorOr<object::SymbolicFile *> ObjOrErr = object::SymbolicFile::createSymbolicFile( MemberBuffer, false, sys::fs::file_magic::unknown, &Context); if (!ObjOrErr) continue; // FIXME: check only for "not an object file" errors. object::SymbolicFile *Obj = ObjOrErr.get(); DeleteIt.push_back(Obj); if (!StartOffset) { printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); StartOffset = Out.tell(); print32BE(Out, 0); } for (object::basic_symbol_iterator I = Obj->symbol_begin(), E = Obj->symbol_end(); I != E; ++I) { uint32_t Symflags = I->getFlags(); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; failIfError(I->printName(NameOS)); NameOS << '\0'; ++NumSyms; MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); print32BE(Out, 0); } } Out << NameOS.str(); for (std::vector<object::SymbolicFile *>::iterator I = DeleteIt.begin(), E = DeleteIt.end(); I != E; ++I) { object::SymbolicFile *O = *I; delete O; } if (StartOffset == 0) return; if (Out.tell() % 2) Out << '\0'; unsigned Pos = Out.tell(); Out.seek(StartOffset - 12); printWithSpacePadding(Out, Pos - StartOffset, 10); Out.seek(StartOffset); print32BE(Out, NumSyms); Out.seek(Pos); }
bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final { assert(NumberOfProcessedInputs <= NumberOfInputs && "Processing more inputs that actually exist!"); assert(HostInputIndex != ~0u && "Host input index not defined."); // If this is not the last output, we don't have to do anything. if (NumberOfProcessedInputs != NumberOfInputs) return false; // Create the bitcode file name to write the resulting code to. Keep it if // save-temps is active. SmallString<128> BitcodeFileName; if (sys::fs::createTemporaryFile("clang-offload-bundler", "bc", BitcodeFileName)) { errs() << "error: unable to create temporary file.\n"; return true; } // Dump the contents of the temporary file if that was requested. if (DumpTemporaryFiles) { errs() << ";\n; Object file bundler IR file.\n;\n"; AuxModule.get()->print(errs(), nullptr, /*ShouldPreserveUseListOrder=*/false, /*IsForDebug=*/true); errs() << '\n'; } // Find clang in order to create the bundle binary. StringRef Dir = sys::path::parent_path(BundlerExecutable); auto ClangBinary = sys::findProgramByName("clang", Dir); if (ClangBinary.getError()) { // Remove bitcode file. sys::fs::remove(BitcodeFileName); errs() << "error: unable to find 'clang' in path.\n"; return true; } // Do the incremental linking. We write to the output file directly. So, we // close it and use the name to pass down to clang. OS.close(); SmallString<128> TargetName = getTriple(TargetNames[HostInputIndex]); std::vector<StringRef> ClangArgs = {"clang", "-r", "-target", TargetName.c_str(), "-o", OutputFileNames.front().c_str(), InputFileNames[HostInputIndex].c_str(), BitcodeFileName.c_str(), "-nostdlib"}; // If the user asked for the commands to be printed out, we do that instead // of executing it. if (PrintExternalCommands) { errs() << "\"" << ClangBinary.get() << "\""; for (StringRef Arg : ClangArgs) errs() << " \"" << Arg << "\""; errs() << "\n"; } else { // Write the bitcode contents to the temporary file. { std::error_code EC; raw_fd_ostream BitcodeFile(BitcodeFileName, EC, sys::fs::F_None); if (EC) { errs() << "error: unable to open temporary file.\n"; return true; } WriteBitcodeToFile(*AuxModule, BitcodeFile); } bool Failed = sys::ExecuteAndWait(ClangBinary.get(), ClangArgs); // Remove bitcode file. sys::fs::remove(BitcodeFileName); if (Failed) { errs() << "error: incremental linking by external tool failed.\n"; return true; } } return false; }
void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final { OS.write(Input.getBufferStart(), Input.getBufferSize()); }
void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final { assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!"); StringRef FC = Input.getBuffer(); OS.write(FC.data() + CurBundleInfo->second.Offset, CurBundleInfo->second.Size); }