Skip to content

Commit

Permalink
[llvm-tapi] initial commit, supports ELF text stubs
Browse files Browse the repository at this point in the history
http://lists.llvm.org/pipermail/llvm-dev/2018-September/126472.html

TextAPI is a library and accompanying tool that allows conversion between binary shared object stubs and textual counterparts. The motivations and uses cases for this are explained thoroughly in the llvm-dev proposal [1]. This initial commit proposes a potential structure for the TAPI library, also including support for reading/writing text-based ELF stubs (.tbe) in addition to preliminary support for reading binary ELF files. The goal for this patch is to ensure the project architecture appropriately welcomes integration of Mach-O stubbing from Apple's TAPI [2].

Added:

 - TextAPI library
 - .tbe read support
 - .tbe write (to raw_ostream) support

[1] http://lists.llvm.org/pipermail/llvm-dev/2018-September/126472.html
[2] https://github.com/ributzka/tapi

Differential Revision: https://reviews.llvm.org/D53051

llvm-svn: 348170
  • Loading branch information
armandomontanez committed Dec 3, 2018
1 parent 00f1d76 commit 1e4b370
Show file tree
Hide file tree
Showing 11 changed files with 575 additions and 0 deletions.
69 changes: 69 additions & 0 deletions llvm/include/llvm/TextAPI/ELF/ELFStub.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//===- ELFStub.h ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===-----------------------------------------------------------------------===/
///
/// \file
/// This file defines an internal representation of an ELF stub.
///
//===-----------------------------------------------------------------------===/

#ifndef LLVM_TEXTAPI_ELF_ELFSTUB_H
#define LLVM_TEXTAPI_ELF_ELFSTUB_H

#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/VersionTuple.h"
#include <vector>
#include <set>

namespace llvm {
namespace elfabi {

typedef uint16_t ELFArch;

enum class ELFSymbolType {
NoType = ELF::STT_NOTYPE,
Object = ELF::STT_OBJECT,
Func = ELF::STT_FUNC,
TLS = ELF::STT_TLS,

// Type information is 4 bits, so 16 is safely out of range.
Unknown = 16,
};

struct ELFSymbol {
ELFSymbol(std::string SymbolName) : Name(SymbolName) {}
std::string Name;
uint64_t Size;
ELFSymbolType Type;
bool Undefined;
bool Weak;
Optional<std::string> Warning;
bool operator<(const ELFSymbol &RHS) const {
return Name < RHS.Name;
}
};

// A cumulative representation of ELF stubs.
// Both textual and binary stubs will read into and write from this object.
class ELFStub {
// TODO: Add support for symbol versioning.
public:
VersionTuple TbeVersion;
std::string SoName;
ELFArch Arch;
std::vector<std::string> NeededLibs;
std::set<ELFSymbol> Symbols;

ELFStub() {}
ELFStub(const ELFStub &Stub);
ELFStub(ELFStub &&Stub);
};
} // end namespace elfabi
} // end namespace llvm

#endif // LLVM_TEXTAPI_ELF_ELFSTUB_H
46 changes: 46 additions & 0 deletions llvm/include/llvm/TextAPI/ELF/TBEHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===- TBEHandler.h ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===-----------------------------------------------------------------------===/
///
/// \file
/// This file declares an interface for reading and writing .tbe (text-based
/// ELF) files.
///
//===-----------------------------------------------------------------------===/

#ifndef LLVM_TEXTAPI_ELF_TBEHANDLER_H
#define LLVM_TEXTAPI_ELF_TBEHANDLER_H

#include "llvm/Support/VersionTuple.h"
#include <memory>

namespace llvm {

class raw_ostream;
class Error;
class StringRef;
class VersionTuple;

namespace elfabi {

class ELFStub;

const VersionTuple TBEVersionCurrent(1, 0);

class TBEHandler {
public:
/// Attempts to read an ELF interface file from a StringRef buffer.
std::unique_ptr<ELFStub> readFile(StringRef Buf);

/// Attempts to write an ELF interface file to a raw_ostream.
Error writeFile(raw_ostream &OS, const ELFStub &Stub);
};
} // end namespace elfabi
} // end namespace llvm

#endif // LLVM_TEXTAPI_ELF_TBEHANDLER_H
1 change: 1 addition & 0 deletions llvm/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ add_subdirectory(AsmParser)
add_subdirectory(LineEditor)
add_subdirectory(ProfileData)
add_subdirectory(Passes)
add_subdirectory(TextAPI)
add_subdirectory(ToolDrivers)
add_subdirectory(XRay)
add_subdirectory(Testing)
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/LLVMBuild.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ subdirectories =
ProfileData
Support
TableGen
TextAPI
Target
Testing
ToolDrivers
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/TextAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
add_llvm_library(LLVMTextAPI
ELF/ELFStub.cpp
ELF/TBEHandler.cpp

ADDITIONAL_HEADER_DIRS
"${LLVM_MAIN_INCLUDE_DIR}/llvm/TextAPI"
)
29 changes: 29 additions & 0 deletions llvm/lib/TextAPI/ELF/ELFStub.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//===- ELFStub.cpp --------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===-----------------------------------------------------------------------===/

#include "llvm/TextAPI/ELF/ELFStub.h"

using namespace llvm;
using namespace llvm::elfabi;

ELFStub::ELFStub(ELFStub const &Stub) {
TbeVersion = Stub.TbeVersion;
Arch = Stub.Arch;
SoName = Stub.SoName;
NeededLibs = Stub.NeededLibs;
Symbols = Stub.Symbols;
}

ELFStub::ELFStub(ELFStub &&Stub) {
TbeVersion = std::move(Stub.TbeVersion);
Arch = std::move(Stub.Arch);
SoName = std::move(Stub.SoName);
NeededLibs = std::move(Stub.NeededLibs);
Symbols = std::move(Stub.Symbols);
}
176 changes: 176 additions & 0 deletions llvm/lib/TextAPI/ELF/TBEHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
//===- TBEHandler.cpp -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===-----------------------------------------------------------------------===/

#include "llvm/TextAPI/ELF/TBEHandler.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/TextAPI/ELF/ELFStub.h"

using namespace llvm;
using namespace llvm::elfabi;

LLVM_YAML_STRONG_TYPEDEF(ELFArch, ELFArchMapper);

namespace llvm {
namespace yaml {

/// YAML traits for ELFSymbolType.
template <> struct ScalarEnumerationTraits<ELFSymbolType> {
static void enumeration(IO &IO, ELFSymbolType &SymbolType) {
IO.enumCase(SymbolType, "NoType", ELFSymbolType::NoType);
IO.enumCase(SymbolType, "Func", ELFSymbolType::Func);
IO.enumCase(SymbolType, "Object", ELFSymbolType::Object);
IO.enumCase(SymbolType, "TLS", ELFSymbolType::TLS);
IO.enumCase(SymbolType, "Unknown", ELFSymbolType::Unknown);
// Treat other symbol types as noise, and map to Unknown.
if (!IO.outputting() && IO.matchEnumFallback())
SymbolType = ELFSymbolType::Unknown;
}
};

/// YAML traits for ELFArch.
template <> struct ScalarTraits<ELFArchMapper> {
static void output(const ELFArchMapper &Value, void *,
llvm::raw_ostream &Out) {
// Map from integer to architecture string.
switch (Value) {
case (ELFArch)ELF::EM_X86_64:
Out << "x86_64";
break;
case (ELFArch)ELF::EM_AARCH64:
Out << "AArch64";
break;
case (ELFArch)ELF::EM_NONE:
default:
Out << "Unknown";
}
}

static StringRef input(StringRef Scalar, void *, ELFArchMapper &Value) {
// Map from architecture string to integer.
Value = StringSwitch<ELFArch>(Scalar)
.Case("x86_64", ELF::EM_X86_64)
.Case("AArch64", ELF::EM_AARCH64)
.Case("Unknown", ELF::EM_NONE)
.Default(ELF::EM_NONE);

// Returning empty StringRef indicates successful parse.
return StringRef();
}

// Don't place quotation marks around architecture value.
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};

/// YAML traits for TbeVersion.
template <> struct ScalarTraits<VersionTuple> {
static void output(const VersionTuple &Value, void *,
llvm::raw_ostream &Out) {
Out << Value.getAsString();
}

static StringRef input(StringRef Scalar, void *, VersionTuple &Value) {
if (Value.tryParse(Scalar))
return StringRef("Can't parse version: invalid version format.");

if (Value > TBEVersionCurrent)
return StringRef("Unsupported TBE version.");

// Returning empty StringRef indicates successful parse.
return StringRef();
}

// Don't place quotation marks around version value.
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};

/// YAML traits for ELFSymbol.
template <> struct MappingTraits<ELFSymbol> {
static void mapping(IO &IO, ELFSymbol &Symbol) {
IO.mapRequired("Type", Symbol.Type);
// The need for symbol size depends on the symbol type.
if (Symbol.Type == ELFSymbolType::NoType) {
IO.mapOptional("Size", Symbol.Size, (uint64_t)0);
} else if (Symbol.Type == ELFSymbolType::Func) {
Symbol.Size = 0;
} else {
IO.mapRequired("Size", Symbol.Size);
}
IO.mapOptional("Undefined", Symbol.Undefined, false);
IO.mapOptional("Warning", Symbol.Warning);
}

// Compacts symbol information into a single line.
static const bool flow = true;
};

/// YAML traits for set of ELFSymbols.
template <> struct CustomMappingTraits<std::set<ELFSymbol>> {
static void inputOne(IO &IO, StringRef Key, std::set<ELFSymbol> &Set) {
ELFSymbol Sym(Key.str());
IO.mapRequired(Key.str().c_str(), Sym);
Set.insert(Sym);
}

static void output(IO &IO, std::set<ELFSymbol> &Set) {
for (auto &Sym : Set)
IO.mapRequired(Sym.Name.c_str(), const_cast<ELFSymbol &>(Sym));
}
};

/// YAML traits for generic string vectors (i.e. list of needed libraries).
template <> struct SequenceTraits<std::vector<std::string>> {
static size_t size(IO &IO, std::vector<std::string> &List) {
return List.size();
}

static std::string &element(IO &IO, std::vector<std::string> &List,
size_t Index) {
if (Index >= List.size())
List.resize(Index + 1);
return List[Index];
}

// Compacts list of needed libraries into a single line.
static const bool flow = true;
};

/// YAML traits for ELFStub objects.
template <> struct MappingTraits<ELFStub> {
static void mapping(IO &IO, ELFStub &Stub) {
if (!IO.mapTag("!tapi-tbe", true))
IO.setError("Not a .tbe YAML file.");
IO.mapRequired("TbeVersion", Stub.TbeVersion);
IO.mapRequired("SoName", Stub.SoName);
IO.mapRequired("Arch", (ELFArchMapper &)Stub.Arch);
IO.mapOptional("NeededLibs", Stub.NeededLibs);
IO.mapRequired("Symbols", Stub.Symbols);
}
};

} // end namespace yaml
} // end namespace llvm

std::unique_ptr<ELFStub> TBEHandler::readFile(StringRef Buf) {
yaml::Input YamlIn(Buf);
std::unique_ptr<ELFStub> Stub(new ELFStub());
YamlIn >> *Stub;
if (YamlIn.error())
return nullptr;
return Stub;
}

Error TBEHandler::writeFile(raw_ostream &OS, const ELFStub &Stub) {
yaml::Output YamlOut(OS, NULL, /*WrapColumn =*/0);

YamlOut << const_cast<ELFStub &>(Stub);
return Error::success();
}
22 changes: 22 additions & 0 deletions llvm/lib/TextAPI/LLVMBuild.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
;===- ./lib/TextAPI/LLVMBuild.txt ------------------------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;

[component_0]
type = Library
name = TextAPI
parent = Libraries
required_libraries = Support BinaryFormat
1 change: 1 addition & 0 deletions llvm/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ add_subdirectory(OptRemarks)
add_subdirectory(Passes)
add_subdirectory(ProfileData)
add_subdirectory(Support)
add_subdirectory(TextAPI)
add_subdirectory(Target)
add_subdirectory(Transforms)
add_subdirectory(XRay)
Expand Down
7 changes: 7 additions & 0 deletions llvm/unittests/TextAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
set(LLVM_LINK_COMPONENTS
TextAPI
)

add_llvm_unittest(TapiTests
ELFYAMLTest.cpp
)
Loading

0 comments on commit 1e4b370

Please sign in to comment.