1 //===- llvm-ifs.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 "ErrorCollector.h" 10 #include "llvm/ADT/StringRef.h" 11 #include "llvm/ADT/StringSwitch.h" 12 #include "llvm/BinaryFormat/ELF.h" 13 #include "llvm/InterfaceStub/ELFObjHandler.h" 14 #include "llvm/InterfaceStub/IFSHandler.h" 15 #include "llvm/InterfaceStub/IFSStub.h" 16 #include "llvm/ObjectYAML/yaml2obj.h" 17 #include "llvm/Option/Arg.h" 18 #include "llvm/Option/ArgList.h" 19 #include "llvm/Option/Option.h" 20 #include "llvm/Support/CommandLine.h" 21 #include "llvm/Support/Debug.h" 22 #include "llvm/Support/Errc.h" 23 #include "llvm/Support/Error.h" 24 #include "llvm/Support/FileOutputBuffer.h" 25 #include "llvm/Support/LLVMDriver.h" 26 #include "llvm/Support/MemoryBuffer.h" 27 #include "llvm/Support/Path.h" 28 #include "llvm/Support/VersionTuple.h" 29 #include "llvm/Support/WithColor.h" 30 #include "llvm/Support/YAMLTraits.h" 31 #include "llvm/Support/raw_ostream.h" 32 #include "llvm/TargetParser/Triple.h" 33 #include "llvm/TextAPI/InterfaceFile.h" 34 #include "llvm/TextAPI/TextAPIReader.h" 35 #include "llvm/TextAPI/TextAPIWriter.h" 36 #include <optional> 37 #include <set> 38 #include <string> 39 #include <vector> 40 41 using namespace llvm; 42 using namespace llvm::yaml; 43 using namespace llvm::MachO; 44 using namespace llvm::ifs; 45 46 #define DEBUG_TYPE "llvm-ifs" 47 48 namespace { 49 const VersionTuple IfsVersionCurrent(3, 0); 50 51 enum class FileFormat { IFS, ELF, TBD }; 52 } // end anonymous namespace 53 54 using namespace llvm::opt; 55 enum ID { 56 OPT_INVALID = 0, // This is not an option ID. 57 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__), 58 #include "Opts.inc" 59 #undef OPTION 60 }; 61 62 #define OPTTABLE_STR_TABLE_CODE 63 #include "Opts.inc" 64 #undef OPTTABLE_STR_TABLE_CODE 65 66 #define OPTTABLE_PREFIXES_TABLE_CODE 67 #include "Opts.inc" 68 #undef OPTTABLE_PREFIXES_TABLE_CODE 69 70 static constexpr opt::OptTable::Info InfoTable[] = { 71 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), 72 #include "Opts.inc" 73 #undef OPTION 74 }; 75 76 class IFSOptTable : public opt::GenericOptTable { 77 public: 78 IFSOptTable() 79 : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) { 80 setGroupedShortOptions(true); 81 } 82 }; 83 84 struct DriverConfig { 85 std::vector<std::string> InputFilePaths; 86 87 std::optional<FileFormat> InputFormat; 88 std::optional<FileFormat> OutputFormat; 89 90 std::optional<std::string> HintIfsTarget; 91 std::optional<std::string> OptTargetTriple; 92 std::optional<IFSArch> OverrideArch; 93 std::optional<IFSBitWidthType> OverrideBitWidth; 94 std::optional<IFSEndiannessType> OverrideEndianness; 95 96 bool StripIfsArch = false; 97 bool StripIfsBitwidth = false; 98 bool StripIfsEndianness = false; 99 bool StripIfsTarget = false; 100 bool StripNeeded = false; 101 bool StripSize = false; 102 bool StripUndefined = false; 103 104 std::vector<std::string> Exclude; 105 106 std::optional<std::string> SoName; 107 108 std::optional<std::string> Output; 109 std::optional<std::string> OutputElf; 110 std::optional<std::string> OutputIfs; 111 std::optional<std::string> OutputTbd; 112 113 bool WriteIfChanged = false; 114 }; 115 116 static std::string getTypeName(IFSSymbolType Type) { 117 switch (Type) { 118 case IFSSymbolType::NoType: 119 return "NoType"; 120 case IFSSymbolType::Func: 121 return "Func"; 122 case IFSSymbolType::Object: 123 return "Object"; 124 case IFSSymbolType::TLS: 125 return "TLS"; 126 case IFSSymbolType::Unknown: 127 return "Unknown"; 128 } 129 llvm_unreachable("Unexpected ifs symbol type."); 130 } 131 132 static Expected<std::unique_ptr<IFSStub>> 133 readInputFile(std::optional<FileFormat> &InputFormat, StringRef FilePath) { 134 // Read in file. 135 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError = 136 MemoryBuffer::getFileOrSTDIN(FilePath, /*IsText=*/true); 137 if (!BufOrError) 138 return createStringError(BufOrError.getError(), "Could not open `%s`", 139 FilePath.data()); 140 141 std::unique_ptr<MemoryBuffer> FileReadBuffer = std::move(*BufOrError); 142 ErrorCollector EC(/*UseFatalErrors=*/false); 143 144 // First try to read as a binary (fails fast if not binary). 145 if (!InputFormat || *InputFormat == FileFormat::ELF) { 146 Expected<std::unique_ptr<IFSStub>> StubFromELF = 147 readELFFile(FileReadBuffer->getMemBufferRef()); 148 if (StubFromELF) { 149 InputFormat = FileFormat::ELF; 150 (*StubFromELF)->IfsVersion = IfsVersionCurrent; 151 return std::move(*StubFromELF); 152 } 153 EC.addError(StubFromELF.takeError(), "BinaryRead"); 154 } 155 156 // Fall back to reading as a ifs. 157 if (!InputFormat || *InputFormat == FileFormat::IFS) { 158 Expected<std::unique_ptr<IFSStub>> StubFromIFS = 159 readIFSFromBuffer(FileReadBuffer->getBuffer()); 160 if (StubFromIFS) { 161 InputFormat = FileFormat::IFS; 162 if ((*StubFromIFS)->IfsVersion > IfsVersionCurrent) 163 EC.addError( 164 createStringError(errc::not_supported, 165 "IFS version " + 166 (*StubFromIFS)->IfsVersion.getAsString() + 167 " is unsupported."), 168 "ReadInputFile"); 169 else 170 return std::move(*StubFromIFS); 171 } else { 172 EC.addError(StubFromIFS.takeError(), "YamlParse"); 173 } 174 } 175 176 // If both readers fail, build a new error that includes all information. 177 EC.addError(createStringError(errc::not_supported, 178 "No file readers succeeded reading `%s` " 179 "(unsupported/malformed file?)", 180 FilePath.data()), 181 "ReadInputFile"); 182 EC.escalateToFatal(); 183 return EC.makeError(); 184 } 185 186 static int writeTbdStub(const Triple &T, const std::vector<IFSSymbol> &Symbols, 187 const StringRef Format, raw_ostream &Out) { 188 189 auto PlatformTypeOrError = 190 [](const llvm::Triple &T) -> llvm::Expected<llvm::MachO::PlatformType> { 191 if (T.isMacOSX()) 192 return llvm::MachO::PLATFORM_MACOS; 193 if (T.isTvOS()) 194 return llvm::MachO::PLATFORM_TVOS; 195 if (T.isWatchOS()) 196 return llvm::MachO::PLATFORM_WATCHOS; 197 // Note: put isiOS last because tvOS and watchOS are also iOS according 198 // to the Triple. 199 if (T.isiOS()) 200 return llvm::MachO::PLATFORM_IOS; 201 202 return createStringError(errc::not_supported, "Invalid Platform.\n"); 203 }(T); 204 205 if (!PlatformTypeOrError) 206 return -1; 207 208 PlatformType Plat = PlatformTypeOrError.get(); 209 TargetList Targets({Target(llvm::MachO::mapToArchitecture(T), Plat)}); 210 211 InterfaceFile File; 212 File.setFileType(FileType::TBD_V3); // Only supporting v3 for now. 213 File.addTargets(Targets); 214 215 for (const auto &Symbol : Symbols) { 216 auto Name = Symbol.Name; 217 auto Kind = EncodeKind::GlobalSymbol; 218 switch (Symbol.Type) { 219 default: 220 case IFSSymbolType::NoType: 221 Kind = EncodeKind::GlobalSymbol; 222 break; 223 case IFSSymbolType::Object: 224 Kind = EncodeKind::GlobalSymbol; 225 break; 226 case IFSSymbolType::Func: 227 Kind = EncodeKind::GlobalSymbol; 228 break; 229 } 230 if (Symbol.Weak) 231 File.addSymbol(Kind, Name, Targets, SymbolFlags::WeakDefined); 232 else 233 File.addSymbol(Kind, Name, Targets); 234 } 235 236 SmallString<4096> Buffer; 237 raw_svector_ostream OS(Buffer); 238 if (Error Result = TextAPIWriter::writeToStream(OS, File)) 239 return -1; 240 Out << OS.str(); 241 return 0; 242 } 243 244 static void fatalError(Error Err) { 245 WithColor::defaultErrorHandler(std::move(Err)); 246 exit(1); 247 } 248 249 static void fatalError(Twine T) { 250 WithColor::error() << T.str() << '\n'; 251 exit(1); 252 } 253 254 /// writeIFS() writes a Text-Based ELF stub to a file using the latest version 255 /// of the YAML parser. 256 static Error writeIFS(StringRef FilePath, IFSStub &Stub, bool WriteIfChanged) { 257 // Write IFS to memory first. 258 std::string IFSStr; 259 raw_string_ostream OutStr(IFSStr); 260 Error YAMLErr = writeIFSToOutputStream(OutStr, Stub); 261 if (YAMLErr) 262 return YAMLErr; 263 OutStr.flush(); 264 265 if (WriteIfChanged) { 266 if (ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError = 267 MemoryBuffer::getFile(FilePath)) { 268 // Compare IFS output with the existing IFS file. If unchanged, avoid 269 // changing the file. 270 if ((*BufOrError)->getBuffer() == IFSStr) 271 return Error::success(); 272 } 273 } 274 // Open IFS file for writing. 275 std::error_code SysErr; 276 raw_fd_ostream Out(FilePath, SysErr); 277 if (SysErr) 278 return createStringError(SysErr, "Couldn't open `%s` for writing", 279 FilePath.data()); 280 Out << IFSStr; 281 return Error::success(); 282 } 283 284 static DriverConfig parseArgs(int argc, char *const *argv) { 285 BumpPtrAllocator A; 286 StringSaver Saver(A); 287 IFSOptTable Tbl; 288 StringRef ToolName = argv[0]; 289 llvm::opt::InputArgList Args = Tbl.parseArgs( 290 argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { fatalError(Msg); }); 291 if (Args.hasArg(OPT_help)) { 292 Tbl.printHelp(llvm::outs(), 293 (Twine(ToolName) + " <input_file> <output_file> [options]") 294 .str() 295 .c_str(), 296 "shared object stubbing tool"); 297 std::exit(0); 298 } 299 if (Args.hasArg(OPT_version)) { 300 llvm::outs() << ToolName << '\n'; 301 cl::PrintVersionMessage(); 302 std::exit(0); 303 } 304 305 DriverConfig Config; 306 for (const opt::Arg *A : Args.filtered(OPT_INPUT)) 307 Config.InputFilePaths.push_back(A->getValue()); 308 if (const opt::Arg *A = Args.getLastArg(OPT_input_format_EQ)) { 309 Config.InputFormat = StringSwitch<std::optional<FileFormat>>(A->getValue()) 310 .Case("IFS", FileFormat::IFS) 311 .Case("ELF", FileFormat::ELF) 312 .Default(std::nullopt); 313 if (!Config.InputFormat) 314 fatalError(Twine("invalid argument '") + A->getValue()); 315 } 316 317 auto OptionNotFound = [ToolName](StringRef FlagName, StringRef OptionName) { 318 fatalError(Twine(ToolName) + ": for the " + FlagName + 319 " option: Cannot find option named '" + OptionName + "'!"); 320 }; 321 if (const opt::Arg *A = Args.getLastArg(OPT_output_format_EQ)) { 322 Config.OutputFormat = StringSwitch<std::optional<FileFormat>>(A->getValue()) 323 .Case("IFS", FileFormat::IFS) 324 .Case("ELF", FileFormat::ELF) 325 .Case("TBD", FileFormat::TBD) 326 .Default(std::nullopt); 327 if (!Config.OutputFormat) 328 OptionNotFound("--output-format", A->getValue()); 329 } 330 if (const opt::Arg *A = Args.getLastArg(OPT_arch_EQ)) { 331 uint16_t eMachine = ELF::convertArchNameToEMachine(A->getValue()); 332 if (eMachine == ELF::EM_NONE) { 333 fatalError(Twine("unknown arch '") + A->getValue() + "'"); 334 } 335 Config.OverrideArch = eMachine; 336 } 337 if (const opt::Arg *A = Args.getLastArg(OPT_bitwidth_EQ)) { 338 size_t Width; 339 llvm::StringRef S(A->getValue()); 340 if (!S.getAsInteger<size_t>(10, Width) || Width == 64 || Width == 32) 341 Config.OverrideBitWidth = 342 Width == 64 ? IFSBitWidthType::IFS64 : IFSBitWidthType::IFS32; 343 else 344 OptionNotFound("--bitwidth", A->getValue()); 345 } 346 if (const opt::Arg *A = Args.getLastArg(OPT_endianness_EQ)) { 347 Config.OverrideEndianness = 348 StringSwitch<std::optional<IFSEndiannessType>>(A->getValue()) 349 .Case("little", IFSEndiannessType::Little) 350 .Case("big", IFSEndiannessType::Big) 351 .Default(std::nullopt); 352 if (!Config.OverrideEndianness) 353 OptionNotFound("--endianness", A->getValue()); 354 } 355 if (const opt::Arg *A = Args.getLastArg(OPT_target_EQ)) 356 Config.OptTargetTriple = A->getValue(); 357 if (const opt::Arg *A = Args.getLastArg(OPT_hint_ifs_target_EQ)) 358 Config.HintIfsTarget = A->getValue(); 359 360 Config.StripIfsArch = Args.hasArg(OPT_strip_ifs_arch); 361 Config.StripIfsBitwidth = Args.hasArg(OPT_strip_ifs_bitwidth); 362 Config.StripIfsEndianness = Args.hasArg(OPT_strip_ifs_endianness); 363 Config.StripIfsTarget = Args.hasArg(OPT_strip_ifs_target); 364 Config.StripUndefined = Args.hasArg(OPT_strip_undefined); 365 Config.StripNeeded = Args.hasArg(OPT_strip_needed); 366 Config.StripSize = Args.hasArg(OPT_strip_size); 367 368 for (const opt::Arg *A : Args.filtered(OPT_exclude_EQ)) 369 Config.Exclude.push_back(A->getValue()); 370 if (const opt::Arg *A = Args.getLastArg(OPT_soname_EQ)) 371 Config.SoName = A->getValue(); 372 if (const opt::Arg *A = Args.getLastArg(OPT_output_EQ)) 373 Config.Output = A->getValue(); 374 if (const opt::Arg *A = Args.getLastArg(OPT_output_elf_EQ)) 375 Config.OutputElf = A->getValue(); 376 if (const opt::Arg *A = Args.getLastArg(OPT_output_ifs_EQ)) 377 Config.OutputIfs = A->getValue(); 378 if (const opt::Arg *A = Args.getLastArg(OPT_output_tbd_EQ)) 379 Config.OutputTbd = A->getValue(); 380 Config.WriteIfChanged = Args.hasArg(OPT_write_if_changed); 381 return Config; 382 } 383 384 int llvm_ifs_main(int argc, char **argv, const llvm::ToolContext &) { 385 DriverConfig Config = parseArgs(argc, argv); 386 387 if (Config.InputFilePaths.empty()) 388 Config.InputFilePaths.push_back("-"); 389 390 // If input files are more than one, they can only be IFS files. 391 if (Config.InputFilePaths.size() > 1) 392 Config.InputFormat = FileFormat::IFS; 393 394 // Attempt to merge input. 395 IFSStub Stub; 396 std::map<std::string, IFSSymbol> SymbolMap; 397 std::string PreviousInputFilePath; 398 for (const std::string &InputFilePath : Config.InputFilePaths) { 399 Expected<std::unique_ptr<IFSStub>> StubOrErr = 400 readInputFile(Config.InputFormat, InputFilePath); 401 if (!StubOrErr) 402 fatalError(StubOrErr.takeError()); 403 404 std::unique_ptr<IFSStub> TargetStub = std::move(StubOrErr.get()); 405 if (PreviousInputFilePath.empty()) { 406 Stub.IfsVersion = TargetStub->IfsVersion; 407 Stub.Target = TargetStub->Target; 408 Stub.SoName = TargetStub->SoName; 409 Stub.NeededLibs = TargetStub->NeededLibs; 410 } else { 411 if (Stub.IfsVersion != TargetStub->IfsVersion) { 412 if (Stub.IfsVersion.getMajor() != IfsVersionCurrent.getMajor()) { 413 WithColor::error() 414 << "Interface Stub: IfsVersion Mismatch." 415 << "\nFilenames: " << PreviousInputFilePath << " " 416 << InputFilePath << "\nIfsVersion Values: " << Stub.IfsVersion 417 << " " << TargetStub->IfsVersion << "\n"; 418 return -1; 419 } 420 if (TargetStub->IfsVersion > Stub.IfsVersion) 421 Stub.IfsVersion = TargetStub->IfsVersion; 422 } 423 if (Stub.Target != TargetStub->Target && !TargetStub->Target.empty()) { 424 WithColor::error() << "Interface Stub: Target Mismatch." 425 << "\nFilenames: " << PreviousInputFilePath << " " 426 << InputFilePath; 427 return -1; 428 } 429 if (Stub.SoName != TargetStub->SoName) { 430 WithColor::error() << "Interface Stub: SoName Mismatch." 431 << "\nFilenames: " << PreviousInputFilePath << " " 432 << InputFilePath 433 << "\nSoName Values: " << Stub.SoName << " " 434 << TargetStub->SoName << "\n"; 435 return -1; 436 } 437 if (Stub.NeededLibs != TargetStub->NeededLibs) { 438 WithColor::error() << "Interface Stub: NeededLibs Mismatch." 439 << "\nFilenames: " << PreviousInputFilePath << " " 440 << InputFilePath << "\n"; 441 return -1; 442 } 443 } 444 445 for (auto Symbol : TargetStub->Symbols) { 446 auto [SI, Inserted] = SymbolMap.try_emplace(Symbol.Name, Symbol); 447 if (Inserted) 448 continue; 449 450 assert(Symbol.Name == SI->second.Name && "Symbol Names Must Match."); 451 452 // Check conflicts: 453 if (Symbol.Type != SI->second.Type) { 454 WithColor::error() << "Interface Stub: Type Mismatch for " 455 << Symbol.Name << ".\nFilename: " << InputFilePath 456 << "\nType Values: " << getTypeName(SI->second.Type) 457 << " " << getTypeName(Symbol.Type) << "\n"; 458 459 return -1; 460 } 461 if (Symbol.Size != SI->second.Size) { 462 WithColor::error() << "Interface Stub: Size Mismatch for " 463 << Symbol.Name << ".\nFilename: " << InputFilePath 464 << "\nSize Values: " << SI->second.Size << " " 465 << Symbol.Size << "\n"; 466 467 return -1; 468 } 469 if (Symbol.Weak != SI->second.Weak) { 470 Symbol.Weak = false; 471 continue; 472 } 473 // TODO: Not checking Warning. Will be dropped. 474 } 475 476 PreviousInputFilePath = InputFilePath; 477 } 478 479 if (Stub.IfsVersion != IfsVersionCurrent) 480 if (Stub.IfsVersion.getMajor() != IfsVersionCurrent.getMajor()) { 481 WithColor::error() << "Interface Stub: Bad IfsVersion: " 482 << Stub.IfsVersion << ", llvm-ifs supported version: " 483 << IfsVersionCurrent << ".\n"; 484 return -1; 485 } 486 487 for (auto &Entry : SymbolMap) 488 Stub.Symbols.push_back(Entry.second); 489 490 // Change SoName before emitting stubs. 491 if (Config.SoName) 492 Stub.SoName = *Config.SoName; 493 494 Error OverrideError = 495 overrideIFSTarget(Stub, Config.OverrideArch, Config.OverrideEndianness, 496 Config.OverrideBitWidth, Config.OptTargetTriple); 497 if (OverrideError) 498 fatalError(std::move(OverrideError)); 499 500 if (Config.StripNeeded) 501 Stub.NeededLibs.clear(); 502 503 if (Error E = filterIFSSyms(Stub, Config.StripUndefined, Config.Exclude)) 504 fatalError(std::move(E)); 505 506 if (Config.StripSize) 507 for (IFSSymbol &Sym : Stub.Symbols) 508 Sym.Size.reset(); 509 510 if (!Config.OutputElf && !Config.OutputIfs && !Config.OutputTbd) { 511 if (!Config.OutputFormat) { 512 WithColor::error() << "at least one output should be specified."; 513 return -1; 514 } 515 } else if (Config.OutputFormat) { 516 WithColor::error() << "'--output-format' cannot be used with " 517 "'--output-{FILE_FORMAT}' options at the same time"; 518 return -1; 519 } 520 if (Config.OutputFormat) { 521 // TODO: Remove OutputFormat flag in the next revision. 522 WithColor::warning() << "--output-format option is deprecated, please use " 523 "--output-{FILE_FORMAT} options instead\n"; 524 switch (*Config.OutputFormat) { 525 case FileFormat::TBD: { 526 std::error_code SysErr; 527 raw_fd_ostream Out(*Config.Output, SysErr); 528 if (SysErr) { 529 WithColor::error() << "Couldn't open " << *Config.Output 530 << " for writing.\n"; 531 return -1; 532 } 533 if (!Stub.Target.Triple) { 534 WithColor::error() 535 << "Triple should be defined when output format is TBD"; 536 return -1; 537 } 538 return writeTbdStub(llvm::Triple(*Stub.Target.Triple), Stub.Symbols, 539 "TBD", Out); 540 } 541 case FileFormat::IFS: { 542 Stub.IfsVersion = IfsVersionCurrent; 543 if (*Config.InputFormat == FileFormat::ELF && Config.HintIfsTarget) { 544 std::error_code HintEC(1, std::generic_category()); 545 IFSTarget HintTarget = parseTriple(*Config.HintIfsTarget); 546 if (*Stub.Target.Arch != *HintTarget.Arch) 547 fatalError(make_error<StringError>( 548 "Triple hint does not match the actual architecture", HintEC)); 549 if (*Stub.Target.Endianness != *HintTarget.Endianness) 550 fatalError(make_error<StringError>( 551 "Triple hint does not match the actual endianness", HintEC)); 552 if (*Stub.Target.BitWidth != *HintTarget.BitWidth) 553 fatalError(make_error<StringError>( 554 "Triple hint does not match the actual bit width", HintEC)); 555 556 stripIFSTarget(Stub, true, false, false, false); 557 Stub.Target.Triple = *Config.HintIfsTarget; 558 } else { 559 stripIFSTarget(Stub, Config.StripIfsTarget, Config.StripIfsArch, 560 Config.StripIfsEndianness, Config.StripIfsBitwidth); 561 } 562 Error IFSWriteError = 563 writeIFS(*Config.Output, Stub, Config.WriteIfChanged); 564 if (IFSWriteError) 565 fatalError(std::move(IFSWriteError)); 566 break; 567 } 568 case FileFormat::ELF: { 569 Error TargetError = validateIFSTarget(Stub, true); 570 if (TargetError) 571 fatalError(std::move(TargetError)); 572 Error BinaryWriteError = 573 writeBinaryStub(*Config.Output, Stub, Config.WriteIfChanged); 574 if (BinaryWriteError) 575 fatalError(std::move(BinaryWriteError)); 576 break; 577 } 578 } 579 } else { 580 // Check if output path for individual format. 581 if (Config.OutputElf) { 582 Error TargetError = validateIFSTarget(Stub, true); 583 if (TargetError) 584 fatalError(std::move(TargetError)); 585 Error BinaryWriteError = 586 writeBinaryStub(*Config.OutputElf, Stub, Config.WriteIfChanged); 587 if (BinaryWriteError) 588 fatalError(std::move(BinaryWriteError)); 589 } 590 if (Config.OutputIfs) { 591 Stub.IfsVersion = IfsVersionCurrent; 592 if (*Config.InputFormat == FileFormat::ELF && Config.HintIfsTarget) { 593 std::error_code HintEC(1, std::generic_category()); 594 IFSTarget HintTarget = parseTriple(*Config.HintIfsTarget); 595 if (*Stub.Target.Arch != *HintTarget.Arch) 596 fatalError(make_error<StringError>( 597 "Triple hint does not match the actual architecture", HintEC)); 598 if (*Stub.Target.Endianness != *HintTarget.Endianness) 599 fatalError(make_error<StringError>( 600 "Triple hint does not match the actual endianness", HintEC)); 601 if (*Stub.Target.BitWidth != *HintTarget.BitWidth) 602 fatalError(make_error<StringError>( 603 "Triple hint does not match the actual bit width", HintEC)); 604 605 stripIFSTarget(Stub, true, false, false, false); 606 Stub.Target.Triple = *Config.HintIfsTarget; 607 } else { 608 stripIFSTarget(Stub, Config.StripIfsTarget, Config.StripIfsArch, 609 Config.StripIfsEndianness, Config.StripIfsBitwidth); 610 } 611 Error IFSWriteError = 612 writeIFS(*Config.OutputIfs, Stub, Config.WriteIfChanged); 613 if (IFSWriteError) 614 fatalError(std::move(IFSWriteError)); 615 } 616 if (Config.OutputTbd) { 617 std::error_code SysErr; 618 raw_fd_ostream Out(*Config.OutputTbd, SysErr); 619 if (SysErr) { 620 WithColor::error() << "Couldn't open " << *Config.OutputTbd 621 << " for writing.\n"; 622 return -1; 623 } 624 if (!Stub.Target.Triple) { 625 WithColor::error() 626 << "Triple should be defined when output format is TBD"; 627 return -1; 628 } 629 return writeTbdStub(llvm::Triple(*Stub.Target.Triple), Stub.Symbols, 630 "TBD", Out); 631 } 632 } 633 return 0; 634 } 635