blob: cb597d8896e811f350c1931fbb1e60fc4549abf7 [file] [log] [blame]
//===- TBEHandler.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
//
//===-----------------------------------------------------------------------===/
#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("Weak", Symbol.Weak, 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 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.mapOptional("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
Expected<std::unique_ptr<ELFStub>> elfabi::readTBEFromBuffer(StringRef Buf) {
yaml::Input YamlIn(Buf);
std::unique_ptr<ELFStub> Stub(new ELFStub());
YamlIn >> *Stub;
if (std::error_code Err = YamlIn.error())
return createStringError(Err, "YAML failed reading as TBE");
return std::move(Stub);
}
Error elfabi::writeTBEToOutputStream(raw_ostream &OS, const ELFStub &Stub) {
yaml::Output YamlOut(OS, NULL, /*WrapColumn =*/0);
YamlOut << const_cast<ELFStub &>(Stub);
return Error::success();
}