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