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