Armando Montanez | 31f0f65 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 1 | //===- llvm-elfabi.cpp ----------------------------------------------------===// |
| 2 | // |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 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 |
Armando Montanez | 31f0f65 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 6 | // |
| 7 | //===-----------------------------------------------------------------------===/ |
| 8 | |
Armando Montanez | 31f0f65 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 9 | #include "ErrorCollector.h" |
Haowei Wu | d650cbc | 2020-08-11 11:44:22 -0700 | [diff] [blame] | 10 | #include "llvm/InterfaceStub/ELFObjHandler.h" |
| 11 | #include "llvm/InterfaceStub/TBEHandler.h" |
Armando Montanez | 31f0f65 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 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" |
Haowei Wu | db91320 | 2020-08-10 21:30:01 -0700 | [diff] [blame] | 17 | #include "llvm/Support/WithColor.h" |
Haowei Wu | d650cbc | 2020-08-11 11:44:22 -0700 | [diff] [blame] | 18 | #include "llvm/Support/raw_ostream.h" |
Armando Montanez | 31f0f65 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 19 | #include <string> |
| 20 | |
Armando Montanez | 488545e | 2019-01-07 17:33:10 +0000 | [diff] [blame] | 21 | namespace llvm { |
| 22 | namespace elfabi { |
| 23 | |
| 24 | enum class FileFormat { |
| 25 | TBE, |
| 26 | ELF |
| 27 | }; |
| 28 | |
| 29 | } // end namespace elfabi |
| 30 | } // end namespace llvm |
| 31 | |
Armando Montanez | 31f0f65 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 32 | using namespace llvm; |
| 33 | using namespace llvm::elfabi; |
| 34 | |
| 35 | // Command line flags: |
Armando Montanez | 488545e | 2019-01-07 17:33:10 +0000 | [diff] [blame] | 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"))); |
Armando Montanez | 31f0f65 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 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")); |
| 52 | |
| 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; |
| 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. |
| 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()); |
| 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 Montanez | 488545e | 2019-01-07 17:33:10 +0000 | [diff] [blame] | 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); |
| 92 | } |
| 93 | EC.addError(StubFromELF.takeError(), "BinaryRead"); |
Armando Montanez | 31f0f65 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 94 | } |
Armando Montanez | 31f0f65 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 95 | |
| 96 | // Fall back to reading as a tbe. |
Armando Montanez | 488545e | 2019-01-07 17:33:10 +0000 | [diff] [blame] | 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); |
| 103 | } |
| 104 | EC.addError(StubFromTBE.takeError(), "YamlParse"); |
Armando Montanez | 31f0f65 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 105 | } |
Armando Montanez | 31f0f65 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 106 | |
| 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 | |
| 117 | int 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 | } |