brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.8 KiB · 662648b Raw
159 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This program takes a YAML description of an object file and outputs the10// 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 <optional>28#include <system_error>29 30using namespace llvm;31 32namespace {33cl::OptionCategory Cat("yaml2obj Options");34 35cl::opt<std::string> Input(cl::Positional, cl::desc("<input file>"),36                           cl::init("-"), cl::cat(Cat));37 38static cl::list<std::string>39    D("D", cl::Prefix,40      cl::desc("Defined the specified macros to their specified "41               "definition. The syntax is <macro>=<definition>"),42      cl::cat(Cat));43 44cl::opt<bool> PreprocessOnly("E", cl::desc("Just print the preprocessed file"),45                             cl::cat(Cat));46 47cl::opt<unsigned>48    DocNum("docnum", cl::init(1),49           cl::desc("Read specified document from input (default = 1)"),50           cl::cat(Cat));51 52static cl::opt<uint64_t> MaxSize(53    "max-size", cl::init(10 * 1024 * 1024),54    cl::desc(55        "Sets the maximum allowed output size (0 means no limit) [ELF only]"),56    cl::cat(Cat));57 58cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),59                                    cl::value_desc("filename"), cl::init("-"),60                                    cl::Prefix, cl::cat(Cat));61} // namespace62 63static std::optional<std::string> preprocess(StringRef Buf,64                                             yaml::ErrorHandler ErrHandler) {65  DenseMap<StringRef, StringRef> Defines;66  for (StringRef Define : D) {67    StringRef Macro, Definition;68    std::tie(Macro, Definition) = Define.split('=');69    if (!Define.count('=') || Macro.empty()) {70      ErrHandler("invalid syntax for -D: " + Define);71      return {};72    }73    if (!Defines.try_emplace(Macro, Definition).second) {74      ErrHandler("'" + Macro + "'" + " redefined");75      return {};76    }77  }78 79  std::string Preprocessed;80  while (!Buf.empty()) {81    if (Buf.starts_with("[[")) {82      size_t I = Buf.find_first_of("[]", 2);83      if (Buf.substr(I).starts_with("]]")) {84        StringRef MacroExpr = Buf.substr(2, I - 2);85        StringRef Macro;86        StringRef Default;87        std::tie(Macro, Default) = MacroExpr.split('=');88 89        // When the -D option is requested, we use the provided value.90        // Otherwise we use a default macro value if present.91        auto It = Defines.find(Macro);92        std::optional<StringRef> Value;93        if (It != Defines.end())94          Value = It->second;95        else if (!Default.empty() || MacroExpr.ends_with("="))96          Value = Default;97 98        if (Value) {99          Preprocessed += *Value;100          Buf = Buf.substr(I + 2);101          continue;102        }103      }104    }105 106    Preprocessed += Buf[0];107    Buf = Buf.substr(1);108  }109 110  return Preprocessed;111}112 113int main(int argc, char **argv) {114  InitLLVM X(argc, argv);115  cl::HideUnrelatedOptions(Cat);116  cl::ParseCommandLineOptions(117      argc, argv, "Create an object file from a YAML description", nullptr,118      nullptr, nullptr, /*LongOptionsUseDoubleDash=*/true);119 120  constexpr StringRef ProgName = "yaml2obj";121  auto ErrHandler = [&](const Twine &Msg) {122    WithColor::error(errs(), ProgName) << Msg << "\n";123  };124 125  std::error_code EC;126  std::unique_ptr<ToolOutputFile> Out(127      new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None));128  if (EC) {129    ErrHandler("failed to open '" + OutputFilename + "': " + EC.message());130    return 1;131  }132 133  ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =134      MemoryBuffer::getFileOrSTDIN(Input, /*IsText=*/true);135  if (std::error_code EC = Buf.getError()) {136    WithColor::error(errs(), ProgName) << Input << ": " << EC.message() << '\n';137    return 1;138  }139 140  std::optional<std::string> Buffer =141      preprocess(Buf.get()->getBuffer(), ErrHandler);142  if (!Buffer)143    return 1;144 145  if (PreprocessOnly) {146    Out->os() << Buffer;147  } else {148    yaml::Input YIn(*Buffer);149 150    if (!convertYAML(YIn, Out->os(), ErrHandler, DocNum,151                     MaxSize == 0 ? UINT64_MAX : MaxSize))152      return 1;153  }154 155  Out->keep();156  Out->os().flush();157  return 0;158}159