diff --git a/llvm/include/llvm/Object/TapiFile.h b/llvm/include/llvm/Object/TapiFile.h --- a/llvm/include/llvm/Object/TapiFile.h +++ b/llvm/include/llvm/Object/TapiFile.h @@ -15,6 +15,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Object/Binary.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/Error.h" #include "llvm/Support/MemoryBufferRef.h" @@ -34,7 +35,7 @@ class TapiFile : public SymbolicFile { public: - TapiFile(MemoryBufferRef Source, const MachO::InterfaceFile &interface, + TapiFile(MemoryBufferRef Source, const MachO::InterfaceFile &Interface, MachO::Architecture Arch); ~TapiFile() override; @@ -48,6 +49,8 @@ basic_symbol_iterator symbol_end() const override; + Expected getSymbolType(DataRefImpl DRI) const; + static bool classof(const Binary *v) { return v->isTapiFile(); } bool is64Bit() const override { return MachO::is64Bit(Arch); } @@ -57,9 +60,11 @@ StringRef Prefix; StringRef Name; uint32_t Flags; + SymbolRef::Type Type; - constexpr Symbol(StringRef Prefix, StringRef Name, uint32_t Flags) - : Prefix(Prefix), Name(Name), Flags(Flags) {} + constexpr Symbol(StringRef Prefix, StringRef Name, uint32_t Flags, + SymbolRef::Type Type) + : Prefix(Prefix), Name(Name), Flags(Flags), Type(Type) {} }; std::vector Symbols; diff --git a/llvm/include/llvm/TextAPI/Symbol.h b/llvm/include/llvm/TextAPI/Symbol.h --- a/llvm/include/llvm/TextAPI/Symbol.h +++ b/llvm/include/llvm/TextAPI/Symbol.h @@ -123,10 +123,7 @@ void dump() const { dump(llvm::errs()); } #endif - bool operator==(const Symbol &O) const { - return std::tie(Name, Kind, Targets, Flags) == - std::tie(O.Name, O.Kind, O.Targets, O.Flags); - } + bool operator==(const Symbol &O) const; bool operator!=(const Symbol &O) const { return !(*this == O); } diff --git a/llvm/lib/BinaryFormat/Magic.cpp b/llvm/lib/BinaryFormat/Magic.cpp --- a/llvm/lib/BinaryFormat/Magic.cpp +++ b/llvm/lib/BinaryFormat/Magic.cpp @@ -228,11 +228,14 @@ return file_magic::coff_object; break; - case 0x2d: // YAML '-' + case 0x2d: // YAML '-' MachO TBD. if (startswith(Magic, "--- !tapi") || startswith(Magic, "---\narchs:")) return file_magic::tapi_file; break; - + case 0x7b: // JSON '{' MachO TBD. + return file_magic::tapi_file; + break; + case 'D': // DirectX container file - DXBC if (startswith(Magic, "DXBC")) return file_magic::dxcontainer_object; diff --git a/llvm/lib/Object/TapiFile.cpp b/llvm/lib/Object/TapiFile.cpp --- a/llvm/lib/Object/TapiFile.cpp +++ b/llvm/lib/Object/TapiFile.cpp @@ -37,35 +37,46 @@ return Flags; } -TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &interface, +static SymbolRef::Type getType(const Symbol *Sym) { + SymbolRef::Type Type = SymbolRef::ST_Unknown; + if (Sym->isData()) + Type = SymbolRef::ST_Data; + else if (Sym->isText()) + Type = SymbolRef::ST_Function; + + return Type; +} + +TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &Interface, Architecture Arch) : SymbolicFile(ID_TapiFile, Source), Arch(Arch) { - for (const auto *Symbol : interface.symbols()) { + for (const auto *Symbol : Interface.symbols()) { if (!Symbol->getArchitectures().has(Arch)) continue; switch (Symbol->getKind()) { case SymbolKind::GlobalSymbol: - Symbols.emplace_back(StringRef(), Symbol->getName(), getFlags(Symbol)); + Symbols.emplace_back(StringRef(), Symbol->getName(), getFlags(Symbol), + ::getType(Symbol)); break; case SymbolKind::ObjectiveCClass: - if (interface.getPlatforms().count(PLATFORM_MACOS) && Arch == AK_i386) { + if (Interface.getPlatforms().count(PLATFORM_MACOS) && Arch == AK_i386) { Symbols.emplace_back(ObjC1ClassNamePrefix, Symbol->getName(), - getFlags(Symbol)); + getFlags(Symbol), ::getType(Symbol)); } else { Symbols.emplace_back(ObjC2ClassNamePrefix, Symbol->getName(), - getFlags(Symbol)); + getFlags(Symbol), ::getType(Symbol)); Symbols.emplace_back(ObjC2MetaClassNamePrefix, Symbol->getName(), - getFlags(Symbol)); + getFlags(Symbol), ::getType(Symbol)); } break; case SymbolKind::ObjectiveCClassEHType: Symbols.emplace_back(ObjC2EHTypePrefix, Symbol->getName(), - getFlags(Symbol)); + getFlags(Symbol), ::getType(Symbol)); break; case SymbolKind::ObjectiveCInstanceVariable: - Symbols.emplace_back(ObjC2IVarPrefix, Symbol->getName(), - getFlags(Symbol)); + Symbols.emplace_back(ObjC2IVarPrefix, Symbol->getName(), getFlags(Symbol), + ::getType(Symbol)); break; } } @@ -82,6 +93,11 @@ return Error::success(); } +Expected TapiFile::getSymbolType(DataRefImpl DRI) const { + assert(DRI.d.a < Symbols.size() && "Attempt to access symbol out of bounds"); + return Symbols[DRI.d.a].Type; +} + Expected TapiFile::getSymbolFlags(DataRefImpl DRI) const { assert(DRI.d.a < Symbols.size() && "Attempt to access symbol out of bounds"); return Symbols[DRI.d.a].Flags; diff --git a/llvm/lib/TextAPI/InterfaceFile.cpp b/llvm/lib/TextAPI/InterfaceFile.cpp --- a/llvm/lib/TextAPI/InterfaceFile.cpp +++ b/llvm/lib/TextAPI/InterfaceFile.cpp @@ -141,6 +141,10 @@ Documents.insert(Pos, Document); } +static bool isYAMLTextStub(const FileType &Kind) { + return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5); +} + bool InterfaceFile::operator==(const InterfaceFile &O) const { if (Targets != O.Targets) return false; @@ -165,6 +169,13 @@ return false; if (Symbols != O.Symbols) return false; + // Don't compare run search paths for older filetypes that cannot express + // them. + if (!(isYAMLTextStub(FileKind)) && !(isYAMLTextStub(O.FileKind))) { + if (RPaths != O.RPaths) + return false; + } + if (!std::equal(Documents.begin(), Documents.end(), O.Documents.begin(), O.Documents.end(), [](const std::shared_ptr LHS, diff --git a/llvm/lib/TextAPI/Symbol.cpp b/llvm/lib/TextAPI/Symbol.cpp --- a/llvm/lib/TextAPI/Symbol.cpp +++ b/llvm/lib/TextAPI/Symbol.cpp @@ -54,5 +54,24 @@ return make_filter_range(Targets, FN); } +bool Symbol::operator==(const Symbol &O) const { + // Older Tapi files do not express all these symbol flags. In those + // cases, ignore those differences. + auto RemoveFlag = [](const Symbol &Sym, SymbolFlags &Flag) { + if (Sym.isData()) + Flag &= ~SymbolFlags::Data; + if (Sym.isText()) + Flag &= ~SymbolFlags::Text; + }; + SymbolFlags LHSFlags = Flags; + SymbolFlags RHSFlags = O.Flags; + if ((!O.isData() && !O.isText()) || (!isData() && !isText())) { + RemoveFlag(*this, LHSFlags); + RemoveFlag(O, RHSFlags); + } + return std::tie(Name, Kind, Targets, LHSFlags) == + std::tie(O.Name, O.Kind, O.Targets, RHSFlags); +} + } // end namespace MachO. } // end namespace llvm. diff --git a/llvm/test/Object/Inputs/tapi-v5.tbd b/llvm/test/Object/Inputs/tapi-v5.tbd new file mode 100644 --- /dev/null +++ b/llvm/test/Object/Inputs/tapi-v5.tbd @@ -0,0 +1,73 @@ +{ + "main_library": { + "current_versions": [ + { + "version": "1.2.3" + } + ], + "exported_symbols": [ + { + "data": { + "global": [ + "_publicGlobalVariable", + "_extraGlobalAPI1", + "_privateGlobalVariable" + ], + "objc_class": [ + "SubClass", + "Basic6", + "Basic1", + "Base", + "Basic3", + "FooClass", + "Basic4", + "ExternalManagedObject" + ], + "objc_eh_type": [ + "SubClass", + "Base" + ], + "objc_ivar": [ + "Basic4.ivar2", + "Basic4.ivar1", + "Basic4_2.ivar2" + ], + "weak": [ + "_weakPrivateGlobalVariable", + "_weakPublicGlobalVariable" + ] + } + }, + { + "text": { + "global": [ + "_publicGlobalFunc" + ] + } + } + ], + "flags": [ + { + "attributes": [ + "not_app_extension_safe" + ] + } + ], + "install_names": [ + { + "name": "/System/Library/Frameworks/Simple.framework/Versions/A/Simple" + } + ], + "target_info": [ + { + "min_deployment": "10.10", + "target": "x86_64-macos" + }, + { + "min_deployment": "10.10", + "target": "arm64-macos" + } + ] + }, + "tapi_tbd_version": 5 +} diff --git a/llvm/test/Object/nm-tapi.test b/llvm/test/Object/nm-tapi.test --- a/llvm/test/Object/nm-tapi.test +++ b/llvm/test/Object/nm-tapi.test @@ -13,6 +13,9 @@ RUN: llvm-nm %p/Inputs/tapi-v4-watchos.tbd \ RUN: | FileCheck %s -check-prefix V4-WATCH +RUN: llvm-nm %p/Inputs/tapi-v5.tbd \ +RUN: | FileCheck %s -check-prefix V5 + V1: /u/l/libfoo.dylib (for architecture armv7): V1-NEXT: 00000000 S _sym V1: /u/l/libfoo.dylib (for architecture armv7s): @@ -64,3 +67,61 @@ V4-WATCH-NEXT: 00000000 S _sym1 V4-WATCH: /u/l/libFoo.dylib (for architecture arm64_32) V4-WATCH-NEXT: 00000000 S _sym1 + +V5: /System/Library/Frameworks/Simple.framework/Versions/A/Simple (for architecture x86_64): +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_Base +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_Basic1 +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_Basic3 +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_Basic4 +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_Basic6 +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_ExternalManagedObject +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_FooClass +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_SubClass +V5-NEXT: 0000000000000000 D _OBJC_EHTYPE_$_Base +V5-NEXT: 0000000000000000 D _OBJC_EHTYPE_$_SubClass +V5-NEXT: 0000000000000000 D _OBJC_IVAR_$_Basic4.ivar1 +V5-NEXT: 0000000000000000 D _OBJC_IVAR_$_Basic4.ivar2 +V5-NEXT: 0000000000000000 D _OBJC_IVAR_$_Basic4_2.ivar2 +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_Base +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_Basic1 +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_Basic3 +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_Basic4 +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_Basic6 +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_ExternalManagedObject +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_FooClass +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_SubClass +V5-NEXT: 0000000000000000 D _extraGlobalAPI1 +V5-NEXT: 0000000000000000 D _privateGlobalVariable +V5-NEXT: 0000000000000000 T _publicGlobalFunc +V5-NEXT: 0000000000000000 D _publicGlobalVariable +V5-NEXT: 0000000000000000 W _weakPrivateGlobalVariable +V5-NEXT: 0000000000000000 W _weakPublicGlobalVariable + +V5: /System/Library/Frameworks/Simple.framework/Versions/A/Simple (for architecture arm64): +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_Base +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_Basic1 +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_Basic3 +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_Basic4 +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_Basic6 +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_ExternalManagedObject +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_FooClass +V5-NEXT: 0000000000000000 D _OBJC_CLASS_$_SubClass +V5-NEXT: 0000000000000000 D _OBJC_EHTYPE_$_Base +V5-NEXT: 0000000000000000 D _OBJC_EHTYPE_$_SubClass +V5-NEXT: 0000000000000000 D _OBJC_IVAR_$_Basic4.ivar1 +V5-NEXT: 0000000000000000 D _OBJC_IVAR_$_Basic4.ivar2 +V5-NEXT: 0000000000000000 D _OBJC_IVAR_$_Basic4_2.ivar2 +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_Base +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_Basic1 +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_Basic3 +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_Basic4 +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_Basic6 +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_ExternalManagedObject +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_FooClass +V5-NEXT: 0000000000000000 D _OBJC_METACLASS_$_SubClass +V5-NEXT: 0000000000000000 D _extraGlobalAPI1 +V5-NEXT: 0000000000000000 D _privateGlobalVariable +V5-NEXT: 0000000000000000 T _publicGlobalFunc +V5-NEXT: 0000000000000000 D _publicGlobalVariable +V5-NEXT: 0000000000000000 W _weakPrivateGlobalVariable +V5-NEXT: 0000000000000000 W _weakPublicGlobalVariable diff --git a/llvm/test/tools/llvm-tapi-diff/matching-tbd.txt b/llvm/test/tools/llvm-tapi-diff/matching-tbd.test rename from llvm/test/tools/llvm-tapi-diff/matching-tbd.txt rename to llvm/test/tools/llvm-tapi-diff/matching-tbd.test diff --git a/llvm/test/tools/llvm-tapi-diff/v5.test b/llvm/test/tools/llvm-tapi-diff/v5.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-tapi-diff/v5.test @@ -0,0 +1,21 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: llvm-tapi-diff %t/Simple_v5.tbd %t/Simple_v5.tbd 2>&1 | FileCheck %s --allow-empty +; RUN: llvm-tapi-diff %t/Simple_v5.tbd %t/Simple_v4.tbd 2>&1 | FileCheck %s --allow-empty + +; CHECK-NOT: error: +; CHECK-NOT: warning: + +//--- Simple_v4.tbd +--- !tapi-tbd +tbd-version: 4 +targets: [ x86_64-macos, arm64-macos ] +flags: [ not_app_extension_safe ] +install-name: '@rpath/libFake.dylib' +exports: + - targets: [ x86_64-macos, arm64-macos ] + symbols: [ _foo ] +... + +//--- Simple_v5.tbd +{"main_library":{"exported_symbols":[{"text":{"global":["_foo"]}}],"flags":[{"attributes":["not_app_extension_safe"]}],"install_names":[{"name":"@rpath/libFake.dylib"}],"target_info":[{"min_deployment":"13","target":"x86_64-macos"},{"min_deployment":"13","target":"arm64-macos"}]},"tapi_tbd_version":5} diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp --- a/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/llvm/tools/llvm-nm/llvm-nm.cpp @@ -1029,7 +1029,15 @@ } static char getSymbolNMTypeChar(TapiFile &Obj, basic_symbol_iterator I) { - return 's'; + auto Type = cantFail(Obj.getSymbolType(I->getRawDataRefImpl())); + switch (Type) { + case SymbolRef::ST_Data: + return 'd'; + case SymbolRef::ST_Function: + return 't'; + default: + return 's'; + } } static char getSymbolNMTypeChar(WasmObjectFile &Obj, basic_symbol_iterator I) { diff --git a/llvm/tools/llvm-tapi-diff/DiffEngine.h b/llvm/tools/llvm-tapi-diff/DiffEngine.h --- a/llvm/tools/llvm-tapi-diff/DiffEngine.h +++ b/llvm/tools/llvm-tapi-diff/DiffEngine.h @@ -83,11 +83,7 @@ SymScalar(InterfaceInputOrder Order, const MachO::Symbol *Sym) : Order(Order), Val(Sym){}; - std::string getFlagString(MachO::SymbolFlags Flags) { - return Flags != MachO::SymbolFlags::None - ? " - " + stringifySymbolFlag(Flags) - : stringifySymbolFlag(Flags); - } + std::string getFlagString(const MachO::Symbol *Sym); void print(raw_ostream &OS, std::string Indent, MachO::Target Targ); @@ -99,7 +95,6 @@ InterfaceInputOrder Order; const MachO::Symbol *Val; StringLiteral getSymbolNamePrefix(MachO::SymbolKind Kind); - std::string stringifySymbolFlag(MachO::SymbolFlags Flag); }; class DiffStrVec : public AttributeDiff { diff --git a/llvm/tools/llvm-tapi-diff/DiffEngine.cpp b/llvm/tools/llvm-tapi-diff/DiffEngine.cpp --- a/llvm/tools/llvm-tapi-diff/DiffEngine.cpp +++ b/llvm/tools/llvm-tapi-diff/DiffEngine.cpp @@ -74,41 +74,42 @@ llvm_unreachable("Unknown llvm::MachO::SymbolKind enum"); } -std::string SymScalar::stringifySymbolFlag(MachO::SymbolFlags Flag) { - switch (Flag) { - case MachO::SymbolFlags::None: - return ""; - case MachO::SymbolFlags::ThreadLocalValue: - return "Thread-Local"; - case MachO::SymbolFlags::WeakDefined: - return "Weak-Defined"; - case MachO::SymbolFlags::WeakReferenced: - return "Weak-Referenced"; - case MachO::SymbolFlags::Undefined: - return "Undefined"; - case MachO::SymbolFlags::Rexported: - return "Reexported"; - default: - return ""; - } - llvm_unreachable("Unknown llvm::MachO::SymbolFlags enum"); +std::string SymScalar::getFlagString(const MachO::Symbol *Sym) { + if (Sym->getFlags() == SymbolFlags::None) + return {}; + SmallString<64> Flags(" - "); + if (Sym->isThreadLocalValue()) + Flags.append("Thread-Local "); + if (Sym->isWeakDefined()) + Flags.append("Weak-Defined "); + if (Sym->isWeakReferenced()) + Flags.append("Weak-Referenced "); + if (Sym->isUndefined()) + Flags.append("Undefined "); + if (Sym->isReexported()) + Flags.append("Reexported "); + if (Sym->isData()) + Flags.append("Data "); + if (Sym->isText()) + Flags.append("Text "); + + return std::string(Flags); } void SymScalar::print(raw_ostream &OS, std::string Indent, MachO::Target Targ) { if (Val->getKind() == MachO::SymbolKind::ObjectiveCClass) { if (Targ.Arch == MachO::AK_i386 && Targ.Platform == MachO::PLATFORM_MACOS) { OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ") - << ObjC1ClassNamePrefix << Val->getName() - << getFlagString(Val->getFlags()) << "\n"; + << ObjC1ClassNamePrefix << Val->getName() << getFlagString(Val) + << "\n"; return; } OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ") - << ObjC2ClassNamePrefix << Val->getName() - << getFlagString(Val->getFlags()) << "\n"; + << ObjC2ClassNamePrefix << Val->getName() << getFlagString(Val) << "\n"; } OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ") << getSymbolNamePrefix(Val->getKind()) << Val->getName() - << getFlagString(Val->getFlags()) << "\n"; + << getFlagString(Val) << "\n"; } bool checkSymbolEquality(llvm::MachO::InterfaceFile::const_symbol_range LHS,