Path: blob/main/contrib/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
35258 views
//===- llvm-objcopy.cpp ---------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "ObjcopyOptions.h"9#include "llvm/ADT/STLExtras.h"10#include "llvm/ADT/SmallVector.h"11#include "llvm/ADT/StringRef.h"12#include "llvm/ADT/Twine.h"13#include "llvm/BinaryFormat/ELF.h"14#include "llvm/ObjCopy/COFF/COFFConfig.h"15#include "llvm/ObjCopy/COFF/COFFObjcopy.h"16#include "llvm/ObjCopy/CommonConfig.h"17#include "llvm/ObjCopy/ELF/ELFConfig.h"18#include "llvm/ObjCopy/ELF/ELFObjcopy.h"19#include "llvm/ObjCopy/MachO/MachOConfig.h"20#include "llvm/ObjCopy/MachO/MachOObjcopy.h"21#include "llvm/ObjCopy/ObjCopy.h"22#include "llvm/ObjCopy/wasm/WasmConfig.h"23#include "llvm/ObjCopy/wasm/WasmObjcopy.h"24#include "llvm/Object/Archive.h"25#include "llvm/Object/ArchiveWriter.h"26#include "llvm/Object/Binary.h"27#include "llvm/Object/COFF.h"28#include "llvm/Object/ELFObjectFile.h"29#include "llvm/Object/ELFTypes.h"30#include "llvm/Object/Error.h"31#include "llvm/Object/MachO.h"32#include "llvm/Object/MachOUniversal.h"33#include "llvm/Object/Wasm.h"34#include "llvm/Option/Arg.h"35#include "llvm/Option/ArgList.h"36#include "llvm/Option/Option.h"37#include "llvm/Support/Casting.h"38#include "llvm/Support/CommandLine.h"39#include "llvm/Support/Errc.h"40#include "llvm/Support/Error.h"41#include "llvm/Support/ErrorHandling.h"42#include "llvm/Support/ErrorOr.h"43#include "llvm/Support/FileUtilities.h"44#include "llvm/Support/LLVMDriver.h"45#include "llvm/Support/Memory.h"46#include "llvm/Support/Path.h"47#include "llvm/Support/Process.h"48#include "llvm/Support/SmallVectorMemoryBuffer.h"49#include "llvm/Support/StringSaver.h"50#include "llvm/Support/WithColor.h"51#include "llvm/Support/raw_ostream.h"52#include "llvm/TargetParser/Host.h"53#include <algorithm>54#include <cassert>55#include <cstdlib>56#include <memory>57#include <system_error>58#include <utility>5960using namespace llvm;61using namespace llvm::objcopy;62using namespace llvm::object;6364// The name this program was invoked as.65static StringRef ToolName;6667static ErrorSuccess reportWarning(Error E) {68assert(E);69WithColor::warning(errs(), ToolName) << toString(std::move(E)) << '\n';70return Error::success();71}7273static Expected<DriverConfig> getDriverConfig(ArrayRef<const char *> Args) {74StringRef Stem = sys::path::stem(ToolName);75auto Is = [=](StringRef Tool) {76// We need to recognize the following filenames:77//78// llvm-objcopy -> objcopy79// strip-10.exe -> strip80// powerpc64-unknown-freebsd13-objcopy -> objcopy81// llvm-install-name-tool -> install-name-tool82auto I = Stem.rfind_insensitive(Tool);83return I != StringRef::npos &&84(I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()]));85};8687if (Is("bitcode-strip") || Is("bitcode_strip"))88return parseBitcodeStripOptions(Args, reportWarning);89else if (Is("strip"))90return parseStripOptions(Args, reportWarning);91else if (Is("install-name-tool") || Is("install_name_tool"))92return parseInstallNameToolOptions(Args);93else94return parseObjcopyOptions(Args, reportWarning);95}9697/// The function executeObjcopyOnIHex does the dispatch based on the format98/// of the output specified by the command line options.99static Error executeObjcopyOnIHex(ConfigManager &ConfigMgr, MemoryBuffer &In,100raw_ostream &Out) {101// TODO: support output formats other than ELF.102Expected<const ELFConfig &> ELFConfig = ConfigMgr.getELFConfig();103if (!ELFConfig)104return ELFConfig.takeError();105106return elf::executeObjcopyOnIHex(ConfigMgr.getCommonConfig(), *ELFConfig, In,107Out);108}109110/// The function executeObjcopyOnRawBinary does the dispatch based on the format111/// of the output specified by the command line options.112static Error executeObjcopyOnRawBinary(ConfigManager &ConfigMgr,113MemoryBuffer &In, raw_ostream &Out) {114const CommonConfig &Config = ConfigMgr.getCommonConfig();115switch (Config.OutputFormat) {116case FileFormat::ELF:117// FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the118// output format is binary/ihex or it's not given. This behavior differs from119// GNU objcopy. See https://bugs.llvm.org/show_bug.cgi?id=42171 for details.120case FileFormat::Binary:121case FileFormat::IHex:122case FileFormat::Unspecified:123case FileFormat::SREC:124Expected<const ELFConfig &> ELFConfig = ConfigMgr.getELFConfig();125if (!ELFConfig)126return ELFConfig.takeError();127128return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out);129}130131llvm_unreachable("unsupported output format");132}133134/// The function executeObjcopy does the higher level dispatch based on the type135/// of input (raw binary, archive or single object file) and takes care of the136/// format-agnostic modifications, i.e. preserving dates.137static Error executeObjcopy(ConfigManager &ConfigMgr) {138CommonConfig &Config = ConfigMgr.Common;139140Expected<FilePermissionsApplier> PermsApplierOrErr =141FilePermissionsApplier::create(Config.InputFilename);142if (!PermsApplierOrErr)143return PermsApplierOrErr.takeError();144145std::function<Error(raw_ostream & OutFile)> ObjcopyFunc;146147OwningBinary<llvm::object::Binary> BinaryHolder;148std::unique_ptr<MemoryBuffer> MemoryBufferHolder;149150if (Config.InputFormat == FileFormat::Binary ||151Config.InputFormat == FileFormat::IHex) {152ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =153MemoryBuffer::getFileOrSTDIN(Config.InputFilename);154if (!BufOrErr)155return createFileError(Config.InputFilename, BufOrErr.getError());156MemoryBufferHolder = std::move(*BufOrErr);157158if (Config.InputFormat == FileFormat::Binary)159ObjcopyFunc = [&](raw_ostream &OutFile) -> Error {160// Handle FileFormat::Binary.161return executeObjcopyOnRawBinary(ConfigMgr, *MemoryBufferHolder,162OutFile);163};164else165ObjcopyFunc = [&](raw_ostream &OutFile) -> Error {166// Handle FileFormat::IHex.167return executeObjcopyOnIHex(ConfigMgr, *MemoryBufferHolder, OutFile);168};169} else {170Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =171createBinary(Config.InputFilename);172if (!BinaryOrErr)173return createFileError(Config.InputFilename, BinaryOrErr.takeError());174BinaryHolder = std::move(*BinaryOrErr);175176if (Archive *Ar = dyn_cast<Archive>(BinaryHolder.getBinary())) {177// Handle Archive.178if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar))179return E;180} else {181// Handle llvm::object::Binary.182ObjcopyFunc = [&](raw_ostream &OutFile) -> Error {183return executeObjcopyOnBinary(ConfigMgr, *BinaryHolder.getBinary(),184OutFile);185};186}187}188189if (ObjcopyFunc) {190if (Config.SplitDWO.empty()) {191// Apply transformations described by Config and store result into192// Config.OutputFilename using specified ObjcopyFunc function.193if (Error E = writeToOutput(Config.OutputFilename, ObjcopyFunc))194return E;195} else {196Config.ExtractDWO = true;197Config.StripDWO = false;198// Copy .dwo tables from the Config.InputFilename into Config.SplitDWO199// file using specified ObjcopyFunc function.200if (Error E = writeToOutput(Config.SplitDWO, ObjcopyFunc))201return E;202Config.ExtractDWO = false;203Config.StripDWO = true;204// Apply transformations described by Config, remove .dwo tables and205// store result into Config.OutputFilename using specified ObjcopyFunc206// function.207if (Error E = writeToOutput(Config.OutputFilename, ObjcopyFunc))208return E;209}210}211212if (Error E =213PermsApplierOrErr->apply(Config.OutputFilename, Config.PreserveDates))214return E;215216if (!Config.SplitDWO.empty())217if (Error E =218PermsApplierOrErr->apply(Config.SplitDWO, Config.PreserveDates,219static_cast<sys::fs::perms>(0666)))220return E;221222return Error::success();223}224225int llvm_objcopy_main(int argc, char **argv, const llvm::ToolContext &) {226ToolName = argv[0];227228// Expand response files.229// TODO: Move these lines, which are copied from lib/Support/CommandLine.cpp,230// into a separate function in the CommandLine library and call that function231// here. This is duplicated code.232SmallVector<const char *, 20> NewArgv(argv, argv + argc);233BumpPtrAllocator A;234StringSaver Saver(A);235cl::ExpandResponseFiles(Saver,236Triple(sys::getProcessTriple()).isOSWindows()237? cl::TokenizeWindowsCommandLine238: cl::TokenizeGNUCommandLine,239NewArgv);240241auto Args = ArrayRef(NewArgv).drop_front();242Expected<DriverConfig> DriverConfig = getDriverConfig(Args);243244if (!DriverConfig) {245logAllUnhandledErrors(DriverConfig.takeError(),246WithColor::error(errs(), ToolName));247return 1;248}249for (ConfigManager &ConfigMgr : DriverConfig->CopyConfigs) {250if (Error E = executeObjcopy(ConfigMgr)) {251logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName));252return 1;253}254}255256return 0;257}258259260