template <class ELFT> static ELFFile<ELFT> createELFObj(MemoryBufferRef MB) { std::error_code EC; ELFFile<ELFT> F(MB.getBuffer(), EC); if (EC) fatal(EC, "failed to read " + MB.getBufferIdentifier()); return F; }
bool llvm::parseAssemblyInto(MemoryBufferRef F, Module &M, SMDiagnostic &Err) { SourceMgr SM; std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(F, false); SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); return LLParser(F.getBuffer(), SM, Err, &M).Run(); }
ErrorOr<std::unique_ptr<ObjectFile>> ObjectFile::createELFObjectFile(MemoryBufferRef Obj) { std::pair<unsigned char, unsigned char> Ident = getElfArchType(Obj.getBuffer()); std::size_t MaxAlignment = 1ULL << countTrailingZeros(uintptr_t(Obj.getBufferStart())); if (MaxAlignment < 2) return object_error::parse_failed; std::error_code EC; std::unique_ptr<ObjectFile> R; if (Ident.first == ELF::ELFCLASS32) { if (Ident.second == ELF::ELFDATA2LSB) R.reset(new ELFObjectFile<ELFType<support::little, false>>(Obj, EC)); else if (Ident.second == ELF::ELFDATA2MSB) R.reset(new ELFObjectFile<ELFType<support::big, false>>(Obj, EC)); else return object_error::parse_failed; } else if (Ident.first == ELF::ELFCLASS64) { if (Ident.second == ELF::ELFDATA2LSB) R.reset(new ELFObjectFile<ELFType<support::little, true>>(Obj, EC)); else if (Ident.second == ELF::ELFDATA2MSB) R.reset(new ELFObjectFile<ELFType<support::big, true>>(Obj, EC)); else return object_error::parse_failed; } else { return object_error::parse_failed; } if (EC) return EC; return std::move(R); }
void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F, const object::Archive::Symbol Sym) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Sym.getName()); if (WasInserted) { replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType); return; } if (!S->body()->isUndefined()) return; // Weak undefined symbols should not fetch members from archives. If we were // to keep old symbol we would not know that an archive member was available // if a strong undefined symbol shows up afterwards in the link. If a strong // undefined symbol never shows up, this lazy symbol will get to the end of // the link and must be treated as the weak undefined one. We already marked // this symbol as used when we added it to the symbol table, but we also need // to preserve its type. FIXME: Move the Type field to Symbol. if (S->isWeak()) { replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type); return; } MemoryBufferRef MBRef = F->getMember(&Sym); if (!MBRef.getBuffer().empty()) addFile(createObjectFile(MBRef, F->getName())); }
bool llvm::parseAssemblyInto(MemoryBufferRef F, Module &M, SMDiagnostic &Err, SlotMapping *Slots, bool UpgradeDebugInfo) { SourceMgr SM; std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(F); SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); return LLParser(F.getBuffer(), SM, Err, &M, Slots, UpgradeDebugInfo).Run(); }
std::unique_ptr<InputFile> LazyArchive::getFile() { MemoryBufferRef MBRef = File->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (MBRef.getBuffer().empty()) return std::unique_ptr<InputFile>(nullptr); return createObjectFile(MBRef, File->getName()); }
static ELFKind getELFKind(MemoryBufferRef MB) { unsigned char Size; unsigned char Endian; std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB) fatal(MB.getBufferIdentifier() + ": invalid data encoding"); if (Size != ELFCLASS32 && Size != ELFCLASS64) fatal(MB.getBufferIdentifier() + ": invalid file class"); size_t BufSize = MB.getBuffer().size(); if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) || (Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr))) fatal(MB.getBufferIdentifier() + ": file is too short"); if (Size == ELFCLASS32) return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind; return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; }
static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB) { // File type is detected by contents, not by file extension. file_magic Magic = identify_magic(MB.getBuffer()); if (Magic == file_magic::archive) return std::unique_ptr<InputFile>(new ArchiveFile(MB)); if (Magic == file_magic::bitcode) return std::unique_ptr<InputFile>(new BitcodeFile(MB)); if (Config->OutputFile == "") Config->OutputFile = getOutputPath(MB.getBufferIdentifier()); return std::unique_ptr<InputFile>(new ObjectFile<llvm::object::ELF64LE>(MB)); }
ErrorOr<std::unique_ptr<SymbolicFile>> SymbolicFile::createSymbolicFile( MemoryBufferRef Object, sys::fs::file_magic Type, LLVMContext *Context) { StringRef Data = Object.getBuffer(); if (Type == sys::fs::file_magic::unknown) Type = sys::fs::identify_magic(Data); switch (Type) { case sys::fs::file_magic::bitcode: if (Context) return IRObjectFile::create(Object, *Context); // Fallthrough case sys::fs::file_magic::unknown: case sys::fs::file_magic::archive: case sys::fs::file_magic::macho_universal_binary: case sys::fs::file_magic::windows_resource: return object_error::invalid_file_type; case sys::fs::file_magic::elf: case sys::fs::file_magic::elf_executable: case sys::fs::file_magic::elf_shared_object: case sys::fs::file_magic::elf_core: case sys::fs::file_magic::macho_executable: case sys::fs::file_magic::macho_fixed_virtual_memory_shared_lib: case sys::fs::file_magic::macho_core: case sys::fs::file_magic::macho_preload_executable: case sys::fs::file_magic::macho_dynamically_linked_shared_lib: case sys::fs::file_magic::macho_dynamic_linker: case sys::fs::file_magic::macho_bundle: case sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: case sys::fs::file_magic::macho_dsym_companion: case sys::fs::file_magic::macho_kext_bundle: case sys::fs::file_magic::pecoff_executable: return ObjectFile::createObjectFile(Object, Type); case sys::fs::file_magic::coff_import_library: return std::unique_ptr<SymbolicFile>(new COFFImportFile(Object)); case sys::fs::file_magic::elf_relocatable: case sys::fs::file_magic::macho_object: case sys::fs::file_magic::coff_object: { ErrorOr<std::unique_ptr<ObjectFile>> Obj = ObjectFile::createObjectFile(Object, Type); if (!Obj || !Context) return std::move(Obj); ErrorOr<MemoryBufferRef> BCData = IRObjectFile::findBitcodeInObject(*Obj->get()); if (!BCData) return std::move(Obj); return IRObjectFile::create( MemoryBufferRef(BCData->getBuffer(), Object.getBufferIdentifier()), *Context); } } llvm_unreachable("Unexpected Binary File Type"); }
std::vector<StringRef> lld::args::getLines(MemoryBufferRef MB) { SmallVector<StringRef, 0> Arr; MB.getBuffer().split(Arr, '\n'); std::vector<StringRef> Ret; for (StringRef S : Arr) { S = S.trim(); if (!S.empty() && S[0] != '#') Ret.push_back(S); } return Ret; }
std::unique_ptr<InputFile> Lazy::getMember() { MemoryBufferRef MBRef = File->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (MBRef.getBuffer().empty()) return std::unique_ptr<InputFile>(nullptr); file_magic Magic = identify_magic(MBRef.getBuffer()); if (Magic == file_magic::coff_import_library) return std::unique_ptr<InputFile>(new ImportFile(MBRef)); std::unique_ptr<InputFile> Obj; if (Magic == file_magic::coff_object) Obj.reset(new ObjectFile(MBRef)); else if (Magic == file_magic::bitcode) Obj.reset(new BitcodeFile(MBRef)); else error(Twine(File->getName()) + ": unknown file type"); Obj->setParentName(File->getName()); return Obj; }
Optional<MemoryBufferRef> elf::readFile(StringRef Path) { log(Path); auto MBOrErr = MemoryBuffer::getFile(Path); if (auto EC = MBOrErr.getError()) { error("cannot open " + Path + ": " + EC.message()); return None; } std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; MemoryBufferRef MBRef = MB->getMemBufferRef(); make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership if (Tar) Tar->append(relativeToRoot(Path), MBRef.getBuffer()); return MBRef; }
// Split S into linker script tokens. void ScriptParserBase::tokenize(MemoryBufferRef MB) { std::vector<StringRef> Vec; MBs.push_back(MB); StringRef S = MB.getBuffer(); StringRef Begin = S; for (;;) { S = skipSpace(S); if (S.empty()) break; // Quoted token. Note that double-quote characters are parts of a token // because, in a glob match context, only unquoted tokens are interpreted // as glob patterns. Double-quoted tokens are literal patterns in that // context. if (S.startswith("\"")) { size_t E = S.find("\"", 1); if (E == StringRef::npos) { StringRef Filename = MB.getBufferIdentifier(); size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n'); error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote"); return; } Vec.push_back(S.take_front(E + 1)); S = S.substr(E + 1); continue; } // Unquoted token. This is more relaxed than tokens in C-like language, // so that you can write "file-name.cpp" as one bare token, for example. size_t Pos = S.find_first_not_of( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789_.$/\\~=+[]*?-:!<>^"); // A character that cannot start a word (which is usually a // punctuation) forms a single character token. if (Pos == 0) Pos = 1; Vec.push_back(S.substr(0, Pos)); S = S.substr(Pos); } Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end()); }
ErrorOr<MemoryBufferRef> IRObjectFile::findBitcodeInMemBuffer(MemoryBufferRef Object) { sys::fs::file_magic Type = sys::fs::identify_magic(Object.getBuffer()); switch (Type) { case sys::fs::file_magic::bitcode: return Object; case sys::fs::file_magic::elf_relocatable: case sys::fs::file_magic::macho_object: case sys::fs::file_magic::coff_object: { ErrorOr<std::unique_ptr<ObjectFile>> ObjFile = ObjectFile::createObjectFile(Object, Type); if (!ObjFile) return ObjFile.getError(); return findBitcodeInObject(*ObjFile->get()); } default: return object_error::invalid_file_type; } }
static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB) { std::pair<unsigned char, unsigned char> Type = object::getElfArchType(MB.getBuffer()); if (Type.second != ELF::ELFDATA2LSB && Type.second != ELF::ELFDATA2MSB) error("Invalid data encoding"); if (Type.first == ELF::ELFCLASS32) { if (Type.second == ELF::ELFDATA2LSB) return make_unique<ObjectFile<object::ELF32LE>>(MB); return make_unique<ObjectFile<object::ELF32BE>>(MB); } if (Type.first == ELF::ELFCLASS64) { if (Type.second == ELF::ELFDATA2LSB) return make_unique<ObjectFile<object::ELF64LE>>(MB); return make_unique<ObjectFile<object::ELF64BE>>(MB); } error("Invalid file class"); }
Expected<std::unique_ptr<ObjectFile>> ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type) { StringRef Data = Object.getBuffer(); if (Type == file_magic::unknown) Type = identify_magic(Data); switch (Type) { case file_magic::unknown: case file_magic::bitcode: case file_magic::coff_cl_gl_object: case file_magic::archive: case file_magic::macho_universal_binary: case file_magic::windows_resource: case file_magic::omf_archive: return errorCodeToError(object_error::invalid_file_type); case file_magic::elf: case file_magic::elf_relocatable: case file_magic::elf_executable: case file_magic::elf_shared_object: case file_magic::elf_core: return createELFObjectFile(Object); case file_magic::macho_object: case file_magic::macho_executable: case file_magic::macho_fixed_virtual_memory_shared_lib: case file_magic::macho_core: case file_magic::macho_preload_executable: case file_magic::macho_dynamically_linked_shared_lib: case file_magic::macho_dynamic_linker: case file_magic::macho_bundle: case file_magic::macho_dynamically_linked_shared_lib_stub: case file_magic::macho_dsym_companion: case file_magic::macho_kext_bundle: return createMachOObjectFile(Object); case file_magic::coff_object: case file_magic::coff_import_library: case file_magic::pecoff_executable: return createCOFFObjectFile(Object); case file_magic::wasm_object: return createWasmObjectFile(Object); case file_magic::omf_object: return createOMFObjectFile(Object); } llvm_unreachable("Unexpected Object File Type"); }
static std::unique_ptr<InputFile> createELFFile(MemoryBufferRef MB) { unsigned char Size; unsigned char Endian; std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB) fatal("invalid data encoding: " + MB.getBufferIdentifier()); if (Size == ELFCLASS32) { if (Endian == ELFDATA2LSB) return createELFFileAux<T<ELF32LE>>(MB); return createELFFileAux<T<ELF32BE>>(MB); } if (Size == ELFCLASS64) { if (Endian == ELFDATA2LSB) return createELFFileAux<T<ELF64LE>>(MB); return createELFFileAux<T<ELF64BE>>(MB); } fatal("invalid file class: " + MB.getBufferIdentifier()); }
void SymbolTable<ELFT>::addLazyObject(StringRef Name, LazyObjectFile &Obj) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceBody<LazyObject>(S, Name, Obj, SymbolBody::UnknownType); return; } if (!S->body()->isUndefined()) return; // See comment for addLazyArchive above. if (S->isWeak()) { replaceBody<LazyObject>(S, Name, Obj, S->body()->Type); } else { MemoryBufferRef MBRef = Obj.getBuffer(); if (!MBRef.getBuffer().empty()) addFile(createObjectFile(MBRef)); } }
// Returns a buffer pointing to a member file containing a given symbol. std::pair<MemoryBufferRef, uint64_t> ArchiveFile::getMember(const Archive::Symbol *Sym) { Archive::Child C = check(Sym->getMember(), "could not get the member for symbol " + Sym->getName()); if (!Seen.insert(C.getChildOffset()).second) return {MemoryBufferRef(), 0}; MemoryBufferRef Ret = check(C.getMemoryBufferRef(), "could not get the buffer for the member defining symbol " + Sym->getName()); if (C.getParent()->isThin() && Driver->Cpio) Driver->Cpio->append(relativeToRoot(check(C.getFullName())), Ret.getBuffer()); if (C.getParent()->isThin()) return {Ret, 0}; return {Ret, C.getChildOffset()}; }
BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, uint64_t OffsetInArchive) : InputFile(BitcodeKind, MB) { this->ArchiveName = ArchiveName; // Here we pass a new MemoryBufferRef which is identified by ArchiveName // (the fully resolved path of the archive) + member name + offset of the // member in the archive. // ThinLTO uses the MemoryBufferRef identifier to access its internal // data structures and if two archives define two members with the same name, // this causes a collision which result in only one of the objects being // taken into consideration at LTO time (which very likely causes undefined // symbols later in the link stage). MemoryBufferRef MBRef(MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() + utostr(OffsetInArchive))); Obj = check(lto::InputFile::create(MBRef), toString(this)); Triple T(Obj->getTargetTriple()); EKind = getBitcodeELFKind(T); EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T); }
Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer, LLVMContext *Context) { sys::fs::file_magic Type = sys::fs::identify_magic(Buffer.getBuffer()); switch (Type) { case sys::fs::file_magic::archive: return Archive::create(Buffer); case sys::fs::file_magic::elf: case sys::fs::file_magic::elf_relocatable: case sys::fs::file_magic::elf_executable: case sys::fs::file_magic::elf_shared_object: case sys::fs::file_magic::elf_core: case sys::fs::file_magic::macho_object: case sys::fs::file_magic::macho_executable: case sys::fs::file_magic::macho_fixed_virtual_memory_shared_lib: case sys::fs::file_magic::macho_core: case sys::fs::file_magic::macho_preload_executable: case sys::fs::file_magic::macho_dynamically_linked_shared_lib: case sys::fs::file_magic::macho_dynamic_linker: case sys::fs::file_magic::macho_bundle: case sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: case sys::fs::file_magic::macho_dsym_companion: case sys::fs::file_magic::macho_kext_bundle: case sys::fs::file_magic::coff_object: case sys::fs::file_magic::coff_import_library: case sys::fs::file_magic::pecoff_executable: case sys::fs::file_magic::bitcode: return ObjectFile::createSymbolicFile(Buffer, Type, Context); case sys::fs::file_magic::macho_universal_binary: return MachOUniversalBinary::create(Buffer); case sys::fs::file_magic::unknown: case sys::fs::file_magic::coff_cl_gl_object: case sys::fs::file_magic::windows_resource: // Unrecognized object file format. return errorCodeToError(object_error::invalid_file_type); } llvm_unreachable("Unexpected Binary File Type"); }
static Expected<std::vector<unsigned>> getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) { std::vector<unsigned> Ret; // In the scenario when LLVMContext is populated SymbolicFile will contain a // reference to it, thus SymbolicFile should be destroyed first. LLVMContext Context; std::unique_ptr<object::SymbolicFile> Obj; if (identify_magic(Buf.getBuffer()) == file_magic::bitcode) { auto ObjOrErr = object::SymbolicFile::createSymbolicFile( Buf, file_magic::bitcode, &Context); if (!ObjOrErr) { // FIXME: check only for "not an object file" errors. consumeError(ObjOrErr.takeError()); return Ret; } Obj = std::move(*ObjOrErr); } else { auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf); if (!ObjOrErr) { // FIXME: check only for "not an object file" errors. consumeError(ObjOrErr.takeError()); return Ret; } Obj = std::move(*ObjOrErr); } HasObject = true; for (const object::BasicSymbolRef &S : Obj->symbols()) { if (!isArchiveSymbol(S)) continue; Ret.push_back(SymNames.tell()); if (auto EC = S.printName(SymNames)) return errorCodeToError(EC); SymNames << '\0'; } return Ret; }
int SolveInst(const MemoryBufferRef &MB, Solver *S) { InstContext IC; std::string ErrStr; std::vector<ParsedReplacement> Reps; std::vector<ReplacementContext> Contexts; if (InferRHS || ParseLHSOnly) { Reps = ParseReplacementLHSs(IC, MB.getBufferIdentifier(), MB.getBuffer(), Contexts, ErrStr); } else { Reps = ParseReplacements(IC, MB.getBufferIdentifier(), MB.getBuffer(), ErrStr); } if (!ErrStr.empty()) { llvm::errs() << ErrStr << '\n'; return 1; } if (EmitLHSDot) { llvm::outs() << "; emitting DOT for parsed LHS souper IR ...\n"; for (auto &Rep : Reps) { llvm::WriteGraph(llvm::outs(), Rep.Mapping.LHS); } } if (ParseOnly || ParseLHSOnly) { llvm::outs() << "; parsing successful\n"; return 0; } unsigned Index = 0; int Ret = 0; int Success = 0, Fail = 0, Error = 0; for (auto Rep : Reps) { if (InferRHS || ReInferRHS) { int OldCost; if (ReInferRHS) { OldCost = cost(Rep.Mapping.RHS); Rep.Mapping.RHS = 0; } if (std::error_code EC = S->infer(Rep.BPCs, Rep.PCs, Rep.Mapping.LHS, Rep.Mapping.RHS, IC)) { llvm::errs() << EC.message() << '\n'; Ret = 1; ++Error; } if (Rep.Mapping.RHS) { ++Success; if (ReInferRHS) { int NewCost = cost(Rep.Mapping.RHS); int LHSCost = cost(Rep.Mapping.LHS); if (NewCost <= OldCost) llvm::outs() << "; RHS inferred successfully, no cost regression"; else llvm::outs() << "; RHS inferred successfully, but cost regressed"; llvm::outs() << " (Old= " << OldCost << ", New= " << NewCost << ", LHS= " << LHSCost << ")\n"; } else { llvm::outs() << "; RHS inferred successfully\n"; } if (PrintRepl) { PrintReplacement(llvm::outs(), Rep.BPCs, Rep.PCs, Rep.Mapping); } else if (PrintReplSplit) { ReplacementContext Context; PrintReplacementLHS(llvm::outs(), Rep.BPCs, Rep.PCs, Rep.Mapping.LHS, Context); PrintReplacementRHS(llvm::outs(), Rep.Mapping.RHS, Context); } else { ReplacementContext Context; PrintReplacementRHS(llvm::outs(), Rep.Mapping.RHS, ReInferRHS ? Context : Contexts[Index]); } } else { ++Fail; llvm::outs() << "; Failed to infer RHS\n"; if (PrintRepl || PrintReplSplit) { ReplacementContext Context; PrintReplacementLHS(llvm::outs(), Rep.BPCs, Rep.PCs, Rep.Mapping.LHS, Context); } } } else { bool Valid; std::vector<std::pair<Inst *, APInt>> Models; if (std::error_code EC = S->isValid(IC, Rep.BPCs, Rep.PCs, Rep.Mapping, Valid, &Models)) { llvm::errs() << EC.message() << '\n'; Ret = 1; ++Error; } if (Valid) { ++Success; llvm::outs() << "; LGTM\n"; if (PrintRepl) PrintReplacement(llvm::outs(), Rep.BPCs, Rep.PCs, Rep.Mapping); if (PrintReplSplit) { ReplacementContext Context; PrintReplacementLHS(llvm::outs(), Rep.BPCs, Rep.PCs, Rep.Mapping.LHS, Context); PrintReplacementRHS(llvm::outs(), Rep.Mapping.RHS, Context); } } else { ++Fail; llvm::outs() << "Invalid"; if (PrintCounterExample && !Models.empty()) { llvm::outs() << ", e.g.\n\n"; std::sort(Models.begin(), Models.end(), [](const std::pair<Inst *, APInt> &A, const std::pair<Inst *, APInt> &B) { return A.first->Name < B.first->Name; }); for (const auto &M : Models) { llvm::outs() << '%' << M.first->Name << " = " << M.second << '\n'; } } else { llvm::outs() << "\n"; } } } ++Index; if (PrintRepl || PrintReplSplit) llvm::outs() << "\n"; } if ((Success + Fail + Error) > 1) llvm::outs() << "successes = " << Success << ", failures = " << Fail << ", errors = " << Error << "\n"; return Ret; }
static void performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, std::vector<NewArchiveIterator> &NewMembers) { SmallString<128> TmpArchive; failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a", TmpArchiveFD, TmpArchive)); TemporaryOutput = TmpArchive.c_str(); tool_output_file Output(TemporaryOutput, TmpArchiveFD); raw_fd_ostream &Out = Output.os(); Out << "!<arch>\n"; std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs; std::vector<std::unique_ptr<MemoryBuffer>> Buffers; std::vector<MemoryBufferRef> Members; for (unsigned I = 0, N = NewMembers.size(); I < N; ++I) { NewArchiveIterator &Member = NewMembers[I]; MemoryBufferRef MemberRef; if (Member.isNewMember()) { StringRef Filename = Member.getNew(); int FD = Member.getFD(); const sys::fs::file_status &Status = Member.getStatus(); ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr = MemoryBuffer::getOpenFile(FD, Filename, Status.getSize(), false); failIfError(MemberBufferOrErr.getError(), Filename); Buffers.push_back(std::move(MemberBufferOrErr.get())); MemberRef = Buffers.back()->getMemBufferRef(); } else { object::Archive::child_iterator OldMember = Member.getOld(); ErrorOr<MemoryBufferRef> MemberBufferOrErr = OldMember->getMemoryBufferRef(); failIfError(MemberBufferOrErr.getError()); MemberRef = MemberBufferOrErr.get(); } Members.push_back(MemberRef); } if (Symtab) { writeSymbolTable(Out, NewMembers, Members, MemberOffsetRefs); } std::vector<unsigned> StringMapIndexes; writeStringTable(Out, NewMembers, StringMapIndexes); std::vector<std::pair<unsigned, unsigned> >::iterator MemberRefsI = MemberOffsetRefs.begin(); unsigned MemberNum = 0; unsigned LongNameMemberNum = 0; for (std::vector<NewArchiveIterator>::iterator I = NewMembers.begin(), E = NewMembers.end(); I != E; ++I, ++MemberNum) { unsigned Pos = Out.tell(); while (MemberRefsI != MemberOffsetRefs.end() && MemberRefsI->second == MemberNum) { Out.seek(MemberRefsI->first); print32BE(Out, Pos); ++MemberRefsI; } Out.seek(Pos); MemoryBufferRef File = Members[MemberNum]; if (I->isNewMember()) { StringRef FileName = I->getNew(); const sys::fs::file_status &Status = I->getStatus(); StringRef Name = sys::path::filename(FileName); if (Name.size() < 16) printMemberHeader(Out, Name, Status.getLastModificationTime(), Status.getUser(), Status.getGroup(), Status.permissions(), Status.getSize()); else printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], Status.getLastModificationTime(), Status.getUser(), Status.getGroup(), Status.permissions(), Status.getSize()); } else { object::Archive::child_iterator OldMember = I->getOld(); StringRef Name = I->getName(); if (Name.size() < 16) printMemberHeader(Out, Name, OldMember->getLastModified(), OldMember->getUID(), OldMember->getGID(), OldMember->getAccessMode(), OldMember->getSize()); else printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], OldMember->getLastModified(), OldMember->getUID(), OldMember->getGID(), OldMember->getAccessMode(), OldMember->getSize()); } Out << File.getBuffer(); if (Out.tell() % 2) Out << '\n'; } Output.keep(); Out.close(); sys::fs::rename(TemporaryOutput, ArchiveName); TemporaryOutput = nullptr; }
std::unique_ptr<MemoryBuffer> MemoryBuffer::getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator) { return std::unique_ptr<MemoryBuffer>(getMemBuffer( Ref.getBuffer(), Ref.getBufferIdentifier(), RequiresNullTerminator)); }
static bool isBitcode(MemoryBufferRef MB) { using namespace sys::fs; return identify_magic(MB.getBuffer()) == file_magic::bitcode; }
static ELFFile<ELFT> createELFObj(MemoryBufferRef MB) { std::error_code EC; ELFFile<ELFT> F(MB.getBuffer(), EC); check(EC); return F; }
void parseModuleDefs(MemoryBufferRef MB, StringSaver *Alloc) { Parser(MB.getBuffer(), Alloc).parse(); }
std::pair<StringRef, std::error_code> llvm::writeArchive(StringRef ArcName, std::vector<NewArchiveMember> &NewMembers, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr<MemoryBuffer> OldArchiveBuf) { assert((!Thin || Kind == object::Archive::K_GNU) && "Only the gnu format has a thin mode"); SmallString<128> TmpArchive; int TmpArchiveFD; if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a", TmpArchiveFD, TmpArchive)) return std::make_pair(ArcName, EC); tool_output_file Output(TmpArchive, TmpArchiveFD); raw_fd_ostream &Out = Output.os(); if (Thin) Out << "!<thin>\n"; else Out << "!<arch>\n"; std::vector<unsigned> MemberOffsetRefs; std::vector<std::unique_ptr<MemoryBuffer>> Buffers; std::vector<MemoryBufferRef> Members; std::vector<sys::fs::file_status> NewMemberStatus; unsigned MemberReferenceOffset = 0; if (WriteSymtab) { ErrorOr<unsigned> MemberReferenceOffsetOrErr = writeSymbolTable( Out, Kind, NewMembers, MemberOffsetRefs, Deterministic); if (auto EC = MemberReferenceOffsetOrErr.getError()) return std::make_pair(ArcName, EC); MemberReferenceOffset = MemberReferenceOffsetOrErr.get(); } std::vector<unsigned> StringMapIndexes; if (Kind != object::Archive::K_BSD) writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin); std::vector<unsigned>::iterator StringMapIndexIter = StringMapIndexes.begin(); std::vector<unsigned> MemberOffset; for (const NewArchiveMember &M : NewMembers) { MemoryBufferRef File = M.Buf->getMemBufferRef(); unsigned Pos = Out.tell(); MemberOffset.push_back(Pos); printMemberHeader(Out, Kind, Thin, sys::path::filename(M.Buf->getBufferIdentifier()), StringMapIndexIter, M.ModTime, M.UID, M.GID, M.Perms, M.Buf->getBufferSize()); if (!Thin) Out << File.getBuffer(); if (Out.tell() % 2) Out << '\n'; } if (MemberReferenceOffset) { Out.seek(MemberReferenceOffset); for (unsigned MemberNum : MemberOffsetRefs) { if (Kind == object::Archive::K_BSD) Out.seek(Out.tell() + 4); // skip over the string offset print32(Out, Kind, MemberOffset[MemberNum]); } } Output.keep(); Out.close(); // At this point, we no longer need whatever backing memory // was used to generate the NewMembers. On Windows, this buffer // could be a mapped view of the file we want to replace (if // we're updating an existing archive, say). In that case, the // rename would still succeed, but it would leave behind a // temporary file (actually the original file renamed) because // a file cannot be deleted while there's a handle open on it, // only renamed. So by freeing this buffer, this ensures that // the last open handle on the destination file, if any, is // closed before we attempt to rename. OldArchiveBuf.reset(); sys::fs::rename(TmpArchive, ArcName); return std::make_pair("", std::error_code()); }
static Expected<std::vector<MemberData>> computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, object::Archive::Kind Kind, bool Thin, bool Deterministic, ArrayRef<NewArchiveMember> NewMembers) { static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; // This ignores the symbol table, but we only need the value mod 8 and the // symbol table is aligned to be a multiple of 8 bytes uint64_t Pos = 0; std::vector<MemberData> Ret; bool HasObject = false; // Deduplicate long member names in the string table and reuse earlier name // offsets. This especially saves space for COFF Import libraries where all // members have the same name. StringMap<uint64_t> MemberNames; // UniqueTimestamps is a special case to improve debugging on Darwin: // // The Darwin linker does not link debug info into the final // binary. Instead, it emits entries of type N_OSO in in the output // binary's symbol table, containing references to the linked-in // object files. Using that reference, the debugger can read the // debug data directly from the object files. Alternatively, an // invocation of 'dsymutil' will link the debug data from the object // files into a dSYM bundle, which can be loaded by the debugger, // instead of the object files. // // For an object file, the N_OSO entries contain the absolute path // path to the file, and the file's timestamp. For an object // included in an archive, the path is formatted like // "/absolute/path/to/archive.a(member.o)", and the timestamp is the // archive member's timestamp, rather than the archive's timestamp. // // However, this doesn't always uniquely identify an object within // an archive -- an archive file can have multiple entries with the // same filename. (This will happen commonly if the original object // files started in different directories.) The only way they get // distinguished, then, is via the timestamp. But this process is // unable to find the correct object file in the archive when there // are two files of the same name and timestamp. // // Additionally, timestamp==0 is treated specially, and causes the // timestamp to be ignored as a match criteria. // // That will "usually" work out okay when creating an archive not in // deterministic timestamp mode, because the objects will probably // have been created at different timestamps. // // To ameliorate this problem, in deterministic archive mode (which // is the default), on Darwin we will emit a unique non-zero // timestamp for each entry with a duplicated name. This is still // deterministic: the only thing affecting that timestamp is the // order of the files in the resultant archive. // // See also the functions that handle the lookup: // in lldb: ObjectContainerBSDArchive::Archive::FindObject() // in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers(). bool UniqueTimestamps = Deterministic && isDarwin(Kind); std::map<StringRef, unsigned> FilenameCount; if (UniqueTimestamps) { for (const NewArchiveMember &M : NewMembers) FilenameCount[M.MemberName]++; for (auto &Entry : FilenameCount) Entry.second = Entry.second > 1 ? 1 : 0; } for (const NewArchiveMember &M : NewMembers) { std::string Header; raw_string_ostream Out(Header); MemoryBufferRef Buf = M.Buf->getMemBufferRef(); StringRef Data = Thin ? "" : Buf.getBuffer(); // ld64 expects the members to be 8-byte aligned for 64-bit content and at // least 4-byte aligned for 32-bit content. Opt for the larger encoding // uniformly. This matches the behaviour with cctools and ensures that ld64 // is happy with archives that we generate. unsigned MemberPadding = isDarwin(Kind) ? OffsetToAlignment(Data.size(), 8) : 0; unsigned TailPadding = OffsetToAlignment(Data.size() + MemberPadding, 2); StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding); sys::TimePoint<std::chrono::seconds> ModTime; if (UniqueTimestamps) // Increment timestamp for each file of a given name. ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++); else ModTime = M.ModTime; printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M, ModTime, Buf.getBufferSize() + MemberPadding); Out.flush(); Expected<std::vector<unsigned>> Symbols = getSymbols(Buf, SymNames, HasObject); if (auto E = Symbols.takeError()) return std::move(E); Pos += Header.size() + Data.size() + Padding.size(); Ret.push_back({std::move(*Symbols), std::move(Header), Data, Padding}); } // If there are no symbols, emit an empty symbol table, to satisfy Solaris // tools, older versions of which expect a symbol table in a non-empty // archive, regardless of whether there are any symbols in it. if (HasObject && SymNames.tell() == 0) SymNames << '\0' << '\0' << '\0'; return Ret; }