llvm-ifs.cpp 23 KB

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