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