diff options
author | Cyndy Ishida <cyndy_ishida@apple.com> | 2023-12-20 08:47:10 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-20 08:47:10 -0800 |
commit | 5ea15fab19eb005c6032ea453c7a01ae32269336 (patch) | |
tree | cb886ce71496c46e52dba158137169baab0f9a2a /llvm/lib/TextAPI | |
parent | 8bbeed05c4da832a2abf532fee8665c0d6576cbc (diff) | |
download | llvm-5ea15fab19eb005c6032ea453c7a01ae32269336.zip llvm-5ea15fab19eb005c6032ea453c7a01ae32269336.tar.gz llvm-5ea15fab19eb005c6032ea453c7a01ae32269336.tar.bz2 |
[TextAPI] Add support to convert RecordSlices -> InterfaceFile (#75007)
Introduce RecordVisitor. This is used for different clients that want to
extract information out of RecordSlice types.
The first and immediate use case is for serializing symbol information
into TBD files.
Diffstat (limited to 'llvm/lib/TextAPI')
-rw-r--r-- | llvm/lib/TextAPI/BinaryReader/DylibReader.cpp | 10 | ||||
-rw-r--r-- | llvm/lib/TextAPI/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/TextAPI/RecordVisitor.cpp | 65 | ||||
-rw-r--r-- | llvm/lib/TextAPI/RecordsSlice.cpp | 120 |
4 files changed, 194 insertions, 2 deletions
diff --git a/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp b/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp index b01130c..40b57b5 100644 --- a/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp +++ b/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp @@ -417,3 +417,13 @@ Expected<Records> DylibReader::readFile(MemoryBufferRef Buffer, return make_error<TextAPIError>(TextAPIErrorCode::EmptyResults); return Results; } + +Expected<std::unique_ptr<InterfaceFile>> +DylibReader::get(MemoryBufferRef Buffer) { + ParseOption Options; + auto SlicesOrErr = readFile(Buffer, Options); + if (!SlicesOrErr) + return SlicesOrErr.takeError(); + + return convertToInterfaceFile(*SlicesOrErr); +} diff --git a/llvm/lib/TextAPI/CMakeLists.txt b/llvm/lib/TextAPI/CMakeLists.txt index 75fc92f..2017a1ad 100644 --- a/llvm/lib/TextAPI/CMakeLists.txt +++ b/llvm/lib/TextAPI/CMakeLists.txt @@ -6,6 +6,7 @@ add_llvm_component_library(LLVMTextAPI PackedVersion.cpp Platform.cpp RecordsSlice.cpp + RecordVisitor.cpp Symbol.cpp SymbolSet.cpp Target.cpp diff --git a/llvm/lib/TextAPI/RecordVisitor.cpp b/llvm/lib/TextAPI/RecordVisitor.cpp new file mode 100644 index 0000000..cee04e6 --- /dev/null +++ b/llvm/lib/TextAPI/RecordVisitor.cpp @@ -0,0 +1,65 @@ +//===- RecordVisitor.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// Implements the TAPI Record Visitor. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/TextAPI/RecordVisitor.h" + +using namespace llvm; +using namespace llvm::MachO; + +RecordVisitor::~RecordVisitor() {} +void RecordVisitor::visitObjCInterface(const ObjCInterfaceRecord &) {} +void RecordVisitor::visitObjCCategory(const ObjCCategoryRecord &) {} + +static bool shouldSkipRecord(const Record &R, const bool RecordUndefs) { + if (R.isExported()) + return false; + + // Skip non exported symbols unless for flat namespace libraries. + return !(RecordUndefs && R.isUndefined()); +} + +void SymbolConverter::visitGlobal(const GlobalRecord &GR) { + auto [SymName, SymKind] = parseSymbol(GR.getName(), GR.getFlags()); + if (shouldSkipRecord(GR, RecordUndefs)) + return; + Symbols->addGlobal(SymKind, SymName, GR.getFlags(), Targ); +} + +void SymbolConverter::addIVars(const ArrayRef<ObjCIVarRecord *> IVars, + StringRef ContainerName) { + for (auto *IV : IVars) { + if (shouldSkipRecord(*IV, RecordUndefs)) + continue; + std::string Name = + ObjCIVarRecord::createScopedName(ContainerName, IV->getName()); + Symbols->addGlobal(SymbolKind::ObjectiveCInstanceVariable, Name, + IV->getFlags(), Targ); + } +} + +void SymbolConverter::visitObjCInterface(const ObjCInterfaceRecord &ObjCR) { + if (!shouldSkipRecord(ObjCR, RecordUndefs)) { + Symbols->addGlobal(SymbolKind::ObjectiveCClass, ObjCR.getName(), + ObjCR.getFlags(), Targ); + if (ObjCR.hasExceptionAttribute()) + Symbols->addGlobal(SymbolKind::ObjectiveCClassEHType, ObjCR.getName(), + ObjCR.getFlags(), Targ); + } + + addIVars(ObjCR.getObjCIVars(), ObjCR.getName()); + for (const auto *Cat : ObjCR.getObjCCategories()) + addIVars(Cat->getObjCIVars(), ObjCR.getName()); +} + +void SymbolConverter::visitObjCCategory(const ObjCCategoryRecord &Cat) { + addIVars(Cat.getObjCIVars(), Cat.getName()); +} diff --git a/llvm/lib/TextAPI/RecordsSlice.cpp b/llvm/lib/TextAPI/RecordsSlice.cpp index a220b25..7ceffc7 100644 --- a/llvm/lib/TextAPI/RecordsSlice.cpp +++ b/llvm/lib/TextAPI/RecordsSlice.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/TextAPI/RecordsSlice.h" +#include "llvm/ADT/SetVector.h" #include "llvm/TextAPI/Record.h" #include "llvm/TextAPI/Symbol.h" #include <utility> @@ -142,8 +143,10 @@ GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage, if (Result.second) Result.first->second = std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV); - else + else { updateLinkage(Result.first->second.get(), Linkage); + updateFlags(Result.first->second.get(), Flags); + } return Result.first->second.get(); } @@ -164,6 +167,19 @@ ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name, return Result.first->second.get(); } +SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) { + // Add Linkage properties into Flags. + switch (Linkage) { + case RecordLinkage::Rexported: + Flags |= SymbolFlags::Rexported; + return Flags; + case RecordLinkage::Undefined: + Flags |= SymbolFlags::Undefined; + return Flags; + default: + return Flags; + } +} bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) { auto Result = Categories.insert({Name, Record}); @@ -188,11 +204,26 @@ ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend, return Result.first->second.get(); } +std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const { + std::vector<ObjCIVarRecord *> Records; + llvm::for_each(IVars, + [&](auto &Record) { Records.push_back(Record.second.get()); }); + return Records; +} + +std::vector<ObjCCategoryRecord *> +ObjCInterfaceRecord::getObjCCategories() const { + std::vector<ObjCCategoryRecord *> Records; + llvm::for_each(Categories, + [&](auto &Record) { Records.push_back(Record.second); }); + return Records; +} + ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar, RecordLinkage Linkage) { auto Result = IVars.insert({IVar, nullptr}); if (Result.second) - Result.first->second = std::make_unique<ObjCIVarRecord>(Name, Linkage); + Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage); return Result.first->second.get(); } @@ -222,3 +253,88 @@ RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() { BA = std::make_unique<BinaryAttrs>(); return *BA; } + +void RecordsSlice::visit(RecordVisitor &V) const { + for (auto &G : Globals) + V.visitGlobal(*G.second); + for (auto &C : Classes) + V.visitObjCInterface(*C.second); + for (auto &Cat : Categories) + V.visitObjCCategory(*Cat.second); +} + +static std::unique_ptr<InterfaceFile> +createInterfaceFile(const Records &Slices, StringRef InstallName) { + // Pickup symbols first. + auto Symbols = std::make_unique<SymbolSet>(); + for (auto &S : Slices) { + if (S->empty()) + continue; + auto &BA = S->getBinaryAttrs(); + if (BA.InstallName != InstallName) + continue; + + SymbolConverter Converter(Symbols.get(), S->getTarget(), + !BA.TwoLevelNamespace); + S->visit(Converter); + } + + auto File = std::make_unique<InterfaceFile>(std::move(Symbols)); + File->setInstallName(InstallName); + // Assign other attributes. + for (auto &S : Slices) { + if (S->empty()) + continue; + auto &BA = S->getBinaryAttrs(); + if (BA.InstallName != InstallName) + continue; + const Target &Targ = S->getTarget(); + File->addTarget(Targ); + if (File->getFileType() == FileType::Invalid) + File->setFileType(BA.File); + if (BA.AppExtensionSafe && !File->isApplicationExtensionSafe()) + File->setApplicationExtensionSafe(); + if (BA.TwoLevelNamespace && !File->isTwoLevelNamespace()) + File->setTwoLevelNamespace(); + if (BA.OSLibNotForSharedCache && !File->isOSLibNotForSharedCache()) + File->setOSLibNotForSharedCache(); + if (File->getCurrentVersion().empty()) + File->setCurrentVersion(BA.CurrentVersion); + if (File->getCompatibilityVersion().empty()) + File->setCompatibilityVersion(BA.CompatVersion); + if (File->getSwiftABIVersion() == 0) + File->setSwiftABIVersion(BA.SwiftABI); + if (File->getPath().empty()) + File->setPath(BA.Path); + if (!BA.ParentUmbrella.empty()) + File->addParentUmbrella(Targ, BA.ParentUmbrella); + for (const auto &Client : BA.AllowableClients) + File->addAllowableClient(Client, Targ); + for (const auto &Lib : BA.RexportedLibraries) + File->addReexportedLibrary(Lib, Targ); + } + + return File; +} + +std::unique_ptr<InterfaceFile> +llvm::MachO::convertToInterfaceFile(const Records &Slices) { + std::unique_ptr<InterfaceFile> File; + if (Slices.empty()) + return File; + + SetVector<StringRef> InstallNames; + for (auto &S : Slices) { + auto Name = S->getBinaryAttrs().InstallName; + if (Name.empty()) + continue; + InstallNames.insert(Name); + } + + File = createInterfaceFile(Slices, *InstallNames.begin()); + for (auto it = std::next(InstallNames.begin()); it != InstallNames.end(); + ++it) + File->addDocument(createInterfaceFile(Slices, *it)); + + return File; +} |