xref: /llvm-project/llvm/tools/llvm-ifs/llvm-ifs.cpp (revision dd647e3e608ed0b2bac7c588d5859b80ef4a5976)
1d719c506SPuyan Lotfi //===- llvm-ifs.cpp -------------------------------------------------------===//
2d719c506SPuyan Lotfi //
3d719c506SPuyan Lotfi // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d719c506SPuyan Lotfi // See https://llvm.org/LICENSE.txt for license information.
5d719c506SPuyan Lotfi // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d719c506SPuyan Lotfi //
7d719c506SPuyan Lotfi //===-----------------------------------------------------------------------===/
8d719c506SPuyan Lotfi 
96103fdfaSHaowei Wu #include "ErrorCollector.h"
10d719c506SPuyan Lotfi #include "llvm/ADT/StringRef.h"
11d719c506SPuyan Lotfi #include "llvm/ADT/StringSwitch.h"
12ed98c1b3Sserge-sans-paille #include "llvm/BinaryFormat/ELF.h"
13db06088dSHaowei Wu #include "llvm/InterfaceStub/ELFObjHandler.h"
1461fa9afeSHaowei Wu #include "llvm/InterfaceStub/IFSHandler.h"
1561fa9afeSHaowei Wu #include "llvm/InterfaceStub/IFSStub.h"
16d719c506SPuyan Lotfi #include "llvm/ObjectYAML/yaml2obj.h"
17480dcdc8SAlex Brachet #include "llvm/Option/Arg.h"
18480dcdc8SAlex Brachet #include "llvm/Option/ArgList.h"
19480dcdc8SAlex Brachet #include "llvm/Option/Option.h"
20d719c506SPuyan Lotfi #include "llvm/Support/CommandLine.h"
21d719c506SPuyan Lotfi #include "llvm/Support/Debug.h"
22d719c506SPuyan Lotfi #include "llvm/Support/Errc.h"
23d719c506SPuyan Lotfi #include "llvm/Support/Error.h"
24d719c506SPuyan Lotfi #include "llvm/Support/FileOutputBuffer.h"
251f173a06SAlex Brachet #include "llvm/Support/LLVMDriver.h"
26d719c506SPuyan Lotfi #include "llvm/Support/MemoryBuffer.h"
27d719c506SPuyan Lotfi #include "llvm/Support/Path.h"
28d719c506SPuyan Lotfi #include "llvm/Support/VersionTuple.h"
29d719c506SPuyan Lotfi #include "llvm/Support/WithColor.h"
30d719c506SPuyan Lotfi #include "llvm/Support/YAMLTraits.h"
31d719c506SPuyan Lotfi #include "llvm/Support/raw_ostream.h"
3262c7f035SArchibald Elliott #include "llvm/TargetParser/Triple.h"
330116d04dSCyndy Ishida #include "llvm/TextAPI/InterfaceFile.h"
340116d04dSCyndy Ishida #include "llvm/TextAPI/TextAPIReader.h"
350116d04dSCyndy Ishida #include "llvm/TextAPI/TextAPIWriter.h"
366e5eeec7SKazu Hirata #include <optional>
37d719c506SPuyan Lotfi #include <set>
38d719c506SPuyan Lotfi #include <string>
39e3033c0cSPuyan Lotfi #include <vector>
40d719c506SPuyan Lotfi 
41d719c506SPuyan Lotfi using namespace llvm;
42d719c506SPuyan Lotfi using namespace llvm::yaml;
43d719c506SPuyan Lotfi using namespace llvm::MachO;
446103fdfaSHaowei Wu using namespace llvm::ifs;
45d719c506SPuyan Lotfi 
46d719c506SPuyan Lotfi #define DEBUG_TYPE "llvm-ifs"
47d719c506SPuyan Lotfi 
48d719c506SPuyan Lotfi namespace {
496103fdfaSHaowei Wu const VersionTuple IfsVersionCurrent(3, 0);
506103fdfaSHaowei Wu 
516103fdfaSHaowei Wu enum class FileFormat { IFS, ELF, TBD };
52e3033c0cSPuyan Lotfi } // end anonymous namespace
53d719c506SPuyan Lotfi 
54480dcdc8SAlex Brachet using namespace llvm::opt;
55480dcdc8SAlex Brachet enum ID {
56480dcdc8SAlex Brachet   OPT_INVALID = 0, // This is not an option ID.
573f092f37SJan Svoboda #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
58480dcdc8SAlex Brachet #include "Opts.inc"
59480dcdc8SAlex Brachet #undef OPTION
60480dcdc8SAlex Brachet };
61669275f8STimm Bäder 
62*dd647e3eSChandler Carruth #define OPTTABLE_STR_TABLE_CODE
63480dcdc8SAlex Brachet #include "Opts.inc"
64*dd647e3eSChandler Carruth #undef OPTTABLE_STR_TABLE_CODE
65*dd647e3eSChandler Carruth 
66*dd647e3eSChandler Carruth #define OPTTABLE_PREFIXES_TABLE_CODE
67*dd647e3eSChandler Carruth #include "Opts.inc"
68*dd647e3eSChandler Carruth #undef OPTTABLE_PREFIXES_TABLE_CODE
69a74d9e74SAlex Brachet 
7007d9ab9aSserge-sans-paille static constexpr opt::OptTable::Info InfoTable[] = {
713f092f37SJan Svoboda #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
72480dcdc8SAlex Brachet #include "Opts.inc"
73480dcdc8SAlex Brachet #undef OPTION
74480dcdc8SAlex Brachet };
7531e61c58SHaowei Wu 
7607bb29d8Sserge-sans-paille class IFSOptTable : public opt::GenericOptTable {
77480dcdc8SAlex Brachet public:
78*dd647e3eSChandler Carruth   IFSOptTable()
79*dd647e3eSChandler Carruth       : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
8007bb29d8Sserge-sans-paille     setGroupedShortOptions(true);
8107bb29d8Sserge-sans-paille   }
82480dcdc8SAlex Brachet };
835e171cebSHaowei Wu 
84480dcdc8SAlex Brachet struct DriverConfig {
85480dcdc8SAlex Brachet   std::vector<std::string> InputFilePaths;
86480dcdc8SAlex Brachet 
87c589730aSKrzysztof Parzyszek   std::optional<FileFormat> InputFormat;
88c589730aSKrzysztof Parzyszek   std::optional<FileFormat> OutputFormat;
89480dcdc8SAlex Brachet 
906e5eeec7SKazu Hirata   std::optional<std::string> HintIfsTarget;
91c589730aSKrzysztof Parzyszek   std::optional<std::string> OptTargetTriple;
92c589730aSKrzysztof Parzyszek   std::optional<IFSArch> OverrideArch;
93c589730aSKrzysztof Parzyszek   std::optional<IFSBitWidthType> OverrideBitWidth;
94c589730aSKrzysztof Parzyszek   std::optional<IFSEndiannessType> OverrideEndianness;
95480dcdc8SAlex Brachet 
96480dcdc8SAlex Brachet   bool StripIfsArch = false;
97480dcdc8SAlex Brachet   bool StripIfsBitwidth = false;
98480dcdc8SAlex Brachet   bool StripIfsEndianness = false;
99480dcdc8SAlex Brachet   bool StripIfsTarget = false;
100480dcdc8SAlex Brachet   bool StripNeeded = false;
101480dcdc8SAlex Brachet   bool StripSize = false;
102480dcdc8SAlex Brachet   bool StripUndefined = false;
103480dcdc8SAlex Brachet 
104480dcdc8SAlex Brachet   std::vector<std::string> Exclude;
105480dcdc8SAlex Brachet 
1066e5eeec7SKazu Hirata   std::optional<std::string> SoName;
107480dcdc8SAlex Brachet 
1086e5eeec7SKazu Hirata   std::optional<std::string> Output;
1096e5eeec7SKazu Hirata   std::optional<std::string> OutputElf;
1106e5eeec7SKazu Hirata   std::optional<std::string> OutputIfs;
1116e5eeec7SKazu Hirata   std::optional<std::string> OutputTbd;
112480dcdc8SAlex Brachet 
113480dcdc8SAlex Brachet   bool WriteIfChanged = false;
114480dcdc8SAlex Brachet };
115d719c506SPuyan Lotfi 
11620e9c36cSFangrui Song static std::string getTypeName(IFSSymbolType Type) {
117d719c506SPuyan Lotfi   switch (Type) {
118d719c506SPuyan Lotfi   case IFSSymbolType::NoType:
119d719c506SPuyan Lotfi     return "NoType";
120d719c506SPuyan Lotfi   case IFSSymbolType::Func:
121d719c506SPuyan Lotfi     return "Func";
122d719c506SPuyan Lotfi   case IFSSymbolType::Object:
123d719c506SPuyan Lotfi     return "Object";
1246103fdfaSHaowei Wu   case IFSSymbolType::TLS:
1256103fdfaSHaowei Wu     return "TLS";
126d719c506SPuyan Lotfi   case IFSSymbolType::Unknown:
127d719c506SPuyan Lotfi     return "Unknown";
128d719c506SPuyan Lotfi   }
1290e0f3029SMichael Liao   llvm_unreachable("Unexpected ifs symbol type.");
130d719c506SPuyan Lotfi }
131d719c506SPuyan Lotfi 
132480dcdc8SAlex Brachet static Expected<std::unique_ptr<IFSStub>>
133c589730aSKrzysztof Parzyszek readInputFile(std::optional<FileFormat> &InputFormat, StringRef FilePath) {
134d719c506SPuyan Lotfi   // Read in file.
135d719c506SPuyan Lotfi   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
136e71994a2SJonathan Crowther       MemoryBuffer::getFileOrSTDIN(FilePath, /*IsText=*/true);
137d719c506SPuyan Lotfi   if (!BufOrError)
138d719c506SPuyan Lotfi     return createStringError(BufOrError.getError(), "Could not open `%s`",
139d719c506SPuyan Lotfi                              FilePath.data());
140d719c506SPuyan Lotfi 
141d719c506SPuyan Lotfi   std::unique_ptr<MemoryBuffer> FileReadBuffer = std::move(*BufOrError);
1426103fdfaSHaowei Wu   ErrorCollector EC(/*UseFatalErrors=*/false);
143d719c506SPuyan Lotfi 
1446103fdfaSHaowei Wu   // First try to read as a binary (fails fast if not binary).
145480dcdc8SAlex Brachet   if (!InputFormat || *InputFormat == FileFormat::ELF) {
1466103fdfaSHaowei Wu     Expected<std::unique_ptr<IFSStub>> StubFromELF =
1476103fdfaSHaowei Wu         readELFFile(FileReadBuffer->getMemBufferRef());
1486103fdfaSHaowei Wu     if (StubFromELF) {
149480dcdc8SAlex Brachet       InputFormat = FileFormat::ELF;
1506103fdfaSHaowei Wu       (*StubFromELF)->IfsVersion = IfsVersionCurrent;
1516103fdfaSHaowei Wu       return std::move(*StubFromELF);
1526103fdfaSHaowei Wu     }
1536103fdfaSHaowei Wu     EC.addError(StubFromELF.takeError(), "BinaryRead");
1546103fdfaSHaowei Wu   }
155d719c506SPuyan Lotfi 
1566103fdfaSHaowei Wu   // Fall back to reading as a ifs.
157480dcdc8SAlex Brachet   if (!InputFormat || *InputFormat == FileFormat::IFS) {
1586103fdfaSHaowei Wu     Expected<std::unique_ptr<IFSStub>> StubFromIFS =
1596103fdfaSHaowei Wu         readIFSFromBuffer(FileReadBuffer->getBuffer());
1606103fdfaSHaowei Wu     if (StubFromIFS) {
161480dcdc8SAlex Brachet       InputFormat = FileFormat::IFS;
1626103fdfaSHaowei Wu       if ((*StubFromIFS)->IfsVersion > IfsVersionCurrent)
1636103fdfaSHaowei Wu         EC.addError(
1646103fdfaSHaowei Wu             createStringError(errc::not_supported,
1656103fdfaSHaowei Wu                               "IFS version " +
1666103fdfaSHaowei Wu                                   (*StubFromIFS)->IfsVersion.getAsString() +
1676103fdfaSHaowei Wu                                   " is unsupported."),
1686103fdfaSHaowei Wu             "ReadInputFile");
1696103fdfaSHaowei Wu       else
1706103fdfaSHaowei Wu         return std::move(*StubFromIFS);
1716103fdfaSHaowei Wu     } else {
1726103fdfaSHaowei Wu       EC.addError(StubFromIFS.takeError(), "YamlParse");
1736103fdfaSHaowei Wu     }
1746103fdfaSHaowei Wu   }
175acb33cbaSCyndy Ishida 
1766103fdfaSHaowei Wu   // If both readers fail, build a new error that includes all information.
1776103fdfaSHaowei Wu   EC.addError(createStringError(errc::not_supported,
1786103fdfaSHaowei Wu                                 "No file readers succeeded reading `%s` "
1796103fdfaSHaowei Wu                                 "(unsupported/malformed file?)",
1806103fdfaSHaowei Wu                                 FilePath.data()),
1816103fdfaSHaowei Wu               "ReadInputFile");
1826103fdfaSHaowei Wu   EC.escalateToFatal();
1836103fdfaSHaowei Wu   return EC.makeError();
184d719c506SPuyan Lotfi }
185d719c506SPuyan Lotfi 
18620e9c36cSFangrui Song static int writeTbdStub(const Triple &T, const std::vector<IFSSymbol> &Symbols,
187d719c506SPuyan Lotfi                         const StringRef Format, raw_ostream &Out) {
188d719c506SPuyan Lotfi 
1893025c3edSJuergen Ributzka   auto PlatformTypeOrError =
1903025c3edSJuergen Ributzka       [](const llvm::Triple &T) -> llvm::Expected<llvm::MachO::PlatformType> {
1915476bd94SPuyan Lotfi     if (T.isMacOSX())
1923025c3edSJuergen Ributzka       return llvm::MachO::PLATFORM_MACOS;
1935476bd94SPuyan Lotfi     if (T.isTvOS())
1943025c3edSJuergen Ributzka       return llvm::MachO::PLATFORM_TVOS;
1955476bd94SPuyan Lotfi     if (T.isWatchOS())
1963025c3edSJuergen Ributzka       return llvm::MachO::PLATFORM_WATCHOS;
1975476bd94SPuyan Lotfi     // Note: put isiOS last because tvOS and watchOS are also iOS according
1985476bd94SPuyan Lotfi     // to the Triple.
1995476bd94SPuyan Lotfi     if (T.isiOS())
2003025c3edSJuergen Ributzka       return llvm::MachO::PLATFORM_IOS;
2015476bd94SPuyan Lotfi 
2025476bd94SPuyan Lotfi     return createStringError(errc::not_supported, "Invalid Platform.\n");
2035476bd94SPuyan Lotfi   }(T);
2045476bd94SPuyan Lotfi 
2053025c3edSJuergen Ributzka   if (!PlatformTypeOrError)
2065476bd94SPuyan Lotfi     return -1;
2075476bd94SPuyan Lotfi 
2083025c3edSJuergen Ributzka   PlatformType Plat = PlatformTypeOrError.get();
20981669d5eSCyndy Ishida   TargetList Targets({Target(llvm::MachO::mapToArchitecture(T), Plat)});
210d719c506SPuyan Lotfi 
211d719c506SPuyan Lotfi   InterfaceFile File;
2125476bd94SPuyan Lotfi   File.setFileType(FileType::TBD_V3); // Only supporting v3 for now.
21381669d5eSCyndy Ishida   File.addTargets(Targets);
214d719c506SPuyan Lotfi 
215d719c506SPuyan Lotfi   for (const auto &Symbol : Symbols) {
216d719c506SPuyan Lotfi     auto Name = Symbol.Name;
217d9a9872eSCyndy Ishida     auto Kind = EncodeKind::GlobalSymbol;
218d719c506SPuyan Lotfi     switch (Symbol.Type) {
219d719c506SPuyan Lotfi     default:
220d719c506SPuyan Lotfi     case IFSSymbolType::NoType:
221d9a9872eSCyndy Ishida       Kind = EncodeKind::GlobalSymbol;
222d719c506SPuyan Lotfi       break;
223d719c506SPuyan Lotfi     case IFSSymbolType::Object:
224d9a9872eSCyndy Ishida       Kind = EncodeKind::GlobalSymbol;
225d719c506SPuyan Lotfi       break;
226d719c506SPuyan Lotfi     case IFSSymbolType::Func:
227d9a9872eSCyndy Ishida       Kind = EncodeKind::GlobalSymbol;
228d719c506SPuyan Lotfi       break;
229d719c506SPuyan Lotfi     }
230d719c506SPuyan Lotfi     if (Symbol.Weak)
23181669d5eSCyndy Ishida       File.addSymbol(Kind, Name, Targets, SymbolFlags::WeakDefined);
232d719c506SPuyan Lotfi     else
23381669d5eSCyndy Ishida       File.addSymbol(Kind, Name, Targets);
234d719c506SPuyan Lotfi   }
235d719c506SPuyan Lotfi 
236d719c506SPuyan Lotfi   SmallString<4096> Buffer;
237d719c506SPuyan Lotfi   raw_svector_ostream OS(Buffer);
238d719c506SPuyan Lotfi   if (Error Result = TextAPIWriter::writeToStream(OS, File))
239d719c506SPuyan Lotfi     return -1;
240d719c506SPuyan Lotfi   Out << OS.str();
241d719c506SPuyan Lotfi   return 0;
242d719c506SPuyan Lotfi }
243d719c506SPuyan Lotfi 
2446103fdfaSHaowei Wu static void fatalError(Error Err) {
2456103fdfaSHaowei Wu   WithColor::defaultErrorHandler(std::move(Err));
2466103fdfaSHaowei Wu   exit(1);
247d719c506SPuyan Lotfi }
248d719c506SPuyan Lotfi 
249480dcdc8SAlex Brachet static void fatalError(Twine T) {
250480dcdc8SAlex Brachet   WithColor::error() << T.str() << '\n';
251480dcdc8SAlex Brachet   exit(1);
252480dcdc8SAlex Brachet }
253480dcdc8SAlex Brachet 
2546103fdfaSHaowei Wu /// writeIFS() writes a Text-Based ELF stub to a file using the latest version
2556103fdfaSHaowei Wu /// of the YAML parser.
256480dcdc8SAlex Brachet static Error writeIFS(StringRef FilePath, IFSStub &Stub, bool WriteIfChanged) {
2576103fdfaSHaowei Wu   // Write IFS to memory first.
2586103fdfaSHaowei Wu   std::string IFSStr;
2596103fdfaSHaowei Wu   raw_string_ostream OutStr(IFSStr);
2606103fdfaSHaowei Wu   Error YAMLErr = writeIFSToOutputStream(OutStr, Stub);
2616103fdfaSHaowei Wu   if (YAMLErr)
2626103fdfaSHaowei Wu     return YAMLErr;
2636103fdfaSHaowei Wu   OutStr.flush();
264db06088dSHaowei Wu 
2656103fdfaSHaowei Wu   if (WriteIfChanged) {
2666103fdfaSHaowei Wu     if (ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
2676103fdfaSHaowei Wu             MemoryBuffer::getFile(FilePath)) {
268480dcdc8SAlex Brachet       // Compare IFS output with the existing IFS file. If unchanged, avoid
269480dcdc8SAlex Brachet       // changing the file.
2706103fdfaSHaowei Wu       if ((*BufOrError)->getBuffer() == IFSStr)
2716103fdfaSHaowei Wu         return Error::success();
2728b4acb06SHaowei Wu     }
273db06088dSHaowei Wu   }
2746103fdfaSHaowei Wu   // Open IFS file for writing.
275db06088dSHaowei Wu   std::error_code SysErr;
2766103fdfaSHaowei Wu   raw_fd_ostream Out(FilePath, SysErr);
2776103fdfaSHaowei Wu   if (SysErr)
2786103fdfaSHaowei Wu     return createStringError(SysErr, "Couldn't open `%s` for writing",
2796103fdfaSHaowei Wu                              FilePath.data());
2806103fdfaSHaowei Wu   Out << IFSStr;
2816103fdfaSHaowei Wu   return Error::success();
282db06088dSHaowei Wu }
283db06088dSHaowei Wu 
284480dcdc8SAlex Brachet static DriverConfig parseArgs(int argc, char *const *argv) {
285480dcdc8SAlex Brachet   BumpPtrAllocator A;
286480dcdc8SAlex Brachet   StringSaver Saver(A);
287480dcdc8SAlex Brachet   IFSOptTable Tbl;
288480dcdc8SAlex Brachet   StringRef ToolName = argv[0];
289480dcdc8SAlex Brachet   llvm::opt::InputArgList Args = Tbl.parseArgs(
290480dcdc8SAlex Brachet       argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { fatalError(Msg); });
291480dcdc8SAlex Brachet   if (Args.hasArg(OPT_help)) {
292480dcdc8SAlex Brachet     Tbl.printHelp(llvm::outs(),
293480dcdc8SAlex Brachet                   (Twine(ToolName) + " <input_file> <output_file> [options]")
294480dcdc8SAlex Brachet                       .str()
295480dcdc8SAlex Brachet                       .c_str(),
296480dcdc8SAlex Brachet                   "shared object stubbing tool");
297480dcdc8SAlex Brachet     std::exit(0);
298480dcdc8SAlex Brachet   }
299480dcdc8SAlex Brachet   if (Args.hasArg(OPT_version)) {
300480dcdc8SAlex Brachet     llvm::outs() << ToolName << '\n';
301480dcdc8SAlex Brachet     cl::PrintVersionMessage();
302480dcdc8SAlex Brachet     std::exit(0);
303480dcdc8SAlex Brachet   }
304d719c506SPuyan Lotfi 
305480dcdc8SAlex Brachet   DriverConfig Config;
306480dcdc8SAlex Brachet   for (const opt::Arg *A : Args.filtered(OPT_INPUT))
307480dcdc8SAlex Brachet     Config.InputFilePaths.push_back(A->getValue());
308480dcdc8SAlex Brachet   if (const opt::Arg *A = Args.getLastArg(OPT_input_format_EQ)) {
309c589730aSKrzysztof Parzyszek     Config.InputFormat = StringSwitch<std::optional<FileFormat>>(A->getValue())
310480dcdc8SAlex Brachet                              .Case("IFS", FileFormat::IFS)
311480dcdc8SAlex Brachet                              .Case("ELF", FileFormat::ELF)
312b4482f7cSKazu Hirata                              .Default(std::nullopt);
313480dcdc8SAlex Brachet     if (!Config.InputFormat)
314480dcdc8SAlex Brachet       fatalError(Twine("invalid argument '") + A->getValue());
315480dcdc8SAlex Brachet   }
316480dcdc8SAlex Brachet 
317480dcdc8SAlex Brachet   auto OptionNotFound = [ToolName](StringRef FlagName, StringRef OptionName) {
318480dcdc8SAlex Brachet     fatalError(Twine(ToolName) + ": for the " + FlagName +
319480dcdc8SAlex Brachet                " option: Cannot find option named '" + OptionName + "'!");
320480dcdc8SAlex Brachet   };
321480dcdc8SAlex Brachet   if (const opt::Arg *A = Args.getLastArg(OPT_output_format_EQ)) {
322c589730aSKrzysztof Parzyszek     Config.OutputFormat = StringSwitch<std::optional<FileFormat>>(A->getValue())
323480dcdc8SAlex Brachet                               .Case("IFS", FileFormat::IFS)
324480dcdc8SAlex Brachet                               .Case("ELF", FileFormat::ELF)
325480dcdc8SAlex Brachet                               .Case("TBD", FileFormat::TBD)
326b4482f7cSKazu Hirata                               .Default(std::nullopt);
327480dcdc8SAlex Brachet     if (!Config.OutputFormat)
328480dcdc8SAlex Brachet       OptionNotFound("--output-format", A->getValue());
329480dcdc8SAlex Brachet   }
330420526fbSHaowei Wu   if (const opt::Arg *A = Args.getLastArg(OPT_arch_EQ)) {
331420526fbSHaowei Wu     uint16_t eMachine = ELF::convertArchNameToEMachine(A->getValue());
332420526fbSHaowei Wu     if (eMachine == ELF::EM_NONE) {
333420526fbSHaowei Wu       fatalError(Twine("unknown arch '") + A->getValue() + "'");
334420526fbSHaowei Wu     }
335420526fbSHaowei Wu     Config.OverrideArch = eMachine;
336420526fbSHaowei Wu   }
337480dcdc8SAlex Brachet   if (const opt::Arg *A = Args.getLastArg(OPT_bitwidth_EQ)) {
338480dcdc8SAlex Brachet     size_t Width;
339480dcdc8SAlex Brachet     llvm::StringRef S(A->getValue());
340480dcdc8SAlex Brachet     if (!S.getAsInteger<size_t>(10, Width) || Width == 64 || Width == 32)
341480dcdc8SAlex Brachet       Config.OverrideBitWidth =
342480dcdc8SAlex Brachet           Width == 64 ? IFSBitWidthType::IFS64 : IFSBitWidthType::IFS32;
343480dcdc8SAlex Brachet     else
344480dcdc8SAlex Brachet       OptionNotFound("--bitwidth", A->getValue());
345480dcdc8SAlex Brachet   }
346480dcdc8SAlex Brachet   if (const opt::Arg *A = Args.getLastArg(OPT_endianness_EQ)) {
347480dcdc8SAlex Brachet     Config.OverrideEndianness =
348c589730aSKrzysztof Parzyszek         StringSwitch<std::optional<IFSEndiannessType>>(A->getValue())
349480dcdc8SAlex Brachet             .Case("little", IFSEndiannessType::Little)
350480dcdc8SAlex Brachet             .Case("big", IFSEndiannessType::Big)
351b4482f7cSKazu Hirata             .Default(std::nullopt);
352480dcdc8SAlex Brachet     if (!Config.OverrideEndianness)
353480dcdc8SAlex Brachet       OptionNotFound("--endianness", A->getValue());
354480dcdc8SAlex Brachet   }
355480dcdc8SAlex Brachet   if (const opt::Arg *A = Args.getLastArg(OPT_target_EQ))
356480dcdc8SAlex Brachet     Config.OptTargetTriple = A->getValue();
357480dcdc8SAlex Brachet   if (const opt::Arg *A = Args.getLastArg(OPT_hint_ifs_target_EQ))
358480dcdc8SAlex Brachet     Config.HintIfsTarget = A->getValue();
359480dcdc8SAlex Brachet 
360480dcdc8SAlex Brachet   Config.StripIfsArch = Args.hasArg(OPT_strip_ifs_arch);
361480dcdc8SAlex Brachet   Config.StripIfsBitwidth = Args.hasArg(OPT_strip_ifs_bitwidth);
362480dcdc8SAlex Brachet   Config.StripIfsEndianness = Args.hasArg(OPT_strip_ifs_endianness);
363480dcdc8SAlex Brachet   Config.StripIfsTarget = Args.hasArg(OPT_strip_ifs_target);
364480dcdc8SAlex Brachet   Config.StripUndefined = Args.hasArg(OPT_strip_undefined);
365480dcdc8SAlex Brachet   Config.StripNeeded = Args.hasArg(OPT_strip_needed);
366480dcdc8SAlex Brachet   Config.StripSize = Args.hasArg(OPT_strip_size);
367480dcdc8SAlex Brachet 
368480dcdc8SAlex Brachet   for (const opt::Arg *A : Args.filtered(OPT_exclude_EQ))
369480dcdc8SAlex Brachet     Config.Exclude.push_back(A->getValue());
370480dcdc8SAlex Brachet   if (const opt::Arg *A = Args.getLastArg(OPT_soname_EQ))
371480dcdc8SAlex Brachet     Config.SoName = A->getValue();
372480dcdc8SAlex Brachet   if (const opt::Arg *A = Args.getLastArg(OPT_output_EQ))
373480dcdc8SAlex Brachet     Config.Output = A->getValue();
374480dcdc8SAlex Brachet   if (const opt::Arg *A = Args.getLastArg(OPT_output_elf_EQ))
375480dcdc8SAlex Brachet     Config.OutputElf = A->getValue();
376480dcdc8SAlex Brachet   if (const opt::Arg *A = Args.getLastArg(OPT_output_ifs_EQ))
377480dcdc8SAlex Brachet     Config.OutputIfs = A->getValue();
378480dcdc8SAlex Brachet   if (const opt::Arg *A = Args.getLastArg(OPT_output_tbd_EQ))
379480dcdc8SAlex Brachet     Config.OutputTbd = A->getValue();
380480dcdc8SAlex Brachet   Config.WriteIfChanged = Args.hasArg(OPT_write_if_changed);
381480dcdc8SAlex Brachet   return Config;
382480dcdc8SAlex Brachet }
383480dcdc8SAlex Brachet 
3841f173a06SAlex Brachet int llvm_ifs_main(int argc, char **argv, const llvm::ToolContext &) {
385480dcdc8SAlex Brachet   DriverConfig Config = parseArgs(argc, argv);
386480dcdc8SAlex Brachet 
387480dcdc8SAlex Brachet   if (Config.InputFilePaths.empty())
388480dcdc8SAlex Brachet     Config.InputFilePaths.push_back("-");
389d719c506SPuyan Lotfi 
3906103fdfaSHaowei Wu   // If input files are more than one, they can only be IFS files.
391480dcdc8SAlex Brachet   if (Config.InputFilePaths.size() > 1)
392480dcdc8SAlex Brachet     Config.InputFormat = FileFormat::IFS;
3936103fdfaSHaowei Wu 
3946103fdfaSHaowei Wu   // Attempt to merge input.
395d719c506SPuyan Lotfi   IFSStub Stub;
396d719c506SPuyan Lotfi   std::map<std::string, IFSSymbol> SymbolMap;
39712fc9ca3SKazu Hirata   std::string PreviousInputFilePath;
398480dcdc8SAlex Brachet   for (const std::string &InputFilePath : Config.InputFilePaths) {
399480dcdc8SAlex Brachet     Expected<std::unique_ptr<IFSStub>> StubOrErr =
400480dcdc8SAlex Brachet         readInputFile(Config.InputFormat, InputFilePath);
4016103fdfaSHaowei Wu     if (!StubOrErr)
4026103fdfaSHaowei Wu       fatalError(StubOrErr.takeError());
403d719c506SPuyan Lotfi 
4046103fdfaSHaowei Wu     std::unique_ptr<IFSStub> TargetStub = std::move(StubOrErr.get());
4056103fdfaSHaowei Wu     if (PreviousInputFilePath.empty()) {
406d719c506SPuyan Lotfi       Stub.IfsVersion = TargetStub->IfsVersion;
4076103fdfaSHaowei Wu       Stub.Target = TargetStub->Target;
4086103fdfaSHaowei Wu       Stub.SoName = TargetStub->SoName;
409d719c506SPuyan Lotfi       Stub.NeededLibs = TargetStub->NeededLibs;
410d719c506SPuyan Lotfi     } else {
411d719c506SPuyan Lotfi       if (Stub.IfsVersion != TargetStub->IfsVersion) {
4126103fdfaSHaowei Wu         if (Stub.IfsVersion.getMajor() != IfsVersionCurrent.getMajor()) {
413d719c506SPuyan Lotfi           WithColor::error()
414d719c506SPuyan Lotfi               << "Interface Stub: IfsVersion Mismatch."
415d719c506SPuyan Lotfi               << "\nFilenames: " << PreviousInputFilePath << " "
416d719c506SPuyan Lotfi               << InputFilePath << "\nIfsVersion Values: " << Stub.IfsVersion
417d719c506SPuyan Lotfi               << " " << TargetStub->IfsVersion << "\n";
418d719c506SPuyan Lotfi           return -1;
419d719c506SPuyan Lotfi         }
420d719c506SPuyan Lotfi         if (TargetStub->IfsVersion > Stub.IfsVersion)
421d719c506SPuyan Lotfi           Stub.IfsVersion = TargetStub->IfsVersion;
422d719c506SPuyan Lotfi       }
4236103fdfaSHaowei Wu       if (Stub.Target != TargetStub->Target && !TargetStub->Target.empty()) {
4246103fdfaSHaowei Wu         WithColor::error() << "Interface Stub: Target Mismatch."
425d719c506SPuyan Lotfi                            << "\nFilenames: " << PreviousInputFilePath << " "
4266103fdfaSHaowei Wu                            << InputFilePath;
427d719c506SPuyan Lotfi         return -1;
428d719c506SPuyan Lotfi       }
4296103fdfaSHaowei Wu       if (Stub.SoName != TargetStub->SoName) {
4306103fdfaSHaowei Wu         WithColor::error() << "Interface Stub: SoName Mismatch."
431d719c506SPuyan Lotfi                            << "\nFilenames: " << PreviousInputFilePath << " "
432d719c506SPuyan Lotfi                            << InputFilePath
4336103fdfaSHaowei Wu                            << "\nSoName Values: " << Stub.SoName << " "
4346103fdfaSHaowei Wu                            << TargetStub->SoName << "\n";
435d719c506SPuyan Lotfi         return -1;
436d719c506SPuyan Lotfi       }
437d719c506SPuyan Lotfi       if (Stub.NeededLibs != TargetStub->NeededLibs) {
438d719c506SPuyan Lotfi         WithColor::error() << "Interface Stub: NeededLibs Mismatch."
439d719c506SPuyan Lotfi                            << "\nFilenames: " << PreviousInputFilePath << " "
440d719c506SPuyan Lotfi                            << InputFilePath << "\n";
441d719c506SPuyan Lotfi         return -1;
442d719c506SPuyan Lotfi       }
443d719c506SPuyan Lotfi     }
444d719c506SPuyan Lotfi 
445d719c506SPuyan Lotfi     for (auto Symbol : TargetStub->Symbols) {
4464c3fccddSKazu Hirata       auto [SI, Inserted] = SymbolMap.try_emplace(Symbol.Name, Symbol);
4474c3fccddSKazu Hirata       if (Inserted)
448d719c506SPuyan Lotfi         continue;
449d719c506SPuyan Lotfi 
450d719c506SPuyan Lotfi       assert(Symbol.Name == SI->second.Name && "Symbol Names Must Match.");
451d719c506SPuyan Lotfi 
452d719c506SPuyan Lotfi       // Check conflicts:
453d719c506SPuyan Lotfi       if (Symbol.Type != SI->second.Type) {
454d719c506SPuyan Lotfi         WithColor::error() << "Interface Stub: Type Mismatch for "
455d719c506SPuyan Lotfi                            << Symbol.Name << ".\nFilename: " << InputFilePath
456d719c506SPuyan Lotfi                            << "\nType Values: " << getTypeName(SI->second.Type)
457d719c506SPuyan Lotfi                            << " " << getTypeName(Symbol.Type) << "\n";
458d719c506SPuyan Lotfi 
459d719c506SPuyan Lotfi         return -1;
460d719c506SPuyan Lotfi       }
461d719c506SPuyan Lotfi       if (Symbol.Size != SI->second.Size) {
462d719c506SPuyan Lotfi         WithColor::error() << "Interface Stub: Size Mismatch for "
463d719c506SPuyan Lotfi                            << Symbol.Name << ".\nFilename: " << InputFilePath
464d719c506SPuyan Lotfi                            << "\nSize Values: " << SI->second.Size << " "
465d719c506SPuyan Lotfi                            << Symbol.Size << "\n";
466d719c506SPuyan Lotfi 
467d719c506SPuyan Lotfi         return -1;
468d719c506SPuyan Lotfi       }
469d719c506SPuyan Lotfi       if (Symbol.Weak != SI->second.Weak) {
470ef7267deSPuyan Lotfi         Symbol.Weak = false;
471ef7267deSPuyan Lotfi         continue;
472d719c506SPuyan Lotfi       }
473d719c506SPuyan Lotfi       // TODO: Not checking Warning. Will be dropped.
474d719c506SPuyan Lotfi     }
475d719c506SPuyan Lotfi 
476d719c506SPuyan Lotfi     PreviousInputFilePath = InputFilePath;
477d719c506SPuyan Lotfi   }
478d719c506SPuyan Lotfi 
4796103fdfaSHaowei Wu   if (Stub.IfsVersion != IfsVersionCurrent)
4806103fdfaSHaowei Wu     if (Stub.IfsVersion.getMajor() != IfsVersionCurrent.getMajor()) {
481d719c506SPuyan Lotfi       WithColor::error() << "Interface Stub: Bad IfsVersion: "
482d719c506SPuyan Lotfi                          << Stub.IfsVersion << ", llvm-ifs supported version: "
4836103fdfaSHaowei Wu                          << IfsVersionCurrent << ".\n";
484d719c506SPuyan Lotfi       return -1;
485d719c506SPuyan Lotfi     }
486d719c506SPuyan Lotfi 
487d719c506SPuyan Lotfi   for (auto &Entry : SymbolMap)
488e3033c0cSPuyan Lotfi     Stub.Symbols.push_back(Entry.second);
489d719c506SPuyan Lotfi 
4906103fdfaSHaowei Wu   // Change SoName before emitting stubs.
491480dcdc8SAlex Brachet   if (Config.SoName)
492480dcdc8SAlex Brachet     Stub.SoName = *Config.SoName;
493480dcdc8SAlex Brachet 
494480dcdc8SAlex Brachet   Error OverrideError =
495480dcdc8SAlex Brachet       overrideIFSTarget(Stub, Config.OverrideArch, Config.OverrideEndianness,
496480dcdc8SAlex Brachet                         Config.OverrideBitWidth, Config.OptTargetTriple);
4976103fdfaSHaowei Wu   if (OverrideError)
4986103fdfaSHaowei Wu     fatalError(std::move(OverrideError));
4996103fdfaSHaowei Wu 
500480dcdc8SAlex Brachet   if (Config.StripNeeded)
501df2812d8SAlex Brachet     Stub.NeededLibs.clear();
502df2812d8SAlex Brachet 
503480dcdc8SAlex Brachet   if (Error E = filterIFSSyms(Stub, Config.StripUndefined, Config.Exclude))
5047aaad7b1SAlex Brachet     fatalError(std::move(E));
5057aaad7b1SAlex Brachet 
506480dcdc8SAlex Brachet   if (Config.StripSize)
507a74d9e74SAlex Brachet     for (IFSSymbol &Sym : Stub.Symbols)
508a74d9e74SAlex Brachet       Sym.Size.reset();
509a74d9e74SAlex Brachet 
510480dcdc8SAlex Brachet   if (!Config.OutputElf && !Config.OutputIfs && !Config.OutputTbd) {
511480dcdc8SAlex Brachet     if (!Config.OutputFormat) {
5125e171cebSHaowei Wu       WithColor::error() << "at least one output should be specified.";
5135e171cebSHaowei Wu       return -1;
5145e171cebSHaowei Wu     }
515480dcdc8SAlex Brachet   } else if (Config.OutputFormat) {
5165e171cebSHaowei Wu     WithColor::error() << "'--output-format' cannot be used with "
5175e171cebSHaowei Wu                           "'--output-{FILE_FORMAT}' options at the same time";
5185e171cebSHaowei Wu     return -1;
5195e171cebSHaowei Wu   }
520480dcdc8SAlex Brachet   if (Config.OutputFormat) {
5215e171cebSHaowei Wu     // TODO: Remove OutputFormat flag in the next revision.
5225e171cebSHaowei Wu     WithColor::warning() << "--output-format option is deprecated, please use "
5235e171cebSHaowei Wu                             "--output-{FILE_FORMAT} options instead\n";
5247a47ee51SKazu Hirata     switch (*Config.OutputFormat) {
5256103fdfaSHaowei Wu     case FileFormat::TBD: {
5266103fdfaSHaowei Wu       std::error_code SysErr;
527480dcdc8SAlex Brachet       raw_fd_ostream Out(*Config.Output, SysErr);
5286103fdfaSHaowei Wu       if (SysErr) {
529480dcdc8SAlex Brachet         WithColor::error() << "Couldn't open " << *Config.Output
5306103fdfaSHaowei Wu                            << " for writing.\n";
5316103fdfaSHaowei Wu         return -1;
5326103fdfaSHaowei Wu       }
5336103fdfaSHaowei Wu       if (!Stub.Target.Triple) {
5346103fdfaSHaowei Wu         WithColor::error()
5356103fdfaSHaowei Wu             << "Triple should be defined when output format is TBD";
5366103fdfaSHaowei Wu         return -1;
5376103fdfaSHaowei Wu       }
53867ba5c50SFangrui Song       return writeTbdStub(llvm::Triple(*Stub.Target.Triple), Stub.Symbols,
53967ba5c50SFangrui Song                           "TBD", Out);
5406103fdfaSHaowei Wu     }
5416103fdfaSHaowei Wu     case FileFormat::IFS: {
5426103fdfaSHaowei Wu       Stub.IfsVersion = IfsVersionCurrent;
54367ba5c50SFangrui Song       if (*Config.InputFormat == FileFormat::ELF && Config.HintIfsTarget) {
5446103fdfaSHaowei Wu         std::error_code HintEC(1, std::generic_category());
545480dcdc8SAlex Brachet         IFSTarget HintTarget = parseTriple(*Config.HintIfsTarget);
54667ba5c50SFangrui Song         if (*Stub.Target.Arch != *HintTarget.Arch)
5476103fdfaSHaowei Wu           fatalError(make_error<StringError>(
5486103fdfaSHaowei Wu               "Triple hint does not match the actual architecture", HintEC));
54967ba5c50SFangrui Song         if (*Stub.Target.Endianness != *HintTarget.Endianness)
5506103fdfaSHaowei Wu           fatalError(make_error<StringError>(
5516103fdfaSHaowei Wu               "Triple hint does not match the actual endianness", HintEC));
55267ba5c50SFangrui Song         if (*Stub.Target.BitWidth != *HintTarget.BitWidth)
5536103fdfaSHaowei Wu           fatalError(make_error<StringError>(
5546103fdfaSHaowei Wu               "Triple hint does not match the actual bit width", HintEC));
5556103fdfaSHaowei Wu 
5566103fdfaSHaowei Wu         stripIFSTarget(Stub, true, false, false, false);
55767ba5c50SFangrui Song         Stub.Target.Triple = *Config.HintIfsTarget;
5586103fdfaSHaowei Wu       } else {
559480dcdc8SAlex Brachet         stripIFSTarget(Stub, Config.StripIfsTarget, Config.StripIfsArch,
560480dcdc8SAlex Brachet                        Config.StripIfsEndianness, Config.StripIfsBitwidth);
5616103fdfaSHaowei Wu       }
562480dcdc8SAlex Brachet       Error IFSWriteError =
56367ba5c50SFangrui Song           writeIFS(*Config.Output, Stub, Config.WriteIfChanged);
5646103fdfaSHaowei Wu       if (IFSWriteError)
5656103fdfaSHaowei Wu         fatalError(std::move(IFSWriteError));
5666103fdfaSHaowei Wu       break;
5676103fdfaSHaowei Wu     }
5686103fdfaSHaowei Wu     case FileFormat::ELF: {
5696103fdfaSHaowei Wu       Error TargetError = validateIFSTarget(Stub, true);
5706103fdfaSHaowei Wu       if (TargetError)
5716103fdfaSHaowei Wu         fatalError(std::move(TargetError));
5726103fdfaSHaowei Wu       Error BinaryWriteError =
573480dcdc8SAlex Brachet           writeBinaryStub(*Config.Output, Stub, Config.WriteIfChanged);
5746103fdfaSHaowei Wu       if (BinaryWriteError)
5756103fdfaSHaowei Wu         fatalError(std::move(BinaryWriteError));
5766103fdfaSHaowei Wu       break;
5776103fdfaSHaowei Wu     }
5786103fdfaSHaowei Wu     }
5795e171cebSHaowei Wu   } else {
5805e171cebSHaowei Wu     // Check if output path for individual format.
581480dcdc8SAlex Brachet     if (Config.OutputElf) {
5825e171cebSHaowei Wu       Error TargetError = validateIFSTarget(Stub, true);
5835e171cebSHaowei Wu       if (TargetError)
5845e171cebSHaowei Wu         fatalError(std::move(TargetError));
5855e171cebSHaowei Wu       Error BinaryWriteError =
586480dcdc8SAlex Brachet           writeBinaryStub(*Config.OutputElf, Stub, Config.WriteIfChanged);
5875e171cebSHaowei Wu       if (BinaryWriteError)
5885e171cebSHaowei Wu         fatalError(std::move(BinaryWriteError));
5895e171cebSHaowei Wu     }
590480dcdc8SAlex Brachet     if (Config.OutputIfs) {
5915e171cebSHaowei Wu       Stub.IfsVersion = IfsVersionCurrent;
59267ba5c50SFangrui Song       if (*Config.InputFormat == FileFormat::ELF && Config.HintIfsTarget) {
5935e171cebSHaowei Wu         std::error_code HintEC(1, std::generic_category());
594480dcdc8SAlex Brachet         IFSTarget HintTarget = parseTriple(*Config.HintIfsTarget);
59567ba5c50SFangrui Song         if (*Stub.Target.Arch != *HintTarget.Arch)
5965e171cebSHaowei Wu           fatalError(make_error<StringError>(
5975e171cebSHaowei Wu               "Triple hint does not match the actual architecture", HintEC));
59867ba5c50SFangrui Song         if (*Stub.Target.Endianness != *HintTarget.Endianness)
5995e171cebSHaowei Wu           fatalError(make_error<StringError>(
6005e171cebSHaowei Wu               "Triple hint does not match the actual endianness", HintEC));
60167ba5c50SFangrui Song         if (*Stub.Target.BitWidth != *HintTarget.BitWidth)
6025e171cebSHaowei Wu           fatalError(make_error<StringError>(
6035e171cebSHaowei Wu               "Triple hint does not match the actual bit width", HintEC));
6045e171cebSHaowei Wu 
6055e171cebSHaowei Wu         stripIFSTarget(Stub, true, false, false, false);
60667ba5c50SFangrui Song         Stub.Target.Triple = *Config.HintIfsTarget;
6075e171cebSHaowei Wu       } else {
608480dcdc8SAlex Brachet         stripIFSTarget(Stub, Config.StripIfsTarget, Config.StripIfsArch,
609480dcdc8SAlex Brachet                        Config.StripIfsEndianness, Config.StripIfsBitwidth);
6105e171cebSHaowei Wu       }
611480dcdc8SAlex Brachet       Error IFSWriteError =
61267ba5c50SFangrui Song           writeIFS(*Config.OutputIfs, Stub, Config.WriteIfChanged);
6135e171cebSHaowei Wu       if (IFSWriteError)
6145e171cebSHaowei Wu         fatalError(std::move(IFSWriteError));
6155e171cebSHaowei Wu     }
616480dcdc8SAlex Brachet     if (Config.OutputTbd) {
6175e171cebSHaowei Wu       std::error_code SysErr;
618480dcdc8SAlex Brachet       raw_fd_ostream Out(*Config.OutputTbd, SysErr);
6195e171cebSHaowei Wu       if (SysErr) {
620480dcdc8SAlex Brachet         WithColor::error() << "Couldn't open " << *Config.OutputTbd
6215e171cebSHaowei Wu                            << " for writing.\n";
6225e171cebSHaowei Wu         return -1;
6235e171cebSHaowei Wu       }
6245e171cebSHaowei Wu       if (!Stub.Target.Triple) {
6255e171cebSHaowei Wu         WithColor::error()
6265e171cebSHaowei Wu             << "Triple should be defined when output format is TBD";
6275e171cebSHaowei Wu         return -1;
6285e171cebSHaowei Wu       }
62967ba5c50SFangrui Song       return writeTbdStub(llvm::Triple(*Stub.Target.Triple), Stub.Symbols,
63067ba5c50SFangrui Song                           "TBD", Out);
6315e171cebSHaowei Wu     }
6325e171cebSHaowei Wu   }
6336103fdfaSHaowei Wu   return 0;
634d719c506SPuyan Lotfi }
635