Armando Montanez | 31f0f65 | 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 | |
| 22 | using namespace llvm; |
| 23 | using namespace llvm::elfabi; |
| 24 | |
| 25 | // Command line flags: |
| 26 | cl::opt<std::string> InputFilePath(cl::Positional, cl::desc("input"), |
| 27 | cl::Required); |
| 28 | cl::opt<std::string> |
| 29 | EmitTBE("emit-tbe", |
| 30 | cl::desc("Emit a text-based ELF stub (.tbe) from the input file"), |
| 31 | cl::value_desc("path")); |
| 32 | cl::opt<std::string> SOName( |
| 33 | "soname", |
| 34 | cl::desc("Manually set the DT_SONAME entry of any emitted files"), |
| 35 | cl::value_desc("name")); |
| 36 | |
| 37 | /// writeTBE() writes a Text-Based ELF stub to a file using the latest version |
| 38 | /// of the YAML parser. |
| 39 | static Error writeTBE(StringRef FilePath, ELFStub &Stub) { |
| 40 | std::error_code SysErr; |
| 41 | |
| 42 | // Open file for writing. |
| 43 | raw_fd_ostream Out(FilePath, SysErr); |
| 44 | if (SysErr) |
| 45 | return createStringError(SysErr, "Couldn't open `%s` for writing", |
| 46 | FilePath.data()); |
| 47 | // Write file. |
| 48 | Error YAMLErr = writeTBEToOutputStream(Out, Stub); |
| 49 | if (YAMLErr) |
| 50 | return YAMLErr; |
| 51 | |
| 52 | return Error::success(); |
| 53 | } |
| 54 | |
| 55 | /// readInputFile populates an ELFStub by attempting to read the |
| 56 | /// input file using both the TBE and binary ELF parsers. |
| 57 | static Expected<std::unique_ptr<ELFStub>> readInputFile(StringRef FilePath) { |
| 58 | // Read in file. |
| 59 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError = |
| 60 | MemoryBuffer::getFile(FilePath); |
| 61 | if (!BufOrError) { |
| 62 | return createStringError(BufOrError.getError(), "Could not open `%s`", |
| 63 | FilePath.data()); |
| 64 | } |
| 65 | |
| 66 | std::unique_ptr<MemoryBuffer> FileReadBuffer = std::move(*BufOrError); |
| 67 | ErrorCollector EC(/*UseFatalErrors=*/false); |
| 68 | |
| 69 | // First try to read as a binary (fails fast if not binary). |
| 70 | Expected<std::unique_ptr<ELFStub>> StubFromELF = |
| 71 | readELFFile(FileReadBuffer->getMemBufferRef()); |
| 72 | if (StubFromELF) { |
| 73 | return std::move(*StubFromELF); |
| 74 | } |
| 75 | EC.addError(StubFromELF.takeError(), "BinaryRead"); |
| 76 | |
| 77 | // Fall back to reading as a tbe. |
| 78 | Expected<std::unique_ptr<ELFStub>> StubFromTBE = |
| 79 | readTBEFromBuffer(FileReadBuffer->getBuffer()); |
| 80 | if (StubFromTBE) { |
| 81 | return std::move(*StubFromTBE); |
| 82 | } |
| 83 | EC.addError(StubFromTBE.takeError(), "YamlParse"); |
| 84 | |
| 85 | // If both readers fail, build a new error that includes all information. |
| 86 | EC.addError(createStringError(errc::not_supported, |
| 87 | "No file readers succeeded reading `%s` " |
| 88 | "(unsupported/malformed file?)", |
| 89 | FilePath.data()), |
| 90 | "ReadInputFile"); |
| 91 | EC.escalateToFatal(); |
| 92 | return EC.makeError(); |
| 93 | } |
| 94 | |
| 95 | int main(int argc, char *argv[]) { |
| 96 | // Parse arguments. |
| 97 | cl::ParseCommandLineOptions(argc, argv); |
| 98 | |
| 99 | Expected<std::unique_ptr<ELFStub>> StubOrErr = readInputFile(InputFilePath); |
| 100 | if (!StubOrErr) { |
| 101 | Error ReadError = StubOrErr.takeError(); |
| 102 | WithColor::error() << ReadError << "\n"; |
| 103 | exit(1); |
| 104 | } |
| 105 | |
| 106 | std::unique_ptr<ELFStub> TargetStub = std::move(StubOrErr.get()); |
| 107 | |
| 108 | // Write out .tbe file. |
| 109 | if (EmitTBE.getNumOccurrences() == 1) { |
| 110 | TargetStub->TbeVersion = TBEVersionCurrent; |
| 111 | if (SOName.getNumOccurrences() == 1) { |
| 112 | TargetStub->SoName = SOName; |
| 113 | } |
| 114 | Error TBEWriteError = writeTBE(EmitTBE, *TargetStub); |
| 115 | if (TBEWriteError) { |
| 116 | WithColor::error() << TBEWriteError << "\n"; |
| 117 | exit(1); |
| 118 | } |
| 119 | } |
| 120 | } |