Skip to content

[TextAPI] Consolidate TextAPI Reader/Writer APIs. #66108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions llvm/include/llvm/Object/TapiFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,12 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/TextAPI/Architecture.h"
#include "llvm/TextAPI/InterfaceFile.h"

namespace llvm {

class raw_ostream;

namespace MachO {

class InterfaceFile;

}

namespace object {

class TapiFile : public SymbolicFile {
Expand All @@ -51,6 +46,8 @@ class TapiFile : public SymbolicFile {

Expected<SymbolRef::Type> getSymbolType(DataRefImpl DRI) const;

bool hasSegmentInfo() { return FileKind >= MachO::FileType::TBD_V5; }

static bool classof(const Binary *v) { return v->isTapiFile(); }

bool is64Bit() const override { return MachO::is64Bit(Arch); }
Expand All @@ -69,6 +66,7 @@ class TapiFile : public SymbolicFile {

std::vector<Symbol> Symbols;
MachO::Architecture Arch;
MachO::FileType FileKind;
};

} // end namespace object.
Expand Down
14 changes: 14 additions & 0 deletions llvm/include/llvm/TextAPI/TextAPIReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,23 @@ class MemoryBufferRef;
namespace MachO {

class InterfaceFile;
enum FileType : unsigned;

class TextAPIReader {
public:
/// Determine whether input can be interpreted as TAPI text file.
/// This allows one to exit early when file is not recognized as TAPI file
/// as opposed to `get` which attempts to full parse and load of library
/// attributes.
///
/// \param InputBuffer Buffer holding contents of TAPI text file.
/// \return The file format version of TAPI text file.
static Expected<FileType> canRead(MemoryBufferRef InputBuffer);

/// Parse and get an InterfaceFile that represents the full
/// library.
///
/// \param InputBuffer Buffer holding contents of TAPI text file.
static Expected<std::unique_ptr<InterfaceFile>>
get(MemoryBufferRef InputBuffer);

Expand Down
12 changes: 10 additions & 2 deletions llvm/include/llvm/TextAPI/TextAPIWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,28 @@
#ifndef LLVM_TEXTAPI_TEXTAPIWRITER_H
#define LLVM_TEXTAPI_TEXTAPIWRITER_H

#include "llvm/TextAPI/InterfaceFile.h"

namespace llvm {

class Error;
class raw_ostream;

namespace MachO {

class InterfaceFile;

class TextAPIWriter {
public:
TextAPIWriter() = delete;

/// Write TAPI text file contents into stream.
///
/// \param OS Stream to write to.
/// \param File Library attributes to write as text file.
/// \param FileKind File format to write text file as. If not specified, it
/// will read from File.
/// \param Compact Whether to limit whitespace in text file.
static Error writeToStream(raw_ostream &OS, const InterfaceFile &File,
const FileType FileKind = FileType::Invalid,
bool Compact = false);
};

Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Object/TapiFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ static SymbolRef::Type getType(const Symbol *Sym) {

TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &Interface,
Architecture Arch)
: SymbolicFile(ID_TapiFile, Source), Arch(Arch) {
: SymbolicFile(ID_TapiFile, Source), Arch(Arch),
FileKind(Interface.getFileType()) {
for (const auto *Symbol : Interface.symbols()) {
if (!Symbol->getArchitectures().has(Arch))
continue;
Expand Down
66 changes: 40 additions & 26 deletions llvm/lib/TextAPI/TextStub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,11 @@ template <> struct MappingTraits<const InterfaceFile *> {
!(Flags & TBDFlags::NotApplicationExtensionSafe));
}

// For older file formats, the segment where the symbol
// comes from is unknown, treat all symbols as Data
// in these cases.
const auto Flags = SymbolFlags::Data;

for (const auto &Section : Exports) {
const auto Targets =
synthesizeTargets(Section.Architectures, Platforms);
Expand All @@ -634,26 +639,27 @@ template <> struct MappingTraits<const InterfaceFile *> {

for (const auto &Symbol : Section.Symbols) {
if (Ctx->FileKind != FileType::TBD_V3 &&
Symbol.value.startswith("_OBJC_EHTYPE_$_"))
Symbol.value.startswith(ObjC2EHTypePrefix))
File->addSymbol(SymbolKind::ObjectiveCClassEHType,
Symbol.value.drop_front(15), Targets);
Symbol.value.drop_front(15), Targets, Flags);
else
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets);
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, Flags);
}
for (auto &Symbol : Section.Classes) {
auto Name = Symbol.value;
if (Ctx->FileKind != FileType::TBD_V3)
Name = Name.drop_front();
File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets);
File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets, Flags);
}
for (auto &Symbol : Section.ClassEHs)
File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets);
File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets,
Flags);
for (auto &Symbol : Section.IVars) {
auto Name = Symbol.value;
if (Ctx->FileKind != FileType::TBD_V3)
Name = Name.drop_front();
File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name,
Targets);
File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets,
Flags);
}
for (auto &Symbol : Section.WeakDefSymbols)
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
Expand All @@ -668,34 +674,35 @@ template <> struct MappingTraits<const InterfaceFile *> {
synthesizeTargets(Section.Architectures, Platforms);
for (auto &Symbol : Section.Symbols) {
if (Ctx->FileKind != FileType::TBD_V3 &&
Symbol.value.startswith("_OBJC_EHTYPE_$_"))
Symbol.value.startswith(ObjC2EHTypePrefix))
File->addSymbol(SymbolKind::ObjectiveCClassEHType,
Symbol.value.drop_front(15), Targets,
SymbolFlags::Undefined);
SymbolFlags::Undefined | Flags);
else
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
SymbolFlags::Undefined);
SymbolFlags::Undefined | Flags);
}
for (auto &Symbol : Section.Classes) {
auto Name = Symbol.value;
if (Ctx->FileKind != FileType::TBD_V3)
Name = Name.drop_front();
File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets,
SymbolFlags::Undefined);
SymbolFlags::Undefined | Flags);
}
for (auto &Symbol : Section.ClassEHs)
File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets,
SymbolFlags::Undefined);
SymbolFlags::Undefined | Flags);
for (auto &Symbol : Section.IVars) {
auto Name = Symbol.value;
if (Ctx->FileKind != FileType::TBD_V3)
Name = Name.drop_front();
File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets,
SymbolFlags::Undefined);
SymbolFlags::Undefined | Flags);
}
for (auto &Symbol : Section.WeakRefSymbols)
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
SymbolFlags::Undefined | SymbolFlags::WeakReferenced);
SymbolFlags::Undefined | SymbolFlags::WeakReferenced |
Flags);
}

return File;
Expand Down Expand Up @@ -906,7 +913,12 @@ template <> struct MappingTraits<const InterfaceFile *> {
}

auto handleSymbols = [File](const SectionList &CurrentSections,
SymbolFlags Flag = SymbolFlags::None) {
SymbolFlags InputFlag = SymbolFlags::None) {
// For older file formats, the segment where the symbol
// comes from is unknown, treat all symbols as Data
// in these cases.
const SymbolFlags Flag = InputFlag | SymbolFlags::Data;

for (const auto &CurrentSection : CurrentSections) {
for (auto &sym : CurrentSection.Symbols)
File->addSymbol(SymbolKind::GlobalSymbol, sym,
Expand All @@ -924,9 +936,10 @@ template <> struct MappingTraits<const InterfaceFile *> {
File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, sym,
CurrentSection.Targets, Flag);

SymbolFlags SymFlag = (Flag == SymbolFlags::Undefined)
? SymbolFlags::WeakReferenced
: SymbolFlags::WeakDefined;
SymbolFlags SymFlag =
((Flag & SymbolFlags::Undefined) == SymbolFlags::Undefined)
? SymbolFlags::WeakReferenced
: SymbolFlags::WeakDefined;
for (auto &sym : CurrentSection.WeakSymbols) {
File->addSymbol(SymbolKind::GlobalSymbol, sym,
CurrentSection.Targets, Flag | SymFlag);
Expand Down Expand Up @@ -1078,9 +1091,7 @@ static void DiagHandler(const SMDiagnostic &Diag, void *Context) {
File->ErrorMessage = ("malformed file\n" + Message).str();
}

namespace {

Expected<FileType> canReadFileType(MemoryBufferRef InputBuffer) {
Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) {
auto TAPIFile = InputBuffer.getBuffer().trim();
if (TAPIFile.startswith("{") && TAPIFile.endswith("}"))
return FileType::TBD_V5;
Expand All @@ -1103,13 +1114,12 @@ Expected<FileType> canReadFileType(MemoryBufferRef InputBuffer) {

return createStringError(std::errc::not_supported, "unsupported file type");
}
} // namespace

Expected<std::unique_ptr<InterfaceFile>>
TextAPIReader::get(MemoryBufferRef InputBuffer) {
TextAPIContext Ctx;
Ctx.Path = std::string(InputBuffer.getBufferIdentifier());
if (auto FTOrErr = canReadFileType(InputBuffer))
if (auto FTOrErr = canRead(InputBuffer))
Ctx.FileKind = *FTOrErr;
else
return FTOrErr.takeError();
Expand Down Expand Up @@ -1145,14 +1155,18 @@ TextAPIReader::get(MemoryBufferRef InputBuffer) {
}

Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File,
bool Compact) {
const FileType FileKind, bool Compact) {
TextAPIContext Ctx;
Ctx.Path = std::string(File.getPath());
Ctx.FileKind = File.getFileType();

// Prefer parameter for format if passed, otherwise fallback to the File
// FileType.
Ctx.FileKind =
(FileKind == FileType::Invalid) ? File.getFileType() : FileKind;

// Write out in JSON format.
if (Ctx.FileKind >= FileType::TBD_V5) {
return serializeInterfaceFileToJSON(OS, File, Compact);
return serializeInterfaceFileToJSON(OS, File, Ctx.FileKind, Compact);
}

llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80);
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/TextAPI/TextStubCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Expected<std::unique_ptr<InterfaceFile>>
getInterfaceFileFromJSON(StringRef JSON);

Error serializeInterfaceFileToJSON(raw_ostream &OS, const InterfaceFile &File,
bool Compact);
const FileType FileKind, bool Compact);
} // namespace MachO

namespace yaml {
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/TextAPI/TextStubV5.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -986,9 +986,8 @@ Expected<Object> serializeIF(const InterfaceFile *File) {
return std::move(Library);
}

Expected<Object> getJSON(const InterfaceFile *File) {
assert(File->getFileType() == FileType::TBD_V5 &&
"unexpected json file format version");
Expected<Object> getJSON(const InterfaceFile *File, const FileType FileKind) {
assert(FileKind == FileType::TBD_V5 && "unexpected json file format version");
Object Root;

auto MainLibOrErr = serializeIF(File);
Expand All @@ -1012,8 +1011,9 @@ Expected<Object> getJSON(const InterfaceFile *File) {

Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS,
const InterfaceFile &File,
const FileType FileKind,
bool Compact) {
auto TextFile = getJSON(&File);
auto TextFile = getJSON(&File, FileKind);
if (!TextFile)
return TextFile.takeError();
if (Compact)
Expand Down
6 changes: 4 additions & 2 deletions llvm/tools/llvm-nm/llvm-nm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1023,10 +1023,12 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
static char getSymbolNMTypeChar(TapiFile &Obj, basic_symbol_iterator I) {
auto Type = cantFail(Obj.getSymbolType(I->getRawDataRefImpl()));
switch (Type) {
case SymbolRef::ST_Data:
return 'd';
case SymbolRef::ST_Function:
return 't';
case SymbolRef::ST_Data:
if (Obj.hasSegmentInfo())
return 'd';
[[fallthrough]];
default:
return 's';
}
Expand Down
11 changes: 8 additions & 3 deletions llvm/unittests/TextAPI/TextStubV5Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,15 @@ TEST(TBDv5, ReadFile) {
"libraries": []
})";

Expected<TBDFile> Result =
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
MemoryBufferRef InputBuf = MemoryBufferRef(TBDv5File, "Test.tbd");
Expected<FileType> ExpectedFT = TextAPIReader::canRead(InputBuf);
EXPECT_TRUE(!!ExpectedFT);

Expected<TBDFile> Result = TextAPIReader::get(InputBuf);
EXPECT_TRUE(!!Result);
TBDFile File = std::move(Result.get());
EXPECT_EQ(FileType::TBD_V5, File->getFileType());
EXPECT_EQ(*ExpectedFT, File->getFileType());
EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName());

TargetList AllTargets = {
Expand Down Expand Up @@ -915,7 +919,8 @@ TEST(TBDv5, WriteMultipleDocuments) {
// against TBDv5File.
SmallString<4096> Buffer;
raw_svector_ostream OS(Buffer);
Error Result = TextAPIWriter::writeToStream(OS, File, /*Compact=*/true);
Error Result = TextAPIWriter::writeToStream(OS, File, FileType::Invalid,
/*Compact=*/true);
EXPECT_FALSE(Result);

Expected<TBDFile> Input =
Expand Down