xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp (revision d65cd7a57bf0600b722afc770838a5d0c1c3a8e1)
10b57cec5SDimitry Andric //===- llvm-objcopy.cpp ---------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm-objcopy.h"
100b57cec5SDimitry Andric #include "Buffer.h"
110b57cec5SDimitry Andric #include "CopyConfig.h"
120b57cec5SDimitry Andric #include "ELF/ELFObjcopy.h"
130b57cec5SDimitry Andric #include "COFF/COFFObjcopy.h"
140b57cec5SDimitry Andric #include "MachO/MachOObjcopy.h"
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
170b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
180b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
190b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
200b57cec5SDimitry Andric #include "llvm/Object/Archive.h"
210b57cec5SDimitry Andric #include "llvm/Object/ArchiveWriter.h"
220b57cec5SDimitry Andric #include "llvm/Object/Binary.h"
230b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
240b57cec5SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
250b57cec5SDimitry Andric #include "llvm/Object/ELFTypes.h"
260b57cec5SDimitry Andric #include "llvm/Object/Error.h"
270b57cec5SDimitry Andric #include "llvm/Object/MachO.h"
280b57cec5SDimitry Andric #include "llvm/Option/Arg.h"
290b57cec5SDimitry Andric #include "llvm/Option/ArgList.h"
300b57cec5SDimitry Andric #include "llvm/Option/Option.h"
310b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
328bcb0991SDimitry Andric #include "llvm/Support/CommandLine.h"
330b57cec5SDimitry Andric #include "llvm/Support/Error.h"
340b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
350b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h"
360b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h"
370b57cec5SDimitry Andric #include "llvm/Support/Memory.h"
380b57cec5SDimitry Andric #include "llvm/Support/Path.h"
390b57cec5SDimitry Andric #include "llvm/Support/Process.h"
408bcb0991SDimitry Andric #include "llvm/Support/StringSaver.h"
410b57cec5SDimitry Andric #include "llvm/Support/WithColor.h"
420b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
430b57cec5SDimitry Andric #include <algorithm>
440b57cec5SDimitry Andric #include <cassert>
450b57cec5SDimitry Andric #include <cstdlib>
460b57cec5SDimitry Andric #include <memory>
470b57cec5SDimitry Andric #include <string>
480b57cec5SDimitry Andric #include <system_error>
490b57cec5SDimitry Andric #include <utility>
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric namespace llvm {
520b57cec5SDimitry Andric namespace objcopy {
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric // The name this program was invoked as.
550b57cec5SDimitry Andric StringRef ToolName;
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
580b57cec5SDimitry Andric   WithColor::error(errs(), ToolName) << Message << "\n";
590b57cec5SDimitry Andric   exit(1);
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric LLVM_ATTRIBUTE_NORETURN void error(Error E) {
630b57cec5SDimitry Andric   assert(E);
640b57cec5SDimitry Andric   std::string Buf;
650b57cec5SDimitry Andric   raw_string_ostream OS(Buf);
660b57cec5SDimitry Andric   logAllUnhandledErrors(std::move(E), OS);
670b57cec5SDimitry Andric   OS.flush();
680b57cec5SDimitry Andric   WithColor::error(errs(), ToolName) << Buf;
690b57cec5SDimitry Andric   exit(1);
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
730b57cec5SDimitry Andric   assert(EC);
740b57cec5SDimitry Andric   error(createFileError(File, EC));
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
780b57cec5SDimitry Andric   assert(E);
790b57cec5SDimitry Andric   std::string Buf;
800b57cec5SDimitry Andric   raw_string_ostream OS(Buf);
810b57cec5SDimitry Andric   logAllUnhandledErrors(std::move(E), OS);
820b57cec5SDimitry Andric   OS.flush();
830b57cec5SDimitry Andric   WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
840b57cec5SDimitry Andric   exit(1);
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric ErrorSuccess reportWarning(Error E) {
880b57cec5SDimitry Andric   assert(E);
898bcb0991SDimitry Andric   WithColor::warning(errs(), ToolName) << toString(std::move(E)) << '\n';
900b57cec5SDimitry Andric   return Error::success();
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric } // end namespace objcopy
940b57cec5SDimitry Andric } // end namespace llvm
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric using namespace llvm;
970b57cec5SDimitry Andric using namespace llvm::object;
980b57cec5SDimitry Andric using namespace llvm::objcopy;
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric // For regular archives this function simply calls llvm::writeArchive,
1010b57cec5SDimitry Andric // For thin archives it writes the archive file itself as well as its members.
1020b57cec5SDimitry Andric static Error deepWriteArchive(StringRef ArcName,
1030b57cec5SDimitry Andric                               ArrayRef<NewArchiveMember> NewMembers,
1040b57cec5SDimitry Andric                               bool WriteSymtab, object::Archive::Kind Kind,
1050b57cec5SDimitry Andric                               bool Deterministic, bool Thin) {
1060b57cec5SDimitry Andric   if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind,
1070b57cec5SDimitry Andric                              Deterministic, Thin))
1080b57cec5SDimitry Andric     return createFileError(ArcName, std::move(E));
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   if (!Thin)
1110b57cec5SDimitry Andric     return Error::success();
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   for (const NewArchiveMember &Member : NewMembers) {
1140b57cec5SDimitry Andric     // Internally, FileBuffer will use the buffer created by
1150b57cec5SDimitry Andric     // FileOutputBuffer::create, for regular files (that is the case for
1160b57cec5SDimitry Andric     // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
1170b57cec5SDimitry Andric     // OnDiskBuffer uses a temporary file and then renames it. So in reality
1180b57cec5SDimitry Andric     // there is no inefficiency / duplicated in-memory buffers in this case. For
1190b57cec5SDimitry Andric     // now in-memory buffers can not be completely avoided since
1200b57cec5SDimitry Andric     // NewArchiveMember still requires them even though writeArchive does not
1210b57cec5SDimitry Andric     // write them on disk.
1220b57cec5SDimitry Andric     FileBuffer FB(Member.MemberName);
1230b57cec5SDimitry Andric     if (Error E = FB.allocate(Member.Buf->getBufferSize()))
1240b57cec5SDimitry Andric       return E;
1250b57cec5SDimitry Andric     std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
1260b57cec5SDimitry Andric               FB.getBufferStart());
1270b57cec5SDimitry Andric     if (Error E = FB.commit())
1280b57cec5SDimitry Andric       return E;
1290b57cec5SDimitry Andric   }
1300b57cec5SDimitry Andric   return Error::success();
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric /// The function executeObjcopyOnIHex does the dispatch based on the format
1340b57cec5SDimitry Andric /// of the output specified by the command line options.
1358bcb0991SDimitry Andric static Error executeObjcopyOnIHex(CopyConfig &Config, MemoryBuffer &In,
1360b57cec5SDimitry Andric                                   Buffer &Out) {
1370b57cec5SDimitry Andric   // TODO: support output formats other than ELF.
1388bcb0991SDimitry Andric   if (Error E = Config.parseELFConfig())
1398bcb0991SDimitry Andric     return E;
1400b57cec5SDimitry Andric   return elf::executeObjcopyOnIHex(Config, In, Out);
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric /// The function executeObjcopyOnRawBinary does the dispatch based on the format
1440b57cec5SDimitry Andric /// of the output specified by the command line options.
1458bcb0991SDimitry Andric static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In,
1468bcb0991SDimitry Andric                                        Buffer &Out) {
1470b57cec5SDimitry Andric   switch (Config.OutputFormat) {
1480b57cec5SDimitry Andric   case FileFormat::ELF:
1490b57cec5SDimitry Andric   // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the
1500b57cec5SDimitry Andric   // output format is binary/ihex or it's not given. This behavior differs from
1510b57cec5SDimitry Andric   // GNU objcopy. See https://bugs.llvm.org/show_bug.cgi?id=42171 for details.
1520b57cec5SDimitry Andric   case FileFormat::Binary:
1530b57cec5SDimitry Andric   case FileFormat::IHex:
1540b57cec5SDimitry Andric   case FileFormat::Unspecified:
1558bcb0991SDimitry Andric     if (Error E = Config.parseELFConfig())
1568bcb0991SDimitry Andric       return E;
1570b57cec5SDimitry Andric     return elf::executeObjcopyOnRawBinary(Config, In, Out);
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   llvm_unreachable("unsupported output format");
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric /// The function executeObjcopyOnBinary does the dispatch based on the format
1640b57cec5SDimitry Andric /// of the input binary (ELF, MachO or COFF).
1658bcb0991SDimitry Andric static Error executeObjcopyOnBinary(CopyConfig &Config, object::Binary &In,
1668bcb0991SDimitry Andric                                     Buffer &Out) {
1678bcb0991SDimitry Andric   if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) {
1688bcb0991SDimitry Andric     if (Error E = Config.parseELFConfig())
1698bcb0991SDimitry Andric       return E;
1700b57cec5SDimitry Andric     return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out);
1718bcb0991SDimitry Andric   } else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In))
1720b57cec5SDimitry Andric     return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out);
1730b57cec5SDimitry Andric   else if (auto *MachOBinary = dyn_cast<object::MachOObjectFile>(&In))
1740b57cec5SDimitry Andric     return macho::executeObjcopyOnBinary(Config, *MachOBinary, Out);
1750b57cec5SDimitry Andric   else
1760b57cec5SDimitry Andric     return createStringError(object_error::invalid_file_type,
1770b57cec5SDimitry Andric                              "unsupported object file format");
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric 
1808bcb0991SDimitry Andric static Error executeObjcopyOnArchive(CopyConfig &Config, const Archive &Ar) {
1810b57cec5SDimitry Andric   std::vector<NewArchiveMember> NewArchiveMembers;
1820b57cec5SDimitry Andric   Error Err = Error::success();
1830b57cec5SDimitry Andric   for (const Archive::Child &Child : Ar.children(Err)) {
1840b57cec5SDimitry Andric     Expected<StringRef> ChildNameOrErr = Child.getName();
1850b57cec5SDimitry Andric     if (!ChildNameOrErr)
1860b57cec5SDimitry Andric       return createFileError(Ar.getFileName(), ChildNameOrErr.takeError());
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric     Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
1890b57cec5SDimitry Andric     if (!ChildOrErr)
1900b57cec5SDimitry Andric       return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")",
1910b57cec5SDimitry Andric                              ChildOrErr.takeError());
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric     MemBuffer MB(ChildNameOrErr.get());
1940b57cec5SDimitry Andric     if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MB))
1950b57cec5SDimitry Andric       return E;
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric     Expected<NewArchiveMember> Member =
1980b57cec5SDimitry Andric         NewArchiveMember::getOldMember(Child, Config.DeterministicArchives);
1990b57cec5SDimitry Andric     if (!Member)
2000b57cec5SDimitry Andric       return createFileError(Ar.getFileName(), Member.takeError());
2010b57cec5SDimitry Andric     Member->Buf = MB.releaseMemoryBuffer();
2020b57cec5SDimitry Andric     Member->MemberName = Member->Buf->getBufferIdentifier();
2030b57cec5SDimitry Andric     NewArchiveMembers.push_back(std::move(*Member));
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric   if (Err)
2060b57cec5SDimitry Andric     return createFileError(Config.InputFilename, std::move(Err));
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric   return deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
2090b57cec5SDimitry Andric                           Ar.hasSymbolTable(), Ar.kind(),
2100b57cec5SDimitry Andric                           Config.DeterministicArchives, Ar.isThin());
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric static Error restoreStatOnFile(StringRef Filename,
2140b57cec5SDimitry Andric                                const sys::fs::file_status &Stat,
2150b57cec5SDimitry Andric                                bool PreserveDates) {
2160b57cec5SDimitry Andric   int FD;
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   // Writing to stdout should not be treated as an error here, just
2190b57cec5SDimitry Andric   // do not set access/modification times or permissions.
2200b57cec5SDimitry Andric   if (Filename == "-")
2210b57cec5SDimitry Andric     return Error::success();
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric   if (auto EC =
2240b57cec5SDimitry Andric           sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
2250b57cec5SDimitry Andric     return createFileError(Filename, EC);
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric   if (PreserveDates)
2280b57cec5SDimitry Andric     if (auto EC = sys::fs::setLastAccessAndModificationTime(
2290b57cec5SDimitry Andric             FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
2300b57cec5SDimitry Andric       return createFileError(Filename, EC);
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   sys::fs::file_status OStat;
2330b57cec5SDimitry Andric   if (std::error_code EC = sys::fs::status(FD, OStat))
2340b57cec5SDimitry Andric     return createFileError(Filename, EC);
2350b57cec5SDimitry Andric   if (OStat.type() == sys::fs::file_type::regular_file)
2360b57cec5SDimitry Andric #ifdef _WIN32
2370b57cec5SDimitry Andric     if (auto EC = sys::fs::setPermissions(
2380b57cec5SDimitry Andric             Filename, static_cast<sys::fs::perms>(Stat.permissions() &
2390b57cec5SDimitry Andric                                                   ~sys::fs::getUmask())))
2400b57cec5SDimitry Andric #else
2410b57cec5SDimitry Andric     if (auto EC = sys::fs::setPermissions(
2420b57cec5SDimitry Andric             FD, static_cast<sys::fs::perms>(Stat.permissions() &
2430b57cec5SDimitry Andric                                             ~sys::fs::getUmask())))
2440b57cec5SDimitry Andric #endif
2450b57cec5SDimitry Andric       return createFileError(Filename, EC);
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric   if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
2480b57cec5SDimitry Andric     return createFileError(Filename, EC);
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   return Error::success();
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric /// The function executeObjcopy does the higher level dispatch based on the type
2540b57cec5SDimitry Andric /// of input (raw binary, archive or single object file) and takes care of the
2550b57cec5SDimitry Andric /// format-agnostic modifications, i.e. preserving dates.
2568bcb0991SDimitry Andric static Error executeObjcopy(CopyConfig &Config) {
2570b57cec5SDimitry Andric   sys::fs::file_status Stat;
2580b57cec5SDimitry Andric   if (Config.InputFilename != "-") {
2590b57cec5SDimitry Andric     if (auto EC = sys::fs::status(Config.InputFilename, Stat))
2600b57cec5SDimitry Andric       return createFileError(Config.InputFilename, EC);
2610b57cec5SDimitry Andric   } else {
2620b57cec5SDimitry Andric     Stat.permissions(static_cast<sys::fs::perms>(0777));
2630b57cec5SDimitry Andric   }
2640b57cec5SDimitry Andric 
2658bcb0991SDimitry Andric   using ProcessRawFn = Error (*)(CopyConfig &, MemoryBuffer &, Buffer &);
2660b57cec5SDimitry Andric   ProcessRawFn ProcessRaw;
2670b57cec5SDimitry Andric   switch (Config.InputFormat) {
2680b57cec5SDimitry Andric   case FileFormat::Binary:
2690b57cec5SDimitry Andric     ProcessRaw = executeObjcopyOnRawBinary;
2700b57cec5SDimitry Andric     break;
2710b57cec5SDimitry Andric   case FileFormat::IHex:
2720b57cec5SDimitry Andric     ProcessRaw = executeObjcopyOnIHex;
2730b57cec5SDimitry Andric     break;
2740b57cec5SDimitry Andric   default:
2750b57cec5SDimitry Andric     ProcessRaw = nullptr;
2760b57cec5SDimitry Andric   }
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric   if (ProcessRaw) {
2790b57cec5SDimitry Andric     auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename);
2800b57cec5SDimitry Andric     if (!BufOrErr)
2810b57cec5SDimitry Andric       return createFileError(Config.InputFilename, BufOrErr.getError());
2820b57cec5SDimitry Andric     FileBuffer FB(Config.OutputFilename);
2830b57cec5SDimitry Andric     if (Error E = ProcessRaw(Config, *BufOrErr->get(), FB))
2840b57cec5SDimitry Andric       return E;
2850b57cec5SDimitry Andric   } else {
2860b57cec5SDimitry Andric     Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
2870b57cec5SDimitry Andric         createBinary(Config.InputFilename);
2880b57cec5SDimitry Andric     if (!BinaryOrErr)
2890b57cec5SDimitry Andric       return createFileError(Config.InputFilename, BinaryOrErr.takeError());
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric     if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
2920b57cec5SDimitry Andric       if (Error E = executeObjcopyOnArchive(Config, *Ar))
2930b57cec5SDimitry Andric         return E;
2940b57cec5SDimitry Andric     } else {
2950b57cec5SDimitry Andric       FileBuffer FB(Config.OutputFilename);
2960b57cec5SDimitry Andric       if (Error E = executeObjcopyOnBinary(Config,
2970b57cec5SDimitry Andric                                            *BinaryOrErr.get().getBinary(), FB))
2980b57cec5SDimitry Andric         return E;
2990b57cec5SDimitry Andric     }
3000b57cec5SDimitry Andric   }
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric   if (Error E =
3030b57cec5SDimitry Andric           restoreStatOnFile(Config.OutputFilename, Stat, Config.PreserveDates))
3040b57cec5SDimitry Andric     return E;
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric   if (!Config.SplitDWO.empty()) {
3070b57cec5SDimitry Andric     Stat.permissions(static_cast<sys::fs::perms>(0666));
3080b57cec5SDimitry Andric     if (Error E =
3090b57cec5SDimitry Andric             restoreStatOnFile(Config.SplitDWO, Stat, Config.PreserveDates))
3100b57cec5SDimitry Andric       return E;
3110b57cec5SDimitry Andric   }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   return Error::success();
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric 
316480093f4SDimitry Andric namespace {
317480093f4SDimitry Andric 
318480093f4SDimitry Andric enum class ToolType { Objcopy, Strip, InstallNameTool };
319480093f4SDimitry Andric 
320480093f4SDimitry Andric } // anonymous namespace
321480093f4SDimitry Andric 
3220b57cec5SDimitry Andric int main(int argc, char **argv) {
3230b57cec5SDimitry Andric   InitLLVM X(argc, argv);
3240b57cec5SDimitry Andric   ToolName = argv[0];
325*d65cd7a5SDimitry Andric 
326*d65cd7a5SDimitry Andric   StringRef Stem = sys::path::stem(ToolName);
327*d65cd7a5SDimitry Andric   auto Is = [=](StringRef Tool) {
328*d65cd7a5SDimitry Andric     // We need to recognize the following filenames:
329*d65cd7a5SDimitry Andric     //
330*d65cd7a5SDimitry Andric     // llvm-objcopy -> objcopy
331*d65cd7a5SDimitry Andric     // strip-10.exe -> strip
332*d65cd7a5SDimitry Andric     // powerpc64-unknown-freebsd13-objcopy -> objcopy
333*d65cd7a5SDimitry Andric     // llvm-install-name-tool -> install-name-tool
334*d65cd7a5SDimitry Andric     auto I = Stem.rfind_lower(Tool);
335*d65cd7a5SDimitry Andric     return I != StringRef::npos &&
336*d65cd7a5SDimitry Andric            (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()]));
337*d65cd7a5SDimitry Andric   };
338*d65cd7a5SDimitry Andric   ToolType Tool = ToolType::Objcopy;
339*d65cd7a5SDimitry Andric   if (Is("strip"))
340*d65cd7a5SDimitry Andric     Tool = ToolType::Strip;
341*d65cd7a5SDimitry Andric   else if (Is("install-name-tool") || Is("install_name_tool"))
342*d65cd7a5SDimitry Andric     Tool = ToolType::InstallNameTool;
343*d65cd7a5SDimitry Andric 
3448bcb0991SDimitry Andric   // Expand response files.
3458bcb0991SDimitry Andric   // TODO: Move these lines, which are copied from lib/Support/CommandLine.cpp,
3468bcb0991SDimitry Andric   // into a separate function in the CommandLine library and call that function
3478bcb0991SDimitry Andric   // here. This is duplicated code.
3488bcb0991SDimitry Andric   SmallVector<const char *, 20> NewArgv(argv, argv + argc);
3498bcb0991SDimitry Andric   BumpPtrAllocator A;
3508bcb0991SDimitry Andric   StringSaver Saver(A);
3518bcb0991SDimitry Andric   cl::ExpandResponseFiles(Saver,
3528bcb0991SDimitry Andric                           Triple(sys::getProcessTriple()).isOSWindows()
3538bcb0991SDimitry Andric                               ? cl::TokenizeWindowsCommandLine
3548bcb0991SDimitry Andric                               : cl::TokenizeGNUCommandLine,
3558bcb0991SDimitry Andric                           NewArgv);
3568bcb0991SDimitry Andric 
3578bcb0991SDimitry Andric   auto Args = makeArrayRef(NewArgv).drop_front();
3580b57cec5SDimitry Andric   Expected<DriverConfig> DriverConfig =
359480093f4SDimitry Andric       (Tool == ToolType::Strip) ? parseStripOptions(Args, reportWarning)
360480093f4SDimitry Andric                                 : ((Tool == ToolType::InstallNameTool)
361480093f4SDimitry Andric                                        ? parseInstallNameToolOptions(Args)
362480093f4SDimitry Andric                                        : parseObjcopyOptions(Args, reportWarning));
3630b57cec5SDimitry Andric   if (!DriverConfig) {
3640b57cec5SDimitry Andric     logAllUnhandledErrors(DriverConfig.takeError(),
3650b57cec5SDimitry Andric                           WithColor::error(errs(), ToolName));
3660b57cec5SDimitry Andric     return 1;
3670b57cec5SDimitry Andric   }
3688bcb0991SDimitry Andric   for (CopyConfig &CopyConfig : DriverConfig->CopyConfigs) {
3690b57cec5SDimitry Andric     if (Error E = executeObjcopy(CopyConfig)) {
3700b57cec5SDimitry Andric       logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName));
3710b57cec5SDimitry Andric       return 1;
3720b57cec5SDimitry Andric     }
3730b57cec5SDimitry Andric   }
3740b57cec5SDimitry Andric 
3750b57cec5SDimitry Andric   return 0;
3760b57cec5SDimitry Andric }
377