1 //===-- llvm-lipo.cpp - a tool for manipulating universal binaries --------===// 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 // A utility for creating / splitting / inspecting universal binaries. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/ADT/STLExtras.h" 14 #include "llvm/BinaryFormat/MachO.h" 15 #include "llvm/IR/LLVMContext.h" 16 #include "llvm/IR/Module.h" 17 #include "llvm/Object/Archive.h" 18 #include "llvm/Object/Binary.h" 19 #include "llvm/Object/IRObjectFile.h" 20 #include "llvm/Object/MachO.h" 21 #include "llvm/Object/MachOUniversal.h" 22 #include "llvm/Object/MachOUniversalWriter.h" 23 #include "llvm/Object/ObjectFile.h" 24 #include "llvm/Option/Arg.h" 25 #include "llvm/Option/ArgList.h" 26 #include "llvm/Support/CommandLine.h" 27 #include "llvm/Support/Error.h" 28 #include "llvm/Support/FileOutputBuffer.h" 29 #include "llvm/Support/LLVMDriver.h" 30 #include "llvm/Support/TargetSelect.h" 31 #include "llvm/Support/WithColor.h" 32 #include "llvm/TargetParser/Triple.h" 33 #include "llvm/TextAPI/Architecture.h" 34 #include <optional> 35 36 using namespace llvm; 37 using namespace llvm::object; 38 39 static const StringRef ToolName = "llvm-lipo"; 40 41 [[noreturn]] static void reportError(Twine Message) { 42 WithColor::error(errs(), ToolName) << Message << "\n"; 43 errs().flush(); 44 exit(EXIT_FAILURE); 45 } 46 47 [[noreturn]] static void reportError(Error E) { 48 assert(E); 49 std::string Buf; 50 raw_string_ostream OS(Buf); 51 logAllUnhandledErrors(std::move(E), OS); 52 OS.flush(); 53 reportError(Buf); 54 } 55 56 [[noreturn]] static void reportError(StringRef File, Error E) { 57 assert(E); 58 std::string Buf; 59 raw_string_ostream OS(Buf); 60 logAllUnhandledErrors(std::move(E), OS); 61 OS.flush(); 62 WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf; 63 exit(EXIT_FAILURE); 64 } 65 66 namespace { 67 enum LipoID { 68 LIPO_INVALID = 0, // This is not an option ID. 69 #define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(LIPO_, __VA_ARGS__), 70 #include "LipoOpts.inc" 71 #undef OPTION 72 }; 73 74 namespace lipo { 75 #define OPTTABLE_STR_TABLE_CODE 76 #include "LipoOpts.inc" 77 #undef OPTTABLE_STR_TABLE_CODE 78 79 #define OPTTABLE_PREFIXES_TABLE_CODE 80 #include "LipoOpts.inc" 81 #undef OPTTABLE_PREFIXES_TABLE_CODE 82 83 using namespace llvm::opt; 84 static constexpr opt::OptTable::Info LipoInfoTable[] = { 85 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(LIPO_, __VA_ARGS__), 86 #include "LipoOpts.inc" 87 #undef OPTION 88 }; 89 } // namespace lipo 90 91 class LipoOptTable : public opt::GenericOptTable { 92 public: 93 LipoOptTable() 94 : opt::GenericOptTable(lipo::OptionStrTable, lipo::OptionPrefixesTable, 95 lipo::LipoInfoTable) {} 96 }; 97 98 enum class LipoAction { 99 PrintArchs, 100 PrintInfo, 101 VerifyArch, 102 ThinArch, 103 ExtractArch, 104 CreateUniversal, 105 ReplaceArch, 106 }; 107 108 struct InputFile { 109 std::optional<StringRef> ArchType; 110 StringRef FileName; 111 }; 112 113 struct Config { 114 SmallVector<InputFile, 1> InputFiles; 115 SmallVector<std::string, 1> VerifyArchList; 116 SmallVector<InputFile, 1> ReplacementFiles; 117 StringMap<const uint32_t> SegmentAlignments; 118 std::string ArchType; 119 std::string OutputFile; 120 LipoAction ActionToPerform; 121 bool UseFat64; 122 }; 123 124 static Slice createSliceFromArchive(LLVMContext &LLVMCtx, const Archive &A) { 125 Expected<Slice> ArchiveOrSlice = Slice::create(A, &LLVMCtx); 126 if (!ArchiveOrSlice) 127 reportError(A.getFileName(), ArchiveOrSlice.takeError()); 128 return *ArchiveOrSlice; 129 } 130 131 static Slice createSliceFromIR(const IRObjectFile &IRO, unsigned Align) { 132 Expected<Slice> IROrErr = Slice::create(IRO, Align); 133 if (!IROrErr) 134 reportError(IRO.getFileName(), IROrErr.takeError()); 135 return *IROrErr; 136 } 137 138 } // end namespace 139 140 static void validateArchitectureName(StringRef ArchitectureName) { 141 if (!MachOObjectFile::isValidArch(ArchitectureName)) { 142 std::string Buf; 143 raw_string_ostream OS(Buf); 144 OS << "Invalid architecture: " << ArchitectureName 145 << "\nValid architecture names are:"; 146 for (auto arch : MachOObjectFile::getValidArchs()) 147 OS << " " << arch; 148 reportError(Buf); 149 } 150 } 151 152 static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) { 153 Config C; 154 LipoOptTable T; 155 unsigned MissingArgumentIndex, MissingArgumentCount; 156 opt::InputArgList InputArgs = 157 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 158 159 if (MissingArgumentCount) 160 reportError("missing argument to " + 161 StringRef(InputArgs.getArgString(MissingArgumentIndex)) + 162 " option"); 163 164 if (InputArgs.size() == 0) { 165 // printHelp does not accept Twine. 166 T.printHelp(errs(), "llvm-lipo input[s] option[s]", "llvm-lipo"); 167 exit(EXIT_FAILURE); 168 } 169 170 if (InputArgs.hasArg(LIPO_help)) { 171 // printHelp does not accept Twine. 172 T.printHelp(outs(), "llvm-lipo input[s] option[s]", "llvm-lipo"); 173 exit(EXIT_SUCCESS); 174 } 175 176 if (InputArgs.hasArg(LIPO_version)) { 177 outs() << ToolName + "\n"; 178 cl::PrintVersionMessage(); 179 exit(EXIT_SUCCESS); 180 } 181 182 for (auto *Arg : InputArgs.filtered(LIPO_UNKNOWN)) 183 reportError("unknown argument '" + Arg->getAsString(InputArgs) + "'"); 184 185 for (auto *Arg : InputArgs.filtered(LIPO_INPUT)) 186 C.InputFiles.push_back({std::nullopt, Arg->getValue()}); 187 for (auto *Arg : InputArgs.filtered(LIPO_arch)) { 188 validateArchitectureName(Arg->getValue(0)); 189 assert(Arg->getValue(1) && "file_name is missing"); 190 C.InputFiles.push_back({StringRef(Arg->getValue(0)), Arg->getValue(1)}); 191 } 192 193 if (C.InputFiles.empty()) 194 reportError("at least one input file should be specified"); 195 196 if (InputArgs.hasArg(LIPO_output)) 197 C.OutputFile = std::string(InputArgs.getLastArgValue(LIPO_output)); 198 199 for (auto *Segalign : InputArgs.filtered(LIPO_segalign)) { 200 if (!Segalign->getValue(1)) 201 reportError("segalign is missing an argument: expects -segalign " 202 "arch_type alignment_value"); 203 204 validateArchitectureName(Segalign->getValue(0)); 205 206 uint32_t AlignmentValue; 207 if (!to_integer<uint32_t>(Segalign->getValue(1), AlignmentValue, 16)) 208 reportError("argument to -segalign <arch_type> " + 209 Twine(Segalign->getValue(1)) + 210 " (hex) is not a proper hexadecimal number"); 211 if (!isPowerOf2_32(AlignmentValue)) 212 reportError("argument to -segalign <arch_type> " + 213 Twine(Segalign->getValue(1)) + 214 " (hex) must be a non-zero power of two"); 215 if (Log2_32(AlignmentValue) > MachOUniversalBinary::MaxSectionAlignment) 216 reportError( 217 "argument to -segalign <arch_type> " + Twine(Segalign->getValue(1)) + 218 " (hex) must be less than or equal to the maximum section align 2^" + 219 Twine(MachOUniversalBinary::MaxSectionAlignment)); 220 auto Entry = C.SegmentAlignments.try_emplace(Segalign->getValue(0), 221 Log2_32(AlignmentValue)); 222 if (!Entry.second) 223 reportError("-segalign " + Twine(Segalign->getValue(0)) + 224 " <alignment_value> specified multiple times: " + 225 Twine(1 << Entry.first->second) + ", " + 226 Twine(AlignmentValue)); 227 } 228 229 C.UseFat64 = InputArgs.hasArg(LIPO_fat64); 230 231 SmallVector<opt::Arg *, 1> ActionArgs(InputArgs.filtered(LIPO_action_group)); 232 if (ActionArgs.empty()) 233 reportError("at least one action should be specified"); 234 // errors if multiple actions specified other than replace 235 // multiple replace flags may be specified, as long as they are not mixed with 236 // other action flags 237 auto ReplacementArgsRange = InputArgs.filtered(LIPO_replace); 238 if (ActionArgs.size() > 1 && 239 ActionArgs.size() != 240 static_cast<size_t>(std::distance(ReplacementArgsRange.begin(), 241 ReplacementArgsRange.end()))) { 242 std::string Buf; 243 raw_string_ostream OS(Buf); 244 OS << "only one of the following actions can be specified:"; 245 for (auto *Arg : ActionArgs) 246 OS << " " << Arg->getSpelling(); 247 reportError(Buf); 248 } 249 250 switch (ActionArgs[0]->getOption().getID()) { 251 case LIPO_verify_arch: 252 for (auto A : InputArgs.getAllArgValues(LIPO_verify_arch)) 253 C.VerifyArchList.push_back(A); 254 if (C.VerifyArchList.empty()) 255 reportError( 256 "verify_arch requires at least one architecture to be specified"); 257 if (C.InputFiles.size() > 1) 258 reportError("verify_arch expects a single input file"); 259 C.ActionToPerform = LipoAction::VerifyArch; 260 return C; 261 262 case LIPO_archs: 263 if (C.InputFiles.size() > 1) 264 reportError("archs expects a single input file"); 265 C.ActionToPerform = LipoAction::PrintArchs; 266 return C; 267 268 case LIPO_info: 269 C.ActionToPerform = LipoAction::PrintInfo; 270 return C; 271 272 case LIPO_thin: 273 if (C.InputFiles.size() > 1) 274 reportError("thin expects a single input file"); 275 if (C.OutputFile.empty()) 276 reportError("thin expects a single output file"); 277 C.ArchType = ActionArgs[0]->getValue(); 278 validateArchitectureName(C.ArchType); 279 C.ActionToPerform = LipoAction::ThinArch; 280 return C; 281 282 case LIPO_extract: 283 if (C.InputFiles.size() > 1) 284 reportError("extract expects a single input file"); 285 if (C.OutputFile.empty()) 286 reportError("extract expects a single output file"); 287 C.ArchType = ActionArgs[0]->getValue(); 288 validateArchitectureName(C.ArchType); 289 C.ActionToPerform = LipoAction::ExtractArch; 290 return C; 291 292 case LIPO_create: 293 if (C.OutputFile.empty()) 294 reportError("create expects a single output file to be specified"); 295 C.ActionToPerform = LipoAction::CreateUniversal; 296 return C; 297 298 case LIPO_replace: 299 for (auto *Action : ActionArgs) { 300 assert(Action->getValue(1) && "file_name is missing"); 301 validateArchitectureName(Action->getValue(0)); 302 C.ReplacementFiles.push_back( 303 {StringRef(Action->getValue(0)), Action->getValue(1)}); 304 } 305 306 if (C.OutputFile.empty()) 307 reportError("replace expects a single output file to be specified"); 308 if (C.InputFiles.size() > 1) 309 reportError("replace expects a single input file"); 310 C.ActionToPerform = LipoAction::ReplaceArch; 311 return C; 312 313 default: 314 reportError("llvm-lipo action unspecified"); 315 } 316 } 317 318 static SmallVector<OwningBinary<Binary>, 1> 319 readInputBinaries(LLVMContext &LLVMCtx, ArrayRef<InputFile> InputFiles) { 320 SmallVector<OwningBinary<Binary>, 1> InputBinaries; 321 for (const InputFile &IF : InputFiles) { 322 Expected<OwningBinary<Binary>> BinaryOrErr = 323 createBinary(IF.FileName, &LLVMCtx); 324 if (!BinaryOrErr) 325 reportError(IF.FileName, BinaryOrErr.takeError()); 326 const Binary *B = BinaryOrErr->getBinary(); 327 if (!B->isArchive() && !B->isMachO() && !B->isMachOUniversalBinary() && 328 !B->isIR()) 329 reportError("File " + IF.FileName + " has unsupported binary format"); 330 if (IF.ArchType && (B->isMachO() || B->isArchive() || B->isIR())) { 331 const auto S = B->isMachO() ? Slice(*cast<MachOObjectFile>(B)) 332 : B->isArchive() 333 ? createSliceFromArchive(LLVMCtx, *cast<Archive>(B)) 334 : createSliceFromIR(*cast<IRObjectFile>(B), 0); 335 const auto SpecifiedCPUType = MachO::getCPUTypeFromArchitecture( 336 MachO::getArchitectureFromName( 337 Triple(*IF.ArchType).getArchName())) 338 .first; 339 // For compatibility with cctools' lipo the comparison is relaxed just to 340 // checking cputypes. 341 if (S.getCPUType() != SpecifiedCPUType) 342 reportError("specified architecture: " + *IF.ArchType + 343 " for file: " + B->getFileName() + 344 " does not match the file's architecture (" + 345 S.getArchString() + ")"); 346 } 347 InputBinaries.push_back(std::move(*BinaryOrErr)); 348 } 349 return InputBinaries; 350 } 351 352 [[noreturn]] static void 353 verifyArch(ArrayRef<OwningBinary<Binary>> InputBinaries, 354 ArrayRef<std::string> VerifyArchList) { 355 assert(!VerifyArchList.empty() && 356 "The list of architectures should be non-empty"); 357 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); 358 359 for (StringRef Arch : VerifyArchList) 360 validateArchitectureName(Arch); 361 362 if (auto UO = 363 dyn_cast<MachOUniversalBinary>(InputBinaries.front().getBinary())) { 364 for (StringRef Arch : VerifyArchList) { 365 Expected<MachOUniversalBinary::ObjectForArch> Obj = 366 UO->getObjectForArch(Arch); 367 if (!Obj) 368 exit(EXIT_FAILURE); 369 } 370 } else if (auto O = 371 dyn_cast<MachOObjectFile>(InputBinaries.front().getBinary())) { 372 const Triple::ArchType ObjectArch = O->getArch(); 373 for (StringRef Arch : VerifyArchList) 374 if (ObjectArch != Triple(Arch).getArch()) 375 exit(EXIT_FAILURE); 376 } else { 377 llvm_unreachable("Unexpected binary format"); 378 } 379 exit(EXIT_SUCCESS); 380 } 381 382 static void printBinaryArchs(LLVMContext &LLVMCtx, const Binary *Binary, 383 raw_ostream &OS) { 384 // Prints trailing space for compatibility with cctools lipo. 385 if (auto UO = dyn_cast<MachOUniversalBinary>(Binary)) { 386 for (const auto &O : UO->objects()) { 387 // Order here is important, because both MachOObjectFile and 388 // IRObjectFile can be created with a binary that has embedded bitcode. 389 Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrError = 390 O.getAsObjectFile(); 391 if (MachOObjOrError) { 392 OS << Slice(*(MachOObjOrError->get())).getArchString() << " "; 393 continue; 394 } 395 Expected<std::unique_ptr<IRObjectFile>> IROrError = 396 O.getAsIRObject(LLVMCtx); 397 if (IROrError) { 398 consumeError(MachOObjOrError.takeError()); 399 Expected<Slice> SliceOrErr = Slice::create(**IROrError, O.getAlign()); 400 if (!SliceOrErr) { 401 reportError(Binary->getFileName(), SliceOrErr.takeError()); 402 continue; 403 } 404 OS << SliceOrErr.get().getArchString() << " "; 405 continue; 406 } 407 Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive(); 408 if (ArchiveOrError) { 409 consumeError(MachOObjOrError.takeError()); 410 consumeError(IROrError.takeError()); 411 OS << createSliceFromArchive(LLVMCtx, **ArchiveOrError).getArchString() 412 << " "; 413 continue; 414 } 415 consumeError(ArchiveOrError.takeError()); 416 reportError(Binary->getFileName(), MachOObjOrError.takeError()); 417 reportError(Binary->getFileName(), IROrError.takeError()); 418 } 419 OS << "\n"; 420 return; 421 } 422 423 if (const auto *MachO = dyn_cast<MachOObjectFile>(Binary)) { 424 OS << Slice(*MachO).getArchString() << " \n"; 425 return; 426 } 427 428 // This should be always the case, as this is tested in readInputBinaries 429 const auto *IR = cast<IRObjectFile>(Binary); 430 Expected<Slice> SliceOrErr = createSliceFromIR(*IR, 0); 431 if (!SliceOrErr) 432 reportError(IR->getFileName(), SliceOrErr.takeError()); 433 434 OS << SliceOrErr->getArchString() << " \n"; 435 } 436 437 [[noreturn]] static void 438 printArchs(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries) { 439 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); 440 printBinaryArchs(LLVMCtx, InputBinaries.front().getBinary(), outs()); 441 exit(EXIT_SUCCESS); 442 } 443 444 [[noreturn]] static void 445 printInfo(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries) { 446 // Group universal and thin files together for compatibility with cctools lipo 447 for (auto &IB : InputBinaries) { 448 const Binary *Binary = IB.getBinary(); 449 if (Binary->isMachOUniversalBinary()) { 450 outs() << "Architectures in the fat file: " << Binary->getFileName() 451 << " are: "; 452 printBinaryArchs(LLVMCtx, Binary, outs()); 453 } 454 } 455 for (auto &IB : InputBinaries) { 456 const Binary *Binary = IB.getBinary(); 457 if (!Binary->isMachOUniversalBinary()) { 458 assert(Binary->isMachO() && "expected MachO binary"); 459 outs() << "Non-fat file: " << Binary->getFileName() 460 << " is architecture: "; 461 printBinaryArchs(LLVMCtx, Binary, outs()); 462 } 463 } 464 exit(EXIT_SUCCESS); 465 } 466 467 [[noreturn]] static void thinSlice(LLVMContext &LLVMCtx, 468 ArrayRef<OwningBinary<Binary>> InputBinaries, 469 StringRef ArchType, 470 StringRef OutputFileName) { 471 assert(!ArchType.empty() && "The architecture type should be non-empty"); 472 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); 473 assert(!OutputFileName.empty() && "Thin expects a single output file"); 474 475 if (InputBinaries.front().getBinary()->isMachO()) { 476 reportError("input file " + 477 InputBinaries.front().getBinary()->getFileName() + 478 " must be a fat file when the -thin option is specified"); 479 exit(EXIT_FAILURE); 480 } 481 482 auto *UO = cast<MachOUniversalBinary>(InputBinaries.front().getBinary()); 483 Expected<std::unique_ptr<MachOObjectFile>> Obj = 484 UO->getMachOObjectForArch(ArchType); 485 Expected<std::unique_ptr<IRObjectFile>> IRObj = 486 UO->getIRObjectForArch(ArchType, LLVMCtx); 487 Expected<std::unique_ptr<Archive>> Ar = UO->getArchiveForArch(ArchType); 488 if (!Obj && !IRObj && !Ar) 489 reportError("fat input file " + UO->getFileName() + 490 " does not contain the specified architecture " + ArchType + 491 " to thin it to"); 492 Binary *B; 493 // Order here is important, because both Obj and IRObj will be valid with a 494 // binary that has embedded bitcode. 495 if (Obj) 496 B = Obj->get(); 497 else if (IRObj) 498 B = IRObj->get(); 499 else 500 B = Ar->get(); 501 502 Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError = 503 FileOutputBuffer::create(OutputFileName, 504 B->getMemoryBufferRef().getBufferSize(), 505 sys::fs::can_execute(UO->getFileName()) 506 ? FileOutputBuffer::F_executable 507 : 0); 508 if (!OutFileOrError) 509 reportError(OutputFileName, OutFileOrError.takeError()); 510 std::copy(B->getMemoryBufferRef().getBufferStart(), 511 B->getMemoryBufferRef().getBufferEnd(), 512 OutFileOrError.get()->getBufferStart()); 513 if (Error E = OutFileOrError.get()->commit()) 514 reportError(OutputFileName, std::move(E)); 515 exit(EXIT_SUCCESS); 516 } 517 518 static void checkArchDuplicates(ArrayRef<Slice> Slices) { 519 DenseMap<uint64_t, const Binary *> CPUIds; 520 for (const auto &S : Slices) { 521 auto Entry = CPUIds.try_emplace(S.getCPUID(), S.getBinary()); 522 if (!Entry.second) 523 reportError(Entry.first->second->getFileName() + " and " + 524 S.getBinary()->getFileName() + 525 " have the same architecture " + S.getArchString() + 526 " and therefore cannot be in the same universal binary"); 527 } 528 } 529 530 template <typename Range> 531 static void updateAlignments(Range &Slices, 532 const StringMap<const uint32_t> &Alignments) { 533 for (auto &Slice : Slices) { 534 auto Alignment = Alignments.find(Slice.getArchString()); 535 if (Alignment != Alignments.end()) 536 Slice.setP2Alignment(Alignment->second); 537 } 538 } 539 540 static void checkUnusedAlignments(ArrayRef<Slice> Slices, 541 const StringMap<const uint32_t> &Alignments) { 542 auto HasArch = [&](StringRef Arch) { 543 return llvm::any_of(Slices, 544 [Arch](Slice S) { return S.getArchString() == Arch; }); 545 }; 546 for (StringRef Arch : Alignments.keys()) 547 if (!HasArch(Arch)) 548 reportError("-segalign " + Arch + 549 " <value> specified but resulting fat file does not contain " 550 "that architecture "); 551 } 552 553 // Updates vector ExtractedObjects with the MachOObjectFiles extracted from 554 // Universal Binary files to transfer ownership. 555 static SmallVector<Slice, 2> 556 buildSlices(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries, 557 const StringMap<const uint32_t> &Alignments, 558 SmallVectorImpl<std::unique_ptr<SymbolicFile>> &ExtractedObjects) { 559 SmallVector<Slice, 2> Slices; 560 for (auto &IB : InputBinaries) { 561 const Binary *InputBinary = IB.getBinary(); 562 if (auto UO = dyn_cast<MachOUniversalBinary>(InputBinary)) { 563 for (const auto &O : UO->objects()) { 564 // Order here is important, because both MachOObjectFile and 565 // IRObjectFile can be created with a binary that has embedded bitcode. 566 Expected<std::unique_ptr<MachOObjectFile>> BinaryOrError = 567 O.getAsObjectFile(); 568 if (BinaryOrError) { 569 Slices.emplace_back(*(BinaryOrError.get()), O.getAlign()); 570 ExtractedObjects.push_back(std::move(BinaryOrError.get())); 571 continue; 572 } 573 Expected<std::unique_ptr<IRObjectFile>> IROrError = 574 O.getAsIRObject(LLVMCtx); 575 if (IROrError) { 576 consumeError(BinaryOrError.takeError()); 577 Slice S = createSliceFromIR(**IROrError, O.getAlign()); 578 ExtractedObjects.emplace_back(std::move(IROrError.get())); 579 Slices.emplace_back(std::move(S)); 580 continue; 581 } 582 reportError(InputBinary->getFileName(), BinaryOrError.takeError()); 583 } 584 } else if (const auto *O = dyn_cast<MachOObjectFile>(InputBinary)) { 585 Slices.emplace_back(*O); 586 } else if (const auto *A = dyn_cast<Archive>(InputBinary)) { 587 Slices.push_back(createSliceFromArchive(LLVMCtx, *A)); 588 } else if (const auto *IRO = dyn_cast<IRObjectFile>(InputBinary)) { 589 // Original Apple's lipo set the alignment to 0 590 Expected<Slice> SliceOrErr = Slice::create(*IRO, 0); 591 if (!SliceOrErr) { 592 reportError(InputBinary->getFileName(), SliceOrErr.takeError()); 593 continue; 594 } 595 Slices.emplace_back(std::move(SliceOrErr.get())); 596 } else { 597 llvm_unreachable("Unexpected binary format"); 598 } 599 } 600 updateAlignments(Slices, Alignments); 601 return Slices; 602 } 603 604 [[noreturn]] static void 605 createUniversalBinary(LLVMContext &LLVMCtx, 606 ArrayRef<OwningBinary<Binary>> InputBinaries, 607 const StringMap<const uint32_t> &Alignments, 608 StringRef OutputFileName, FatHeaderType HeaderType) { 609 assert(InputBinaries.size() >= 1 && "Incorrect number of input binaries"); 610 assert(!OutputFileName.empty() && "Create expects a single output file"); 611 612 SmallVector<std::unique_ptr<SymbolicFile>, 1> ExtractedObjects; 613 SmallVector<Slice, 1> Slices = 614 buildSlices(LLVMCtx, InputBinaries, Alignments, ExtractedObjects); 615 checkArchDuplicates(Slices); 616 checkUnusedAlignments(Slices, Alignments); 617 618 llvm::stable_sort(Slices); 619 if (Error E = writeUniversalBinary(Slices, OutputFileName, HeaderType)) 620 reportError(std::move(E)); 621 622 exit(EXIT_SUCCESS); 623 } 624 625 [[noreturn]] static void 626 extractSlice(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries, 627 const StringMap<const uint32_t> &Alignments, StringRef ArchType, 628 StringRef OutputFileName) { 629 assert(!ArchType.empty() && 630 "The architecture type should be non-empty"); 631 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); 632 assert(!OutputFileName.empty() && "Thin expects a single output file"); 633 634 if (InputBinaries.front().getBinary()->isMachO()) { 635 reportError("input file " + 636 InputBinaries.front().getBinary()->getFileName() + 637 " must be a fat file when the -extract option is specified"); 638 } 639 640 SmallVector<std::unique_ptr<SymbolicFile>, 2> ExtractedObjects; 641 SmallVector<Slice, 2> Slices = 642 buildSlices(LLVMCtx, InputBinaries, Alignments, ExtractedObjects); 643 erase_if(Slices, [ArchType](const Slice &S) { 644 return ArchType != S.getArchString(); 645 }); 646 647 if (Slices.empty()) 648 reportError( 649 "fat input file " + InputBinaries.front().getBinary()->getFileName() + 650 " does not contain the specified architecture " + ArchType); 651 652 llvm::stable_sort(Slices); 653 if (Error E = writeUniversalBinary(Slices, OutputFileName)) 654 reportError(std::move(E)); 655 exit(EXIT_SUCCESS); 656 } 657 658 static StringMap<Slice> 659 buildReplacementSlices(ArrayRef<OwningBinary<Binary>> ReplacementBinaries, 660 const StringMap<const uint32_t> &Alignments) { 661 StringMap<Slice> Slices; 662 // populates StringMap of slices to replace with; error checks for mismatched 663 // replace flag args, fat files, and duplicate arch_types 664 for (const auto &OB : ReplacementBinaries) { 665 const Binary *ReplacementBinary = OB.getBinary(); 666 auto O = dyn_cast<MachOObjectFile>(ReplacementBinary); 667 if (!O) 668 reportError("replacement file: " + ReplacementBinary->getFileName() + 669 " is a fat file (must be a thin file)"); 670 Slice S(*O); 671 auto Entry = Slices.try_emplace(S.getArchString(), S); 672 if (!Entry.second) 673 reportError("-replace " + S.getArchString() + 674 " <file_name> specified multiple times: " + 675 Entry.first->second.getBinary()->getFileName() + ", " + 676 O->getFileName()); 677 } 678 auto SlicesMapRange = map_range( 679 Slices, [](StringMapEntry<Slice> &E) -> Slice & { return E.getValue(); }); 680 updateAlignments(SlicesMapRange, Alignments); 681 return Slices; 682 } 683 684 [[noreturn]] static void 685 replaceSlices(LLVMContext &LLVMCtx, 686 ArrayRef<OwningBinary<Binary>> InputBinaries, 687 const StringMap<const uint32_t> &Alignments, 688 StringRef OutputFileName, ArrayRef<InputFile> ReplacementFiles) { 689 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); 690 assert(!OutputFileName.empty() && "Replace expects a single output file"); 691 692 if (InputBinaries.front().getBinary()->isMachO()) 693 reportError("input file " + 694 InputBinaries.front().getBinary()->getFileName() + 695 " must be a fat file when the -replace option is specified"); 696 697 SmallVector<OwningBinary<Binary>, 1> ReplacementBinaries = 698 readInputBinaries(LLVMCtx, ReplacementFiles); 699 700 StringMap<Slice> ReplacementSlices = 701 buildReplacementSlices(ReplacementBinaries, Alignments); 702 SmallVector<std::unique_ptr<SymbolicFile>, 2> ExtractedObjects; 703 SmallVector<Slice, 2> Slices = 704 buildSlices(LLVMCtx, InputBinaries, Alignments, ExtractedObjects); 705 706 for (auto &Slice : Slices) { 707 auto It = ReplacementSlices.find(Slice.getArchString()); 708 if (It != ReplacementSlices.end()) { 709 Slice = It->second; 710 ReplacementSlices.erase(It); // only keep remaining replacing arch_types 711 } 712 } 713 714 if (!ReplacementSlices.empty()) 715 reportError("-replace " + ReplacementSlices.begin()->first() + 716 " <file_name> specified but fat file: " + 717 InputBinaries.front().getBinary()->getFileName() + 718 " does not contain that architecture"); 719 720 checkUnusedAlignments(Slices, Alignments); 721 722 llvm::stable_sort(Slices); 723 if (Error E = writeUniversalBinary(Slices, OutputFileName)) 724 reportError(std::move(E)); 725 exit(EXIT_SUCCESS); 726 } 727 728 int llvm_lipo_main(int argc, char **argv, const llvm::ToolContext &) { 729 llvm::InitializeAllTargetInfos(); 730 llvm::InitializeAllTargetMCs(); 731 llvm::InitializeAllAsmParsers(); 732 733 Config C = parseLipoOptions(ArrayRef(argv + 1, argc - 1)); 734 LLVMContext LLVMCtx; 735 SmallVector<OwningBinary<Binary>, 1> InputBinaries = 736 readInputBinaries(LLVMCtx, C.InputFiles); 737 738 switch (C.ActionToPerform) { 739 case LipoAction::VerifyArch: 740 verifyArch(InputBinaries, C.VerifyArchList); 741 break; 742 case LipoAction::PrintArchs: 743 printArchs(LLVMCtx, InputBinaries); 744 break; 745 case LipoAction::PrintInfo: 746 printInfo(LLVMCtx, InputBinaries); 747 break; 748 case LipoAction::ThinArch: 749 thinSlice(LLVMCtx, InputBinaries, C.ArchType, C.OutputFile); 750 break; 751 case LipoAction::ExtractArch: 752 extractSlice(LLVMCtx, InputBinaries, C.SegmentAlignments, C.ArchType, 753 C.OutputFile); 754 break; 755 case LipoAction::CreateUniversal: 756 createUniversalBinary( 757 LLVMCtx, InputBinaries, C.SegmentAlignments, C.OutputFile, 758 C.UseFat64 ? FatHeaderType::Fat64Header : FatHeaderType::FatHeader); 759 break; 760 case LipoAction::ReplaceArch: 761 replaceSlices(LLVMCtx, InputBinaries, C.SegmentAlignments, C.OutputFile, 762 C.ReplacementFiles); 763 break; 764 } 765 return EXIT_SUCCESS; 766 } 767