LCOV - code coverage report
Current view: top level - lib/Object - ArchiveWriter.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 239 247 96.8 %
Date: 2018-10-20 13:21:21 Functions: 24 24 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- ArchiveWriter.cpp - ar File Format implementation --------*- C++ -*-===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // This file defines the writeArchive function.
      11             : //
      12             : //===----------------------------------------------------------------------===//
      13             : 
      14             : #include "llvm/Object/ArchiveWriter.h"
      15             : #include "llvm/ADT/ArrayRef.h"
      16             : #include "llvm/ADT/StringRef.h"
      17             : #include "llvm/BinaryFormat/Magic.h"
      18             : #include "llvm/IR/LLVMContext.h"
      19             : #include "llvm/Object/Archive.h"
      20             : #include "llvm/Object/ObjectFile.h"
      21             : #include "llvm/Object/SymbolicFile.h"
      22             : #include "llvm/Support/EndianStream.h"
      23             : #include "llvm/Support/Errc.h"
      24             : #include "llvm/Support/ErrorHandling.h"
      25             : #include "llvm/Support/Format.h"
      26             : #include "llvm/Support/Path.h"
      27             : #include "llvm/Support/ToolOutputFile.h"
      28             : #include "llvm/Support/raw_ostream.h"
      29             : 
      30             : #include <map>
      31             : 
      32             : #if !defined(_MSC_VER) && !defined(__MINGW32__)
      33             : #include <unistd.h>
      34             : #else
      35             : #include <io.h>
      36             : #endif
      37             : 
      38             : using namespace llvm;
      39             : 
      40         659 : NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef)
      41             :     : Buf(MemoryBuffer::getMemBuffer(BufRef, false)),
      42         659 :       MemberName(BufRef.getBufferIdentifier()) {}
      43             : 
      44             : Expected<NewArchiveMember>
      45          74 : NewArchiveMember::getOldMember(const object::Archive::Child &OldMember,
      46             :                                bool Deterministic) {
      47          74 :   Expected<llvm::MemoryBufferRef> BufOrErr = OldMember.getMemoryBufferRef();
      48          74 :   if (!BufOrErr)
      49             :     return BufOrErr.takeError();
      50             : 
      51          74 :   NewArchiveMember M;
      52             :   assert(M.IsNew == false);
      53          74 :   M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
      54          74 :   M.MemberName = M.Buf->getBufferIdentifier();
      55          74 :   if (!Deterministic) {
      56             :     auto ModTimeOrErr = OldMember.getLastModified();
      57           1 :     if (!ModTimeOrErr)
      58             :       return ModTimeOrErr.takeError();
      59           1 :     M.ModTime = ModTimeOrErr.get();
      60             :     Expected<unsigned> UIDOrErr = OldMember.getUID();
      61           1 :     if (!UIDOrErr)
      62             :       return UIDOrErr.takeError();
      63           1 :     M.UID = UIDOrErr.get();
      64             :     Expected<unsigned> GIDOrErr = OldMember.getGID();
      65           1 :     if (!GIDOrErr)
      66             :       return GIDOrErr.takeError();
      67           1 :     M.GID = GIDOrErr.get();
      68             :     Expected<sys::fs::perms> AccessModeOrErr = OldMember.getAccessMode();
      69           1 :     if (!AccessModeOrErr)
      70             :       return AccessModeOrErr.takeError();
      71           1 :     M.Perms = AccessModeOrErr.get();
      72             :   }
      73             :   return std::move(M);
      74             : }
      75             : 
      76         305 : Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName,
      77             :                                                      bool Deterministic) {
      78         305 :   sys::fs::file_status Status;
      79             :   int FD;
      80         305 :   if (auto EC = sys::fs::openFileForRead(FileName, FD))
      81           1 :     return errorCodeToError(EC);
      82             :   assert(FD != -1);
      83             : 
      84         304 :   if (auto EC = sys::fs::status(FD, Status))
      85           0 :     return errorCodeToError(EC);
      86             : 
      87             :   // Opening a directory doesn't make sense. Let it fail.
      88             :   // Linux cannot open directories with open(2), although
      89             :   // cygwin and *bsd can.
      90         304 :   if (Status.type() == sys::fs::file_type::directory_file)
      91           1 :     return errorCodeToError(make_error_code(errc::is_a_directory));
      92             : 
      93             :   ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr =
      94         606 :       MemoryBuffer::getOpenFile(FD, FileName, Status.getSize(), false);
      95         303 :   if (!MemberBufferOrErr)
      96           0 :     return errorCodeToError(MemberBufferOrErr.getError());
      97             : 
      98         303 :   if (close(FD) != 0)
      99           0 :     return errorCodeToError(std::error_code(errno, std::generic_category()));
     100             : 
     101             :   NewArchiveMember M;
     102             :   M.IsNew = true;
     103             :   M.Buf = std::move(*MemberBufferOrErr);
     104         303 :   M.MemberName = M.Buf->getBufferIdentifier();
     105         303 :   if (!Deterministic) {
     106             :     M.ModTime = std::chrono::time_point_cast<std::chrono::seconds>(
     107          20 :         Status.getLastModificationTime());
     108          20 :     M.UID = Status.getUser();
     109          20 :     M.GID = Status.getGroup();
     110          20 :     M.Perms = Status.permissions();
     111             :   }
     112             :   return std::move(M);
     113             : }
     114             : 
     115             : template <typename T>
     116        8646 : static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
     117             :   uint64_t OldPos = OS.tell();
     118        3739 :   OS << Data;
     119        8646 :   unsigned SizeSoFar = OS.tell() - OldPos;
     120             :   assert(SizeSoFar <= Size && "Data doesn't fit in Size");
     121        8646 :   OS.indent(Size - SizeSoFar);
     122        8646 : }
     123         279 : 
     124             : static bool isDarwin(object::Archive::Kind Kind) {
     125         279 :   return Kind == object::Archive::K_DARWIN ||
     126         279 :          Kind == object::Archive::K_DARWIN64;
     127             : }
     128         279 : 
     129         279 : static bool isBSDLike(object::Archive::Kind Kind) {
     130         764 :   switch (Kind) {
     131             :   case object::Archive::K_GNU:
     132         764 :   case object::Archive::K_GNU64:
     133         764 :     return false;
     134             :   case object::Archive::K_BSD:
     135         764 :   case object::Archive::K_DARWIN:
     136         764 :   case object::Archive::K_DARWIN64:
     137         584 :     return true;
     138             :   case object::Archive::K_COFF:
     139             :     break;
     140         584 :   }
     141             :   llvm_unreachable("not supported for writting");
     142         584 : }
     143         584 : 
     144        1348 : template <class T>
     145             : static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
     146        1348 :   support::endian::write(Out, Val,
     147        1348 :                          isBSDLike(Kind) ? support::little : support::big);
     148             : }
     149        1348 : 
     150        1348 : static void printRestOfMemberHeader(
     151        4323 :     raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime,
     152             :     unsigned UID, unsigned GID, unsigned Perms, unsigned Size) {
     153             :   printWithSpacePadding(Out, sys::toTimeT(ModTime), 12);
     154        4323 : 
     155             :   // The format has only 6 chars for uid and gid. Truncate if the provided
     156        4323 :   // values don't fit.
     157        4323 :   printWithSpacePadding(Out, UID % 1000000, 6);
     158        1348 :   printWithSpacePadding(Out, GID % 1000000, 6);
     159             : 
     160        1348 :   printWithSpacePadding(Out, format("%o", Perms), 8);
     161        1348 :   printWithSpacePadding(Out, Size, 10);
     162             :   Out << "`\n";
     163        1348 : }
     164        1348 : 
     165             : static void
     166             : printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name,
     167        1423 :                           const sys::TimePoint<std::chrono::seconds> &ModTime,
     168             :                           unsigned UID, unsigned GID, unsigned Perms,
     169             :                           unsigned Size) {
     170             :   printWithSpacePadding(Out, Twine(Name) + "/", 16);
     171             :   printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
     172         954 : }
     173             : 
     174             : static void
     175             : printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
     176             :                      const sys::TimePoint<std::chrono::seconds> &ModTime,
     177             :                      unsigned UID, unsigned GID, unsigned Perms,
     178             :                      unsigned Size) {
     179             :   uint64_t PosAfterHeader = Pos + 60 + Name.size();
     180             :   // Pad so that even 64 bit object files are aligned.
     181             :   unsigned Pad = OffsetToAlignment(PosAfterHeader, 8);
     182             :   unsigned NameWithPadding = Name.size() + Pad;
     183           0 :   printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16);
     184             :   printRestOfMemberHeader(Out, ModTime, UID, GID, Perms,
     185             :                           NameWithPadding + Size);
     186             :   Out << Name;
     187        4850 :   while (Pad--)
     188        4850 :     Out.write(uint8_t(0));
     189             : }
     190        4850 : 
     191        4838 : static bool useStringTable(bool Thin, StringRef Name) {
     192        4838 :   return Thin || Name.size() >= 16 || Name.contains('/');
     193             : }
     194        4838 : 
     195          12 : // Compute the relative path from From to To.
     196          12 : static std::string computeRelativePath(StringRef From, StringRef To) {
     197             :   if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
     198          12 :     return To;
     199             : 
     200        1348 :   StringRef DirFrom = sys::path::parent_path(From);
     201             :   auto FromI = sys::path::begin(DirFrom);
     202             :   auto ToI = sys::path::begin(To);
     203        1348 :   while (*FromI == *ToI) {
     204             :     ++FromI;
     205             :     ++ToI;
     206             :   }
     207        1348 : 
     208        1348 :   SmallString<128> Relative;
     209             :   for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
     210        1348 :     sys::path::append(Relative, "..");
     211        1348 : 
     212        1348 :   for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
     213        1348 :     sys::path::append(Relative, *ToI);
     214             : 
     215             : #ifdef _WIN32
     216         533 :   // Replace backslashes with slashes so that the path is portable between *nix
     217             :   // and Windows.
     218             :   std::replace(Relative.begin(), Relative.end(), '\\', '/');
     219             : #endif
     220         533 : 
     221         533 :   return Relative.str();
     222         533 : }
     223             : 
     224             : static bool is64BitKind(object::Archive::Kind Kind) {
     225          51 :   switch (Kind) {
     226             :   case object::Archive::K_GNU:
     227             :   case object::Archive::K_BSD:
     228             :   case object::Archive::K_DARWIN:
     229          51 :   case object::Archive::K_COFF:
     230             :     return false;
     231          51 :   case object::Archive::K_DARWIN64:
     232          51 :   case object::Archive::K_GNU64:
     233          51 :     return true;
     234          51 :   }
     235             :   llvm_unreachable("not supported for writting");
     236          51 : }
     237         219 : 
     238         168 : static void addToStringTable(raw_ostream &Out, StringRef ArcName,
     239          51 :                              const NewArchiveMember &M, bool Thin) {
     240             :   StringRef ID = M.Buf->getBufferIdentifier();
     241             :   if (Thin) {
     242        1200 :     if (M.IsNew)
     243             :       Out << computeRelativePath(ArcName, ID);
     244             :     else
     245             :       Out << ID;
     246          25 :   } else
     247          25 :     Out << M.MemberName;
     248             :   Out << "/\n";
     249             : }
     250          10 : 
     251          10 : static void printMemberHeader(raw_ostream &Out, uint64_t Pos,
     252          10 :                               raw_ostream &StringTable,
     253           3 :                               object::Archive::Kind Kind, bool Thin,
     254           3 :                               StringRef ArcName, const NewArchiveMember &M,
     255           3 :                               sys::TimePoint<std::chrono::seconds> ModTime,
     256             :                               unsigned Size) {
     257             : 
     258             :   if (isBSDLike(Kind))
     259          24 :     return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
     260           4 :                                 M.Perms, Size);
     261             :   if (!useStringTable(Thin, M.MemberName))
     262          32 :     return printGNUSmallMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
     263          12 :                                      M.Perms, Size);
     264             :   Out << '/';
     265             :   uint64_t NamePos = StringTable.tell();
     266             :   addToStringTable(StringTable, ArcName, M, Thin);
     267             :   printWithSpacePadding(Out, NamePos, 15);
     268             :   printRestOfMemberHeader(Out, ModTime, M.UID, M.GID, M.Perms, Size);
     269             : }
     270             : 
     271             : namespace {
     272             : struct MemberData {
     273             :   std::vector<unsigned> Symbols;
     274             :   std::string Header;
     275             :   StringRef Data;
     276             :   StringRef Padding;
     277             : };
     278             : } // namespace
     279             : 
     280             : static MemberData computeStringTable(StringRef Names) {
     281             :   unsigned Size = Names.size();
     282             :   unsigned Pad = OffsetToAlignment(Size, 2);
     283             :   std::string Header;
     284             :   raw_string_ostream Out(Header);
     285           0 :   printWithSpacePadding(Out, "//", 48);
     286             :   printWithSpacePadding(Out, Size + Pad, 10);
     287             :   Out << "`\n";
     288         764 :   Out.flush();
     289             :   return {{}, std::move(Header), Names, Pad ? "\n" : ""};
     290         764 : }
     291         764 : 
     292          30 : static sys::TimePoint<std::chrono::seconds> now(bool Deterministic) {
     293          50 :   using namespace std::chrono;
     294             : 
     295           5 :   if (!Deterministic)
     296             :     return time_point_cast<seconds>(system_clock::now());
     297         734 :   return sys::TimePoint<seconds>();
     298         764 : }
     299         764 : 
     300             : static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
     301        1030 :   uint32_t Symflags = S.getFlags();
     302             :   if (Symflags & object::SymbolRef::SF_FormatSpecific)
     303             :     return false;
     304             :   if (!(Symflags & object::SymbolRef::SF_Global))
     305             :     return false;
     306             :   if (Symflags & object::SymbolRef::SF_Undefined)
     307             :     return false;
     308             :   return true;
     309          34 : }
     310          34 : 
     311        1730 : static void printNBits(raw_ostream &Out, object::Archive::Kind Kind,
     312         232 :                        uint64_t Val) {
     313         232 :   if (is64BitKind(Kind))
     314             :     print<uint64_t>(Out, Kind, Val);
     315             :   else
     316         764 :     print<uint32_t>(Out, Kind, Val);
     317         764 : }
     318         764 : 
     319             : static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
     320             :                              bool Deterministic, ArrayRef<MemberData> Members,
     321             :                              StringRef StringTable) {
     322        5008 :   // We don't write a symbol table on an archive with no members -- except on
     323             :   // Darwin, where the linker will abort unless the archive has a symbol table.
     324             :   if (StringTable.empty() && !isDarwin(Kind))
     325             :     return;
     326             : 
     327             :   unsigned NumSyms = 0;
     328             :   for (const MemberData &M : Members)
     329             :     NumSyms += M.Symbols.size();
     330         279 : 
     331         279 :   unsigned Size = 0;
     332         279 :   unsigned OffsetSize = is64BitKind(Kind) ? sizeof(uint64_t) : sizeof(uint32_t);
     333             : 
     334         279 :   Size += OffsetSize; // Number of entries
     335         279 :   if (isBSDLike(Kind))
     336         279 :     Size += NumSyms * OffsetSize * 2; // Table
     337         279 :   else
     338             :     Size += NumSyms * OffsetSize; // Table
     339         279 :   if (isBSDLike(Kind))
     340             :     Size += OffsetSize; // byte count
     341             :   Size += StringTable.size();
     342             :   // ld64 expects the members to be 8-byte aligned for 64-bit content and at
     343             :   // least 4-byte aligned for 32-bit content.  Opt for the larger encoding
     344             :   // uniformly.
     345         318 :   // We do this for all bsd formats because it simplifies aligning members.
     346           7 :   unsigned Alignment = isBSDLike(Kind) ? 8 : 2;
     347             :   unsigned Pad = OffsetToAlignment(Size, Alignment);
     348             :   Size += Pad;
     349             : 
     350       11232 :   if (isBSDLike(Kind)) {
     351       11232 :     const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
     352       11232 :     printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
     353             :                          Size);
     354        8207 :   } else {
     355             :     const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
     356        5807 :     printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
     357        1292 :   }
     358             : 
     359             :   uint64_t Pos = Out.tell() + Size;
     360             : 
     361        4850 :   if (isBSDLike(Kind))
     362             :     printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
     363             :   else
     364          12 :     printNBits(Out, Kind, NumSyms);
     365             : 
     366        4838 :   for (const MemberData &M : Members) {
     367        4850 :     for (unsigned StringOffset : M.Symbols) {
     368             :       if (isBSDLike(Kind))
     369         356 :         printNBits(Out, Kind, StringOffset);
     370             :       printNBits(Out, Kind, Pos); // member offset
     371             :     }
     372             :     Pos += M.Header.size() + M.Data.size() + M.Padding.size();
     373             :   }
     374         356 : 
     375             :   if (isBSDLike(Kind))
     376             :     // byte count of the string table
     377             :     printNBits(Out, Kind, StringTable.size());
     378        1530 :   Out << StringTable;
     379        2424 : 
     380             :   while (Pad--)
     381             :     Out.write(uint8_t(0));
     382             : }
     383             : 
     384             : static Expected<std::vector<unsigned>>
     385             : getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) {
     386          17 :   std::vector<unsigned> Ret;
     387             : 
     388         301 :   // In the scenario when LLVMContext is populated SymbolicFile will contain a
     389             :   // reference to it, thus SymbolicFile should be destroyed first.
     390          17 :   LLVMContext Context;
     391         318 :   std::unique_ptr<object::SymbolicFile> Obj;
     392             :   if (identify_magic(Buf.getBuffer()) == file_magic::bitcode) {
     393             :     auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
     394             :         Buf, file_magic::bitcode, &Context);
     395             :     if (!ObjOrErr) {
     396             :       // FIXME: check only for "not an object file" errors.
     397         318 :       consumeError(ObjOrErr.takeError());
     398         318 :       return Ret;
     399             :     }
     400             :     Obj = std::move(*ObjOrErr);
     401             :   } else {
     402          17 :     auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
     403             :     if (!ObjOrErr) {
     404             :       // FIXME: check only for "not an object file" errors.
     405             :       consumeError(ObjOrErr.takeError());
     406         602 :       return Ret;
     407             :     }
     408             :     Obj = std::move(*ObjOrErr);
     409         318 :   }
     410             : 
     411             :   HasObject = true;
     412          17 :   for (const object::BasicSymbolRef &S : Obj->symbols()) {
     413             :     if (!isArchiveSymbol(S))
     414         301 :       continue;
     415             :     Ret.push_back(SymNames.tell());
     416        1530 :     if (auto EC = S.printName(SymNames))
     417        5714 :       return errorCodeToError(EC);
     418             :     SymNames << '\0';
     419          13 :   }
     420        4502 :   return Ret;
     421             : }
     422        3636 : 
     423             : static Expected<std::vector<MemberData>>
     424             : computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
     425             :                   object::Archive::Kind Kind, bool Thin, StringRef ArcName,
     426             :                   bool Deterministic, ArrayRef<NewArchiveMember> NewMembers) {
     427          17 :   static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
     428         318 : 
     429             :   // This ignores the symbol table, but we only need the value mod 8 and the
     430         455 :   // symbol table is aligned to be a multiple of 8 bytes
     431         137 :   uint64_t Pos = 0;
     432             : 
     433             :   std::vector<MemberData> Ret;
     434             :   bool HasObject = false;
     435        1030 : 
     436             :   // UniqueTimestamps is a special case to improve debugging on Darwin:
     437             :   //
     438             :   // The Darwin linker does not link debug info into the final
     439             :   // binary. Instead, it emits entries of type N_OSO in in the output
     440        2060 :   // binary's symbol table, containing references to the linked-in
     441             :   // object files. Using that reference, the debugger can read the
     442        1030 :   // debug data directly from the object files. Alternatively, an
     443             :   // invocation of 'dsymutil' will link the debug data from the object
     444          29 :   // files into a dSYM bundle, which can be loaded by the debugger,
     445          29 :   // instead of the object files.
     446             :   //
     447           0 :   // For an object file, the N_OSO entries contain the absolute path
     448           0 :   // path to the file, and the file's timestamp. For an object
     449             :   // included in an archive, the path is formatted like
     450             :   // "/absolute/path/to/archive.a(member.o)", and the timestamp is the
     451             :   // archive member's timestamp, rather than the archive's timestamp.
     452        1001 :   //
     453        1001 :   // However, this doesn't always uniquely identify an object within
     454             :   // an archive -- an archive file can have multiple entries with the
     455         190 :   // same filename. (This will happen commonly if the original object
     456          95 :   // files started in different directories.) The only way they get
     457             :   // distinguished, then, is via the timestamp. But this process is
     458             :   // unable to find the correct object file in the archive when there
     459             :   // are two files of the same name and timestamp.
     460             :   //
     461         935 :   // Additionally, timestamp==0 is treated specially, and causes the
     462       12167 :   // timestamp to be ignored as a match criteria.
     463       11232 :   //
     464             :   // That will "usually" work out okay when creating an archive not in
     465        4515 :   // deterministic timestamp mode, because the objects will probably
     466        4515 :   // have been created at different timestamps.
     467           0 :   //
     468             :   // To ameliorate this problem, in deterministic archive mode (which
     469             :   // is the default), on Darwin we will emit a unique non-zero
     470             :   // timestamp for each entry with a duplicated name. This is still
     471             :   // deterministic: the only thing affecting that timestamp is the
     472             :   // order of the files in the resultant archive.
     473             :   //
     474         365 :   // See also the functions that handle the lookup:
     475             :   // in lldb: ObjectContainerBSDArchive::Archive::FindObject()
     476             :   // in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers().
     477             :   bool UniqueTimestamps = Deterministic && isDarwin(Kind);
     478             :   std::map<StringRef, unsigned> FilenameCount;
     479             :   if (UniqueTimestamps) {
     480             :     for (const NewArchiveMember &M : NewMembers)
     481             :       FilenameCount[M.MemberName]++;
     482             :     for (auto &Entry : FilenameCount)
     483         365 :       Entry.second = Entry.second > 1 ? 1 : 0;
     484         365 :   }
     485             : 
     486             :   for (const NewArchiveMember &M : NewMembers) {
     487             :     std::string Header;
     488             :     raw_string_ostream Out(Header);
     489             : 
     490             :     MemoryBufferRef Buf = M.Buf->getMemBufferRef();
     491             :     StringRef Data = Thin ? "" : Buf.getBuffer();
     492             : 
     493             :     // ld64 expects the members to be 8-byte aligned for 64-bit content and at
     494             :     // least 4-byte aligned for 32-bit content.  Opt for the larger encoding
     495             :     // uniformly.  This matches the behaviour with cctools and ensures that ld64
     496             :     // is happy with archives that we generate.
     497             :     unsigned MemberPadding =
     498             :         isDarwin(Kind) ? OffsetToAlignment(Data.size(), 8) : 0;
     499             :     unsigned TailPadding = OffsetToAlignment(Data.size() + MemberPadding, 2);
     500             :     StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding);
     501             : 
     502             :     sys::TimePoint<std::chrono::seconds> ModTime;
     503             :     if (UniqueTimestamps)
     504             :       // Increment timestamp for each file of a given name.
     505             :       ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
     506             :     else
     507             :       ModTime = M.ModTime;
     508             :     printMemberHeader(Out, Pos, StringTable, Kind, Thin, ArcName, M, ModTime,
     509             :                       Buf.getBufferSize() + MemberPadding);
     510             :     Out.flush();
     511             : 
     512             :     Expected<std::vector<unsigned>> Symbols =
     513             :         getSymbols(Buf, SymNames, HasObject);
     514             :     if (auto E = Symbols.takeError())
     515             :       return std::move(E);
     516             : 
     517             :     Pos += Header.size() + Data.size() + Padding.size();
     518             :     Ret.push_back({std::move(*Symbols), std::move(Header), Data, Padding});
     519             :   }
     520             :   // If there are no symbols, emit an empty symbol table, to satisfy Solaris
     521             :   // tools, older versions of which expect a symbol table in a non-empty
     522             :   // archive, regardless of whether there are any symbols in it.
     523             :   if (HasObject && SymNames.tell() == 0)
     524             :     SymNames << '\0' << '\0' << '\0';
     525             :   return Ret;
     526             : }
     527         365 : 
     528             : Error llvm::writeArchive(StringRef ArcName,
     529         365 :                          ArrayRef<NewArchiveMember> NewMembers,
     530          18 :                          bool WriteSymtab, object::Archive::Kind Kind,
     531          10 :                          bool Deterministic, bool Thin,
     532          17 :                          std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
     533          17 :   assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
     534             : 
     535             :   SmallString<0> SymNamesBuf;
     536        1395 :   raw_svector_ostream SymNames(SymNamesBuf);
     537             :   SmallString<0> StringTableBuf;
     538        1030 :   raw_svector_ostream StringTable(StringTableBuf);
     539             : 
     540        1030 :   Expected<std::vector<MemberData>> DataOrErr = computeMemberData(
     541        1030 :       StringTable, SymNames, Kind, Thin, ArcName, Deterministic, NewMembers);
     542             :   if (Error E = DataOrErr.takeError())
     543             :     return E;
     544             :   std::vector<MemberData> &Data = *DataOrErr;
     545             : 
     546             :   if (!StringTableBuf.empty())
     547             :     Data.insert(Data.begin(), computeStringTable(StringTableBuf));
     548        1030 : 
     549        1030 :   // We would like to detect if we need to switch to a 64-bit symbol table.
     550        1030 :   if (WriteSymtab) {
     551             :     uint64_t MaxOffset = 0;
     552             :     uint64_t LastOffset = MaxOffset;
     553        1030 :     for (const auto &M : Data) {
     554             :       // Record the start of the member's offset
     555          10 :       LastOffset = MaxOffset;
     556             :       // Account for the size of each part associated with the member.
     557        1020 :       MaxOffset += M.Header.size() + M.Data.size() + M.Padding.size();
     558        1030 :       // We assume 32-bit symbols to see if 32-bit symbols are possible or not.
     559             :       MaxOffset += M.Symbols.size() * 4;
     560             :     }
     561             : 
     562             :     // The SYM64 format is used when an archive's member offsets are larger than
     563        1030 :     // 32-bits can hold. The need for this shift in format is detected by
     564        1030 :     // writeArchive. To test this we need to generate a file with a member that
     565             :     // has an offset larger than 32-bits but this demands a very slow test. To
     566             :     // speed the test up we use this environment variable to pretend like the
     567        1030 :     // cutoff happens before 32-bits and instead happens at some much smaller
     568        1030 :     // value.
     569             :     const char *Sym64Env = std::getenv("SYM64_THRESHOLD");
     570             :     int Sym64Threshold = 32;
     571             :     if (Sym64Env)
     572             :       StringRef(Sym64Env).getAsInteger(10, Sym64Threshold);
     573         687 : 
     574             :     // If LastOffset isn't going to fit in a 32-bit varible we need to switch
     575             :     // to 64-bit. Note that the file can be larger than 4GB as long as the last
     576             :     // member starts before the 4GB offset.
     577             :     if (LastOffset >= (1ULL << Sym64Threshold)) {
     578         365 :       if (Kind == object::Archive::K_DARWIN)
     579             :         Kind = object::Archive::K_DARWIN64;
     580             :       else
     581             :         Kind = object::Archive::K_GNU64;
     582             :     }
     583             :   }
     584             : 
     585             :   Expected<sys::fs::TempFile> Temp =
     586             :       sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a");
     587             :   if (!Temp)
     588             :     return Temp.takeError();
     589             : 
     590             :   raw_fd_ostream Out(Temp->FD, false);
     591         730 :   if (Thin)
     592         365 :     Out << "!<thin>\n";
     593             :   else
     594             :     Out << "!<arch>\n";
     595             : 
     596         365 :   if (WriteSymtab)
     597         558 :     writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf);
     598             : 
     599             :   for (const MemberData &M : Data)
     600         365 :     Out << M.Header << M.Data << M.Padding;
     601             : 
     602             :   Out.flush();
     603        1645 : 
     604             :   // At this point, we no longer need whatever backing memory
     605             :   // was used to generate the NewMembers. On Windows, this buffer
     606             :   // could be a mapped view of the file we want to replace (if
     607        2578 :   // we're updating an existing archive, say). In that case, the
     608             :   // rename would still succeed, but it would leave behind a
     609        2578 :   // temporary file (actually the original file renamed) because
     610             :   // a file cannot be deleted while there's a handle open on it,
     611             :   // only renamed. So by freeing this buffer, this ensures that
     612             :   // the last open handle on the destination file, if any, is
     613             :   // closed before we attempt to rename.
     614             :   OldArchiveBuf.reset();
     615             : 
     616             :   return Temp->keep(ArcName);
     617             : }

Generated by: LCOV version 1.13