[yaml2obj/obj2yaml] - Add support for .stack_sizes sections.
[llvm-complete.git] / tools / llvm-elfabi / llvm-elfabi.cpp
blob044b5f77c6d71d3a1a7e3282b6d7b707d8a21e52
1 //===- llvm-elfabi.cpp ----------------------------------------------------===//
2 //
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
6 //
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"
19 #include <string>
21 namespace llvm {
22 namespace elfabi {
24 enum class FileFormat {
25 TBE,
26 ELF
29 } // end namespace elfabi
30 } // end namespace llvm
32 using 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"),
43 cl::Required);
44 cl::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"));
48 cl::opt<std::string> SOName(
49 "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);
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;
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) {
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());
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());
90 if (StubFromELF) {
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());
101 if (StubFromTBE) {
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?)",
111 FilePath.data()),
112 "ReadInputFile");
113 EC.escalateToFatal();
114 return EC.makeError();
117 int main(int argc, char *argv[]) {
118 // Parse arguments.
119 cl::ParseCommandLineOptions(argc, argv);
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);
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);
137 if (TBEWriteError) {
138 WithColor::error() << TBEWriteError << "\n";
139 exit(1);