summaryrefslogtreecommitdiff
path: root/tools/llvm-elfabi/llvm-elfabi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-elfabi/llvm-elfabi.cpp')
-rw-r--r--tools/llvm-elfabi/llvm-elfabi.cpp143
1 files changed, 143 insertions, 0 deletions
diff --git a/tools/llvm-elfabi/llvm-elfabi.cpp b/tools/llvm-elfabi/llvm-elfabi.cpp
new file mode 100644
index 000000000000..4c15bc2eaf34
--- /dev/null
+++ b/tools/llvm-elfabi/llvm-elfabi.cpp
@@ -0,0 +1,143 @@
+//===- llvm-elfabi.cpp ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-----------------------------------------------------------------------===/
+
+#include "ELFObjHandler.h"
+#include "ErrorCollector.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/TextAPI/ELF/TBEHandler.h"
+#include <string>
+
+namespace llvm {
+namespace elfabi {
+
+enum class FileFormat {
+ TBE,
+ ELF
+};
+
+} // end namespace elfabi
+} // end namespace llvm
+
+using namespace llvm;
+using namespace llvm::elfabi;
+
+// Command line flags:
+cl::opt<FileFormat> InputFileFormat(
+ cl::desc("Force input file format:"),
+ cl::values(clEnumValN(FileFormat::TBE,
+ "tbe", "Read `input` as text-based ELF stub"),
+ clEnumValN(FileFormat::ELF,
+ "elf", "Read `input` as ELF binary")));
+cl::opt<std::string> InputFilePath(cl::Positional, cl::desc("input"),
+ cl::Required);
+cl::opt<std::string>
+ EmitTBE("emit-tbe",
+ cl::desc("Emit a text-based ELF stub (.tbe) from the input file"),
+ cl::value_desc("path"));
+cl::opt<std::string> SOName(
+ "soname",
+ cl::desc("Manually set the DT_SONAME entry of any emitted files"),
+ cl::value_desc("name"));
+
+/// writeTBE() writes a Text-Based ELF stub to a file using the latest version
+/// of the YAML parser.
+static Error writeTBE(StringRef FilePath, ELFStub &Stub) {
+ std::error_code SysErr;
+
+ // Open file for writing.
+ raw_fd_ostream Out(FilePath, SysErr);
+ if (SysErr)
+ return createStringError(SysErr, "Couldn't open `%s` for writing",
+ FilePath.data());
+ // Write file.
+ Error YAMLErr = writeTBEToOutputStream(Out, Stub);
+ if (YAMLErr)
+ return YAMLErr;
+
+ return Error::success();
+}
+
+/// readInputFile populates an ELFStub by attempting to read the
+/// input file using both the TBE and binary ELF parsers.
+static Expected<std::unique_ptr<ELFStub>> readInputFile(StringRef FilePath) {
+ // Read in file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
+ MemoryBuffer::getFile(FilePath);
+ if (!BufOrError) {
+ return createStringError(BufOrError.getError(), "Could not open `%s`",
+ FilePath.data());
+ }
+
+ std::unique_ptr<MemoryBuffer> FileReadBuffer = std::move(*BufOrError);
+ ErrorCollector EC(/*UseFatalErrors=*/false);
+
+ // First try to read as a binary (fails fast if not binary).
+ if (InputFileFormat.getNumOccurrences() == 0 ||
+ InputFileFormat == FileFormat::ELF) {
+ Expected<std::unique_ptr<ELFStub>> StubFromELF =
+ readELFFile(FileReadBuffer->getMemBufferRef());
+ if (StubFromELF) {
+ return std::move(*StubFromELF);
+ }
+ EC.addError(StubFromELF.takeError(), "BinaryRead");
+ }
+
+ // Fall back to reading as a tbe.
+ if (InputFileFormat.getNumOccurrences() == 0 ||
+ InputFileFormat == FileFormat::TBE) {
+ Expected<std::unique_ptr<ELFStub>> StubFromTBE =
+ readTBEFromBuffer(FileReadBuffer->getBuffer());
+ if (StubFromTBE) {
+ return std::move(*StubFromTBE);
+ }
+ EC.addError(StubFromTBE.takeError(), "YamlParse");
+ }
+
+ // If both readers fail, build a new error that includes all information.
+ EC.addError(createStringError(errc::not_supported,
+ "No file readers succeeded reading `%s` "
+ "(unsupported/malformed file?)",
+ FilePath.data()),
+ "ReadInputFile");
+ EC.escalateToFatal();
+ return EC.makeError();
+}
+
+int main(int argc, char *argv[]) {
+ // Parse arguments.
+ cl::ParseCommandLineOptions(argc, argv);
+
+ Expected<std::unique_ptr<ELFStub>> StubOrErr = readInputFile(InputFilePath);
+ if (!StubOrErr) {
+ Error ReadError = StubOrErr.takeError();
+ WithColor::error() << ReadError << "\n";
+ exit(1);
+ }
+
+ std::unique_ptr<ELFStub> TargetStub = std::move(StubOrErr.get());
+
+ // Write out .tbe file.
+ if (EmitTBE.getNumOccurrences() == 1) {
+ TargetStub->TbeVersion = TBEVersionCurrent;
+ if (SOName.getNumOccurrences() == 1) {
+ TargetStub->SoName = SOName;
+ }
+ Error TBEWriteError = writeTBE(EmitTBE, *TargetStub);
+ if (TBEWriteError) {
+ WithColor::error() << TBEWriteError << "\n";
+ exit(1);
+ }
+ }
+}