blob: e7c81604ee1816b5c8ad0ac06826b9ff082fd187 [file] [log] [blame]
Armando Montanez31f0f652019-01-03 18:32:36 +00001//===- llvm-elfabi.cpp ----------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===-----------------------------------------------------------------------===/
9
10#include "ELFObjHandler.h"
11#include "ErrorCollector.h"
12#include "llvm/Support/CommandLine.h"
13#include "llvm/Support/Errc.h"
14#include "llvm/Support/FileOutputBuffer.h"
15#include "llvm/Support/MemoryBuffer.h"
16#include "llvm/Support/Path.h"
17#include "llvm/Support/raw_ostream.h"
18#include "llvm/Support/WithColor.h"
19#include "llvm/TextAPI/ELF/TBEHandler.h"
20#include <string>
21
22using namespace llvm;
23using namespace llvm::elfabi;
24
25// Command line flags:
26cl::opt<std::string> InputFilePath(cl::Positional, cl::desc("input"),
27 cl::Required);
28cl::opt<std::string>
29 EmitTBE("emit-tbe",
30 cl::desc("Emit a text-based ELF stub (.tbe) from the input file"),
31 cl::value_desc("path"));
32cl::opt<std::string> SOName(
33 "soname",
34 cl::desc("Manually set the DT_SONAME entry of any emitted files"),
35 cl::value_desc("name"));
36
37/// writeTBE() writes a Text-Based ELF stub to a file using the latest version
38/// of the YAML parser.
39static Error writeTBE(StringRef FilePath, ELFStub &Stub) {
40 std::error_code SysErr;
41
42 // Open file for writing.
43 raw_fd_ostream Out(FilePath, SysErr);
44 if (SysErr)
45 return createStringError(SysErr, "Couldn't open `%s` for writing",
46 FilePath.data());
47 // Write file.
48 Error YAMLErr = writeTBEToOutputStream(Out, Stub);
49 if (YAMLErr)
50 return YAMLErr;
51
52 return Error::success();
53}
54
55/// readInputFile populates an ELFStub by attempting to read the
56/// input file using both the TBE and binary ELF parsers.
57static Expected<std::unique_ptr<ELFStub>> readInputFile(StringRef FilePath) {
58 // Read in file.
59 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
60 MemoryBuffer::getFile(FilePath);
61 if (!BufOrError) {
62 return createStringError(BufOrError.getError(), "Could not open `%s`",
63 FilePath.data());
64 }
65
66 std::unique_ptr<MemoryBuffer> FileReadBuffer = std::move(*BufOrError);
67 ErrorCollector EC(/*UseFatalErrors=*/false);
68
69 // First try to read as a binary (fails fast if not binary).
70 Expected<std::unique_ptr<ELFStub>> StubFromELF =
71 readELFFile(FileReadBuffer->getMemBufferRef());
72 if (StubFromELF) {
73 return std::move(*StubFromELF);
74 }
75 EC.addError(StubFromELF.takeError(), "BinaryRead");
76
77 // Fall back to reading as a tbe.
78 Expected<std::unique_ptr<ELFStub>> StubFromTBE =
79 readTBEFromBuffer(FileReadBuffer->getBuffer());
80 if (StubFromTBE) {
81 return std::move(*StubFromTBE);
82 }
83 EC.addError(StubFromTBE.takeError(), "YamlParse");
84
85 // If both readers fail, build a new error that includes all information.
86 EC.addError(createStringError(errc::not_supported,
87 "No file readers succeeded reading `%s` "
88 "(unsupported/malformed file?)",
89 FilePath.data()),
90 "ReadInputFile");
91 EC.escalateToFatal();
92 return EC.makeError();
93}
94
95int main(int argc, char *argv[]) {
96 // Parse arguments.
97 cl::ParseCommandLineOptions(argc, argv);
98
99 Expected<std::unique_ptr<ELFStub>> StubOrErr = readInputFile(InputFilePath);
100 if (!StubOrErr) {
101 Error ReadError = StubOrErr.takeError();
102 WithColor::error() << ReadError << "\n";
103 exit(1);
104 }
105
106 std::unique_ptr<ELFStub> TargetStub = std::move(StubOrErr.get());
107
108 // Write out .tbe file.
109 if (EmitTBE.getNumOccurrences() == 1) {
110 TargetStub->TbeVersion = TBEVersionCurrent;
111 if (SOName.getNumOccurrences() == 1) {
112 TargetStub->SoName = SOName;
113 }
114 Error TBEWriteError = writeTBE(EmitTBE, *TargetStub);
115 if (TBEWriteError) {
116 WithColor::error() << TBEWriteError << "\n";
117 exit(1);
118 }
119 }
120}