//===- Archive.cpp - ar File Format implementation --------------*- C++ -*-===////// The LLVM Compiler Infrastructure//// This file is distributed under the University of Illinois Open Source// License. See LICENSE.TXT for details.////===----------------------------------------------------------------------===////// This file defines the ArchiveObjectFile class.////===----------------------------------------------------------------------===//#include"llvm/Object/Archive.h"#include"llvm/ADT/APInt.h"#include"llvm/ADT/SmallString.h"#include"llvm/ADT/Twine.h"#include"llvm/Support/Endian.h"#include"llvm/Support/MemoryBuffer.h"usingnamespacellvm;usingnamespaceobject;staticconstchar*constMagic="!<arch>\n";staticconstchar*constThinMagic="!<thin>\n";voidArchive::anchor(){}StringRefArchiveMemberHeader::getName()const{charEndCond;if(Name[0]=='/'||Name[0]=='#')EndCond=' ';elseEndCond='/';llvm::StringRef::size_typeend=llvm::StringRef(Name,sizeof(Name)).find(EndCond);if(end==llvm::StringRef::npos)end=sizeof(Name);assert(end<=sizeof(Name)&&end>0);// Don't include the EndCond if there is one.returnllvm::StringRef(Name,end);}uint32_tArchiveMemberHeader::getSize()const{uint32_tRet;if(llvm::StringRef(Size,sizeof(Size)).rtrim(" ").getAsInteger(10,Ret))llvm_unreachable("Size is not a decimal number.");returnRet;}sys::fs::permsArchiveMemberHeader::getAccessMode()const{unsignedRet;if(StringRef(AccessMode,sizeof(AccessMode)).rtrim(" ").getAsInteger(8,Ret))llvm_unreachable("Access mode is not an octal number.");returnstatic_cast<sys::fs::perms>(Ret);}sys::TimeValueArchiveMemberHeader::getLastModified()const{unsignedSeconds;if(StringRef(LastModified,sizeof(LastModified)).rtrim(" ").getAsInteger(10,Seconds))llvm_unreachable("Last modified time not a decimal number.");sys::TimeValueRet;Ret.fromEpochTime(Seconds);returnRet;}unsignedArchiveMemberHeader::getUID()const{unsignedRet;if(StringRef(UID,sizeof(UID)).rtrim(" ").getAsInteger(10,Ret))llvm_unreachable("UID time not a decimal number.");returnRet;}unsignedArchiveMemberHeader::getGID()const{unsignedRet;if(StringRef(GID,sizeof(GID)).rtrim(" ").getAsInteger(10,Ret))llvm_unreachable("GID time not a decimal number.");returnRet;}Archive::Child::Child(constArchive*Parent,constchar*Start):Parent(Parent){if(!Start)return;constArchiveMemberHeader*Header=reinterpret_cast<constArchiveMemberHeader*>(Start);uint64_tSize=sizeof(ArchiveMemberHeader);if(!Parent->IsThin||Header->getName()=="/"||Header->getName()=="//")Size+=Header->getSize();Data=StringRef(Start,Size);// Setup StartOfFile and PaddingBytes.StartOfFile=sizeof(ArchiveMemberHeader);// Don't include attached name.StringRefName=Header->getName();if(Name.startswith("#1/")){uint64_tNameSize;if(Name.substr(3).rtrim(" ").getAsInteger(10,NameSize))llvm_unreachable("Long name length is not an integer");StartOfFile+=NameSize;}}uint64_tArchive::Child::getSize()const{if(Parent->IsThin)returngetHeader()->getSize();returnData.size()-StartOfFile;}Archive::ChildArchive::Child::getNext()const{size_tSpaceToSkip=Data.size();// If it's odd, add 1 to make it even.if(SpaceToSkip&1)++SpaceToSkip;constchar*NextLoc=Data.data()+SpaceToSkip;// Check to see if this is past the end of the archive.if(NextLoc>=Parent->Data.getBufferEnd())returnChild(Parent,nullptr);returnChild(Parent,NextLoc);}ErrorOr<StringRef>Archive::Child::getName()const{StringRefname=getRawName();// Check if it's a special name.if(name[0]=='/'){if(name.size()==1)// Linker member.returnname;if(name.size()==2&&name[1]=='/')// String table.returnname;// It's a long name.// Get the offset.std::size_toffset;if(name.substr(1).rtrim(" ").getAsInteger(10,offset))llvm_unreachable("Long name offset is not an integer");constchar*addr=Parent->StringTable->Data.begin()+sizeof(ArchiveMemberHeader)+offset;// Verify it.if(Parent->StringTable==Parent->child_end()||addr<(Parent->StringTable->Data.begin()+sizeof(ArchiveMemberHeader))||addr>(Parent->StringTable->Data.begin()+sizeof(ArchiveMemberHeader)+Parent->StringTable->getSize()))returnobject_error::parse_failed;// GNU long file names end with a /.if(Parent->kind()==K_GNU){StringRef::size_typeEnd=StringRef(addr).find('/');returnStringRef(addr,End);}returnStringRef(addr);}elseif(name.startswith("#1/")){uint64_tname_size;if(name.substr(3).rtrim(" ").getAsInteger(10,name_size))llvm_unreachable("Long name length is not an ingeter");returnData.substr(sizeof(ArchiveMemberHeader),name_size).rtrim(StringRef("\0",1));}// It's a simple name.if(name[name.size()-1]=='/')returnname.substr(0,name.size()-1);returnname;}ErrorOr<MemoryBufferRef>Archive::Child::getMemoryBufferRef()const{ErrorOr<StringRef>NameOrErr=getName();if(std::error_codeEC=NameOrErr.getError())returnEC;StringRefName=NameOrErr.get();returnMemoryBufferRef(getBuffer(),Name);}ErrorOr<std::unique_ptr<Binary>>Archive::Child::getAsBinary(LLVMContext*Context)const{ErrorOr<MemoryBufferRef>BuffOrErr=getMemoryBufferRef();if(std::error_codeEC=BuffOrErr.getError())returnEC;returncreateBinary(BuffOrErr.get(),Context);}ErrorOr<std::unique_ptr<Archive>>Archive::create(MemoryBufferRefSource){std::error_codeEC;std::unique_ptr<Archive>Ret(newArchive(Source,EC));if(EC)returnEC;returnstd::move(Ret);}Archive::Archive(MemoryBufferRefSource,std::error_code&ec):Binary(Binary::ID_Archive,Source),SymbolTable(child_end()){StringRefBuffer=Data.getBuffer();// Check for sufficient magic.if(Buffer.startswith(ThinMagic)){IsThin=true;}elseif(Buffer.startswith(Magic)){IsThin=false;}else{ec=object_error::invalid_file_type;return;}// Get the special members.child_iteratori=child_begin(false);child_iteratore=child_end();if(i==e){ec=object_error::success;return;}StringRefName=i->getRawName();// Below is the pattern that is used to figure out the archive format// GNU archive format// First member : / (may exist, if it exists, points to the symbol table )// Second member : // (may exist, if it exists, points to the string table)// Note : The string table is used if the filename exceeds 15 characters// BSD archive format// First member : __.SYMDEF or "__.SYMDEF SORTED" (the symbol table)// There is no string table, if the filename exceeds 15 characters or has a// embedded space, the filename has #1/<size>, The size represents the size// of the filename that needs to be read after the archive header// COFF archive format// First member : /// Second member : / (provides a directory of symbols)// Third member : // (may exist, if it exists, contains the string table)// Note: Microsoft PE/COFF Spec 8.3 says that the third member is present// even if the string table is empty. However, lib.exe does not in fact// seem to create the third member if there's no member whose filename// exceeds 15 characters. So the third member is optional.if(Name=="__.SYMDEF"){Format=K_BSD;SymbolTable=i;++i;FirstRegular=i;ec=object_error::success;return;}if(Name.startswith("#1/")){Format=K_BSD;// We know this is BSD, so getName will work since there is no string table.ErrorOr<StringRef>NameOrErr=i->getName();ec=NameOrErr.getError();if(ec)return;Name=NameOrErr.get();if(Name=="__.SYMDEF SORTED"||Name=="__.SYMDEF"){SymbolTable=i;++i;}FirstRegular=i;return;}if(Name=="/"){SymbolTable=i;++i;if(i==e){ec=object_error::parse_failed;return;}Name=i->getRawName();}if(Name=="//"){Format=K_GNU;StringTable=i;++i;FirstRegular=i;ec=object_error::success;return;}if(Name[0]!='/'){Format=K_GNU;FirstRegular=i;ec=object_error::success;return;}if(Name!="/"){ec=object_error::parse_failed;return;}Format=K_COFF;SymbolTable=i;++i;if(i==e){FirstRegular=i;ec=object_error::success;return;}Name=i->getRawName();if(Name=="//"){StringTable=i;++i;}FirstRegular=i;ec=object_error::success;}Archive::child_iteratorArchive::child_begin(boolSkipInternal)const{if(Data.getBufferSize()==8)// empty archive.returnchild_end();if(SkipInternal)returnFirstRegular;constchar*Loc=Data.getBufferStart()+strlen(Magic);Childc(this,Loc);returnc;}Archive::child_iteratorArchive::child_end()const{returnChild(this,nullptr);}StringRefArchive::Symbol::getName()const{returnParent->SymbolTable->getBuffer().begin()+StringIndex;}ErrorOr<Archive::child_iterator>Archive::Symbol::getMember()const{constchar*Buf=Parent->SymbolTable->getBuffer().begin();constchar*Offsets=Buf+4;uint32_tOffset=0;if(Parent->kind()==K_GNU){Offset=*(reinterpret_cast<constsupport::ubig32_t*>(Offsets)+SymbolIndex);}elseif(Parent->kind()==K_BSD){// The SymbolIndex is an index into the ranlib structs that start at// Offsets (the first uint32_t is the number of bytes of the ranlib// structs). The ranlib structs are a pair of uint32_t's the first// being a string table offset and the second being the offset into// the archive of the member that defines the symbol. Which is what// is needed here.Offset=*(reinterpret_cast<constsupport::ulittle32_t*>(Offsets)+(SymbolIndex*2)+1);}else{uint32_tMemberCount=*reinterpret_cast<constsupport::ulittle32_t*>(Buf);// Skip offsets.Buf+=sizeof(support::ulittle32_t)+(MemberCount*sizeof(support::ulittle32_t));uint32_tSymbolCount=*reinterpret_cast<constsupport::ulittle32_t*>(Buf);if(SymbolIndex>=SymbolCount)returnobject_error::parse_failed;// Skip SymbolCount to get to the indices table.constchar*Indices=Buf+sizeof(support::ulittle32_t);// Get the index of the offset in the file member offset table for this// symbol.uint16_tOffsetIndex=*(reinterpret_cast<constsupport::ulittle16_t*>(Indices)+SymbolIndex);// Subtract 1 since OffsetIndex is 1 based.--OffsetIndex;if(OffsetIndex>=MemberCount)returnobject_error::parse_failed;Offset=*(reinterpret_cast<constsupport::ulittle32_t*>(Offsets)+OffsetIndex);}constchar*Loc=Parent->getData().begin()+Offset;child_iteratorIter(Child(Parent,Loc));returnIter;}Archive::SymbolArchive::Symbol::getNext()const{Symbolt(*this);if(Parent->kind()==K_BSD){// t.StringIndex is an offset from the start of the __.SYMDEF or// "__.SYMDEF SORTED" member into the string table for the ranlib// struct indexed by t.SymbolIndex . To change t.StringIndex to the// offset in the string table for t.SymbolIndex+1 we subtract the// its offset from the start of the string table for t.SymbolIndex// and add the offset of the string table for t.SymbolIndex+1.// The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t// which is the number of bytes of ranlib structs that follow. The ranlib// structs are a pair of uint32_t's the first being a string table offset// and the second being the offset into the archive of the member that// define the symbol. After that the next uint32_t is the byte count of// the string table followed by the string table.constchar*Buf=Parent->SymbolTable->getBuffer().begin();uint32_tRanlibCount=0;RanlibCount=(*reinterpret_cast<constsupport::ulittle32_t*>(Buf))/(sizeof(uint32_t)*2);// If t.SymbolIndex + 1 will be past the count of symbols (the RanlibCount)// don't change the t.StringIndex as we don't want to reference a ranlib// past RanlibCount.if(t.SymbolIndex+1<RanlibCount){constchar*Ranlibs=Buf+4;uint32_tCurRanStrx=0;uint32_tNextRanStrx=0;CurRanStrx=*(reinterpret_cast<constsupport::ulittle32_t*>(Ranlibs)+(t.SymbolIndex*2));NextRanStrx=*(reinterpret_cast<constsupport::ulittle32_t*>(Ranlibs)+((t.SymbolIndex+1)*2));t.StringIndex-=CurRanStrx;t.StringIndex+=NextRanStrx;}}else{// Go to one past next null.t.StringIndex=Parent->SymbolTable->getBuffer().find('\0',t.StringIndex)+1;}++t.SymbolIndex;returnt;}Archive::symbol_iteratorArchive::symbol_begin()const{if(!hasSymbolTable())returnsymbol_iterator(Symbol(this,0,0));constchar*buf=SymbolTable->getBuffer().begin();if(kind()==K_GNU){uint32_tsymbol_count=0;symbol_count=*reinterpret_cast<constsupport::ubig32_t*>(buf);buf+=sizeof(uint32_t)+(symbol_count*(sizeof(uint32_t)));}elseif(kind()==K_BSD){// The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t// which is the number of bytes of ranlib structs that follow. The ranlib// structs are a pair of uint32_t's the first being a string table offset// and the second being the offset into the archive of the member that// define the symbol. After that the next uint32_t is the byte count of// the string table followed by the string table.uint32_tranlib_count=0;ranlib_count=(*reinterpret_cast<constsupport::ulittle32_t*>(buf))/(sizeof(uint32_t)*2);constchar*ranlibs=buf+4;uint32_tran_strx=0;ran_strx=*(reinterpret_cast<constsupport::ulittle32_t*>(ranlibs));buf+=sizeof(uint32_t)+(ranlib_count*(2*(sizeof(uint32_t))));// Skip the byte count of the string table.buf+=sizeof(uint32_t);buf+=ran_strx;}else{uint32_tmember_count=0;uint32_tsymbol_count=0;member_count=*reinterpret_cast<constsupport::ulittle32_t*>(buf);buf+=4+(member_count*4);// Skip offsets.symbol_count=*reinterpret_cast<constsupport::ulittle32_t*>(buf);buf+=4+(symbol_count*2);// Skip indices.}uint32_tstring_start_offset=buf-SymbolTable->getBuffer().begin();returnsymbol_iterator(Symbol(this,0,string_start_offset));}Archive::symbol_iteratorArchive::symbol_end()const{if(!hasSymbolTable())returnsymbol_iterator(Symbol(this,0,0));constchar*buf=SymbolTable->getBuffer().begin();uint32_tsymbol_count=0;if(kind()==K_GNU){symbol_count=*reinterpret_cast<constsupport::ubig32_t*>(buf);}elseif(kind()==K_BSD){symbol_count=(*reinterpret_cast<constsupport::ulittle32_t*>(buf))/(sizeof(uint32_t)*2);}else{uint32_tmember_count=0;member_count=*reinterpret_cast<constsupport::ulittle32_t*>(buf);buf+=4+(member_count*4);// Skip offsets.symbol_count=*reinterpret_cast<constsupport::ulittle32_t*>(buf);}returnsymbol_iterator(Symbol(this,symbol_count,0));}Archive::child_iteratorArchive::findSym(StringRefname)const{Archive::symbol_iteratorbs=symbol_begin();Archive::symbol_iteratores=symbol_end();for(;bs!=es;++bs){StringRefSymName=bs->getName();if(SymName==name){ErrorOr<Archive::child_iterator>ResultOrErr=bs->getMember();// FIXME: Should we really eat the error?if(ResultOrErr.getError())returnchild_end();returnResultOrErr.get();}}returnchild_end();}boolArchive::hasSymbolTable()const{returnSymbolTable!=child_end();}