blob: 8bf2ad4ed537364bdebbb10e4566e52b0f12c461 [file] [log] [blame]
Armando Montanez31f0f652019-01-03 18:32:36 +00001//===- llvm-elfabi.cpp ----------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Armando Montanez31f0f652019-01-03 18:32:36 +00006//
7//===-----------------------------------------------------------------------===/
8
Armando Montanez31f0f652019-01-03 18:32:36 +00009#include "ErrorCollector.h"
Haowei Wud650cbc2020-08-11 11:44:22 -070010#include "llvm/InterfaceStub/ELFObjHandler.h"
11#include "llvm/InterfaceStub/TBEHandler.h"
Armando Montanez31f0f652019-01-03 18:32:36 +000012#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"
Haowei Wudb913202020-08-10 21:30:01 -070017#include "llvm/Support/WithColor.h"
Haowei Wud650cbc2020-08-11 11:44:22 -070018#include "llvm/Support/raw_ostream.h"
Armando Montanez31f0f652019-01-03 18:32:36 +000019#include <string>
20
Armando Montanez488545e2019-01-07 17:33:10 +000021namespace llvm {
22namespace elfabi {
23
24enum class FileFormat {
25 TBE,
26 ELF
27};
28
29} // end namespace elfabi
30} // end namespace llvm
31
Armando Montanez31f0f652019-01-03 18:32:36 +000032using namespace llvm;
33using namespace llvm::elfabi;
34
35// Command line flags:
Armando Montanez488545e2019-01-07 17:33:10 +000036cl::opt<FileFormat> InputFileFormat(
37 cl::desc("Force input file format:"),
38 cl::values(clEnumValN(FileFormat::TBE,
39 "tbe", "Read `input` as text-based ELF stub"),
40 clEnumValN(FileFormat::ELF,
41 "elf", "Read `input` as ELF binary")));
Armando Montanez31f0f652019-01-03 18:32:36 +000042cl::opt<std::string> InputFilePath(cl::Positional, cl::desc("input"),
43 cl::Required);
44cl::opt<std::string>
45 EmitTBE("emit-tbe",
46 cl::desc("Emit a text-based ELF stub (.tbe) from the input file"),
47 cl::value_desc("path"));
48cl::opt<std::string> SOName(
49 "soname",
50 cl::desc("Manually set the DT_SONAME entry of any emitted files"),
51 cl::value_desc("name"));
52
53/// writeTBE() writes a Text-Based ELF stub to a file using the latest version
54/// of the YAML parser.
55static Error writeTBE(StringRef FilePath, ELFStub &Stub) {
56 std::error_code SysErr;
57
58 // Open file for writing.
59 raw_fd_ostream Out(FilePath, SysErr);
60 if (SysErr)
61 return createStringError(SysErr, "Couldn't open `%s` for writing",
62 FilePath.data());
63 // Write file.
64 Error YAMLErr = writeTBEToOutputStream(Out, Stub);
65 if (YAMLErr)
66 return YAMLErr;
67
68 return Error::success();
69}
70
71/// readInputFile populates an ELFStub by attempting to read the
72/// input file using both the TBE and binary ELF parsers.
73static Expected<std::unique_ptr<ELFStub>> readInputFile(StringRef FilePath) {
74 // Read in file.
75 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
76 MemoryBuffer::getFile(FilePath);
77 if (!BufOrError) {
78 return createStringError(BufOrError.getError(), "Could not open `%s`",
79 FilePath.data());
80 }
81
82 std::unique_ptr<MemoryBuffer> FileReadBuffer = std::move(*BufOrError);
83 ErrorCollector EC(/*UseFatalErrors=*/false);
84
85 // First try to read as a binary (fails fast if not binary).
Armando Montanez488545e2019-01-07 17:33:10 +000086 if (InputFileFormat.getNumOccurrences() == 0 ||
87 InputFileFormat == FileFormat::ELF) {
88 Expected<std::unique_ptr<ELFStub>> StubFromELF =
89 readELFFile(FileReadBuffer->getMemBufferRef());
90 if (StubFromELF) {
91 return std::move(*StubFromELF);
92 }
93 EC.addError(StubFromELF.takeError(), "BinaryRead");
Armando Montanez31f0f652019-01-03 18:32:36 +000094 }
Armando Montanez31f0f652019-01-03 18:32:36 +000095
96 // Fall back to reading as a tbe.
Armando Montanez488545e2019-01-07 17:33:10 +000097 if (InputFileFormat.getNumOccurrences() == 0 ||
98 InputFileFormat == FileFormat::TBE) {
99 Expected<std::unique_ptr<ELFStub>> StubFromTBE =
100 readTBEFromBuffer(FileReadBuffer->getBuffer());
101 if (StubFromTBE) {
102 return std::move(*StubFromTBE);
103 }
104 EC.addError(StubFromTBE.takeError(), "YamlParse");
Armando Montanez31f0f652019-01-03 18:32:36 +0000105 }
Armando Montanez31f0f652019-01-03 18:32:36 +0000106
107 // If both readers fail, build a new error that includes all information.
108 EC.addError(createStringError(errc::not_supported,
109 "No file readers succeeded reading `%s` "
110 "(unsupported/malformed file?)",
111 FilePath.data()),
112 "ReadInputFile");
113 EC.escalateToFatal();
114 return EC.makeError();
115}
116
117int main(int argc, char *argv[]) {
118 // Parse arguments.
119 cl::ParseCommandLineOptions(argc, argv);
120
121 Expected<std::unique_ptr<ELFStub>> StubOrErr = readInputFile(InputFilePath);
122 if (!StubOrErr) {
123 Error ReadError = StubOrErr.takeError();
124 WithColor::error() << ReadError << "\n";
125 exit(1);
126 }
127
128 std::unique_ptr<ELFStub> TargetStub = std::move(StubOrErr.get());
129
130 // Write out .tbe file.
131 if (EmitTBE.getNumOccurrences() == 1) {
132 TargetStub->TbeVersion = TBEVersionCurrent;
133 if (SOName.getNumOccurrences() == 1) {
134 TargetStub->SoName = SOName;
135 }
136 Error TBEWriteError = writeTBE(EmitTBE, *TargetStub);
137 if (TBEWriteError) {
138 WithColor::error() << TBEWriteError << "\n";
139 exit(1);
140 }
141 }
142}