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 cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), 48 cl::value_desc("filename"), cl::init("-"), 49 cl::Prefix, cl::cat(Cat)); 50 } // namespace 51 52 static Optional<std::string> preprocess(StringRef Buf, 53 yaml::ErrorHandler ErrHandler) { 54 DenseMap<StringRef, StringRef> Defines; 55 for (StringRef Define : D) { 56 StringRef Macro, Definition; 57 std::tie(Macro, Definition) = Define.split('='); 58 if (!Define.count('=') || Macro.empty()) { 59 ErrHandler("invalid syntax for -D: " + Define); 60 return {}; 61 } 62 if (!Defines.try_emplace(Macro, Definition).second) { 63 ErrHandler("'" + Macro + "'" + " redefined"); 64 return {}; 65 } 66 } 67 68 std::string Preprocessed; 69 while (!Buf.empty()) { 70 if (Buf.startswith("[[")) { 71 size_t I = Buf.find_first_of("[]", 2); 72 if (Buf.substr(I).startswith("]]")) { 73 StringRef Macro = Buf.substr(2, I - 2); 74 auto It = Defines.find(Macro); 75 if (It != Defines.end()) { 76 Preprocessed += It->second; 77 Buf = Buf.substr(I + 2); 78 continue; 79 } 80 } 81 } 82 83 Preprocessed += Buf[0]; 84 Buf = Buf.substr(1); 85 } 86 87 return Preprocessed; 88 } 89 90 int main(int argc, char **argv) { 91 InitLLVM X(argc, argv); 92 cl::HideUnrelatedOptions(Cat); 93 cl::ParseCommandLineOptions( 94 argc, argv, "Create an object file from a YAML description", nullptr, 95 nullptr, /*LongOptionsUseDoubleDash=*/true); 96 97 auto ErrHandler = [](const Twine &Msg) { 98 WithColor::error(errs(), "yaml2obj") << Msg << "\n"; 99 }; 100 101 std::error_code EC; 102 std::unique_ptr<ToolOutputFile> Out( 103 new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None)); 104 if (EC) { 105 ErrHandler("failed to open '" + OutputFilename + "': " + EC.message()); 106 return 1; 107 } 108 109 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = 110 MemoryBuffer::getFileOrSTDIN(Input); 111 if (!Buf) 112 return 1; 113 114 Optional<std::string> Buffer = preprocess(Buf.get()->getBuffer(), ErrHandler); 115 if (!Buffer) 116 return 1; 117 yaml::Input YIn(*Buffer); 118 if (!convertYAML(YIn, Out->os(), ErrHandler, DocNum)) 119 return 1; 120 121 Out->keep(); 122 Out->os().flush(); 123 return 0; 124 } 125