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 "llvm-objcopy.h" 10 #include "COFF/COFFConfig.h" 11 #include "COFF/COFFObjcopy.h" 12 #include "CommonConfig.h" 13 #include "ConfigManager.h" 14 #include "ELF/ELFConfig.h" 15 #include "ELF/ELFObjcopy.h" 16 #include "MachO/MachOConfig.h" 17 #include "MachO/MachOObjcopy.h" 18 #include "wasm/WasmConfig.h" 19 #include "wasm/WasmObjcopy.h" 20 21 #include "llvm/ADT/STLExtras.h" 22 #include "llvm/ADT/SmallVector.h" 23 #include "llvm/ADT/StringRef.h" 24 #include "llvm/ADT/Twine.h" 25 #include "llvm/BinaryFormat/ELF.h" 26 #include "llvm/Object/Archive.h" 27 #include "llvm/Object/ArchiveWriter.h" 28 #include "llvm/Object/Binary.h" 29 #include "llvm/Object/COFF.h" 30 #include "llvm/Object/ELFObjectFile.h" 31 #include "llvm/Object/ELFTypes.h" 32 #include "llvm/Object/Error.h" 33 #include "llvm/Object/MachO.h" 34 #include "llvm/Object/MachOUniversal.h" 35 #include "llvm/Object/Wasm.h" 36 #include "llvm/Option/Arg.h" 37 #include "llvm/Option/ArgList.h" 38 #include "llvm/Option/Option.h" 39 #include "llvm/Support/Casting.h" 40 #include "llvm/Support/CommandLine.h" 41 #include "llvm/Support/Errc.h" 42 #include "llvm/Support/Error.h" 43 #include "llvm/Support/ErrorHandling.h" 44 #include "llvm/Support/ErrorOr.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); 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 // For regular archives this function simply calls llvm::writeArchive, 100 // For thin archives it writes the archive file itself as well as its members. 101 static Error deepWriteArchive(StringRef ArcName, 102 ArrayRef<NewArchiveMember> NewMembers, 103 bool WriteSymtab, object::Archive::Kind Kind, 104 bool Deterministic, bool Thin) { 105 if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind, 106 Deterministic, Thin)) 107 return createFileError(ArcName, std::move(E)); 108 109 if (!Thin) 110 return Error::success(); 111 112 for (const NewArchiveMember &Member : NewMembers) { 113 // For regular files (as is the case for deepWriteArchive), 114 // FileOutputBuffer::create will return OnDiskBuffer. 115 // OnDiskBuffer uses a temporary file and then renames it. So in reality 116 // there is no inefficiency / duplicated in-memory buffers in this case. For 117 // now in-memory buffers can not be completely avoided since 118 // NewArchiveMember still requires them even though writeArchive does not 119 // write them on disk. 120 Expected<std::unique_ptr<FileOutputBuffer>> FB = 121 FileOutputBuffer::create(Member.MemberName, Member.Buf->getBufferSize(), 122 FileOutputBuffer::F_executable); 123 if (!FB) 124 return FB.takeError(); 125 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(), 126 (*FB)->getBufferStart()); 127 if (Error E = (*FB)->commit()) 128 return E; 129 } 130 return Error::success(); 131 } 132 133 /// The function executeObjcopyOnIHex does the dispatch based on the format 134 /// of the output specified by the command line options. 135 static Error executeObjcopyOnIHex(ConfigManager &ConfigMgr, MemoryBuffer &In, 136 raw_ostream &Out) { 137 // TODO: support output formats other than ELF. 138 Expected<const ELFConfig &> ELFConfig = ConfigMgr.getELFConfig(); 139 if (!ELFConfig) 140 return ELFConfig.takeError(); 141 142 return elf::executeObjcopyOnIHex(ConfigMgr.getCommonConfig(), *ELFConfig, In, 143 Out); 144 } 145 146 /// The function executeObjcopyOnRawBinary does the dispatch based on the format 147 /// of the output specified by the command line options. 148 static Error executeObjcopyOnRawBinary(ConfigManager &ConfigMgr, 149 MemoryBuffer &In, raw_ostream &Out) { 150 const CommonConfig &Config = ConfigMgr.getCommonConfig(); 151 switch (Config.OutputFormat) { 152 case FileFormat::ELF: 153 // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the 154 // output format is binary/ihex or it's not given. This behavior differs from 155 // GNU objcopy. See https://bugs.llvm.org/show_bug.cgi?id=42171 for details. 156 case FileFormat::Binary: 157 case FileFormat::IHex: 158 case FileFormat::Unspecified: 159 Expected<const ELFConfig &> ELFConfig = ConfigMgr.getELFConfig(); 160 if (!ELFConfig) 161 return ELFConfig.takeError(); 162 163 return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out); 164 } 165 166 llvm_unreachable("unsupported output format"); 167 } 168 169 /// The function executeObjcopyOnBinary does the dispatch based on the format 170 /// of the input binary (ELF, MachO or COFF). 171 static Error executeObjcopyOnBinary(const MultiFormatConfig &Config, 172 object::Binary &In, raw_ostream &Out) { 173 if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) { 174 Expected<const ELFConfig &> ELFConfig = Config.getELFConfig(); 175 if (!ELFConfig) 176 return ELFConfig.takeError(); 177 178 return elf::executeObjcopyOnBinary(Config.getCommonConfig(), *ELFConfig, 179 *ELFBinary, Out); 180 } else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In)) { 181 Expected<const COFFConfig &> COFFConfig = Config.getCOFFConfig(); 182 if (!COFFConfig) 183 return COFFConfig.takeError(); 184 185 return coff::executeObjcopyOnBinary(Config.getCommonConfig(), *COFFConfig, 186 *COFFBinary, Out); 187 } else if (auto *MachOBinary = dyn_cast<object::MachOObjectFile>(&In)) { 188 Expected<const MachOConfig &> MachOConfig = Config.getMachOConfig(); 189 if (!MachOConfig) 190 return MachOConfig.takeError(); 191 192 return macho::executeObjcopyOnBinary(Config.getCommonConfig(), *MachOConfig, 193 *MachOBinary, Out); 194 } else if (auto *MachOUniversalBinary = 195 dyn_cast<object::MachOUniversalBinary>(&In)) { 196 return macho::executeObjcopyOnMachOUniversalBinary( 197 Config, *MachOUniversalBinary, Out); 198 } else if (auto *WasmBinary = dyn_cast<object::WasmObjectFile>(&In)) { 199 Expected<const WasmConfig &> WasmConfig = Config.getWasmConfig(); 200 if (!WasmConfig) 201 return WasmConfig.takeError(); 202 203 return objcopy::wasm::executeObjcopyOnBinary(Config.getCommonConfig(), 204 *WasmConfig, *WasmBinary, Out); 205 } else 206 return createStringError(object_error::invalid_file_type, 207 "unsupported object file format"); 208 } 209 210 namespace llvm { 211 namespace objcopy { 212 213 Expected<std::vector<NewArchiveMember>> 214 createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) { 215 std::vector<NewArchiveMember> NewArchiveMembers; 216 Error Err = Error::success(); 217 for (const Archive::Child &Child : Ar.children(Err)) { 218 Expected<StringRef> ChildNameOrErr = Child.getName(); 219 if (!ChildNameOrErr) 220 return createFileError(Ar.getFileName(), ChildNameOrErr.takeError()); 221 222 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); 223 if (!ChildOrErr) 224 return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")", 225 ChildOrErr.takeError()); 226 227 SmallVector<char, 0> Buffer; 228 raw_svector_ostream MemStream(Buffer); 229 230 if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream)) 231 return std::move(E); 232 233 Expected<NewArchiveMember> Member = NewArchiveMember::getOldMember( 234 Child, Config.getCommonConfig().DeterministicArchives); 235 if (!Member) 236 return createFileError(Ar.getFileName(), Member.takeError()); 237 238 Member->Buf = std::make_unique<SmallVectorMemoryBuffer>( 239 std::move(Buffer), ChildNameOrErr.get()); 240 Member->MemberName = Member->Buf->getBufferIdentifier(); 241 NewArchiveMembers.push_back(std::move(*Member)); 242 } 243 if (Err) 244 return createFileError(Config.getCommonConfig().InputFilename, 245 std::move(Err)); 246 return std::move(NewArchiveMembers); 247 } 248 249 } // end namespace objcopy 250 } // end namespace llvm 251 252 static Error executeObjcopyOnArchive(const ConfigManager &ConfigMgr, 253 const object::Archive &Ar) { 254 Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr = 255 createNewArchiveMembers(ConfigMgr, Ar); 256 if (!NewArchiveMembersOrErr) 257 return NewArchiveMembersOrErr.takeError(); 258 const CommonConfig &Config = ConfigMgr.getCommonConfig(); 259 return deepWriteArchive(Config.OutputFilename, *NewArchiveMembersOrErr, 260 Ar.hasSymbolTable(), Ar.kind(), 261 Config.DeterministicArchives, Ar.isThin()); 262 } 263 264 static Error restoreStatOnFile(StringRef Filename, 265 const sys::fs::file_status &Stat, 266 const ConfigManager &ConfigMgr) { 267 int FD; 268 const CommonConfig &Config = ConfigMgr.getCommonConfig(); 269 270 // Writing to stdout should not be treated as an error here, just 271 // do not set access/modification times or permissions. 272 if (Filename == "-") 273 return Error::success(); 274 275 if (auto EC = 276 sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting)) 277 return createFileError(Filename, EC); 278 279 if (Config.PreserveDates) 280 if (auto EC = sys::fs::setLastAccessAndModificationTime( 281 FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime())) 282 return createFileError(Filename, EC); 283 284 sys::fs::file_status OStat; 285 if (std::error_code EC = sys::fs::status(FD, OStat)) 286 return createFileError(Filename, EC); 287 if (OStat.type() == sys::fs::file_type::regular_file) { 288 #ifndef _WIN32 289 // Keep ownership if llvm-objcopy is called under root. 290 if (Config.InputFilename == Config.OutputFilename && OStat.getUser() == 0) 291 sys::fs::changeFileOwnership(FD, Stat.getUser(), Stat.getGroup()); 292 #endif 293 294 sys::fs::perms Perm = Stat.permissions(); 295 if (Config.InputFilename != Config.OutputFilename) 296 Perm = static_cast<sys::fs::perms>(Perm & ~sys::fs::getUmask() & ~06000); 297 #ifdef _WIN32 298 if (auto EC = sys::fs::setPermissions(Filename, Perm)) 299 #else 300 if (auto EC = sys::fs::setPermissions(FD, Perm)) 301 #endif 302 return createFileError(Filename, EC); 303 } 304 305 if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD)) 306 return createFileError(Filename, EC); 307 308 return Error::success(); 309 } 310 311 /// The function executeObjcopy does the higher level dispatch based on the type 312 /// of input (raw binary, archive or single object file) and takes care of the 313 /// format-agnostic modifications, i.e. preserving dates. 314 static Error executeObjcopy(ConfigManager &ConfigMgr) { 315 CommonConfig &Config = ConfigMgr.Common; 316 317 sys::fs::file_status Stat; 318 if (Config.InputFilename != "-") { 319 if (auto EC = sys::fs::status(Config.InputFilename, Stat)) 320 return createFileError(Config.InputFilename, EC); 321 } else { 322 Stat.permissions(static_cast<sys::fs::perms>(0777)); 323 } 324 325 std::function<Error(raw_ostream & OutFile)> ObjcopyFunc; 326 327 OwningBinary<llvm::object::Binary> BinaryHolder; 328 std::unique_ptr<MemoryBuffer> MemoryBufferHolder; 329 330 if (Config.InputFormat == FileFormat::Binary || 331 Config.InputFormat == FileFormat::IHex) { 332 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = 333 MemoryBuffer::getFileOrSTDIN(Config.InputFilename); 334 if (!BufOrErr) 335 return createFileError(Config.InputFilename, BufOrErr.getError()); 336 MemoryBufferHolder = std::move(*BufOrErr); 337 338 if (Config.InputFormat == FileFormat::Binary) 339 ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { 340 // Handle FileFormat::Binary. 341 return executeObjcopyOnRawBinary(ConfigMgr, *MemoryBufferHolder, 342 OutFile); 343 }; 344 else 345 ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { 346 // Handle FileFormat::IHex. 347 return executeObjcopyOnIHex(ConfigMgr, *MemoryBufferHolder, OutFile); 348 }; 349 } else { 350 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr = 351 createBinary(Config.InputFilename); 352 if (!BinaryOrErr) 353 return createFileError(Config.InputFilename, BinaryOrErr.takeError()); 354 BinaryHolder = std::move(*BinaryOrErr); 355 356 if (Archive *Ar = dyn_cast<Archive>(BinaryHolder.getBinary())) { 357 // Handle Archive. 358 if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar)) 359 return E; 360 } else { 361 // Handle llvm::object::Binary. 362 ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { 363 return executeObjcopyOnBinary(ConfigMgr, *BinaryHolder.getBinary(), 364 OutFile); 365 }; 366 } 367 } 368 369 if (ObjcopyFunc) { 370 if (Config.SplitDWO.empty()) { 371 // Apply transformations described by Config and store result into 372 // Config.OutputFilename using specified ObjcopyFunc function. 373 if (Error E = writeToOutput(Config.OutputFilename, ObjcopyFunc)) 374 return E; 375 } else { 376 Config.ExtractDWO = true; 377 Config.StripDWO = false; 378 // Copy .dwo tables from the Config.InputFilename into Config.SplitDWO 379 // file using specified ObjcopyFunc function. 380 if (Error E = writeToOutput(Config.SplitDWO, ObjcopyFunc)) 381 return E; 382 Config.ExtractDWO = false; 383 Config.StripDWO = true; 384 // Apply transformations described by Config, remove .dwo tables and 385 // store result into Config.OutputFilename using specified ObjcopyFunc 386 // function. 387 if (Error E = writeToOutput(Config.OutputFilename, ObjcopyFunc)) 388 return E; 389 } 390 } 391 392 if (Error E = restoreStatOnFile(Config.OutputFilename, Stat, ConfigMgr)) 393 return E; 394 395 if (!Config.SplitDWO.empty()) { 396 Stat.permissions(static_cast<sys::fs::perms>(0666)); 397 if (Error E = restoreStatOnFile(Config.SplitDWO, Stat, ConfigMgr)) 398 return E; 399 } 400 401 return Error::success(); 402 } 403 404 int main(int argc, char **argv) { 405 InitLLVM X(argc, argv); 406 ToolName = argv[0]; 407 408 // Expand response files. 409 // TODO: Move these lines, which are copied from lib/Support/CommandLine.cpp, 410 // into a separate function in the CommandLine library and call that function 411 // here. This is duplicated code. 412 SmallVector<const char *, 20> NewArgv(argv, argv + argc); 413 BumpPtrAllocator A; 414 StringSaver Saver(A); 415 cl::ExpandResponseFiles(Saver, 416 Triple(sys::getProcessTriple()).isOSWindows() 417 ? cl::TokenizeWindowsCommandLine 418 : cl::TokenizeGNUCommandLine, 419 NewArgv); 420 421 auto Args = makeArrayRef(NewArgv).drop_front(); 422 Expected<DriverConfig> DriverConfig = getDriverConfig(Args); 423 424 if (!DriverConfig) { 425 logAllUnhandledErrors(DriverConfig.takeError(), 426 WithColor::error(errs(), ToolName)); 427 return 1; 428 } 429 for (ConfigManager &ConfigMgr : DriverConfig->CopyConfigs) { 430 if (Error E = executeObjcopy(ConfigMgr)) { 431 logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName)); 432 return 1; 433 } 434 } 435 436 return 0; 437 } 438