1 //===- llvm-objcopy.cpp ---------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ObjcopyOptions.h" 10 #include "llvm/ADT/STLExtras.h" 11 #include "llvm/ADT/SmallVector.h" 12 #include "llvm/ADT/StringRef.h" 13 #include "llvm/ADT/Twine.h" 14 #include "llvm/BinaryFormat/ELF.h" 15 #include "llvm/ObjCopy/COFF/COFFConfig.h" 16 #include "llvm/ObjCopy/COFF/COFFObjcopy.h" 17 #include "llvm/ObjCopy/CommonConfig.h" 18 #include "llvm/ObjCopy/ELF/ELFConfig.h" 19 #include "llvm/ObjCopy/ELF/ELFObjcopy.h" 20 #include "llvm/ObjCopy/MachO/MachOConfig.h" 21 #include "llvm/ObjCopy/MachO/MachOObjcopy.h" 22 #include "llvm/ObjCopy/ObjCopy.h" 23 #include "llvm/ObjCopy/wasm/WasmConfig.h" 24 #include "llvm/ObjCopy/wasm/WasmObjcopy.h" 25 #include "llvm/Object/Archive.h" 26 #include "llvm/Object/ArchiveWriter.h" 27 #include "llvm/Object/Binary.h" 28 #include "llvm/Object/COFF.h" 29 #include "llvm/Object/ELFObjectFile.h" 30 #include "llvm/Object/ELFTypes.h" 31 #include "llvm/Object/Error.h" 32 #include "llvm/Object/MachO.h" 33 #include "llvm/Object/MachOUniversal.h" 34 #include "llvm/Object/Wasm.h" 35 #include "llvm/Option/Arg.h" 36 #include "llvm/Option/ArgList.h" 37 #include "llvm/Option/Option.h" 38 #include "llvm/Support/Casting.h" 39 #include "llvm/Support/CommandLine.h" 40 #include "llvm/Support/Errc.h" 41 #include "llvm/Support/Error.h" 42 #include "llvm/Support/ErrorHandling.h" 43 #include "llvm/Support/ErrorOr.h" 44 #include "llvm/Support/FileUtilities.h" 45 #include "llvm/Support/Host.h" 46 #include "llvm/Support/InitLLVM.h" 47 #include "llvm/Support/Memory.h" 48 #include "llvm/Support/Path.h" 49 #include "llvm/Support/Process.h" 50 #include "llvm/Support/SmallVectorMemoryBuffer.h" 51 #include "llvm/Support/StringSaver.h" 52 #include "llvm/Support/WithColor.h" 53 #include "llvm/Support/raw_ostream.h" 54 #include <algorithm> 55 #include <cassert> 56 #include <cstdlib> 57 #include <memory> 58 #include <string> 59 #include <system_error> 60 #include <utility> 61 62 using namespace llvm; 63 using namespace llvm::objcopy; 64 using namespace llvm::object; 65 66 // The name this program was invoked as. 67 static StringRef ToolName; 68 69 static ErrorSuccess reportWarning(Error E) { 70 assert(E); 71 WithColor::warning(errs(), ToolName) << toString(std::move(E)) << '\n'; 72 return Error::success(); 73 } 74 75 static Expected<DriverConfig> getDriverConfig(ArrayRef<const char *> Args) { 76 StringRef Stem = sys::path::stem(ToolName); 77 auto Is = [=](StringRef Tool) { 78 // We need to recognize the following filenames: 79 // 80 // llvm-objcopy -> objcopy 81 // strip-10.exe -> strip 82 // powerpc64-unknown-freebsd13-objcopy -> objcopy 83 // llvm-install-name-tool -> install-name-tool 84 auto I = Stem.rfind_insensitive(Tool); 85 return I != StringRef::npos && 86 (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); 87 }; 88 89 if (Is("bitcode-strip") || Is("bitcode_strip")) 90 return parseBitcodeStripOptions(Args, reportWarning); 91 else if (Is("strip")) 92 return parseStripOptions(Args, reportWarning); 93 else if (Is("install-name-tool") || Is("install_name_tool")) 94 return parseInstallNameToolOptions(Args); 95 else 96 return parseObjcopyOptions(Args, reportWarning); 97 } 98 99 /// The function executeObjcopyOnIHex does the dispatch based on the format 100 /// of the output specified by the command line options. 101 static Error executeObjcopyOnIHex(ConfigManager &ConfigMgr, MemoryBuffer &In, 102 raw_ostream &Out) { 103 // TODO: support output formats other than ELF. 104 Expected<const ELFConfig &> ELFConfig = ConfigMgr.getELFConfig(); 105 if (!ELFConfig) 106 return ELFConfig.takeError(); 107 108 return elf::executeObjcopyOnIHex(ConfigMgr.getCommonConfig(), *ELFConfig, In, 109 Out); 110 } 111 112 /// The function executeObjcopyOnRawBinary does the dispatch based on the format 113 /// of the output specified by the command line options. 114 static Error executeObjcopyOnRawBinary(ConfigManager &ConfigMgr, 115 MemoryBuffer &In, raw_ostream &Out) { 116 const CommonConfig &Config = ConfigMgr.getCommonConfig(); 117 switch (Config.OutputFormat) { 118 case FileFormat::ELF: 119 // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the 120 // output format is binary/ihex or it's not given. This behavior differs from 121 // GNU objcopy. See https://bugs.llvm.org/show_bug.cgi?id=42171 for details. 122 case FileFormat::Binary: 123 case FileFormat::IHex: 124 case FileFormat::Unspecified: 125 Expected<const ELFConfig &> ELFConfig = ConfigMgr.getELFConfig(); 126 if (!ELFConfig) 127 return ELFConfig.takeError(); 128 129 return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out); 130 } 131 132 llvm_unreachable("unsupported output format"); 133 } 134 135 /// The function executeObjcopy does the higher level dispatch based on the type 136 /// of input (raw binary, archive or single object file) and takes care of the 137 /// format-agnostic modifications, i.e. preserving dates. 138 static Error executeObjcopy(ConfigManager &ConfigMgr) { 139 CommonConfig &Config = ConfigMgr.Common; 140 141 Expected<FilePermissionsApplier> PermsApplierOrErr = 142 FilePermissionsApplier::create(Config.InputFilename); 143 if (!PermsApplierOrErr) 144 return PermsApplierOrErr.takeError(); 145 146 std::function<Error(raw_ostream & OutFile)> ObjcopyFunc; 147 148 OwningBinary<llvm::object::Binary> BinaryHolder; 149 std::unique_ptr<MemoryBuffer> MemoryBufferHolder; 150 151 if (Config.InputFormat == FileFormat::Binary || 152 Config.InputFormat == FileFormat::IHex) { 153 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = 154 MemoryBuffer::getFileOrSTDIN(Config.InputFilename); 155 if (!BufOrErr) 156 return createFileError(Config.InputFilename, BufOrErr.getError()); 157 MemoryBufferHolder = std::move(*BufOrErr); 158 159 if (Config.InputFormat == FileFormat::Binary) 160 ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { 161 // Handle FileFormat::Binary. 162 return executeObjcopyOnRawBinary(ConfigMgr, *MemoryBufferHolder, 163 OutFile); 164 }; 165 else 166 ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { 167 // Handle FileFormat::IHex. 168 return executeObjcopyOnIHex(ConfigMgr, *MemoryBufferHolder, OutFile); 169 }; 170 } else { 171 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr = 172 createBinary(Config.InputFilename); 173 if (!BinaryOrErr) 174 return createFileError(Config.InputFilename, BinaryOrErr.takeError()); 175 BinaryHolder = std::move(*BinaryOrErr); 176 177 if (Archive *Ar = dyn_cast<Archive>(BinaryHolder.getBinary())) { 178 // Handle Archive. 179 if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar)) 180 return E; 181 } else { 182 // Handle llvm::object::Binary. 183 ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { 184 return executeObjcopyOnBinary(ConfigMgr, *BinaryHolder.getBinary(), 185 OutFile); 186 }; 187 } 188 } 189 190 if (ObjcopyFunc) { 191 if (Config.SplitDWO.empty()) { 192 // Apply transformations described by Config and store result into 193 // Config.OutputFilename using specified ObjcopyFunc function. 194 if (Error E = writeToOutput(Config.OutputFilename, ObjcopyFunc)) 195 return E; 196 } else { 197 Config.ExtractDWO = true; 198 Config.StripDWO = false; 199 // Copy .dwo tables from the Config.InputFilename into Config.SplitDWO 200 // file using specified ObjcopyFunc function. 201 if (Error E = writeToOutput(Config.SplitDWO, ObjcopyFunc)) 202 return E; 203 Config.ExtractDWO = false; 204 Config.StripDWO = true; 205 // Apply transformations described by Config, remove .dwo tables and 206 // store result into Config.OutputFilename using specified ObjcopyFunc 207 // function. 208 if (Error E = writeToOutput(Config.OutputFilename, ObjcopyFunc)) 209 return E; 210 } 211 } 212 213 if (Error E = 214 PermsApplierOrErr->apply(Config.OutputFilename, Config.PreserveDates)) 215 return E; 216 217 if (!Config.SplitDWO.empty()) 218 if (Error E = 219 PermsApplierOrErr->apply(Config.SplitDWO, Config.PreserveDates, 220 static_cast<sys::fs::perms>(0666))) 221 return E; 222 223 return Error::success(); 224 } 225 226 int llvm_objcopy_main(int argc, char **argv) { 227 InitLLVM X(argc, argv); 228 ToolName = argv[0]; 229 230 // Expand response files. 231 // TODO: Move these lines, which are copied from lib/Support/CommandLine.cpp, 232 // into a separate function in the CommandLine library and call that function 233 // here. This is duplicated code. 234 SmallVector<const char *, 20> NewArgv(argv, argv + argc); 235 BumpPtrAllocator A; 236 StringSaver Saver(A); 237 cl::ExpandResponseFiles(Saver, 238 Triple(sys::getProcessTriple()).isOSWindows() 239 ? cl::TokenizeWindowsCommandLine 240 : cl::TokenizeGNUCommandLine, 241 NewArgv); 242 243 auto Args = ArrayRef(NewArgv).drop_front(); 244 Expected<DriverConfig> DriverConfig = getDriverConfig(Args); 245 246 if (!DriverConfig) { 247 logAllUnhandledErrors(DriverConfig.takeError(), 248 WithColor::error(errs(), ToolName)); 249 return 1; 250 } 251 for (ConfigManager &ConfigMgr : DriverConfig->CopyConfigs) { 252 if (Error E = executeObjcopy(ConfigMgr)) { 253 logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName)); 254 return 1; 255 } 256 } 257 258 return 0; 259 } 260