[llvm] r350341 - [elfabi] Introduce tool for ELF TextAPI

Armando Montanez via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 3 10:32:36 PST 2019


Author: amontanez
Date: Thu Jan  3 10:32:36 2019
New Revision: 350341

URL: http://llvm.org/viewvc/llvm-project?rev=350341&view=rev
Log:
[elfabi] Introduce tool for ELF TextAPI

Follow up for D53051

This patch introduces the tool associated with the ELF implementation of
TextAPI (previously llvm-tapi, renamed for better distinction). This
tool will house a number of features related to enalysis and
manipulation of shared object's exposed interfaces. The first major
feature for this tool is support for producing binary stubs that are
useful for compile-time linking of shared objects. This patch introduces
beginnings of support for reading binary ELF objects to work towards
that goal.

Added:

 - elfabi tool.
 - support for reading architecture from a binary ELF file into an
 ELFStub.
 - Support for writing .tbe files.

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

Added:
    llvm/trunk/test/tools/llvm-elfabi/
    llvm/trunk/test/tools/llvm-elfabi/binary-read-arch.test
    llvm/trunk/test/tools/llvm-elfabi/fail-file-open.test
    llvm/trunk/test/tools/llvm-elfabi/read-unsupported-file.test
    llvm/trunk/test/tools/llvm-elfabi/replace-soname-tbe.test
    llvm/trunk/test/tools/llvm-elfabi/tbe-emits-current-version.test
    llvm/trunk/test/tools/llvm-elfabi/tbe-read-basic.test
    llvm/trunk/tools/llvm-elfabi/
    llvm/trunk/tools/llvm-elfabi/CMakeLists.txt
    llvm/trunk/tools/llvm-elfabi/ELFObjHandler.cpp
    llvm/trunk/tools/llvm-elfabi/ELFObjHandler.h
    llvm/trunk/tools/llvm-elfabi/ErrorCollector.cpp
    llvm/trunk/tools/llvm-elfabi/ErrorCollector.h
    llvm/trunk/tools/llvm-elfabi/LLVMBuild.txt
    llvm/trunk/tools/llvm-elfabi/llvm-elfabi.cpp
Modified:
    llvm/trunk/test/CMakeLists.txt
    llvm/trunk/tools/LLVMBuild.txt

Modified: llvm/trunk/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CMakeLists.txt?rev=350341&r1=350340&r2=350341&view=diff
==============================================================================
--- llvm/trunk/test/CMakeLists.txt (original)
+++ llvm/trunk/test/CMakeLists.txt Thu Jan  3 10:32:36 2019
@@ -61,6 +61,7 @@ set(LLVM_TEST_DEPENDS
           dsymutil
           llvm-dwarfdump
           llvm-dwp
+          llvm-elfabi
           llvm-exegesis
           llvm-extract
           llvm-isel-fuzzer

Added: llvm/trunk/test/tools/llvm-elfabi/binary-read-arch.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-elfabi/binary-read-arch.test?rev=350341&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-elfabi/binary-read-arch.test (added)
+++ llvm/trunk/test/tools/llvm-elfabi/binary-read-arch.test Thu Jan  3 10:32:36 2019
@@ -0,0 +1,15 @@
+# RUN: yaml2obj %s > %t
+# RUN: llvm-elfabi %t --emit-tbe=- | FileCheck %s
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_X86_64
+
+# CHECK:      --- !tapi-tbe
+# CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}}
+# CHECK-NEXT: Arch: x86_64
+# CHECK-NEXT: Symbols: {}
+# CHECK-NEXT: ...

Added: llvm/trunk/test/tools/llvm-elfabi/fail-file-open.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-elfabi/fail-file-open.test?rev=350341&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-elfabi/fail-file-open.test (added)
+++ llvm/trunk/test/tools/llvm-elfabi/fail-file-open.test Thu Jan  3 10:32:36 2019
@@ -0,0 +1,5 @@
+# RUN: not llvm-elfabi %s.NotAFileInTestingDir --emit-tbe=%t 2>&1 | FileCheck %s
+
+This file will not be read. An invalid file path is fed to llvm-elfabi.
+
+# CHECK: error: Could not open `{{.*}}.NotAFileInTestingDir`

Added: llvm/trunk/test/tools/llvm-elfabi/read-unsupported-file.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-elfabi/read-unsupported-file.test?rev=350341&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-elfabi/read-unsupported-file.test (added)
+++ llvm/trunk/test/tools/llvm-elfabi/read-unsupported-file.test Thu Jan  3 10:32:36 2019
@@ -0,0 +1,7 @@
+# RUN: not llvm-elfabi %s --emit-tbe=%t 2>&1 | FileCheck %s
+
+This is just some text that cannot be read by llvm-elfabi.
+
+# CHECK: The file was not recognized as a valid object file
+# CHECK: YAML failed reading as TBE
+# CHECK: No file readers succeeded reading `{{.*}}` (unsupported/malformed file?)

Added: llvm/trunk/test/tools/llvm-elfabi/replace-soname-tbe.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-elfabi/replace-soname-tbe.test?rev=350341&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-elfabi/replace-soname-tbe.test (added)
+++ llvm/trunk/test/tools/llvm-elfabi/replace-soname-tbe.test Thu Jan  3 10:32:36 2019
@@ -0,0 +1,16 @@
+# RUN: yaml2obj %s > %t
+# RUN: llvm-elfabi %t --emit-tbe=- --soname=best.so | FileCheck %s
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_AARCH64
+
+# CHECK:      --- !tapi-tbe
+# CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}}
+# CHECK-NEXT: SoName: best.so
+# CHECK-NEXT: Arch: AArch64
+# CHECK-NEXT: Symbols: {}
+# CHECK-NEXT: ...

Added: llvm/trunk/test/tools/llvm-elfabi/tbe-emits-current-version.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-elfabi/tbe-emits-current-version.test?rev=350341&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-elfabi/tbe-emits-current-version.test (added)
+++ llvm/trunk/test/tools/llvm-elfabi/tbe-emits-current-version.test Thu Jan  3 10:32:36 2019
@@ -0,0 +1,13 @@
+# RUN: llvm-elfabi %s --emit-tbe=- | FileCheck %s
+
+--- !tapi-tbe
+TbeVersion: 1.0
+Arch: AArch64
+Symbols: {}
+...
+
+# As the tbe reader/writer is updated, update this check to ensure --emit-tbe
+# uses the latest tbe writer by default.
+
+# CHECK:      --- !tapi-tbe
+# CHECK-NEXT: TbeVersion: 1.0

Added: llvm/trunk/test/tools/llvm-elfabi/tbe-read-basic.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-elfabi/tbe-read-basic.test?rev=350341&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-elfabi/tbe-read-basic.test (added)
+++ llvm/trunk/test/tools/llvm-elfabi/tbe-read-basic.test Thu Jan  3 10:32:36 2019
@@ -0,0 +1,25 @@
+# RUN: llvm-elfabi %s --emit-tbe=- | FileCheck %s
+
+--- !tapi-tbe
+SoName: somelib.so
+TbeVersion: 1.0
+Arch: x86_64
+Symbols:
+  foo: { Type: Func }
+  bar: { Type: Object, Size: 42 }
+  baz: { Type: Object, Size: 8 }
+  not: { Type: Object, Undefined: true, Size: 128 }
+  nor: { Type: Func, Undefined: true }
+...
+
+# CHECK:      --- !tapi-tbe
+# CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}}
+# CHECK-NEXT: SoName: somelib.so
+# CHECK-NEXT: Arch: x86_64
+# CHECK-NEXT: Symbols:
+# CHECK-NEXT:   bar: { Type: Object, Size: 42 }
+# CHECK-NEXT:   baz: { Type: Object, Size: 8 }
+# CHECK-NEXT:   foo: { Type: Func }
+# CHECK-NEXT:   nor: { Type: Func, Undefined: true }
+# CHECK-NEXT:   not: { Type: Object, Size: 128, Undefined: true }
+# CHECK-NEXT: ...

Modified: llvm/trunk/tools/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/LLVMBuild.txt?rev=350341&r1=350340&r2=350341&view=diff
==============================================================================
--- llvm/trunk/tools/LLVMBuild.txt (original)
+++ llvm/trunk/tools/LLVMBuild.txt Thu Jan  3 10:32:36 2019
@@ -32,6 +32,7 @@ subdirectories =
  llvm-dis
  llvm-dwarfdump
  llvm-dwp
+ llvm-elfabi
  llvm-exegesis
  llvm-extract
  llvm-jitlistener

Added: llvm/trunk/tools/llvm-elfabi/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-elfabi/CMakeLists.txt?rev=350341&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-elfabi/CMakeLists.txt (added)
+++ llvm/trunk/tools/llvm-elfabi/CMakeLists.txt Thu Jan  3 10:32:36 2019
@@ -0,0 +1,11 @@
+set(LLVM_LINK_COMPONENTS
+  Object
+  Support
+  TextAPI
+  )
+
+add_llvm_tool(llvm-elfabi
+  ELFObjHandler.cpp
+  ErrorCollector.cpp
+  llvm-elfabi.cpp
+  )

Added: llvm/trunk/tools/llvm-elfabi/ELFObjHandler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-elfabi/ELFObjHandler.cpp?rev=350341&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-elfabi/ELFObjHandler.cpp (added)
+++ llvm/trunk/tools/llvm-elfabi/ELFObjHandler.cpp Thu Jan  3 10:32:36 2019
@@ -0,0 +1,68 @@
+//===- ELFObjHandler.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 "llvm/Object/Binary.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/TextAPI/ELF/ELFStub.h"
+
+using llvm::MemoryBufferRef;
+using llvm::object::ELFObjectFile;
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::elfabi;
+using namespace llvm::ELF;
+
+namespace llvm {
+namespace elfabi {
+
+/// Returns a new ELFStub with all members populated from an ELFObjectFile.
+/// @param ElfObj Source ELFObjectFile.
+template <class ELFT>
+Expected<std::unique_ptr<ELFStub>>
+buildStub(const ELFObjectFile<ELFT> &ElfObj) {
+  std::unique_ptr<ELFStub> DestStub = make_unique<ELFStub>();
+  const ELFFile<ELFT> *ElfFile = ElfObj.getELFFile();
+
+  DestStub->Arch = ElfFile->getHeader()->e_machine;
+
+  // TODO: Populate SoName from .dynamic entries and linked string table.
+  // TODO: Populate NeededLibs from .dynamic entries and linked string table.
+  // TODO: Populate Symbols from .dynsym table and linked string table.
+
+  return std::move(DestStub);
+}
+
+Expected<std::unique_ptr<ELFStub>> readELFFile(MemoryBufferRef Buf) {
+  Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buf);
+  if (!BinOrErr) {
+    return BinOrErr.takeError();
+  }
+
+  Binary *Bin = BinOrErr->get();
+  if (auto Obj = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {
+    return buildStub(*Obj);
+  } else if (auto Obj = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {
+    return buildStub(*Obj);
+  } else if (auto Obj = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {
+    return buildStub(*Obj);
+  } else if (auto Obj = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {
+    return buildStub(*Obj);
+  }
+
+  return createStringError(errc::not_supported, "Unsupported binary format");
+}
+
+} // end namespace elfabi
+} // end namespace llvm

Added: llvm/trunk/tools/llvm-elfabi/ELFObjHandler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-elfabi/ELFObjHandler.h?rev=350341&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-elfabi/ELFObjHandler.h (added)
+++ llvm/trunk/tools/llvm-elfabi/ELFObjHandler.h Thu Jan  3 10:32:36 2019
@@ -0,0 +1,33 @@
+//===- ELFObjHandler.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-----------------------------------------------------------------------===/
+///
+/// This supports reading and writing of elf dynamic shared objects.
+///
+//===-----------------------------------------------------------------------===/
+
+#ifndef LLVM_TOOLS_ELFABI_ELFOBJHANDLER_H
+#define LLVM_TOOLS_ELFABI_ELFOBJHANDLER_H
+
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/TextAPI/ELF/ELFStub.h"
+
+namespace llvm {
+
+class MemoryBuffer;
+
+namespace elfabi {
+
+/// Attempt to read a binary ELF file from a MemoryBuffer.
+Expected<std::unique_ptr<ELFStub>> readELFFile(MemoryBufferRef Buf);
+
+} // end namespace elfabi
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_ELFABI_ELFOBJHANDLER_H

Added: llvm/trunk/tools/llvm-elfabi/ErrorCollector.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-elfabi/ErrorCollector.cpp?rev=350341&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-elfabi/ErrorCollector.cpp (added)
+++ llvm/trunk/tools/llvm-elfabi/ErrorCollector.cpp Thu Jan  3 10:32:36 2019
@@ -0,0 +1,70 @@
+//===- ErrorCollector.cpp -------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-----------------------------------------------------------------------===/
+
+#include "ErrorCollector.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/WithColor.h"
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::elfabi;
+
+void ErrorCollector::escalateToFatal() {
+  ErrorsAreFatal = true;
+}
+
+void ErrorCollector::addError(Error &&Err, StringRef Tag) {
+  if (Err) {
+    Errors.push_back(std::move(Err));
+    Tags.push_back(Tag.str());
+  }
+}
+
+Error ErrorCollector::makeError() {
+  // TODO: Make this return something (an AggregateError?) that gives more
+  // individual control over each error and which might be of interest.
+  Error JoinedErrors = Error::success();
+  for (Error &E : Errors) {
+    JoinedErrors = joinErrors(std::move(JoinedErrors), std::move(E));
+  }
+  Errors.clear();
+  Tags.clear();
+  return JoinedErrors;
+}
+
+void ErrorCollector::log(raw_ostream &OS) {
+  OS << "Encountered multiple errors:\n";
+  for (size_t i = 0; i < Errors.size(); ++i) {
+    WithColor::error(OS) << "(" << Tags[i] << ") " << Errors[i];
+    if (i != Errors.size() - 1)
+      OS << "\n";
+  }
+}
+
+bool ErrorCollector::allErrorsHandled() const {
+  return Errors.empty();
+}
+
+ErrorCollector::~ErrorCollector() {
+  if (ErrorsAreFatal && !allErrorsHandled())
+    fatalUnhandledError();
+
+  for (Error &E : Errors) {
+    consumeError(std::move(E));
+  }
+}
+
+LLVM_ATTRIBUTE_NORETURN void ErrorCollector::fatalUnhandledError() {
+  errs() << "Program aborted due to unhandled Error(s):\n";
+  log(errs());
+  errs() << "\n";
+  abort();
+}

Added: llvm/trunk/tools/llvm-elfabi/ErrorCollector.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-elfabi/ErrorCollector.h?rev=350341&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-elfabi/ErrorCollector.h (added)
+++ llvm/trunk/tools/llvm-elfabi/ErrorCollector.h Thu Jan  3 10:32:36 2019
@@ -0,0 +1,75 @@
+//===- ErrorCollector.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-----------------------------------------------------------------------===/
+///
+/// This class collects errors that should be reported or ignored in aggregate.
+///
+/// Like llvm::Error, an ErrorCollector cannot be copied. Unlike llvm::Error,
+/// an ErrorCollector may be destroyed if it was originally constructed to treat
+/// errors as non-fatal. In this case, all Errors are consumed upon destruction.
+/// An ErrorCollector may be initially constructed (or escalated) such that
+/// errors are treated as fatal. This causes a crash if an attempt is made to
+/// delete the ErrorCollector when some Errors have not been retrieved via
+/// makeError().
+///
+//===-----------------------------------------------------------------------===/
+
+#ifndef LLVM_TOOLS_ELFABI_ERRORCOLLECTOR_H
+#define LLVM_TOOLS_ELFABI_ERRORCOLLECTOR_H
+
+#include "llvm/Support/Error.h"
+#include <vector>
+
+namespace llvm {
+namespace elfabi {
+
+class ErrorCollector {
+public:
+  /// Upon destruction, an ErrorCollector will crash if UseFatalErrors=true and
+  /// there are remaining errors that haven't been fetched by makeError().
+  ErrorCollector(bool UseFatalErrors = true) : ErrorsAreFatal(UseFatalErrors) {}
+  // Don't allow copying.
+  ErrorCollector(const ErrorCollector &Stub) = delete;
+  ErrorCollector &operator=(const ErrorCollector &Other) = delete;
+  ~ErrorCollector();
+
+  // TODO: Add move constructor and operator= when a testable situation arises.
+
+  /// Returns a single error that contains messages for all stored Errors.
+  Error makeError();
+
+  /// Adds an error with a descriptive tag that helps with identification.
+  /// If the error is an Error::success(), it is checked and discarded.
+  void addError(Error &&E, StringRef Tag);
+
+  /// This ensures an ErrorCollector will treat unhandled errors as fatal.
+  /// This function should be called if errors that usually can be ignored
+  /// are suddenly of concern (i.e. attempt multiple things that return Error,
+  /// but only care about the Errors if no attempt succeeds).
+  void escalateToFatal();
+
+private:
+  /// Logs all errors to a raw_ostream.
+  void log(raw_ostream &OS);
+
+  /// Returns true if all errors have been retrieved through makeError(), or
+  /// false if errors have been added since the last makeError() call.
+  bool allErrorsHandled() const;
+
+  /// Dump output and crash.
+  LLVM_ATTRIBUTE_NORETURN void fatalUnhandledError();
+
+  bool ErrorsAreFatal;
+  std::vector<Error> Errors;
+  std::vector<std::string> Tags;
+};
+
+} // end namespace elfabi
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_ELFABI_ERRORCOLLECTOR_H

Added: llvm/trunk/tools/llvm-elfabi/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-elfabi/LLVMBuild.txt?rev=350341&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-elfabi/LLVMBuild.txt (added)
+++ llvm/trunk/tools/llvm-elfabi/LLVMBuild.txt Thu Jan  3 10:32:36 2019
@@ -0,0 +1,22 @@
+;===- ./tools/llvm-elfabi/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 = Tool
+name = llvm-elfabi
+parent = Tools
+required_libraries = Object Support TextAPI

Added: llvm/trunk/tools/llvm-elfabi/llvm-elfabi.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-elfabi/llvm-elfabi.cpp?rev=350341&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-elfabi/llvm-elfabi.cpp (added)
+++ llvm/trunk/tools/llvm-elfabi/llvm-elfabi.cpp Thu Jan  3 10:32:36 2019
@@ -0,0 +1,120 @@
+//===- 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>
+
+using namespace llvm;
+using namespace llvm::elfabi;
+
+// Command line flags:
+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).
+  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.
+  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);
+    }
+  }
+}




More information about the llvm-commits mailing list