2018-12-03 20:30:52 +01:00
|
|
|
//===- TBEHandler.cpp -----------------------------------------------------===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// 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
|
2018-12-03 20:30:52 +01:00
|
|
|
//
|
|
|
|
//===-----------------------------------------------------------------------===/
|
|
|
|
|
2020-08-11 20:44:22 +02:00
|
|
|
#include "llvm/InterfaceStub/TBEHandler.h"
|
2018-12-03 20:30:52 +01:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2020-08-11 20:44:22 +02:00
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2021-04-01 01:48:56 +02:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2020-08-11 20:44:22 +02:00
|
|
|
#include "llvm/InterfaceStub/ELFStub.h"
|
2018-12-03 20:30:52 +01:00
|
|
|
#include "llvm/Support/Error.h"
|
2021-04-01 01:48:56 +02:00
|
|
|
#include "llvm/Support/LineIterator.h"
|
2018-12-03 20:30:52 +01:00
|
|
|
#include "llvm/Support/YAMLTraits.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::elfabi;
|
|
|
|
|
2021-04-01 01:48:56 +02:00
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(ELFSymbol)
|
2018-12-03 20:30:52 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-04-01 01:48:56 +02:00
|
|
|
template <> struct ScalarTraits<ELFEndiannessType> {
|
|
|
|
static void output(const ELFEndiannessType &Value, void *,
|
2018-12-03 20:30:52 +01:00
|
|
|
llvm::raw_ostream &Out) {
|
|
|
|
switch (Value) {
|
2021-04-01 01:48:56 +02:00
|
|
|
case ELFEndiannessType::Big:
|
|
|
|
Out << "big";
|
2018-12-03 20:30:52 +01:00
|
|
|
break;
|
2021-04-01 01:48:56 +02:00
|
|
|
case ELFEndiannessType::Little:
|
|
|
|
Out << "little";
|
2018-12-03 20:30:52 +01:00
|
|
|
break;
|
|
|
|
default:
|
2021-04-01 01:48:56 +02:00
|
|
|
llvm_unreachable("Unsupported endianness");
|
2018-12-03 20:30:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-01 01:48:56 +02:00
|
|
|
static StringRef input(StringRef Scalar, void *, ELFEndiannessType &Value) {
|
|
|
|
Value = StringSwitch<ELFEndiannessType>(Scalar)
|
|
|
|
.Case("big", ELFEndiannessType::Big)
|
|
|
|
.Case("little", ELFEndiannessType::Little)
|
|
|
|
.Default(ELFEndiannessType::Unknown);
|
|
|
|
if (Value == ELFEndiannessType::Unknown) {
|
|
|
|
return "Unsupported endianness";
|
|
|
|
}
|
|
|
|
return StringRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <> struct ScalarTraits<ELFBitWidthType> {
|
|
|
|
static void output(const ELFBitWidthType &Value, void *,
|
|
|
|
llvm::raw_ostream &Out) {
|
|
|
|
switch (Value) {
|
|
|
|
case ELFBitWidthType::ELF32:
|
|
|
|
Out << "32";
|
|
|
|
break;
|
|
|
|
case ELFBitWidthType::ELF64:
|
|
|
|
Out << "64";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unsupported bit width");
|
|
|
|
}
|
|
|
|
}
|
2018-12-03 20:30:52 +01:00
|
|
|
|
2021-04-01 01:48:56 +02:00
|
|
|
static StringRef input(StringRef Scalar, void *, ELFBitWidthType &Value) {
|
|
|
|
Value = StringSwitch<ELFBitWidthType>(Scalar)
|
|
|
|
.Case("32", ELFBitWidthType::ELF32)
|
|
|
|
.Case("64", ELFBitWidthType::ELF64)
|
|
|
|
.Default(ELFBitWidthType::Unknown);
|
|
|
|
if (Value == ELFBitWidthType::Unknown) {
|
|
|
|
return "Unsupported bit width";
|
|
|
|
}
|
2018-12-03 20:30:52 +01:00
|
|
|
return StringRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
|
|
|
|
};
|
|
|
|
|
2021-04-01 01:48:56 +02:00
|
|
|
template <> struct MappingTraits<IFSTarget> {
|
|
|
|
static void mapping(IO &IO, IFSTarget &Target) {
|
|
|
|
IO.mapOptional("ObjectFormat", Target.ObjectFormat);
|
|
|
|
IO.mapOptional("Arch", Target.ArchString);
|
|
|
|
IO.mapOptional("Endianness", Target.Endianness);
|
|
|
|
IO.mapOptional("BitWidth", Target.BitWidth);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compacts symbol information into a single line.
|
|
|
|
static const bool flow = true; // NOLINT(readability-identifier-naming)
|
|
|
|
};
|
|
|
|
|
2018-12-03 20:30:52 +01:00
|
|
|
/// YAML traits for ELFSymbol.
|
|
|
|
template <> struct MappingTraits<ELFSymbol> {
|
|
|
|
static void mapping(IO &IO, ELFSymbol &Symbol) {
|
2021-04-01 01:48:56 +02:00
|
|
|
IO.mapRequired("Name", Symbol.Name);
|
2018-12-03 20:30:52 +01:00
|
|
|
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);
|
2018-12-21 21:45:58 +01:00
|
|
|
IO.mapOptional("Weak", Symbol.Weak, false);
|
2018-12-03 20:30:52 +01:00
|
|
|
IO.mapOptional("Warning", Symbol.Warning);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compacts symbol information into a single line.
|
2021-04-01 01:48:56 +02:00
|
|
|
static const bool flow = true; // NOLINT(readability-identifier-naming)
|
2018-12-03 20:30:52 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/// YAML traits for ELFStub objects.
|
|
|
|
template <> struct MappingTraits<ELFStub> {
|
|
|
|
static void mapping(IO &IO, ELFStub &Stub) {
|
2021-04-01 01:48:56 +02:00
|
|
|
if (!IO.mapTag("!ifs-v1", true))
|
2018-12-03 20:30:52 +01:00
|
|
|
IO.setError("Not a .tbe YAML file.");
|
|
|
|
IO.mapRequired("TbeVersion", Stub.TbeVersion);
|
2018-12-11 02:00:16 +01:00
|
|
|
IO.mapOptional("SoName", Stub.SoName);
|
2021-04-01 01:48:56 +02:00
|
|
|
IO.mapOptional("Target", Stub.Target);
|
2018-12-07 02:31:28 +01:00
|
|
|
IO.mapOptional("NeededLibs", Stub.NeededLibs);
|
2018-12-03 20:30:52 +01:00
|
|
|
IO.mapRequired("Symbols", Stub.Symbols);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-04-01 01:48:56 +02:00
|
|
|
/// YAML traits for ELFStubTriple objects.
|
|
|
|
template <> struct MappingTraits<ELFStubTriple> {
|
|
|
|
static void mapping(IO &IO, ELFStubTriple &Stub) {
|
|
|
|
if (!IO.mapTag("!ifs-v1", true))
|
|
|
|
IO.setError("Not a .tbe YAML file.");
|
|
|
|
IO.mapRequired("TbeVersion", Stub.TbeVersion);
|
|
|
|
IO.mapOptional("SoName", Stub.SoName);
|
|
|
|
IO.mapOptional("Target", Stub.Target.Triple);
|
|
|
|
IO.mapOptional("NeededLibs", Stub.NeededLibs);
|
|
|
|
IO.mapRequired("Symbols", Stub.Symbols);
|
|
|
|
}
|
|
|
|
};
|
2018-12-03 20:30:52 +01:00
|
|
|
} // end namespace yaml
|
|
|
|
} // end namespace llvm
|
|
|
|
|
2021-04-01 01:48:56 +02:00
|
|
|
/// Attempt to determine if a Text stub uses target triple.
|
|
|
|
bool usesTriple(StringRef Buf) {
|
|
|
|
for (line_iterator I(MemoryBufferRef(Buf, "ELFStub")); !I.is_at_eof(); ++I) {
|
|
|
|
StringRef Line = (*I).trim();
|
|
|
|
if (Line.startswith("Target:")) {
|
|
|
|
if (Line == "Target:" || (Line.find("{") != Line.npos)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-12-10 03:36:33 +01:00
|
|
|
Expected<std::unique_ptr<ELFStub>> elfabi::readTBEFromBuffer(StringRef Buf) {
|
2018-12-03 20:30:52 +01:00
|
|
|
yaml::Input YamlIn(Buf);
|
2021-04-01 01:48:56 +02:00
|
|
|
std::unique_ptr<ELFStubTriple> Stub(new ELFStubTriple());
|
|
|
|
if (usesTriple(Buf)) {
|
|
|
|
YamlIn >> *Stub;
|
|
|
|
} else {
|
|
|
|
YamlIn >> *static_cast<ELFStub *>(Stub.get());
|
|
|
|
}
|
|
|
|
if (std::error_code Err = YamlIn.error()) {
|
2018-12-10 03:36:33 +01:00
|
|
|
return createStringError(Err, "YAML failed reading as TBE");
|
2021-04-01 01:48:56 +02:00
|
|
|
}
|
2018-12-10 03:36:33 +01:00
|
|
|
|
2020-10-21 02:50:29 +02:00
|
|
|
if (Stub->TbeVersion > elfabi::TBEVersionCurrent)
|
|
|
|
return make_error<StringError>(
|
|
|
|
"TBE version " + Stub->TbeVersion.getAsString() + " is unsupported.",
|
|
|
|
std::make_error_code(std::errc::invalid_argument));
|
2021-04-01 01:48:56 +02:00
|
|
|
if (Stub->Target.ArchString) {
|
|
|
|
Stub->Target.Arch =
|
|
|
|
ELF::convertArchNameToEMachine(Stub->Target.ArchString.getValue());
|
|
|
|
}
|
2020-02-10 16:06:45 +01:00
|
|
|
return std::move(Stub);
|
2018-12-03 20:30:52 +01:00
|
|
|
}
|
|
|
|
|
2018-12-10 03:36:33 +01:00
|
|
|
Error elfabi::writeTBEToOutputStream(raw_ostream &OS, const ELFStub &Stub) {
|
2018-12-03 20:30:52 +01:00
|
|
|
yaml::Output YamlOut(OS, NULL, /*WrapColumn =*/0);
|
2021-04-01 01:48:56 +02:00
|
|
|
std::unique_ptr<ELFStubTriple> CopyStub(new ELFStubTriple(Stub));
|
|
|
|
if (Stub.Target.Arch) {
|
|
|
|
CopyStub->Target.ArchString = std::string(
|
|
|
|
ELF::convertEMachineToArchName(Stub.Target.Arch.getValue()));
|
|
|
|
}
|
|
|
|
IFSTarget Target = Stub.Target;
|
|
|
|
|
|
|
|
if (CopyStub->Target.Triple ||
|
|
|
|
(!CopyStub->Target.ArchString && !CopyStub->Target.Endianness &&
|
|
|
|
!CopyStub->Target.BitWidth))
|
|
|
|
YamlOut << *CopyStub;
|
|
|
|
else
|
|
|
|
YamlOut << *static_cast<ELFStub *>(CopyStub.get());
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
Error elfabi::overrideTBETarget(ELFStub &Stub, Optional<ELFArch> OverrideArch,
|
|
|
|
Optional<ELFEndiannessType> OverrideEndianness,
|
|
|
|
Optional<ELFBitWidthType> OverrideBitWidth,
|
|
|
|
Optional<std::string> OverrideTriple) {
|
|
|
|
std::error_code OverrideEC(1, std::generic_category());
|
|
|
|
if (OverrideArch) {
|
|
|
|
if (Stub.Target.Arch &&
|
|
|
|
Stub.Target.Arch.getValue() != OverrideArch.getValue()) {
|
|
|
|
return make_error<StringError>(
|
|
|
|
"Supplied Arch conflicts with the text stub", OverrideEC);
|
|
|
|
}
|
|
|
|
Stub.Target.Arch = OverrideArch.getValue();
|
|
|
|
}
|
|
|
|
if (OverrideEndianness) {
|
|
|
|
if (Stub.Target.Endianness &&
|
|
|
|
Stub.Target.Endianness.getValue() != OverrideEndianness.getValue()) {
|
|
|
|
return make_error<StringError>(
|
|
|
|
"Supplied Endianness conflicts with the text stub", OverrideEC);
|
|
|
|
}
|
|
|
|
Stub.Target.Endianness = OverrideEndianness.getValue();
|
|
|
|
}
|
|
|
|
if (OverrideBitWidth) {
|
|
|
|
if (Stub.Target.BitWidth &&
|
|
|
|
Stub.Target.BitWidth.getValue() != OverrideBitWidth.getValue()) {
|
|
|
|
return make_error<StringError>(
|
|
|
|
"Supplied BitWidth conflicts with the text stub", OverrideEC);
|
|
|
|
}
|
|
|
|
Stub.Target.BitWidth = OverrideBitWidth.getValue();
|
|
|
|
}
|
|
|
|
if (OverrideTriple) {
|
|
|
|
if (Stub.Target.Triple &&
|
|
|
|
Stub.Target.Triple.getValue() != OverrideTriple.getValue()) {
|
|
|
|
return make_error<StringError>(
|
|
|
|
"Supplied Triple conflicts with the text stub", OverrideEC);
|
|
|
|
}
|
|
|
|
Stub.Target.Triple = OverrideTriple.getValue();
|
|
|
|
}
|
|
|
|
return Error::success();
|
|
|
|
}
|
2018-12-03 20:30:52 +01:00
|
|
|
|
2021-04-01 01:48:56 +02:00
|
|
|
Error elfabi::validateTBETarget(ELFStub &Stub, bool ParseTriple) {
|
|
|
|
std::error_code ValidationEC(1, std::generic_category());
|
|
|
|
if (Stub.Target.Triple) {
|
|
|
|
if (Stub.Target.Arch || Stub.Target.BitWidth || Stub.Target.Endianness ||
|
|
|
|
Stub.Target.ObjectFormat) {
|
|
|
|
return make_error<StringError>(
|
|
|
|
"Target triple cannot be used simultaneously with ELF target format",
|
|
|
|
ValidationEC);
|
|
|
|
}
|
|
|
|
if (ParseTriple) {
|
|
|
|
IFSTarget TargetFromTriple = parseTriple(Stub.Target.Triple.getValue());
|
|
|
|
Stub.Target.Arch = TargetFromTriple.Arch;
|
|
|
|
Stub.Target.BitWidth = TargetFromTriple.BitWidth;
|
|
|
|
Stub.Target.Endianness = TargetFromTriple.Endianness;
|
|
|
|
}
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
if (!Stub.Target.Arch || !Stub.Target.BitWidth || !Stub.Target.Endianness) {
|
|
|
|
// TODO: unify the error message.
|
|
|
|
if (!Stub.Target.Arch) {
|
|
|
|
return make_error<StringError>("Arch is not defined in the text stub",
|
|
|
|
ValidationEC);
|
|
|
|
}
|
|
|
|
if (!Stub.Target.BitWidth) {
|
|
|
|
return make_error<StringError>("BitWidth is not defined in the text stub",
|
|
|
|
ValidationEC);
|
|
|
|
}
|
|
|
|
if (!Stub.Target.Endianness) {
|
|
|
|
return make_error<StringError>(
|
|
|
|
"Endianness is not defined in the text stub", ValidationEC);
|
|
|
|
}
|
|
|
|
}
|
2018-12-03 20:30:52 +01:00
|
|
|
return Error::success();
|
|
|
|
}
|
2021-04-01 01:48:56 +02:00
|
|
|
|
|
|
|
IFSTarget elfabi::parseTriple(StringRef TripleStr) {
|
|
|
|
Triple IFSTriple(TripleStr);
|
|
|
|
IFSTarget RetTarget;
|
|
|
|
// TODO: Implement a Triple Arch enum to e_machine map.
|
|
|
|
switch (IFSTriple.getArch()) {
|
|
|
|
case Triple::ArchType::aarch64:
|
|
|
|
RetTarget.Arch = (ELFArch)ELF::EM_AARCH64;
|
|
|
|
break;
|
|
|
|
case Triple::ArchType::x86_64:
|
|
|
|
RetTarget.Arch = (ELFArch)ELF::EM_X86_64;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
RetTarget.Arch = (ELFArch)ELF::EM_NONE;
|
|
|
|
}
|
|
|
|
RetTarget.Endianness = IFSTriple.isLittleEndian() ? ELFEndiannessType::Little
|
|
|
|
: ELFEndiannessType::Big;
|
|
|
|
RetTarget.BitWidth =
|
|
|
|
IFSTriple.isArch64Bit() ? ELFBitWidthType::ELF64 : ELFBitWidthType::ELF32;
|
|
|
|
return RetTarget;
|
|
|
|
}
|
|
|
|
|
|
|
|
void elfabi::stripTBETarget(ELFStub &Stub, bool StripTriple, bool StripArch,
|
|
|
|
bool StripEndianness, bool StripBitWidth) {
|
|
|
|
if (StripTriple || StripArch) {
|
|
|
|
Stub.Target.Arch.reset();
|
|
|
|
Stub.Target.ArchString.reset();
|
|
|
|
}
|
|
|
|
if (StripTriple || StripEndianness) {
|
|
|
|
Stub.Target.Endianness.reset();
|
|
|
|
}
|
|
|
|
if (StripTriple || StripBitWidth) {
|
|
|
|
Stub.Target.BitWidth.reset();
|
|
|
|
}
|
|
|
|
if (StripTriple) {
|
|
|
|
Stub.Target.Triple.reset();
|
|
|
|
}
|
|
|
|
if (!Stub.Target.Arch && !Stub.Target.BitWidth && !Stub.Target.Endianness) {
|
|
|
|
Stub.Target.ObjectFormat.reset();
|
|
|
|
}
|
|
|
|
}
|