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