1 //===- yaml2obj - Convert YAML to a binary object file --------------------===// 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 //===----------------------------------------------------------------------===// 8 // 9 // This program takes a YAML description of an object file and outputs the 10 // binary equivalent. 11 // 12 // This is used for writing tests that require binary files. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/ObjectYAML/yaml2obj.h" 17 #include "llvm/ADT/StringExtras.h" 18 #include "llvm/ObjectYAML/ObjectYAML.h" 19 #include "llvm/Support/CommandLine.h" 20 #include "llvm/Support/FileSystem.h" 21 #include "llvm/Support/InitLLVM.h" 22 #include "llvm/Support/MemoryBuffer.h" 23 #include "llvm/Support/ToolOutputFile.h" 24 #include "llvm/Support/WithColor.h" 25 #include "llvm/Support/YAMLTraits.h" 26 #include "llvm/Support/raw_ostream.h" 27 #include <system_error> 28 29 using namespace llvm; 30 31 namespace { 32 cl::OptionCategory Cat("yaml2obj Options"); 33 34 cl::opt<std::string> Input(cl::Positional, cl::desc("<input file>"), 35 cl::init("-"), cl::cat(Cat)); 36 37 cl::list<std::string> 38 D("D", cl::Prefix, 39 cl::desc("Defined the specified macros to their specified " 40 "definition. The syntax is <macro>=<definition>")); 41 42 cl::opt<unsigned> 43 DocNum("docnum", cl::init(1), 44 cl::desc("Read specified document from input (default = 1)"), 45 cl::cat(Cat)); 46 47 static cl::opt<uint64_t> MaxSize( 48 "max-size", cl::init(10 * 1024 * 1024), 49 cl::desc( 50 "Sets the maximum allowed output size (0 means no limit) [ELF only]")); 51 52 cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), 53 cl::value_desc("filename"), cl::init("-"), 54 cl::Prefix, cl::cat(Cat)); 55 } // namespace 56 57 static Optional<std::string> preprocess(StringRef Buf, 58 yaml::ErrorHandler ErrHandler) { 59 DenseMap<StringRef, StringRef> Defines; 60 for (StringRef Define : D) { 61 StringRef Macro, Definition; 62 std::tie(Macro, Definition) = Define.split('='); 63 if (!Define.count('=') || Macro.empty()) { 64 ErrHandler("invalid syntax for -D: " + Define); 65 return {}; 66 } 67 if (!Defines.try_emplace(Macro, Definition).second) { 68 ErrHandler("'" + Macro + "'" + " redefined"); 69 return {}; 70 } 71 } 72 73 std::string Preprocessed; 74 while (!Buf.empty()) { 75 if (Buf.startswith("[[")) { 76 size_t I = Buf.find_first_of("[]", 2); 77 if (Buf.substr(I).startswith("]]")) { 78 StringRef MacroExpr = Buf.substr(2, I - 2); 79 StringRef Macro; 80 StringRef Default; 81 std::tie(Macro, Default) = MacroExpr.split('='); 82 83 // When the -D option is requested, we use the provided value. 84 // Otherwise we use a default macro value if present. 85 auto It = Defines.find(Macro); 86 Optional<StringRef> Value; 87 if (It != Defines.end()) 88 Value = It->second; 89 else if (!Default.empty() || MacroExpr.endswith("=")) 90 Value = Default; 91 92 if (Value) { 93 Preprocessed += *Value; 94 Buf = Buf.substr(I + 2); 95 continue; 96 } 97 } 98 } 99 100 Preprocessed += Buf[0]; 101 Buf = Buf.substr(1); 102 } 103 104 return Preprocessed; 105 } 106 107 int main(int argc, char **argv) { 108 InitLLVM X(argc, argv); 109 cl::HideUnrelatedOptions(Cat); 110 cl::ParseCommandLineOptions( 111 argc, argv, "Create an object file from a YAML description", nullptr, 112 nullptr, /*LongOptionsUseDoubleDash=*/true); 113 114 auto ErrHandler = [](const Twine &Msg) { 115 WithColor::error(errs(), "yaml2obj") << Msg << "\n"; 116 }; 117 118 std::error_code EC; 119 std::unique_ptr<ToolOutputFile> Out( 120 new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None)); 121 if (EC) { 122 ErrHandler("failed to open '" + OutputFilename + "': " + EC.message()); 123 return 1; 124 } 125 126 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = 127 MemoryBuffer::getFileOrSTDIN(Input); 128 if (!Buf) 129 return 1; 130 131 Optional<std::string> Buffer = preprocess(Buf.get()->getBuffer(), ErrHandler); 132 if (!Buffer) 133 return 1; 134 yaml::Input YIn(*Buffer); 135 136 if (!convertYAML(YIn, Out->os(), ErrHandler, DocNum, 137 MaxSize == 0 ? UINT64_MAX : MaxSize)) 138 return 1; 139 140 Out->keep(); 141 Out->os().flush(); 142 return 0; 143 } 144