blob: 4c15bc2eaf3466957265617222b441b52e6d7fb1 [file] [log] [blame]
Armando Montanez18952b82019-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
Armando Montanez6101a1a2019-01-07 17:33:10 +000022namespace llvm {
23namespace elfabi {
24
25enum class FileFormat {
26 TBE,
27 ELF
28};
29
30} // end namespace elfabi
31} // end namespace llvm
32
Armando Montanez18952b82019-01-03 18:32:36 +000033using namespace llvm;
34using namespace llvm::elfabi;
35
36// Command line flags:
Armando Montanez6101a1a2019-01-07 17:33:10 +000037cl::opt<FileFormat> InputFileFormat(
38 cl::desc("Force input file format:"),
39 cl::values(clEnumValN(FileFormat::TBE,
40 "tbe", "Read `input` as text-based ELF stub"),
41 clEnumValN(FileFormat::ELF,
42 "elf", "Read `input` as ELF binary")));
Armando Montanez18952b82019-01-03 18:32:36 +000043cl::opt<std::string> InputFilePath(cl::Positional, cl::desc("input"),
44 cl::Required);
45cl::opt<std::string>
46 EmitTBE("emit-tbe",
47 cl::desc("Emit a text-based ELF stub (.tbe) from the input file"),
48 cl::value_desc("path"));
49cl::opt<std::string> SOName(
50 "soname",
51 cl::desc("Manually set the DT_SONAME entry of any emitted files"),
52 cl::value_desc("name"));
53
54/// writeTBE() writes a Text-Based ELF stub to a file using the latest version
55/// of the YAML parser.
56static Error writeTBE(StringRef FilePath, ELFStub &Stub) {
57 std::error_code SysErr;
58
59 // Open file for writing.
60 raw_fd_ostream Out(FilePath, SysErr);
61 if (SysErr)
62 return createStringError(SysErr, "Couldn't open `%s` for writing",
63 FilePath.data());
64 // Write file.
65 Error YAMLErr = writeTBEToOutputStream(Out, Stub);
66 if (YAMLErr)
67 return YAMLErr;
68
69 return Error::success();
70}
71
72/// readInputFile populates an ELFStub by attempting to read the
73/// input file using both the TBE and binary ELF parsers.
74static Expected<std::unique_ptr<ELFStub>> readInputFile(StringRef FilePath) {
75 // Read in file.
76 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
77 MemoryBuffer::getFile(FilePath);
78 if (!BufOrError) {
79 return createStringError(BufOrError.getError(), "Could not open `%s`",
80 FilePath.data());
81 }
82
83 std::unique_ptr<MemoryBuffer> FileReadBuffer = std::move(*BufOrError);
84 ErrorCollector EC(/*UseFatalErrors=*/false);
85
86 // First try to read as a binary (fails fast if not binary).
Armando Montanez6101a1a2019-01-07 17:33:10 +000087 if (InputFileFormat.getNumOccurrences() == 0 ||
88 InputFileFormat == FileFormat::ELF) {
89 Expected<std::unique_ptr<ELFStub>> StubFromELF =
90 readELFFile(FileReadBuffer->getMemBufferRef());
91 if (StubFromELF) {
92 return std::move(*StubFromELF);
93 }
94 EC.addError(StubFromELF.takeError(), "BinaryRead");
Armando Montanez18952b82019-01-03 18:32:36 +000095 }
Armando Montanez18952b82019-01-03 18:32:36 +000096
97 // Fall back to reading as a tbe.
Armando Montanez6101a1a2019-01-07 17:33:10 +000098 if (InputFileFormat.getNumOccurrences() == 0 ||
99 InputFileFormat == FileFormat::TBE) {
100 Expected<std::unique_ptr<ELFStub>> StubFromTBE =
101 readTBEFromBuffer(FileReadBuffer->getBuffer());
102 if (StubFromTBE) {
103 return std::move(*StubFromTBE);
104 }
105 EC.addError(StubFromTBE.takeError(), "YamlParse");
Armando Montanez18952b82019-01-03 18:32:36 +0000106 }
Armando Montanez18952b82019-01-03 18:32:36 +0000107
108 // If both readers fail, build a new error that includes all information.
109 EC.addError(createStringError(errc::not_supported,
110 "No file readers succeeded reading `%s` "
111 "(unsupported/malformed file?)",
112 FilePath.data()),
113 "ReadInputFile");
114 EC.escalateToFatal();
115 return EC.makeError();
116}
117
118int main(int argc, char *argv[]) {
119 // Parse arguments.
120 cl::ParseCommandLineOptions(argc, argv);
121
122 Expected<std::unique_ptr<ELFStub>> StubOrErr = readInputFile(InputFilePath);
123 if (!StubOrErr) {
124 Error ReadError = StubOrErr.takeError();
125 WithColor::error() << ReadError << "\n";
126 exit(1);
127 }
128
129 std::unique_ptr<ELFStub> TargetStub = std::move(StubOrErr.get());
130
131 // Write out .tbe file.
132 if (EmitTBE.getNumOccurrences() == 1) {
133 TargetStub->TbeVersion = TBEVersionCurrent;
134 if (SOName.getNumOccurrences() == 1) {
135 TargetStub->SoName = SOName;
136 }
137 Error TBEWriteError = writeTBE(EmitTBE, *TargetStub);
138 if (TBEWriteError) {
139 WithColor::error() << TBEWriteError << "\n";
140 exit(1);
141 }
142 }
143}