master
   1//===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===//
   2//
   3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
   4// See https://llvm.org/LICENSE.txt for license information.
   5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
   6//
   7//===----------------------------------------------------------------------===//
   8//
   9// Builds up (relatively) standard unix archive files (.a) containing LLVM
  10// bitcode or other files.
  11//
  12//===----------------------------------------------------------------------===//
  13
  14#include "llvm/ADT/StringExtras.h"
  15#include "llvm/ADT/StringSwitch.h"
  16#include "llvm/BinaryFormat/Magic.h"
  17#include "llvm/IR/LLVMContext.h"
  18#include "llvm/Object/Archive.h"
  19#include "llvm/Object/ArchiveWriter.h"
  20#include "llvm/Object/SymbolicFile.h"
  21#include "llvm/Support/Chrono.h"
  22#include "llvm/Support/CommandLine.h"
  23#include "llvm/Support/ConvertUTF.h"
  24#include "llvm/Support/Errc.h"
  25#include "llvm/Support/FileSystem.h"
  26#include "llvm/Support/Format.h"
  27#include "llvm/Support/FormatVariadic.h"
  28#include "llvm/Support/LLVMDriver.h"
  29#include "llvm/Support/LineIterator.h"
  30#include "llvm/Support/MemoryBuffer.h"
  31#include "llvm/Support/Path.h"
  32#include "llvm/Support/Process.h"
  33#include "llvm/Support/StringSaver.h"
  34#include "llvm/Support/TargetSelect.h"
  35#include "llvm/Support/ToolOutputFile.h"
  36#include "llvm/Support/WithColor.h"
  37#include "llvm/Support/raw_ostream.h"
  38#include "llvm/TargetParser/Host.h"
  39#include "llvm/TargetParser/Triple.h"
  40#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
  41#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
  42
  43#if !defined(_MSC_VER) && !defined(__MINGW32__)
  44#include <unistd.h>
  45#else
  46#include <io.h>
  47#endif
  48
  49#ifdef _WIN32
  50#include "llvm/Support/Windows/WindowsSupport.h"
  51#endif
  52
  53using namespace llvm;
  54using namespace llvm::object;
  55
  56// The name this program was invoked as.
  57static StringRef ToolName;
  58
  59// The basename of this program.
  60static StringRef Stem;
  61
  62static void printRanLibHelp(StringRef ToolName) {
  63  outs() << "OVERVIEW: LLVM ranlib\n\n"
  64         << "Generate an index for archives\n\n"
  65         << "USAGE: " + ToolName + " archive...\n\n"
  66         << "OPTIONS:\n"
  67         << "  -h --help             - Display available options\n"
  68         << "  -V --version          - Display the version of this program\n"
  69         << "  -D                    - Use zero for timestamps and uids/gids "
  70            "(default)\n"
  71         << "  -U                    - Use actual timestamps and uids/gids\n"
  72         << "  -X{32|64|32_64|any}   - Specify which archive symbol tables "
  73            "should be generated if they do not already exist (AIX OS only)\n";
  74}
  75
  76static void printArHelp(StringRef ToolName) {
  77  const char ArOptions[] =
  78      R"(OPTIONS:
  79  --format              - archive format to create
  80    =default            -   default
  81    =gnu                -   gnu
  82    =darwin             -   darwin
  83    =bsd                -   bsd
  84    =bigarchive         -   big archive (AIX OS)
  85    =coff               -   coff
  86  --plugin=<string>     - ignored for compatibility
  87  -h --help             - display this help and exit
  88  --output              - the directory to extract archive members to
  89  --rsp-quoting         - quoting style for response files
  90    =posix              -   posix
  91    =windows            -   windows
  92  --thin                - create a thin archive
  93  --version             - print the version and exit
  94  -X{32|64|32_64|any}   - object mode (only for AIX OS)
  95  @<file>               - read options from <file>
  96
  97OPERATIONS:
  98  d - delete [files] from the archive
  99  m - move [files] in the archive
 100  p - print contents of [files] found in the archive
 101  q - quick append [files] to the archive
 102  r - replace or insert [files] into the archive
 103  s - act as ranlib
 104  t - display list of files in archive
 105  x - extract [files] from the archive
 106
 107MODIFIERS:
 108  [a] - put [files] after [relpos]
 109  [b] - put [files] before [relpos] (same as [i])
 110  [c] - do not warn if archive had to be created
 111  [D] - use zero for timestamps and uids/gids (default)
 112  [h] - display this help and exit
 113  [i] - put [files] before [relpos] (same as [b])
 114  [l] - ignored for compatibility
 115  [L] - add archive's contents
 116  [N] - use instance [count] of name
 117  [o] - preserve original dates
 118  [O] - display member offsets
 119  [P] - use full names when matching (implied for thin archives)
 120  [s] - create an archive index (cf. ranlib)
 121  [S] - do not build a symbol table
 122  [T] - deprecated, use --thin instead
 123  [u] - update only [files] newer than archive contents
 124  [U] - use actual timestamps and uids/gids
 125  [v] - be verbose about actions taken
 126  [V] - display the version and exit
 127)";
 128
 129  outs() << "OVERVIEW: LLVM Archiver\n\n"
 130         << "USAGE: " + ToolName +
 131                " [options] [-]<operation>[modifiers] [relpos] "
 132                "[count] <archive> [files]\n"
 133         << "       " + ToolName + " -M [< mri-script]\n\n";
 134
 135  outs() << ArOptions;
 136}
 137
 138static void printHelpMessage() {
 139  if (Stem.contains_insensitive("ranlib"))
 140    printRanLibHelp(Stem);
 141  else if (Stem.contains_insensitive("ar"))
 142    printArHelp(Stem);
 143}
 144
 145static unsigned MRILineNumber;
 146static bool ParsingMRIScript;
 147
 148// Show the error plus the usage message, and exit.
 149[[noreturn]] static void badUsage(Twine Error) {
 150  WithColor::error(errs(), ToolName) << Error << "\n";
 151  printHelpMessage();
 152  exit(1);
 153}
 154
 155// Show the error message and exit.
 156[[noreturn]] static void fail(Twine Error) {
 157  if (ParsingMRIScript) {
 158    WithColor::error(errs(), ToolName)
 159        << "script line " << MRILineNumber << ": " << Error << "\n";
 160  } else {
 161    WithColor::error(errs(), ToolName) << Error << "\n";
 162  }
 163  exit(1);
 164}
 165
 166static void failIfError(std::error_code EC, Twine Context = "") {
 167  if (!EC)
 168    return;
 169
 170  std::string ContextStr = Context.str();
 171  if (ContextStr.empty())
 172    fail(EC.message());
 173  fail(Context + ": " + EC.message());
 174}
 175
 176static void failIfError(Error E, Twine Context = "") {
 177  if (!E)
 178    return;
 179
 180  handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) {
 181    std::string ContextStr = Context.str();
 182    if (ContextStr.empty())
 183      fail(EIB.message());
 184    fail(Context + ": " + EIB.message());
 185  });
 186}
 187
 188static void warn(Twine Message) {
 189  WithColor::warning(errs(), ToolName) << Message << "\n";
 190}
 191
 192static SmallVector<const char *, 256> PositionalArgs;
 193
 194static bool MRI;
 195
 196namespace {
 197enum Format { Default, GNU, COFF, BSD, DARWIN, BIGARCHIVE, Unknown };
 198}
 199
 200static Format FormatType = Default;
 201
 202static std::string Options;
 203
 204// This enumeration delineates the kinds of operations on an archive
 205// that are permitted.
 206enum ArchiveOperation {
 207  Print,           ///< Print the contents of the archive
 208  Delete,          ///< Delete the specified members
 209  Move,            ///< Move members to end or as given by {a,b,i} modifiers
 210  QuickAppend,     ///< Quickly append to end of archive
 211  ReplaceOrInsert, ///< Replace or Insert members
 212  DisplayTable,    ///< Display the table of contents
 213  Extract,         ///< Extract files back to file system
 214  CreateSymTab     ///< Create a symbol table in an existing archive
 215};
 216
 217enum class BitModeTy { Bit32, Bit64, Bit32_64, Any, Unknown };
 218
 219static BitModeTy BitMode = BitModeTy::Bit32;
 220
 221// Modifiers to follow operation to vary behavior
 222static bool AddAfter = false;             ///< 'a' modifier
 223static bool AddBefore = false;            ///< 'b' modifier
 224static bool Create = false;               ///< 'c' modifier
 225static bool OriginalDates = false;        ///< 'o' modifier
 226static bool DisplayMemberOffsets = false; ///< 'O' modifier
 227static bool CompareFullPath = false;      ///< 'P' modifier
 228static bool OnlyUpdate = false;           ///< 'u' modifier
 229static bool Verbose = false;              ///< 'v' modifier
 230static SymtabWritingMode Symtab =
 231    SymtabWritingMode::NormalSymtab;      ///< 's' modifier
 232static bool Deterministic = true;         ///< 'D' and 'U' modifiers
 233static bool Thin = false;                 ///< 'T' modifier
 234static bool AddLibrary = false;           ///< 'L' modifier
 235
 236// Relative Positional Argument (for insert/move). This variable holds
 237// the name of the archive member to which the 'a', 'b' or 'i' modifier
 238// refers. Only one of 'a', 'b' or 'i' can be specified so we only need
 239// one variable.
 240static std::string RelPos;
 241
 242// Count parameter for 'N' modifier. This variable specifies which file should
 243// match for extract/delete operations when there are multiple matches. This is
 244// 1-indexed. A value of 0 is invalid, and implies 'N' is not used.
 245static int CountParam = 0;
 246
 247// This variable holds the name of the archive file as given on the
 248// command line.
 249static std::string ArchiveName;
 250
 251// Output directory specified by --output.
 252static std::string OutputDir;
 253
 254static std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
 255static std::vector<std::unique_ptr<object::Archive>> Archives;
 256
 257// This variable holds the list of member files to proecess, as given
 258// on the command line.
 259static std::vector<StringRef> Members;
 260
 261// Static buffer to hold StringRefs.
 262static BumpPtrAllocator Alloc;
 263
 264// Extract the member filename from the command line for the [relpos] argument
 265// associated with a, b, and i modifiers
 266static void getRelPos() {
 267  if (PositionalArgs.empty())
 268    fail("expected [relpos] for 'a', 'b', or 'i' modifier");
 269  RelPos = PositionalArgs[0];
 270  PositionalArgs.erase(PositionalArgs.begin());
 271}
 272
 273// Extract the parameter from the command line for the [count] argument
 274// associated with the N modifier
 275static void getCountParam() {
 276  if (PositionalArgs.empty())
 277    badUsage("expected [count] for 'N' modifier");
 278  auto CountParamArg = StringRef(PositionalArgs[0]);
 279  if (CountParamArg.getAsInteger(10, CountParam))
 280    badUsage("value for [count] must be numeric, got: " + CountParamArg);
 281  if (CountParam < 1)
 282    badUsage("value for [count] must be positive, got: " + CountParamArg);
 283  PositionalArgs.erase(PositionalArgs.begin());
 284}
 285
 286// Get the archive file name from the command line
 287static void getArchive() {
 288  if (PositionalArgs.empty())
 289    badUsage("an archive name must be specified");
 290  ArchiveName = PositionalArgs[0];
 291  PositionalArgs.erase(PositionalArgs.begin());
 292}
 293
 294static object::Archive &readLibrary(const Twine &Library) {
 295  auto BufOrErr = MemoryBuffer::getFile(Library, /*IsText=*/false,
 296                                        /*RequiresNullTerminator=*/false);
 297  failIfError(BufOrErr.getError(), "could not open library " + Library);
 298  ArchiveBuffers.push_back(std::move(*BufOrErr));
 299  auto LibOrErr =
 300      object::Archive::create(ArchiveBuffers.back()->getMemBufferRef());
 301  failIfError(errorToErrorCode(LibOrErr.takeError()),
 302              "could not parse library");
 303  Archives.push_back(std::move(*LibOrErr));
 304  return *Archives.back();
 305}
 306
 307static void runMRIScript();
 308
 309// Parse the command line options as presented and return the operation
 310// specified. Process all modifiers and check to make sure that constraints on
 311// modifier/operation pairs have not been violated.
 312static ArchiveOperation parseCommandLine() {
 313  if (MRI) {
 314    if (!PositionalArgs.empty() || !Options.empty())
 315      badUsage("cannot mix -M and other options");
 316    runMRIScript();
 317  }
 318
 319  // Keep track of number of operations. We can only specify one
 320  // per execution.
 321  unsigned NumOperations = 0;
 322
 323  // Keep track of the number of positional modifiers (a,b,i). Only
 324  // one can be specified.
 325  unsigned NumPositional = 0;
 326
 327  // Keep track of which operation was requested
 328  ArchiveOperation Operation;
 329
 330  bool MaybeJustCreateSymTab = false;
 331
 332  for (unsigned i = 0; i < Options.size(); ++i) {
 333    switch (Options[i]) {
 334    case 'd':
 335      ++NumOperations;
 336      Operation = Delete;
 337      break;
 338    case 'm':
 339      ++NumOperations;
 340      Operation = Move;
 341      break;
 342    case 'p':
 343      ++NumOperations;
 344      Operation = Print;
 345      break;
 346    case 'q':
 347      ++NumOperations;
 348      Operation = QuickAppend;
 349      break;
 350    case 'r':
 351      ++NumOperations;
 352      Operation = ReplaceOrInsert;
 353      break;
 354    case 't':
 355      ++NumOperations;
 356      Operation = DisplayTable;
 357      break;
 358    case 'x':
 359      ++NumOperations;
 360      Operation = Extract;
 361      break;
 362    case 'c':
 363      Create = true;
 364      break;
 365    case 'l': /* accepted but unused */
 366      break;
 367    case 'o':
 368      OriginalDates = true;
 369      break;
 370    case 'O':
 371      DisplayMemberOffsets = true;
 372      break;
 373    case 'P':
 374      CompareFullPath = true;
 375      break;
 376    case 's':
 377      Symtab = SymtabWritingMode::NormalSymtab;
 378      MaybeJustCreateSymTab = true;
 379      break;
 380    case 'S':
 381      Symtab = SymtabWritingMode::NoSymtab;
 382      break;
 383    case 'u':
 384      OnlyUpdate = true;
 385      break;
 386    case 'v':
 387      Verbose = true;
 388      break;
 389    case 'a':
 390      getRelPos();
 391      AddAfter = true;
 392      NumPositional++;
 393      break;
 394    case 'b':
 395      getRelPos();
 396      AddBefore = true;
 397      NumPositional++;
 398      break;
 399    case 'i':
 400      getRelPos();
 401      AddBefore = true;
 402      NumPositional++;
 403      break;
 404    case 'D':
 405      Deterministic = true;
 406      break;
 407    case 'U':
 408      Deterministic = false;
 409      break;
 410    case 'N':
 411      getCountParam();
 412      break;
 413    case 'T':
 414      Thin = true;
 415      break;
 416    case 'L':
 417      AddLibrary = true;
 418      break;
 419    case 'V':
 420      cl::PrintVersionMessage();
 421      exit(0);
 422    case 'h':
 423      printHelpMessage();
 424      exit(0);
 425    default:
 426      badUsage(std::string("unknown option ") + Options[i]);
 427    }
 428  }
 429
 430  // Thin archives store path names, so P should be forced.
 431  if (Thin)
 432    CompareFullPath = true;
 433
 434  // At this point, the next thing on the command line must be
 435  // the archive name.
 436  getArchive();
 437
 438  // Everything on the command line at this point is a member.
 439  Members.assign(PositionalArgs.begin(), PositionalArgs.end());
 440
 441  if (NumOperations == 0 && MaybeJustCreateSymTab) {
 442    NumOperations = 1;
 443    Operation = CreateSymTab;
 444    if (!Members.empty())
 445      badUsage("the 's' operation takes only an archive as argument");
 446  }
 447
 448  // Perform various checks on the operation/modifier specification
 449  // to make sure we are dealing with a legal request.
 450  if (NumOperations == 0)
 451    badUsage("you must specify at least one of the operations");
 452  if (NumOperations > 1)
 453    badUsage("only one operation may be specified");
 454  if (NumPositional > 1)
 455    badUsage("you may only specify one of 'a', 'b', and 'i' modifiers");
 456  if (AddAfter || AddBefore)
 457    if (Operation != Move && Operation != ReplaceOrInsert)
 458      badUsage("the 'a', 'b' and 'i' modifiers can only be specified with "
 459               "the 'm' or 'r' operations");
 460  if (CountParam)
 461    if (Operation != Extract && Operation != Delete)
 462      badUsage("the 'N' modifier can only be specified with the 'x' or 'd' "
 463               "operations");
 464  if (OriginalDates && Operation != Extract)
 465    badUsage("the 'o' modifier is only applicable to the 'x' operation");
 466  if (OnlyUpdate && Operation != ReplaceOrInsert)
 467    badUsage("the 'u' modifier is only applicable to the 'r' operation");
 468  if (AddLibrary && Operation != QuickAppend)
 469    badUsage("the 'L' modifier is only applicable to the 'q' operation");
 470
 471  if (!OutputDir.empty()) {
 472    if (Operation != Extract)
 473      badUsage("--output is only applicable to the 'x' operation");
 474    bool IsDir = false;
 475    // If OutputDir is not a directory, create_directories may still succeed if
 476    // all components of the path prefix are directories. Test is_directory as
 477    // well.
 478    if (!sys::fs::create_directories(OutputDir))
 479      sys::fs::is_directory(OutputDir, IsDir);
 480    if (!IsDir)
 481      fail("'" + OutputDir + "' is not a directory");
 482  }
 483
 484  // Return the parsed operation to the caller
 485  return Operation;
 486}
 487
 488// Implements the 'p' operation. This function traverses the archive
 489// looking for members that match the path list.
 490static void doPrint(StringRef Name, const object::Archive::Child &C) {
 491  if (Verbose)
 492    outs() << "Printing " << Name << "\n";
 493
 494  Expected<StringRef> DataOrErr = C.getBuffer();
 495  failIfError(DataOrErr.takeError());
 496  StringRef Data = *DataOrErr;
 497  outs().write(Data.data(), Data.size());
 498}
 499
 500// Utility function for printing out the file mode when the 't' operation is in
 501// verbose mode.
 502static void printMode(unsigned mode) {
 503  outs() << ((mode & 004) ? "r" : "-");
 504  outs() << ((mode & 002) ? "w" : "-");
 505  outs() << ((mode & 001) ? "x" : "-");
 506}
 507
 508// Implement the 't' operation. This function prints out just
 509// the file names of each of the members. However, if verbose mode is requested
 510// ('v' modifier) then the file type, permission mode, user, group, size, and
 511// modification time are also printed.
 512static void doDisplayTable(StringRef Name, const object::Archive::Child &C) {
 513  if (Verbose) {
 514    Expected<sys::fs::perms> ModeOrErr = C.getAccessMode();
 515    failIfError(ModeOrErr.takeError());
 516    sys::fs::perms Mode = ModeOrErr.get();
 517    printMode((Mode >> 6) & 007);
 518    printMode((Mode >> 3) & 007);
 519    printMode(Mode & 007);
 520    Expected<unsigned> UIDOrErr = C.getUID();
 521    failIfError(UIDOrErr.takeError());
 522    outs() << ' ' << UIDOrErr.get();
 523    Expected<unsigned> GIDOrErr = C.getGID();
 524    failIfError(GIDOrErr.takeError());
 525    outs() << '/' << GIDOrErr.get();
 526    Expected<uint64_t> Size = C.getSize();
 527    failIfError(Size.takeError());
 528    outs() << ' ' << format("%6llu", Size.get());
 529    auto ModTimeOrErr = C.getLastModified();
 530    failIfError(ModTimeOrErr.takeError());
 531    // Note: formatv() only handles the default TimePoint<>, which is in
 532    // nanoseconds.
 533    // TODO: fix format_provider<TimePoint<>> to allow other units.
 534    sys::TimePoint<> ModTimeInNs = ModTimeOrErr.get();
 535    outs() << ' ' << formatv("{0:%b %e %H:%M %Y}", ModTimeInNs);
 536    outs() << ' ';
 537  }
 538
 539  if (C.getParent()->isThin()) {
 540    if (!sys::path::is_absolute(Name)) {
 541      StringRef ParentDir = sys::path::parent_path(ArchiveName);
 542      if (!ParentDir.empty())
 543        outs() << sys::path::convert_to_slash(ParentDir) << '/';
 544    }
 545    outs() << Name;
 546  } else {
 547    outs() << Name;
 548    if (DisplayMemberOffsets)
 549      outs() << " 0x" << utohexstr(C.getDataOffset(), true);
 550  }
 551  outs() << '\n';
 552}
 553
 554static std::string normalizePath(StringRef Path) {
 555  return CompareFullPath ? sys::path::convert_to_slash(Path)
 556                         : std::string(sys::path::filename(Path));
 557}
 558
 559static bool comparePaths(StringRef Path1, StringRef Path2) {
 560// When on Windows this function calls CompareStringOrdinal
 561// as Windows file paths are case-insensitive.
 562// CompareStringOrdinal compares two Unicode strings for
 563// binary equivalence and allows for case insensitivity.
 564#ifdef _WIN32
 565  SmallVector<wchar_t, 128> WPath1, WPath2;
 566  failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path1), WPath1));
 567  failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path2), WPath2));
 568
 569  return CompareStringOrdinal(WPath1.data(), WPath1.size(), WPath2.data(),
 570                              WPath2.size(), true) == CSTR_EQUAL;
 571#else
 572  return normalizePath(Path1) == normalizePath(Path2);
 573#endif
 574}
 575
 576// Implement the 'x' operation. This function extracts files back to the file
 577// system.
 578static void doExtract(StringRef Name, const object::Archive::Child &C) {
 579  // Retain the original mode.
 580  Expected<sys::fs::perms> ModeOrErr = C.getAccessMode();
 581  failIfError(ModeOrErr.takeError());
 582  sys::fs::perms Mode = ModeOrErr.get();
 583
 584  StringRef outputFilePath;
 585  SmallString<128> path;
 586  if (OutputDir.empty()) {
 587    outputFilePath = sys::path::filename(Name);
 588  } else {
 589    sys::path::append(path, OutputDir, sys::path::filename(Name));
 590    outputFilePath = path.str();
 591  }
 592
 593  if (Verbose)
 594    outs() << "x - " << outputFilePath << '\n';
 595
 596  int FD;
 597  failIfError(sys::fs::openFileForWrite(outputFilePath, FD,
 598                                        sys::fs::CD_CreateAlways,
 599                                        sys::fs::OF_None, Mode),
 600              Name);
 601
 602  {
 603    raw_fd_ostream file(FD, false);
 604
 605    // Get the data and its length
 606    Expected<StringRef> BufOrErr = C.getBuffer();
 607    failIfError(BufOrErr.takeError());
 608    StringRef Data = BufOrErr.get();
 609
 610    // Write the data.
 611    file.write(Data.data(), Data.size());
 612  }
 613
 614  // If we're supposed to retain the original modification times, etc. do so
 615  // now.
 616  if (OriginalDates) {
 617    auto ModTimeOrErr = C.getLastModified();
 618    failIfError(ModTimeOrErr.takeError());
 619    failIfError(
 620        sys::fs::setLastAccessAndModificationTime(FD, ModTimeOrErr.get()));
 621  }
 622
 623  if (close(FD))
 624    fail("Could not close the file");
 625}
 626
 627static bool shouldCreateArchive(ArchiveOperation Op) {
 628  switch (Op) {
 629  case Print:
 630  case Delete:
 631  case Move:
 632  case DisplayTable:
 633  case Extract:
 634  case CreateSymTab:
 635    return false;
 636
 637  case QuickAppend:
 638  case ReplaceOrInsert:
 639    return true;
 640  }
 641
 642  llvm_unreachable("Missing entry in covered switch.");
 643}
 644
 645static bool isValidInBitMode(Binary &Bin) {
 646  if (BitMode == BitModeTy::Bit32_64 || BitMode == BitModeTy::Any)
 647    return true;
 648
 649  if (SymbolicFile *SymFile = dyn_cast<SymbolicFile>(&Bin)) {
 650    bool Is64Bit = SymFile->is64Bit();
 651    if ((Is64Bit && (BitMode == BitModeTy::Bit32)) ||
 652        (!Is64Bit && (BitMode == BitModeTy::Bit64)))
 653      return false;
 654  }
 655  // In AIX "ar", non-object files are always considered to have a valid bit
 656  // mode.
 657  return true;
 658}
 659
 660Expected<std::unique_ptr<Binary>> getAsBinary(const NewArchiveMember &NM,
 661                                              LLVMContext *Context) {
 662  auto BinaryOrErr = createBinary(NM.Buf->getMemBufferRef(), Context);
 663  if (BinaryOrErr)
 664    return std::move(*BinaryOrErr);
 665  return BinaryOrErr.takeError();
 666}
 667
 668Expected<std::unique_ptr<Binary>> getAsBinary(const Archive::Child &C,
 669                                              LLVMContext *Context) {
 670  return C.getAsBinary(Context);
 671}
 672
 673template <class A> static bool isValidInBitMode(const A &Member) {
 674  if (object::Archive::getDefaultKind() != object::Archive::K_AIXBIG)
 675    return true;
 676  LLVMContext Context;
 677  Expected<std::unique_ptr<Binary>> BinOrErr = getAsBinary(Member, &Context);
 678  // In AIX "ar", if there is a non-object file member, it is never ignored due
 679  // to the bit mode setting.
 680  if (!BinOrErr) {
 681    consumeError(BinOrErr.takeError());
 682    return true;
 683  }
 684  return isValidInBitMode(*BinOrErr.get());
 685}
 686
 687static void warnInvalidObjectForFileMode(Twine Name) {
 688  warn("'" + Name + "' is not valid with the current object file mode");
 689}
 690
 691static void performReadOperation(ArchiveOperation Operation,
 692                                 object::Archive *OldArchive) {
 693  if (Operation == Extract && OldArchive->isThin())
 694    fail("extracting from a thin archive is not supported");
 695
 696  bool Filter = !Members.empty();
 697  StringMap<int> MemberCount;
 698  {
 699    Error Err = Error::success();
 700    for (auto &C : OldArchive->children(Err)) {
 701      Expected<StringRef> NameOrErr = C.getName();
 702      failIfError(NameOrErr.takeError());
 703      StringRef Name = NameOrErr.get();
 704
 705      // Check whether to ignore this object due to its bitness.
 706      if (!isValidInBitMode(C))
 707        continue;
 708
 709      if (Filter) {
 710        auto I = find_if(Members, [Name](StringRef Path) {
 711          return comparePaths(Name, Path);
 712        });
 713        if (I == Members.end())
 714          continue;
 715        if (CountParam && ++MemberCount[Name] != CountParam)
 716          continue;
 717        Members.erase(I);
 718      }
 719
 720      switch (Operation) {
 721      default:
 722        llvm_unreachable("Not a read operation");
 723      case Print:
 724        doPrint(Name, C);
 725        break;
 726      case DisplayTable:
 727        doDisplayTable(Name, C);
 728        break;
 729      case Extract:
 730        doExtract(Name, C);
 731        break;
 732      }
 733    }
 734    failIfError(std::move(Err));
 735  }
 736
 737  if (Members.empty())
 738    return;
 739  for (StringRef Name : Members)
 740    WithColor::error(errs(), ToolName) << "'" << Name << "' was not found\n";
 741  exit(1);
 742}
 743
 744static void addChildMember(std::vector<NewArchiveMember> &Members,
 745                           const object::Archive::Child &M,
 746                           bool FlattenArchive = false) {
 747  Expected<NewArchiveMember> NMOrErr =
 748      NewArchiveMember::getOldMember(M, Deterministic);
 749  failIfError(NMOrErr.takeError());
 750  // If the child member we're trying to add is thin, use the path relative to
 751  // the archive it's in, so the file resolves correctly.
 752  if (Thin && FlattenArchive) {
 753    StringSaver Saver(Alloc);
 754    Expected<std::string> FileNameOrErr(M.getName());
 755    failIfError(FileNameOrErr.takeError());
 756    if (sys::path::is_absolute(*FileNameOrErr)) {
 757      NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(*FileNameOrErr));
 758    } else {
 759      FileNameOrErr = M.getFullName();
 760      failIfError(FileNameOrErr.takeError());
 761      Expected<std::string> PathOrErr =
 762          computeArchiveRelativePath(ArchiveName, *FileNameOrErr);
 763      NMOrErr->MemberName = Saver.save(
 764          PathOrErr ? *PathOrErr : sys::path::convert_to_slash(*FileNameOrErr));
 765    }
 766  }
 767  if (FlattenArchive &&
 768      identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
 769    Expected<std::string> FileNameOrErr = M.getFullName();
 770    failIfError(FileNameOrErr.takeError());
 771    object::Archive &Lib = readLibrary(*FileNameOrErr);
 772    // When creating thin archives, only flatten if the member is also thin.
 773    if (!Thin || Lib.isThin()) {
 774      Error Err = Error::success();
 775      // Only Thin archives are recursively flattened.
 776      for (auto &Child : Lib.children(Err))
 777        addChildMember(Members, Child, /*FlattenArchive=*/Thin);
 778      failIfError(std::move(Err));
 779      return;
 780    }
 781  }
 782  Members.push_back(std::move(*NMOrErr));
 783}
 784
 785static NewArchiveMember getArchiveMember(StringRef FileName) {
 786  Expected<NewArchiveMember> NMOrErr =
 787      NewArchiveMember::getFile(FileName, Deterministic);
 788  failIfError(NMOrErr.takeError(), FileName);
 789  StringSaver Saver(Alloc);
 790  // For regular archives, use the basename of the object path for the member
 791  // name. For thin archives, use the full relative paths so the file resolves
 792  // correctly.
 793  if (!Thin) {
 794    NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
 795  } else {
 796    if (sys::path::is_absolute(FileName))
 797      NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(FileName));
 798    else {
 799      Expected<std::string> PathOrErr =
 800          computeArchiveRelativePath(ArchiveName, FileName);
 801      NMOrErr->MemberName = Saver.save(
 802          PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName));
 803    }
 804  }
 805  return std::move(*NMOrErr);
 806}
 807
 808static void addMember(std::vector<NewArchiveMember> &Members,
 809                      NewArchiveMember &NM) {
 810  Members.push_back(std::move(NM));
 811}
 812
 813static void addMember(std::vector<NewArchiveMember> &Members,
 814                      StringRef FileName, bool FlattenArchive = false) {
 815  NewArchiveMember NM = getArchiveMember(FileName);
 816  if (!isValidInBitMode(NM)) {
 817    warnInvalidObjectForFileMode(FileName);
 818    return;
 819  }
 820
 821  if (FlattenArchive &&
 822      identify_magic(NM.Buf->getBuffer()) == file_magic::archive) {
 823    object::Archive &Lib = readLibrary(FileName);
 824    // When creating thin archives, only flatten if the member is also thin.
 825    if (!Thin || Lib.isThin()) {
 826      Error Err = Error::success();
 827      // Only Thin archives are recursively flattened.
 828      for (auto &Child : Lib.children(Err))
 829        addChildMember(Members, Child, /*FlattenArchive=*/Thin);
 830      failIfError(std::move(Err));
 831      return;
 832    }
 833  }
 834  Members.push_back(std::move(NM));
 835}
 836
 837enum InsertAction {
 838  IA_AddOldMember,
 839  IA_AddNewMember,
 840  IA_Delete,
 841  IA_MoveOldMember,
 842  IA_MoveNewMember
 843};
 844
 845static InsertAction computeInsertAction(ArchiveOperation Operation,
 846                                        const object::Archive::Child &Member,
 847                                        StringRef Name,
 848                                        std::vector<StringRef>::iterator &Pos,
 849                                        StringMap<int> &MemberCount) {
 850  if (!isValidInBitMode(Member))
 851    return IA_AddOldMember;
 852
 853  if (Operation == QuickAppend || Members.empty())
 854    return IA_AddOldMember;
 855
 856  auto MI = find_if(Members, [Name](StringRef Path) {
 857    if (Thin && !sys::path::is_absolute(Path)) {
 858      Expected<std::string> PathOrErr =
 859          computeArchiveRelativePath(ArchiveName, Path);
 860      return comparePaths(Name, PathOrErr ? *PathOrErr : Path);
 861    } else {
 862      return comparePaths(Name, Path);
 863    }
 864  });
 865
 866  if (MI == Members.end())
 867    return IA_AddOldMember;
 868
 869  Pos = MI;
 870
 871  if (Operation == Delete) {
 872    if (CountParam && ++MemberCount[Name] != CountParam)
 873      return IA_AddOldMember;
 874    return IA_Delete;
 875  }
 876
 877  if (Operation == Move)
 878    return IA_MoveOldMember;
 879
 880  if (Operation == ReplaceOrInsert) {
 881    if (!OnlyUpdate) {
 882      if (RelPos.empty())
 883        return IA_AddNewMember;
 884      return IA_MoveNewMember;
 885    }
 886
 887    // We could try to optimize this to a fstat, but it is not a common
 888    // operation.
 889    sys::fs::file_status Status;
 890    failIfError(sys::fs::status(*MI, Status), *MI);
 891    auto ModTimeOrErr = Member.getLastModified();
 892    failIfError(ModTimeOrErr.takeError());
 893    if (Status.getLastModificationTime() < ModTimeOrErr.get()) {
 894      if (RelPos.empty())
 895        return IA_AddOldMember;
 896      return IA_MoveOldMember;
 897    }
 898
 899    if (RelPos.empty())
 900      return IA_AddNewMember;
 901    return IA_MoveNewMember;
 902  }
 903  llvm_unreachable("No such operation");
 904}
 905
 906// We have to walk this twice and computing it is not trivial, so creating an
 907// explicit std::vector is actually fairly efficient.
 908static std::vector<NewArchiveMember>
 909computeNewArchiveMembers(ArchiveOperation Operation,
 910                         object::Archive *OldArchive) {
 911  std::vector<NewArchiveMember> Ret;
 912  std::vector<NewArchiveMember> Moved;
 913  int InsertPos = -1;
 914  if (OldArchive) {
 915    Error Err = Error::success();
 916    StringMap<int> MemberCount;
 917    for (auto &Child : OldArchive->children(Err)) {
 918      int Pos = Ret.size();
 919      Expected<StringRef> NameOrErr = Child.getName();
 920      failIfError(NameOrErr.takeError());
 921      std::string Name = std::string(NameOrErr.get());
 922      if (comparePaths(Name, RelPos) && isValidInBitMode(Child)) {
 923        assert(AddAfter || AddBefore);
 924        if (AddBefore)
 925          InsertPos = Pos;
 926        else
 927          InsertPos = Pos + 1;
 928      }
 929
 930      std::vector<StringRef>::iterator MemberI = Members.end();
 931      InsertAction Action =
 932          computeInsertAction(Operation, Child, Name, MemberI, MemberCount);
 933
 934      auto HandleNewMember = [](auto Member, auto &Members, auto &Child) {
 935        NewArchiveMember NM = getArchiveMember(*Member);
 936        if (isValidInBitMode(NM))
 937          addMember(Members, NM);
 938        else {
 939          // If a new member is not a valid object for the bit mode, add
 940          // the old member back.
 941          warnInvalidObjectForFileMode(*Member);
 942          addChildMember(Members, Child, /*FlattenArchive=*/Thin);
 943        }
 944      };
 945
 946      switch (Action) {
 947      case IA_AddOldMember:
 948        addChildMember(Ret, Child, /*FlattenArchive=*/Thin);
 949        break;
 950      case IA_AddNewMember:
 951        HandleNewMember(MemberI, Ret, Child);
 952        break;
 953      case IA_Delete:
 954        break;
 955      case IA_MoveOldMember:
 956        addChildMember(Moved, Child, /*FlattenArchive=*/Thin);
 957        break;
 958      case IA_MoveNewMember:
 959        HandleNewMember(MemberI, Moved, Child);
 960        break;
 961      }
 962      // When processing elements with the count param, we need to preserve the
 963      // full members list when iterating over all archive members. For
 964      // instance, "llvm-ar dN 2 archive.a member.o" should delete the second
 965      // file named member.o it sees; we are not done with member.o the first
 966      // time we see it in the archive.
 967      if (MemberI != Members.end() && !CountParam)
 968        Members.erase(MemberI);
 969    }
 970    failIfError(std::move(Err));
 971  }
 972
 973  if (Operation == Delete)
 974    return Ret;
 975
 976  if (!RelPos.empty() && InsertPos == -1)
 977    fail("insertion point not found");
 978
 979  if (RelPos.empty())
 980    InsertPos = Ret.size();
 981
 982  assert(unsigned(InsertPos) <= Ret.size());
 983  int Pos = InsertPos;
 984  for (auto &M : Moved) {
 985    Ret.insert(Ret.begin() + Pos, std::move(M));
 986    ++Pos;
 987  }
 988
 989  if (AddLibrary) {
 990    assert(Operation == QuickAppend);
 991    for (auto &Member : Members)
 992      addMember(Ret, Member, /*FlattenArchive=*/true);
 993    return Ret;
 994  }
 995
 996  std::vector<NewArchiveMember> NewMembers;
 997  for (auto &Member : Members)
 998    addMember(NewMembers, Member, /*FlattenArchive=*/Thin);
 999  Ret.reserve(Ret.size() + NewMembers.size());
1000  std::move(NewMembers.begin(), NewMembers.end(),
1001            std::inserter(Ret, std::next(Ret.begin(), InsertPos)));
1002
1003  return Ret;
1004}
1005
1006static void performWriteOperation(ArchiveOperation Operation,
1007                                  object::Archive *OldArchive,
1008                                  std::unique_ptr<MemoryBuffer> OldArchiveBuf,
1009                                  std::vector<NewArchiveMember> *NewMembersP) {
1010  if (OldArchive) {
1011    if (Thin && !OldArchive->isThin())
1012      fail("cannot convert a regular archive to a thin one");
1013
1014    if (OldArchive->isThin())
1015      Thin = true;
1016  }
1017
1018  std::vector<NewArchiveMember> NewMembers;
1019  if (!NewMembersP)
1020    NewMembers = computeNewArchiveMembers(Operation, OldArchive);
1021
1022  object::Archive::Kind Kind;
1023  switch (FormatType) {
1024  case Default:
1025    if (Thin)
1026      Kind = object::Archive::K_GNU;
1027    else if (OldArchive) {
1028      Kind = OldArchive->kind();
1029      std::optional<object::Archive::Kind> AltKind;
1030      if (Kind == object::Archive::K_BSD)
1031        AltKind = object::Archive::K_DARWIN;
1032      else if (Kind == object::Archive::K_GNU && !OldArchive->hasSymbolTable())
1033        // If there is no symbol table, we can't tell GNU from COFF format
1034        // from the old archive type.
1035        AltKind = object::Archive::K_COFF;
1036      if (AltKind) {
1037        auto InferredKind = Kind;
1038        if (NewMembersP && !NewMembersP->empty())
1039          InferredKind = NewMembersP->front().detectKindFromObject();
1040        else if (!NewMembers.empty())
1041          InferredKind = NewMembers.front().detectKindFromObject();
1042        if (InferredKind == AltKind)
1043          Kind = *AltKind;
1044      }
1045    } else if (NewMembersP)
1046      Kind = !NewMembersP->empty() ? NewMembersP->front().detectKindFromObject()
1047                                   : object::Archive::getDefaultKind();
1048    else
1049      Kind = !NewMembers.empty() ? NewMembers.front().detectKindFromObject()
1050                                 : object::Archive::getDefaultKind();
1051    break;
1052  case GNU:
1053    Kind = object::Archive::K_GNU;
1054    break;
1055  case COFF:
1056    Kind = object::Archive::K_COFF;
1057    break;
1058  case BSD:
1059    if (Thin)
1060      fail("only the gnu format has a thin mode");
1061    Kind = object::Archive::K_BSD;
1062    break;
1063  case DARWIN:
1064    if (Thin)
1065      fail("only the gnu format has a thin mode");
1066    Kind = object::Archive::K_DARWIN;
1067    break;
1068  case BIGARCHIVE:
1069    if (Thin)
1070      fail("only the gnu format has a thin mode");
1071    Kind = object::Archive::K_AIXBIG;
1072    break;
1073  case Unknown:
1074    llvm_unreachable("");
1075  }
1076
1077  Error E =
1078      writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab,
1079                   Kind, Deterministic, Thin, std::move(OldArchiveBuf));
1080  failIfError(std::move(E), ArchiveName);
1081}
1082
1083static void createSymbolTable(object::Archive *OldArchive) {
1084  // When an archive is created or modified, if the s option is given, the
1085  // resulting archive will have a current symbol table. If the S option
1086  // is given, it will have no symbol table.
1087  // In summary, we only need to update the symbol table if we have none.
1088  // This is actually very common because of broken build systems that think
1089  // they have to run ranlib.
1090  if (OldArchive->hasSymbolTable()) {
1091    if (OldArchive->kind() != object::Archive::K_AIXBIG)
1092      return;
1093
1094    // For archives in the Big Archive format, the bit mode option specifies
1095    // which symbol table to generate. The presence of a symbol table that does
1096    // not match the specified bit mode does not prevent creation of the symbol
1097    // table that has been requested.
1098    if (OldArchive->kind() == object::Archive::K_AIXBIG) {
1099      BigArchive *BigArc = dyn_cast<BigArchive>(OldArchive);
1100      if (BigArc->has32BitGlobalSymtab() &&
1101          Symtab == SymtabWritingMode::BigArchive32)
1102        return;
1103
1104      if (BigArc->has64BitGlobalSymtab() &&
1105          Symtab == SymtabWritingMode::BigArchive64)
1106        return;
1107
1108      if (BigArc->has32BitGlobalSymtab() && BigArc->has64BitGlobalSymtab() &&
1109          Symtab == SymtabWritingMode::NormalSymtab)
1110        return;
1111
1112      Symtab = SymtabWritingMode::NormalSymtab;
1113    }
1114  }
1115  if (OldArchive->isThin())
1116    Thin = true;
1117  performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr);
1118}
1119
1120static void performOperation(ArchiveOperation Operation,
1121                             object::Archive *OldArchive,
1122                             std::unique_ptr<MemoryBuffer> OldArchiveBuf,
1123                             std::vector<NewArchiveMember> *NewMembers) {
1124  switch (Operation) {
1125  case Print:
1126  case DisplayTable:
1127  case Extract:
1128    performReadOperation(Operation, OldArchive);
1129    return;
1130
1131  case Delete:
1132  case Move:
1133  case QuickAppend:
1134  case ReplaceOrInsert:
1135    performWriteOperation(Operation, OldArchive, std::move(OldArchiveBuf),
1136                          NewMembers);
1137    return;
1138  case CreateSymTab:
1139    createSymbolTable(OldArchive);
1140    return;
1141  }
1142  llvm_unreachable("Unknown operation.");
1143}
1144
1145static int performOperation(ArchiveOperation Operation) {
1146  // Create or open the archive object.
1147  ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile(
1148      ArchiveName, /*IsText=*/false, /*RequiresNullTerminator=*/false);
1149  std::error_code EC = Buf.getError();
1150  if (EC && EC != errc::no_such_file_or_directory)
1151    fail("unable to open '" + ArchiveName + "': " + EC.message());
1152
1153  if (!EC) {
1154    Expected<std::unique_ptr<object::Archive>> ArchiveOrError =
1155        object::Archive::create(Buf.get()->getMemBufferRef());
1156    if (!ArchiveOrError)
1157      failIfError(ArchiveOrError.takeError(),
1158                  "unable to load '" + ArchiveName + "'");
1159
1160    std::unique_ptr<object::Archive> Archive = std::move(ArchiveOrError.get());
1161    if (Archive->isThin())
1162      CompareFullPath = true;
1163    performOperation(Operation, Archive.get(), std::move(Buf.get()),
1164                     /*NewMembers=*/nullptr);
1165    return 0;
1166  }
1167
1168  assert(EC == errc::no_such_file_or_directory);
1169
1170  if (!shouldCreateArchive(Operation)) {
1171    failIfError(EC, Twine("unable to load '") + ArchiveName + "'");
1172  } else {
1173    if (!Create) {
1174      // Produce a warning if we should and we're creating the archive
1175      warn("creating " + ArchiveName);
1176    }
1177  }
1178
1179  performOperation(Operation, nullptr, nullptr, /*NewMembers=*/nullptr);
1180  return 0;
1181}
1182
1183static void runMRIScript() {
1184  enum class MRICommand { AddLib, AddMod, Create, CreateThin, Delete, Save, End, Invalid };
1185
1186  ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getSTDIN();
1187  failIfError(Buf.getError());
1188  const MemoryBuffer &Ref = *Buf.get();
1189  bool Saved = false;
1190  std::vector<NewArchiveMember> NewMembers;
1191  ParsingMRIScript = true;
1192
1193  for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) {
1194    ++MRILineNumber;
1195    StringRef Line = *I;
1196    Line = Line.split(';').first;
1197    Line = Line.split('*').first;
1198    Line = Line.trim();
1199    if (Line.empty())
1200      continue;
1201    StringRef CommandStr, Rest;
1202    std::tie(CommandStr, Rest) = Line.split(' ');
1203    Rest = Rest.trim();
1204    if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"')
1205      Rest = Rest.drop_front().drop_back();
1206    auto Command = StringSwitch<MRICommand>(CommandStr.lower())
1207                       .Case("addlib", MRICommand::AddLib)
1208                       .Case("addmod", MRICommand::AddMod)
1209                       .Case("create", MRICommand::Create)
1210                       .Case("createthin", MRICommand::CreateThin)
1211                       .Case("delete", MRICommand::Delete)
1212                       .Case("save", MRICommand::Save)
1213                       .Case("end", MRICommand::End)
1214                       .Default(MRICommand::Invalid);
1215
1216    switch (Command) {
1217    case MRICommand::AddLib: {
1218      if (!Create)
1219        fail("no output archive has been opened");
1220      object::Archive &Lib = readLibrary(Rest);
1221      {
1222        if (Thin && !Lib.isThin())
1223          fail("cannot add a regular archive's contents to a thin archive");
1224        Error Err = Error::success();
1225        for (auto &Member : Lib.children(Err))
1226          addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin);
1227        failIfError(std::move(Err));
1228      }
1229      break;
1230    }
1231    case MRICommand::AddMod:
1232      if (!Create)
1233        fail("no output archive has been opened");
1234      addMember(NewMembers, Rest);
1235      break;
1236    case MRICommand::CreateThin:
1237      Thin = true;
1238      [[fallthrough]];
1239    case MRICommand::Create:
1240      Create = true;
1241      if (!ArchiveName.empty())
1242        fail("editing multiple archives not supported");
1243      if (Saved)
1244        fail("file already saved");
1245      ArchiveName = std::string(Rest);
1246      if (ArchiveName.empty())
1247        fail("missing archive name");
1248      break;
1249    case MRICommand::Delete: {
1250      llvm::erase_if(NewMembers, [=](NewArchiveMember &M) {
1251        return comparePaths(M.MemberName, Rest);
1252      });
1253      break;
1254    }
1255    case MRICommand::Save:
1256      Saved = true;
1257      break;
1258    case MRICommand::End:
1259      break;
1260    case MRICommand::Invalid:
1261      fail("unknown command: " + CommandStr);
1262    }
1263  }
1264
1265  ParsingMRIScript = false;
1266
1267  // Nothing to do if not saved.
1268  if (Saved)
1269    performOperation(ReplaceOrInsert, /*OldArchive=*/nullptr,
1270                     /*OldArchiveBuf=*/nullptr, &NewMembers);
1271  exit(0);
1272}
1273
1274static bool handleGenericOption(StringRef arg) {
1275  if (arg == "--help" || arg == "-h") {
1276    printHelpMessage();
1277    return true;
1278  }
1279  if (arg == "--version") {
1280    cl::PrintVersionMessage();
1281    return true;
1282  }
1283  return false;
1284}
1285
1286static BitModeTy getBitMode(const char *RawBitMode) {
1287  return StringSwitch<BitModeTy>(RawBitMode)
1288      .Case("32", BitModeTy::Bit32)
1289      .Case("64", BitModeTy::Bit64)
1290      .Case("32_64", BitModeTy::Bit32_64)
1291      .Case("any", BitModeTy::Any)
1292      .Default(BitModeTy::Unknown);
1293}
1294
1295static const char *matchFlagWithArg(StringRef Expected,
1296                                    ArrayRef<const char *>::iterator &ArgIt,
1297                                    ArrayRef<const char *> Args) {
1298  StringRef Arg = *ArgIt;
1299
1300  Arg.consume_front("--");
1301
1302  size_t len = Expected.size();
1303  if (Arg == Expected) {
1304    if (++ArgIt == Args.end())
1305      fail(std::string(Expected) + " requires an argument");
1306
1307    return *ArgIt;
1308  }
1309  if (Arg.starts_with(Expected) && Arg.size() > len && Arg[len] == '=')
1310    return Arg.data() + len + 1;
1311
1312  return nullptr;
1313}
1314
1315static cl::TokenizerCallback getRspQuoting(ArrayRef<const char *> ArgsArr) {
1316  cl::TokenizerCallback Ret =
1317      Triple(sys::getProcessTriple()).getOS() == Triple::Win32
1318          ? cl::TokenizeWindowsCommandLine
1319          : cl::TokenizeGNUCommandLine;
1320
1321  for (ArrayRef<const char *>::iterator ArgIt = ArgsArr.begin();
1322       ArgIt != ArgsArr.end(); ++ArgIt) {
1323    if (const char *Match = matchFlagWithArg("rsp-quoting", ArgIt, ArgsArr)) {
1324      StringRef MatchRef = Match;
1325      if (MatchRef == "posix")
1326        Ret = cl::TokenizeGNUCommandLine;
1327      else if (MatchRef == "windows")
1328        Ret = cl::TokenizeWindowsCommandLine;
1329      else
1330        fail(std::string("Invalid response file quoting style ") + Match);
1331    }
1332  }
1333
1334  return Ret;
1335}
1336
1337static int ar_main(int argc, char **argv) {
1338  SmallVector<const char *, 0> Argv(argv + 1, argv + argc);
1339  StringSaver Saver(Alloc);
1340
1341  cl::ExpandResponseFiles(Saver, getRspQuoting(ArrayRef(argv, argc)), Argv);
1342
1343  // Get BitMode from enviorment variable "OBJECT_MODE" for AIX OS, if
1344  // specified.
1345  if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) {
1346    BitMode = getBitMode(getenv("OBJECT_MODE"));
1347    if (BitMode == BitModeTy::Unknown)
1348      BitMode = BitModeTy::Bit32;
1349  }
1350
1351  for (ArrayRef<const char *>::iterator ArgIt = Argv.begin();
1352       ArgIt != Argv.end(); ++ArgIt) {
1353    const char *Match = nullptr;
1354
1355    if (handleGenericOption(*ArgIt))
1356      return 0;
1357    if (strcmp(*ArgIt, "--") == 0) {
1358      ++ArgIt;
1359      for (; ArgIt != Argv.end(); ++ArgIt)
1360        PositionalArgs.push_back(*ArgIt);
1361      break;
1362    }
1363
1364    if (*ArgIt[0] != '-') {
1365      if (Options.empty())
1366        Options += *ArgIt;
1367      else
1368        PositionalArgs.push_back(*ArgIt);
1369      continue;
1370    }
1371
1372    if (strcmp(*ArgIt, "-M") == 0) {
1373      MRI = true;
1374      continue;
1375    }
1376
1377    if (strcmp(*ArgIt, "--thin") == 0) {
1378      Thin = true;
1379      continue;
1380    }
1381
1382    Match = matchFlagWithArg("format", ArgIt, Argv);
1383    if (Match) {
1384      FormatType = StringSwitch<Format>(Match)
1385                       .Case("default", Default)
1386                       .Case("gnu", GNU)
1387                       .Case("darwin", DARWIN)
1388                       .Case("bsd", BSD)
1389                       .Case("bigarchive", BIGARCHIVE)
1390                       .Case("coff", COFF)
1391                       .Default(Unknown);
1392      if (FormatType == Unknown)
1393        fail(std::string("Invalid format ") + Match);
1394      continue;
1395    }
1396
1397    if ((Match = matchFlagWithArg("output", ArgIt, Argv))) {
1398      OutputDir = Match;
1399      continue;
1400    }
1401
1402    if (matchFlagWithArg("plugin", ArgIt, Argv) ||
1403        matchFlagWithArg("rsp-quoting", ArgIt, Argv))
1404      continue;
1405
1406    if (strncmp(*ArgIt, "-X", 2) == 0) {
1407      if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) {
1408        Match = *(*ArgIt + 2) != '\0' ? *ArgIt + 2 : *(++ArgIt);
1409        BitMode = getBitMode(Match);
1410        if (BitMode == BitModeTy::Unknown)
1411          fail(Twine("invalid bit mode: ") + Match);
1412        continue;
1413      } else {
1414        fail(Twine(*ArgIt) + " option not supported on non AIX OS");
1415      }
1416    }
1417
1418    Options += *ArgIt + 1;
1419  }
1420
1421  return performOperation(parseCommandLine());
1422}
1423
1424static int ranlib_main(int argc, char **argv) {
1425  std::vector<StringRef> Archives;
1426  bool HasAIXXOption = false;
1427
1428  for (int i = 1; i < argc; ++i) {
1429    StringRef arg(argv[i]);
1430    if (handleGenericOption(arg)) {
1431      return 0;
1432    } else if (arg.consume_front("-")) {
1433      // Handle the -D/-U flag
1434      while (!arg.empty()) {
1435        if (arg.front() == 'D') {
1436          Deterministic = true;
1437        } else if (arg.front() == 'U') {
1438          Deterministic = false;
1439        } else if (arg.front() == 'h') {
1440          printHelpMessage();
1441          return 0;
1442        } else if (arg.front() == 'V') {
1443          cl::PrintVersionMessage();
1444          return 0;
1445        } else if (arg.front() == 'X') {
1446          if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) {
1447            HasAIXXOption = true;
1448            arg.consume_front("X");
1449            const char *Xarg = arg.data();
1450            if (Xarg[0] == '\0') {
1451              if (argv[i + 1][0] != '-')
1452                BitMode = getBitMode(argv[++i]);
1453              else
1454                BitMode = BitModeTy::Unknown;
1455            } else
1456              BitMode = getBitMode(arg.data());
1457
1458            if (BitMode == BitModeTy::Unknown)
1459              fail("the specified object mode is not valid. Specify -X32, "
1460                   "-X64, -X32_64, or -Xany");
1461          } else {
1462            fail(Twine("-") + Twine(arg) +
1463                 " option not supported on non AIX OS");
1464          }
1465          break;
1466        } else {
1467          // TODO: GNU ranlib also supports a -t flag
1468          fail("Invalid option: '-" + arg + "'");
1469        }
1470        arg = arg.drop_front(1);
1471      }
1472    } else {
1473      Archives.push_back(arg);
1474    }
1475  }
1476
1477  if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) {
1478    // If not specify -X option, get BitMode from enviorment variable
1479    // "OBJECT_MODE" for AIX OS if specify.
1480    if (!HasAIXXOption) {
1481      if (char *EnvObjectMode = getenv("OBJECT_MODE")) {
1482        BitMode = getBitMode(EnvObjectMode);
1483        if (BitMode == BitModeTy::Unknown)
1484          fail("the OBJECT_MODE environment variable has an invalid value. "
1485               "OBJECT_MODE must be 32, 64, 32_64, or any");
1486      }
1487    }
1488
1489    switch (BitMode) {
1490    case BitModeTy::Bit32:
1491      Symtab = SymtabWritingMode::BigArchive32;
1492      break;
1493    case BitModeTy::Bit64:
1494      Symtab = SymtabWritingMode::BigArchive64;
1495      break;
1496    default:
1497      Symtab = SymtabWritingMode::NormalSymtab;
1498      break;
1499    }
1500  }
1501
1502  for (StringRef Archive : Archives) {
1503    ArchiveName = Archive.str();
1504    performOperation(CreateSymTab);
1505  }
1506  if (Archives.empty())
1507    badUsage("an archive name must be specified");
1508  return 0;
1509}
1510
1511static int llvm_ar_main(int argc, char **argv, const llvm::ToolContext &) {
1512  ToolName = argv[0];
1513
1514  llvm::InitializeAllTargetInfos();
1515  llvm::InitializeAllTargetMCs();
1516  llvm::InitializeAllAsmParsers();
1517
1518  Stem = sys::path::stem(ToolName);
1519  auto Is = [](StringRef Tool) {
1520    // We need to recognize the following filenames.
1521    //
1522    // Lib.exe -> lib (see D44808, MSBuild runs Lib.exe)
1523    // dlltool.exe -> dlltool
1524    // arm-pokymllib32-linux-gnueabi-llvm-ar-10 -> ar
1525    auto I = Stem.rfind_insensitive(Tool);
1526    return I != StringRef::npos &&
1527           (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()]));
1528  };
1529
1530  if (Is("dlltool"))
1531    return dlltoolDriverMain(ArrayRef(argv, argc));
1532  if (Is("ranlib"))
1533    return ranlib_main(argc, argv);
1534  if (Is("lib"))
1535    return libDriverMain(ArrayRef(argv, argc));
1536  if (Is("ar"))
1537    return ar_main(argc, argv);
1538
1539  fail("not ranlib, ar, lib or dlltool");
1540}
1541
1542extern "C" int ZigLlvmAr_main(int, char **);
1543int ZigLlvmAr_main(int argc, char **argv) {
1544  return llvm_ar_main(argc, argv, {argv[0], nullptr, false});
1545}