aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/TextAPI
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/TextAPI')
-rw-r--r--contrib/llvm-project/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp429
-rw-r--r--contrib/llvm-project/llvm/lib/TextAPI/RecordVisitor.cpp65
-rw-r--r--contrib/llvm-project/llvm/lib/TextAPI/RecordsSlice.cpp120
-rw-r--r--contrib/llvm-project/llvm/lib/TextAPI/Utils.cpp40
4 files changed, 652 insertions, 2 deletions
diff --git a/contrib/llvm-project/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp b/contrib/llvm-project/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp
new file mode 100644
index 000000000000..40b57b5e40ea
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp
@@ -0,0 +1,429 @@
+//===- DylibReader.cpp -------------- TAPI MachO Dylib Reader --*- C++ -*-===//
+//
+// 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 Reader for Mach-O dynamic libraries.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TextAPI/DylibReader.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/TargetParser/Triple.h"
+#include "llvm/TextAPI/RecordsSlice.h"
+#include "llvm/TextAPI/TextAPIError.h"
+#include <iomanip>
+#include <set>
+#include <sstream>
+#include <string>
+#include <tuple>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::MachO;
+using namespace llvm::MachO::DylibReader;
+
+using TripleVec = std::vector<Triple>;
+static typename TripleVec::iterator emplace(TripleVec &Container, Triple &&T) {
+ auto I = partition_point(Container, [=](const Triple &CT) {
+ return std::forward_as_tuple(CT.getArch(), CT.getOS(),
+ CT.getEnvironment()) <
+ std::forward_as_tuple(T.getArch(), T.getOS(), T.getEnvironment());
+ });
+
+ if (I != Container.end() && *I == T)
+ return I;
+ return Container.emplace(I, T);
+}
+
+static TripleVec constructTriples(MachOObjectFile *Obj,
+ const Architecture ArchT) {
+ auto getOSVersionStr = [](uint32_t V) {
+ PackedVersion OSVersion(V);
+ std::string Vers;
+ raw_string_ostream VStream(Vers);
+ VStream << OSVersion;
+ return VStream.str();
+ };
+ auto getOSVersion = [&](const MachOObjectFile::LoadCommandInfo &cmd) {
+ auto Vers = Obj->getVersionMinLoadCommand(cmd);
+ return getOSVersionStr(Vers.version);
+ };
+
+ TripleVec Triples;
+ bool IsIntel = ArchitectureSet(ArchT).hasX86();
+ auto Arch = getArchitectureName(ArchT);
+
+ for (const auto &cmd : Obj->load_commands()) {
+ std::string OSVersion;
+ switch (cmd.C.cmd) {
+ case MachO::LC_VERSION_MIN_MACOSX:
+ OSVersion = getOSVersion(cmd);
+ emplace(Triples, {Arch, "apple", "macos" + OSVersion});
+ break;
+ case MachO::LC_VERSION_MIN_IPHONEOS:
+ OSVersion = getOSVersion(cmd);
+ if (IsIntel)
+ emplace(Triples, {Arch, "apple", "ios" + OSVersion, "simulator"});
+ else
+ emplace(Triples, {Arch, "apple", "ios" + OSVersion});
+ break;
+ case MachO::LC_VERSION_MIN_TVOS:
+ OSVersion = getOSVersion(cmd);
+ if (IsIntel)
+ emplace(Triples, {Arch, "apple", "tvos" + OSVersion, "simulator"});
+ else
+ emplace(Triples, {Arch, "apple", "tvos" + OSVersion});
+ break;
+ case MachO::LC_VERSION_MIN_WATCHOS:
+ OSVersion = getOSVersion(cmd);
+ if (IsIntel)
+ emplace(Triples, {Arch, "apple", "watchos" + OSVersion, "simulator"});
+ else
+ emplace(Triples, {Arch, "apple", "watchos" + OSVersion});
+ break;
+ case MachO::LC_BUILD_VERSION: {
+ OSVersion = getOSVersionStr(Obj->getBuildVersionLoadCommand(cmd).minos);
+ switch (Obj->getBuildVersionLoadCommand(cmd).platform) {
+ case MachO::PLATFORM_MACOS:
+ emplace(Triples, {Arch, "apple", "macos" + OSVersion});
+ break;
+ case MachO::PLATFORM_IOS:
+ emplace(Triples, {Arch, "apple", "ios" + OSVersion});
+ break;
+ case MachO::PLATFORM_TVOS:
+ emplace(Triples, {Arch, "apple", "tvos" + OSVersion});
+ break;
+ case MachO::PLATFORM_WATCHOS:
+ emplace(Triples, {Arch, "apple", "watchos" + OSVersion});
+ break;
+ case MachO::PLATFORM_BRIDGEOS:
+ emplace(Triples, {Arch, "apple", "bridgeos" + OSVersion});
+ break;
+ case MachO::PLATFORM_MACCATALYST:
+ emplace(Triples, {Arch, "apple", "ios" + OSVersion, "macabi"});
+ break;
+ case MachO::PLATFORM_IOSSIMULATOR:
+ emplace(Triples, {Arch, "apple", "ios" + OSVersion, "simulator"});
+ break;
+ case MachO::PLATFORM_TVOSSIMULATOR:
+ emplace(Triples, {Arch, "apple", "tvos" + OSVersion, "simulator"});
+ break;
+ case MachO::PLATFORM_WATCHOSSIMULATOR:
+ emplace(Triples, {Arch, "apple", "watchos" + OSVersion, "simulator"});
+ break;
+ case MachO::PLATFORM_DRIVERKIT:
+ emplace(Triples, {Arch, "apple", "driverkit" + OSVersion});
+ break;
+ default:
+ break; // Skip any others.
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ // Record unknown platform for older binaries that don't enforce platform
+ // load commands.
+ if (Triples.empty())
+ emplace(Triples, {Arch, "apple", "unknown"});
+
+ return Triples;
+}
+
+static Error readMachOHeader(MachOObjectFile *Obj, RecordsSlice &Slice) {
+ auto H = Obj->getHeader();
+ auto &BA = Slice.getBinaryAttrs();
+
+ switch (H.filetype) {
+ default:
+ llvm_unreachable("unsupported binary type");
+ case MachO::MH_DYLIB:
+ BA.File = FileType::MachO_DynamicLibrary;
+ break;
+ case MachO::MH_DYLIB_STUB:
+ BA.File = FileType::MachO_DynamicLibrary_Stub;
+ break;
+ case MachO::MH_BUNDLE:
+ BA.File = FileType::MachO_Bundle;
+ break;
+ }
+
+ if (H.flags & MachO::MH_TWOLEVEL)
+ BA.TwoLevelNamespace = true;
+ if (H.flags & MachO::MH_APP_EXTENSION_SAFE)
+ BA.AppExtensionSafe = true;
+
+ for (const auto &LCI : Obj->load_commands()) {
+ switch (LCI.C.cmd) {
+ case MachO::LC_ID_DYLIB: {
+ auto DLLC = Obj->getDylibIDLoadCommand(LCI);
+ BA.InstallName = Slice.copyString(LCI.Ptr + DLLC.dylib.name);
+ BA.CurrentVersion = DLLC.dylib.current_version;
+ BA.CompatVersion = DLLC.dylib.compatibility_version;
+ break;
+ }
+ case MachO::LC_REEXPORT_DYLIB: {
+ auto DLLC = Obj->getDylibIDLoadCommand(LCI);
+ BA.RexportedLibraries.emplace_back(
+ Slice.copyString(LCI.Ptr + DLLC.dylib.name));
+ break;
+ }
+ case MachO::LC_SUB_FRAMEWORK: {
+ auto SFC = Obj->getSubFrameworkCommand(LCI);
+ BA.ParentUmbrella = Slice.copyString(LCI.Ptr + SFC.umbrella);
+ break;
+ }
+ case MachO::LC_SUB_CLIENT: {
+ auto SCLC = Obj->getSubClientCommand(LCI);
+ BA.AllowableClients.emplace_back(Slice.copyString(LCI.Ptr + SCLC.client));
+ break;
+ }
+ case MachO::LC_UUID: {
+ auto UUIDLC = Obj->getUuidCommand(LCI);
+ std::stringstream Stream;
+ for (unsigned I = 0; I < 16; ++I) {
+ if (I == 4 || I == 6 || I == 8 || I == 10)
+ Stream << '-';
+ Stream << std::setfill('0') << std::setw(2) << std::uppercase
+ << std::hex << static_cast<int>(UUIDLC.uuid[I]);
+ }
+ BA.UUID = Slice.copyString(Stream.str());
+ break;
+ }
+ case MachO::LC_RPATH: {
+ auto RPLC = Obj->getRpathCommand(LCI);
+ BA.RPaths.emplace_back(Slice.copyString(LCI.Ptr + RPLC.path));
+ break;
+ }
+ case MachO::LC_SEGMENT_SPLIT_INFO: {
+ auto SSILC = Obj->getLinkeditDataLoadCommand(LCI);
+ if (SSILC.datasize == 0)
+ BA.OSLibNotForSharedCache = true;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ for (auto &Sect : Obj->sections()) {
+ auto SectName = Sect.getName();
+ if (!SectName)
+ return SectName.takeError();
+ if (*SectName != "__objc_imageinfo" && *SectName != "__image_info")
+ continue;
+
+ auto Content = Sect.getContents();
+ if (!Content)
+ return Content.takeError();
+
+ if ((Content->size() >= 8) && (Content->front() == 0)) {
+ uint32_t Flags;
+ if (Obj->isLittleEndian()) {
+ auto *p =
+ reinterpret_cast<const support::ulittle32_t *>(Content->data() + 4);
+ Flags = *p;
+ } else {
+ auto *p =
+ reinterpret_cast<const support::ubig32_t *>(Content->data() + 4);
+ Flags = *p;
+ }
+ BA.SwiftABI = (Flags >> 8) & 0xFF;
+ }
+ }
+ return Error::success();
+}
+
+static Error readSymbols(MachOObjectFile *Obj, RecordsSlice &Slice,
+ const ParseOption &Opt) {
+
+ auto parseExport = [](const auto ExportFlags,
+ auto Addr) -> std::tuple<SymbolFlags, RecordLinkage> {
+ SymbolFlags Flags = SymbolFlags::None;
+ switch (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) {
+ case MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
+ if (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION)
+ Flags |= SymbolFlags::WeakDefined;
+ break;
+ case MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
+ Flags |= SymbolFlags::ThreadLocalValue;
+ break;
+ }
+
+ RecordLinkage Linkage = (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT)
+ ? RecordLinkage::Rexported
+ : RecordLinkage::Exported;
+ return {Flags, Linkage};
+ };
+
+ Error Err = Error::success();
+
+ StringMap<std::pair<SymbolFlags, RecordLinkage>> Exports;
+ // Collect symbols from export trie first. Sometimes, there are more exports
+ // in the trie than in n-list due to stripping. This is common for swift
+ // mangled symbols.
+ for (auto &Sym : Obj->exports(Err)) {
+ auto [Flags, Linkage] = parseExport(Sym.flags(), Sym.address());
+ Slice.addRecord(Sym.name(), Flags, GlobalRecord::Kind::Unknown, Linkage);
+ Exports[Sym.name()] = {Flags, Linkage};
+ }
+
+ for (const auto &Sym : Obj->symbols()) {
+ auto FlagsOrErr = Sym.getFlags();
+ if (!FlagsOrErr)
+ return FlagsOrErr.takeError();
+ auto Flags = *FlagsOrErr;
+
+ auto NameOrErr = Sym.getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ auto Name = *NameOrErr;
+
+ RecordLinkage Linkage = RecordLinkage::Unknown;
+ SymbolFlags RecordFlags = SymbolFlags::None;
+
+ if (Opt.Undefineds && (Flags & SymbolRef::SF_Undefined)) {
+ Linkage = RecordLinkage::Undefined;
+ if (Flags & SymbolRef::SF_Weak)
+ RecordFlags |= SymbolFlags::WeakReferenced;
+ } else if (Flags & SymbolRef::SF_Exported) {
+ auto Exp = Exports.find(Name);
+ // This should never be possible when binaries are produced with Apple
+ // linkers. However it is possible to craft dylibs where the export trie
+ // is either malformed or has conflicting symbols compared to n_list.
+ if (Exp != Exports.end())
+ std::tie(RecordFlags, Linkage) = Exp->second;
+ else
+ Linkage = RecordLinkage::Exported;
+ } else if (Flags & SymbolRef::SF_Hidden) {
+ Linkage = RecordLinkage::Internal;
+ } else
+ continue;
+
+ auto TypeOrErr = Sym.getType();
+ if (!TypeOrErr)
+ return TypeOrErr.takeError();
+ auto Type = *TypeOrErr;
+
+ GlobalRecord::Kind GV = (Type & SymbolRef::ST_Function)
+ ? GlobalRecord::Kind::Function
+ : GlobalRecord::Kind::Variable;
+
+ if (GV == GlobalRecord::Kind::Function)
+ RecordFlags |= SymbolFlags::Text;
+ else
+ RecordFlags |= SymbolFlags::Data;
+
+ Slice.addRecord(Name, RecordFlags, GV, Linkage);
+ }
+ return Err;
+}
+
+static Error load(MachOObjectFile *Obj, RecordsSlice &Slice,
+ const ParseOption &Opt, const Architecture Arch) {
+ if (Arch == AK_unknown)
+ return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget);
+
+ if (Opt.MachOHeader)
+ if (auto Err = readMachOHeader(Obj, Slice))
+ return Err;
+
+ if (Opt.SymbolTable)
+ if (auto Err = readSymbols(Obj, Slice, Opt))
+ return Err;
+
+ return Error::success();
+}
+
+Expected<Records> DylibReader::readFile(MemoryBufferRef Buffer,
+ const ParseOption &Opt) {
+ Records Results;
+
+ auto BinOrErr = createBinary(Buffer);
+ if (!BinOrErr)
+ return BinOrErr.takeError();
+
+ Binary &Bin = *BinOrErr.get();
+ if (auto *Obj = dyn_cast<MachOObjectFile>(&Bin)) {
+ const auto Arch = getArchitectureFromCpuType(Obj->getHeader().cputype,
+ Obj->getHeader().cpusubtype);
+ if (!Opt.Archs.has(Arch))
+ return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
+
+ auto Triples = constructTriples(Obj, Arch);
+ for (const auto &T : Triples) {
+ if (mapToPlatformType(T) == PLATFORM_UNKNOWN)
+ return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget);
+ Results.emplace_back(std::make_shared<RecordsSlice>(RecordsSlice({T})));
+ if (auto Err = load(Obj, *Results.back(), Opt, Arch))
+ return std::move(Err);
+ Results.back()->getBinaryAttrs().Path = Buffer.getBufferIdentifier();
+ }
+ return Results;
+ }
+
+ // Only expect MachO universal binaries at this point.
+ assert(isa<MachOUniversalBinary>(&Bin) &&
+ "Expected a MachO universal binary.");
+ auto *UB = cast<MachOUniversalBinary>(&Bin);
+
+ for (auto OI = UB->begin_objects(), OE = UB->end_objects(); OI != OE; ++OI) {
+ // Skip architecture if not requested.
+ auto Arch =
+ getArchitectureFromCpuType(OI->getCPUType(), OI->getCPUSubType());
+ if (!Opt.Archs.has(Arch))
+ continue;
+
+ // Skip unknown architectures.
+ if (Arch == AK_unknown)
+ continue;
+
+ // This can fail if the object is an archive.
+ auto ObjOrErr = OI->getAsObjectFile();
+
+ // Skip the archive and consume the error.
+ if (!ObjOrErr) {
+ consumeError(ObjOrErr.takeError());
+ continue;
+ }
+
+ auto &Obj = *ObjOrErr.get();
+ switch (Obj.getHeader().filetype) {
+ default:
+ break;
+ case MachO::MH_BUNDLE:
+ case MachO::MH_DYLIB:
+ case MachO::MH_DYLIB_STUB:
+ for (const auto &T : constructTriples(&Obj, Arch)) {
+ Results.emplace_back(std::make_shared<RecordsSlice>(RecordsSlice({T})));
+ if (auto Err = load(&Obj, *Results.back(), Opt, Arch))
+ return std::move(Err);
+ }
+ break;
+ }
+ }
+
+ if (Results.empty())
+ 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/contrib/llvm-project/llvm/lib/TextAPI/RecordVisitor.cpp b/contrib/llvm-project/llvm/lib/TextAPI/RecordVisitor.cpp
new file mode 100644
index 000000000000..cee04e644755
--- /dev/null
+++ b/contrib/llvm-project/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/contrib/llvm-project/llvm/lib/TextAPI/RecordsSlice.cpp b/contrib/llvm-project/llvm/lib/TextAPI/RecordsSlice.cpp
index a220b255aea3..7ceffc7c9284 100644
--- a/contrib/llvm-project/llvm/lib/TextAPI/RecordsSlice.cpp
+++ b/contrib/llvm-project/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;
+}
diff --git a/contrib/llvm-project/llvm/lib/TextAPI/Utils.cpp b/contrib/llvm-project/llvm/lib/TextAPI/Utils.cpp
new file mode 100644
index 000000000000..6d85083e0b54
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/TextAPI/Utils.cpp
@@ -0,0 +1,40 @@
+//===- Utils.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 utility functions for TextAPI Darwin operations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TextAPI/Utils.h"
+
+using namespace llvm;
+using namespace llvm::MachO;
+
+void llvm::MachO::replace_extension(SmallVectorImpl<char> &Path,
+ const Twine &Extension) {
+ StringRef P(Path.begin(), Path.size());
+ auto ParentPath = sys::path::parent_path(P);
+ auto Filename = sys::path::filename(P);
+
+ if (!ParentPath.ends_with(Filename.str() + ".framework")) {
+ sys::path::replace_extension(Path, Extension);
+ return;
+ }
+ // Framework dylibs do not have a file extension, in those cases the new
+ // extension is appended. e.g. given Path: "Foo.framework/Foo" and Extension:
+ // "tbd", the result is "Foo.framework/Foo.tbd".
+ SmallString<8> Storage;
+ StringRef Ext = Extension.toStringRef(Storage);
+
+ // Append '.' if needed.
+ if (!Ext.empty() && Ext[0] != '.')
+ Path.push_back('.');
+
+ // Append extension.
+ Path.append(Ext.begin(), Ext.end());
+}