Armando Montanez | 18952b8 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 1 | //===- 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 Montanez | 6101a1a | 2019-01-07 17:33:10 +0000 | [diff] [blame] | 22 | namespace llvm { |
| 23 | namespace elfabi { |
| 24 | |
| 25 | enum class FileFormat { |
| 26 | TBE, |
| 27 | ELF |
| 28 | }; |
| 29 | |
| 30 | } // end namespace elfabi |
| 31 | } // end namespace llvm |
| 32 | |
Armando Montanez | 18952b8 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 33 | using namespace llvm; |
| 34 | using namespace llvm::elfabi; |
| 35 | |
| 36 | // Command line flags: |
Armando Montanez | 6101a1a | 2019-01-07 17:33:10 +0000 | [diff] [blame] | 37 | cl::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 Montanez | 18952b8 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 43 | cl::opt<std::string> InputFilePath(cl::Positional, cl::desc("input"), |
| 44 | cl::Required); |
| 45 | cl::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")); |
| 49 | cl::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. |
| 56 | static 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. |
| 74 | static 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 Montanez | 6101a1a | 2019-01-07 17:33:10 +0000 | [diff] [blame] | 87 | 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 Montanez | 18952b8 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 95 | } |
Armando Montanez | 18952b8 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 96 | |
| 97 | // Fall back to reading as a tbe. |
Armando Montanez | 6101a1a | 2019-01-07 17:33:10 +0000 | [diff] [blame] | 98 | 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 Montanez | 18952b8 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 106 | } |
Armando Montanez | 18952b8 | 2019-01-03 18:32:36 +0000 | [diff] [blame] | 107 | |
| 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 | |
| 118 | int 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 | } |