1 //===- llvm-elfabi.cpp ----------------------------------------------------===//
3 // 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
7 //===-----------------------------------------------------------------------===/
9 #include "ELFObjHandler.h"
10 #include "ErrorCollector.h"
11 #include "llvm/Support/CommandLine.h"
12 #include "llvm/Support/Errc.h"
13 #include "llvm/Support/FileOutputBuffer.h"
14 #include "llvm/Support/MemoryBuffer.h"
15 #include "llvm/Support/Path.h"
16 #include "llvm/Support/raw_ostream.h"
17 #include "llvm/Support/WithColor.h"
18 #include "llvm/TextAPI/ELF/TBEHandler.h"
24 enum class FileFormat
{
29 } // end namespace elfabi
30 } // end namespace llvm
33 using namespace llvm::elfabi
;
35 // Command line flags:
36 cl::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")));
42 cl::opt
<std::string
> InputFilePath(cl::Positional
, cl::desc("input"),
46 cl::desc("Emit a text-based ELF stub (.tbe) from the input file"),
47 cl::value_desc("path"));
48 cl::opt
<std::string
> SOName(
50 cl::desc("Manually set the DT_SONAME entry of any emitted files"),
51 cl::value_desc("name"));
53 /// writeTBE() writes a Text-Based ELF stub to a file using the latest version
54 /// of the YAML parser.
55 static Error
writeTBE(StringRef FilePath
, ELFStub
&Stub
) {
56 std::error_code SysErr
;
58 // Open file for writing.
59 raw_fd_ostream
Out(FilePath
, SysErr
);
61 return createStringError(SysErr
, "Couldn't open `%s` for writing",
64 Error YAMLErr
= writeTBEToOutputStream(Out
, Stub
);
68 return Error::success();
71 /// readInputFile populates an ELFStub by attempting to read the
72 /// input file using both the TBE and binary ELF parsers.
73 static Expected
<std::unique_ptr
<ELFStub
>> readInputFile(StringRef FilePath
) {
75 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> BufOrError
=
76 MemoryBuffer::getFile(FilePath
);
78 return createStringError(BufOrError
.getError(), "Could not open `%s`",
82 std::unique_ptr
<MemoryBuffer
> FileReadBuffer
= std::move(*BufOrError
);
83 ErrorCollector
EC(/*UseFatalErrors=*/false);
85 // First try to read as a binary (fails fast if not binary).
86 if (InputFileFormat
.getNumOccurrences() == 0 ||
87 InputFileFormat
== FileFormat::ELF
) {
88 Expected
<std::unique_ptr
<ELFStub
>> StubFromELF
=
89 readELFFile(FileReadBuffer
->getMemBufferRef());
91 return std::move(*StubFromELF
);
93 EC
.addError(StubFromELF
.takeError(), "BinaryRead");
96 // Fall back to reading as a tbe.
97 if (InputFileFormat
.getNumOccurrences() == 0 ||
98 InputFileFormat
== FileFormat::TBE
) {
99 Expected
<std::unique_ptr
<ELFStub
>> StubFromTBE
=
100 readTBEFromBuffer(FileReadBuffer
->getBuffer());
102 return std::move(*StubFromTBE
);
104 EC
.addError(StubFromTBE
.takeError(), "YamlParse");
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?)",
113 EC
.escalateToFatal();
114 return EC
.makeError();
117 int main(int argc
, char *argv
[]) {
119 cl::ParseCommandLineOptions(argc
, argv
);
121 Expected
<std::unique_ptr
<ELFStub
>> StubOrErr
= readInputFile(InputFilePath
);
123 Error ReadError
= StubOrErr
.takeError();
124 WithColor::error() << ReadError
<< "\n";
128 std::unique_ptr
<ELFStub
> TargetStub
= std::move(StubOrErr
.get());
130 // Write out .tbe file.
131 if (EmitTBE
.getNumOccurrences() == 1) {
132 TargetStub
->TbeVersion
= TBEVersionCurrent
;
133 if (SOName
.getNumOccurrences() == 1) {
134 TargetStub
->SoName
= SOName
;
136 Error TBEWriteError
= writeTBE(EmitTBE
, *TargetStub
);
138 WithColor::error() << TBEWriteError
<< "\n";