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 cl::cat(Cat)); 42 43 cl::opt<unsigned> 44 DocNum("docnum", cl::init(1), 45 cl::desc("Read specified document from input (default = 1)"), 46 cl::cat(Cat)); 47 48 static cl::opt<uint64_t> MaxSize( 49 "max-size", cl::init(10 * 1024 * 1024), 50 cl::desc( 51 "Sets the maximum allowed output size (0 means no limit) [ELF only]"), 52 cl::cat(Cat)); 53 54 cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), 55 cl::value_desc("filename"), cl::init("-"), 56 cl::Prefix, cl::cat(Cat)); 57 } // namespace 58 59 static Optional<std::string> preprocess(StringRef Buf, 60 yaml::ErrorHandler ErrHandler) { 61 DenseMap<StringRef, StringRef> Defines; 62 for (StringRef Define : D) { 63 StringRef Macro, Definition; 64 std::tie(Macro, Definition) = Define.split('='); 65 if (!Define.count('=') || Macro.empty()) { 66 ErrHandler("invalid syntax for -D: " + Define); 67 return {}; 68 } 69 if (!Defines.try_emplace(Macro, Definition).second) { 70 ErrHandler("'" + Macro + "'" + " redefined"); 71 return {}; 72 } 73 } 74 75 std::string Preprocessed; 76 while (!Buf.empty()) { 77 if (Buf.startswith("[[")) { 78 size_t I = Buf.find_first_of("[]", 2); 79 if (Buf.substr(I).startswith("]]")) { 80 StringRef MacroExpr = Buf.substr(2, I - 2); 81 StringRef Macro; 82 StringRef Default; 83 std::tie(Macro, Default) = MacroExpr.split('='); 84 85 // When the -D option is requested, we use the provided value. 86 // Otherwise we use a default macro value if present. 87 auto It = Defines.find(Macro); 88 Optional<StringRef> Value; 89 if (It != Defines.end()) 90 Value = It->second; 91 else if (!Default.empty() || MacroExpr.endswith("=")) 92 Value = Default; 93 94 if (Value) { 95 Preprocessed += *Value; 96 Buf = Buf.substr(I + 2); 97 continue; 98 } 99 } 100 } 101 102 Preprocessed += Buf[0]; 103 Buf = Buf.substr(1); 104 } 105 106 return Preprocessed; 107 } 108 109 int main(int argc, char **argv) { 110 InitLLVM X(argc, argv); 111 cl::HideUnrelatedOptions(Cat); 112 cl::ParseCommandLineOptions( 113 argc, argv, "Create an object file from a YAML description", nullptr, 114 nullptr, /*LongOptionsUseDoubleDash=*/true); 115 116 auto ErrHandler = [](const Twine &Msg) { 117 WithColor::error(errs(), "yaml2obj") << Msg << "\n"; 118 }; 119 120 std::error_code EC; 121 std::unique_ptr<ToolOutputFile> Out( 122 new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None)); 123 if (EC) { 124 ErrHandler("failed to open '" + OutputFilename + "': " + EC.message()); 125 return 1; 126 } 127 128 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = 129 MemoryBuffer::getFileOrSTDIN(Input); 130 if (!Buf) 131 return 1; 132 133 Optional<std::string> Buffer = preprocess(Buf.get()->getBuffer(), ErrHandler); 134 if (!Buffer) 135 return 1; 136 yaml::Input YIn(*Buffer); 137 138 if (!convertYAML(YIn, Out->os(), ErrHandler, DocNum, 139 MaxSize == 0 ? UINT64_MAX : MaxSize)) 140 return 1; 141 142 Out->keep(); 143 Out->os().flush(); 144 return 0; 145 } 146