diff options
Diffstat (limited to 'contrib/llvm/tools/llvm-ar/llvm-ar.cpp')
-rw-r--r-- | contrib/llvm/tools/llvm-ar/llvm-ar.cpp | 334 |
1 files changed, 7 insertions, 327 deletions
diff --git a/contrib/llvm/tools/llvm-ar/llvm-ar.cpp b/contrib/llvm/tools/llvm-ar/llvm-ar.cpp index f72762a..1f55e8a 100644 --- a/contrib/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/contrib/llvm/tools/llvm-ar/llvm-ar.cpp @@ -16,6 +16,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Errc.h" @@ -24,6 +25,7 @@ #include "llvm/Support/LineIterator.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" @@ -44,16 +46,9 @@ using namespace llvm; // The name this program was invoked as. static StringRef ToolName; -static const char *TemporaryOutput; -static int TmpArchiveFD = -1; - // Show the error message and exit. LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { outs() << ToolName << ": " << Error << ".\n"; - if (TmpArchiveFD != -1) - close(TmpArchiveFD); - if (TemporaryOutput) - sys::fs::remove(TemporaryOutput); exit(1); } @@ -92,7 +87,6 @@ static cl::extrahelp MoreHelp( " [a] - put file(s) after [relpos]\n" " [b] - put file(s) before [relpos] (same as [i])\n" " [i] - put file(s) before [relpos] (same as [b])\n" - " [N] - use instance [count] of name\n" " [o] - preserve original dates\n" " [s] - create an archive index (cf. ranlib)\n" " [S] - do not build a symbol table\n" @@ -405,70 +399,6 @@ static void performReadOperation(ArchiveOperation Operation, } } -namespace { -class NewArchiveIterator { - bool IsNewMember; - StringRef Name; - - object::Archive::child_iterator OldI; - - StringRef NewFilename; - -public: - NewArchiveIterator(object::Archive::child_iterator I, StringRef Name); - NewArchiveIterator(StringRef I, StringRef Name); - NewArchiveIterator(); - bool isNewMember() const; - StringRef getName() const; - - object::Archive::child_iterator getOld() const; - - StringRef getNew() const; - int getFD(sys::fs::file_status &NewStatus) const; - const sys::fs::file_status &getStatus() const; -}; -} - -NewArchiveIterator::NewArchiveIterator() {} - -NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I, - StringRef Name) - : IsNewMember(false), Name(Name), OldI(I) {} - -NewArchiveIterator::NewArchiveIterator(StringRef NewFilename, StringRef Name) - : IsNewMember(true), Name(Name), NewFilename(NewFilename) {} - -StringRef NewArchiveIterator::getName() const { return Name; } - -bool NewArchiveIterator::isNewMember() const { return IsNewMember; } - -object::Archive::child_iterator NewArchiveIterator::getOld() const { - assert(!IsNewMember); - return OldI; -} - -StringRef NewArchiveIterator::getNew() const { - assert(IsNewMember); - return NewFilename; -} - -int NewArchiveIterator::getFD(sys::fs::file_status &NewStatus) const { - assert(IsNewMember); - int NewFD; - failIfError(sys::fs::openFileForRead(NewFilename, NewFD), NewFilename); - assert(NewFD != -1); - - failIfError(sys::fs::status(NewFD, NewStatus), NewFilename); - - // Opening a directory doesn't make sense. Let it fail. - // Linux cannot open directories with open(2), although - // cygwin and *bsd can. - if (NewStatus.type() == sys::fs::file_type::directory_file) - failIfError(make_error_code(errc::is_a_directory), NewFilename); - - return NewFD; -} - template <typename T> void addMember(std::vector<NewArchiveIterator> &Members, T I, StringRef Name, int Pos = -1) { @@ -605,269 +535,19 @@ computeNewArchiveMembers(ArchiveOperation Operation, return Ret; } -template <typename T> -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) { - unsigned Remaining = Size - SizeSoFar; - for (unsigned I = 0; I < Remaining; ++I) - OS << ' '; - } 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 print32BE(raw_fd_ostream &Out, unsigned Val) { - for (int I = 3; I >= 0; --I) { - char V = (Val >> (8 * I)) & 0xff; - Out << V; - } -} - -static void printRestOfMemberHeader(raw_fd_ostream &Out, - const sys::TimeValue &ModTime, unsigned UID, - unsigned GID, unsigned Perms, - unsigned Size) { - printWithSpacePadding(Out, ModTime.toEpochTime(), 12); - printWithSpacePadding(Out, UID, 6, true); - printWithSpacePadding(Out, GID, 6, true); - printWithSpacePadding(Out, format("%o", Perms), 8); - printWithSpacePadding(Out, Size, 10); - Out << "`\n"; -} - -static void printMemberHeader(raw_fd_ostream &Out, StringRef Name, - const sys::TimeValue &ModTime, unsigned UID, - unsigned GID, unsigned Perms, unsigned Size) { - printWithSpacePadding(Out, Twine(Name) + "/", 16); - printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); -} - -static void printMemberHeader(raw_fd_ostream &Out, unsigned NameOffset, - const sys::TimeValue &ModTime, unsigned UID, - unsigned GID, unsigned Perms, unsigned Size) { - Out << '/'; - printWithSpacePadding(Out, NameOffset, 15); - printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); -} - -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); -} - -// Returns the offset of the first reference to a member offset. -static unsigned writeSymbolTable(raw_fd_ostream &Out, - ArrayRef<NewArchiveIterator> Members, - ArrayRef<MemoryBufferRef> Buffers, - std::vector<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) { - MemoryBufferRef 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(MemberNum); - print32BE(Out, 0); - } - } - Out << NameOS.str(); - - if (StartOffset == 0) - return 0; - - 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); - return StartOffset + 4; -} - -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<unsigned> MemberOffsetRefs; - - std::vector<std::unique_ptr<MemoryBuffer>> Buffers; - std::vector<MemoryBufferRef> Members; - std::vector<sys::fs::file_status> NewMemberStatus; - - for (unsigned I = 0, N = NewMembers.size(); I < N; ++I) { - NewArchiveIterator &Member = NewMembers[I]; - MemoryBufferRef MemberRef; - - if (Member.isNewMember()) { - StringRef Filename = Member.getNew(); - NewMemberStatus.resize(NewMemberStatus.size() + 1); - sys::fs::file_status &Status = NewMemberStatus.back(); - int FD = Member.getFD(Status); - ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr = - MemoryBuffer::getOpenFile(FD, Filename, Status.getSize(), false); - failIfError(MemberBufferOrErr.getError(), Filename); - if (close(FD) != 0) - fail("Could not close file"); - 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); - } - - unsigned MemberReferenceOffset = 0; - if (Symtab) { - MemberReferenceOffset = - writeSymbolTable(Out, NewMembers, Members, MemberOffsetRefs); - } - - std::vector<unsigned> StringMapIndexes; - writeStringTable(Out, NewMembers, StringMapIndexes); - - unsigned MemberNum = 0; - unsigned LongNameMemberNum = 0; - unsigned NewMemberNum = 0; - std::vector<unsigned> MemberOffset; - for (std::vector<NewArchiveIterator>::iterator I = NewMembers.begin(), - E = NewMembers.end(); - I != E; ++I, ++MemberNum) { - - unsigned Pos = Out.tell(); - MemberOffset.push_back(Pos); - - MemoryBufferRef File = Members[MemberNum]; - if (I->isNewMember()) { - StringRef FileName = I->getNew(); - const sys::fs::file_status &Status = NewMemberStatus[NewMemberNum]; - NewMemberNum++; - - 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'; - } - - if (MemberReferenceOffset) { - Out.seek(MemberReferenceOffset); - for (unsigned MemberNum : MemberOffsetRefs) - print32BE(Out, MemberOffset[MemberNum]); - } - - Output.keep(); - Out.close(); - sys::fs::rename(TemporaryOutput, ArchiveName); - TemporaryOutput = nullptr; -} - static void performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, std::vector<NewArchiveIterator> *NewMembersP) { if (NewMembersP) { - performWriteOperation(Operation, OldArchive, *NewMembersP); + std::pair<StringRef, std::error_code> Result = + writeArchive(ArchiveName, *NewMembersP, Symtab); + failIfError(Result.second, Result.first); return; } std::vector<NewArchiveIterator> NewMembers = computeNewArchiveMembers(Operation, OldArchive); - performWriteOperation(Operation, OldArchive, NewMembers); + auto Result = writeArchive(ArchiveName, NewMembers, Symtab); + failIfError(Result.second, Result.first); } static void createSymbolTable(object::Archive *OldArchive) { |