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