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