diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 | 
| commit | 71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch) | |
| tree | 5343938942df402b49ec7300a1c25a2d4ccd5821 /tools/yaml2obj | |
| parent | 31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff) | |
Diffstat (limited to 'tools/yaml2obj')
| -rw-r--r-- | tools/yaml2obj/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | tools/yaml2obj/yaml2dwarf.cpp | 330 | ||||
| -rw-r--r-- | tools/yaml2obj/yaml2macho.cpp | 32 | ||||
| -rw-r--r-- | tools/yaml2obj/yaml2obj.cpp | 28 | ||||
| -rw-r--r-- | tools/yaml2obj/yaml2obj.h | 16 | ||||
| -rw-r--r-- | tools/yaml2obj/yaml2wasm.cpp | 377 | 
6 files changed, 420 insertions, 365 deletions
diff --git a/tools/yaml2obj/CMakeLists.txt b/tools/yaml2obj/CMakeLists.txt index 5e726496003f..a885547598d8 100644 --- a/tools/yaml2obj/CMakeLists.txt +++ b/tools/yaml2obj/CMakeLists.txt @@ -8,7 +8,7 @@ set(LLVM_LINK_COMPONENTS  add_llvm_tool(yaml2obj    yaml2obj.cpp    yaml2coff.cpp -  yaml2dwarf.cpp    yaml2elf.cpp    yaml2macho.cpp +  yaml2wasm.cpp    ) diff --git a/tools/yaml2obj/yaml2dwarf.cpp b/tools/yaml2obj/yaml2dwarf.cpp deleted file mode 100644 index 3ceb7772b969..000000000000 --- a/tools/yaml2obj/yaml2dwarf.cpp +++ /dev/null @@ -1,330 +0,0 @@ -//===- yaml2dwarf - Convert YAML to DWARF binary data ---------------------===// -// -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief The DWARF component of yaml2obj. -/// -//===----------------------------------------------------------------------===// - -#include "llvm/ObjectYAML/DWARFYAML.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/LEB128.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/SwapByteOrder.h" - -#include <algorithm> - -using namespace llvm; - -template <typename T> -void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) { -  if (IsLittleEndian != sys::IsLittleEndianHost) -    sys::swapByteOrder(Integer); -  OS.write(reinterpret_cast<char *>(&Integer), sizeof(T)); -} - -void writeVariableSizedInteger(uint64_t Integer, size_t Size, raw_ostream &OS, -                               bool IsLittleEndian) { -  if (8 == Size) -    writeInteger((uint64_t)Integer, OS, IsLittleEndian); -  else if (4 == Size) -    writeInteger((uint32_t)Integer, OS, IsLittleEndian); -  else if (2 == Size) -    writeInteger((uint16_t)Integer, OS, IsLittleEndian); -  else if (1 == Size) -    writeInteger((uint8_t)Integer, OS, IsLittleEndian); -  else -    assert(false && "Invalid integer write size."); -} - -void ZeroFillBytes(raw_ostream &OS, size_t Size) { -  std::vector<uint8_t> FillData; -  FillData.insert(FillData.begin(), Size, 0); -  OS.write(reinterpret_cast<char *>(FillData.data()), Size); -} - -void yaml2debug_str(raw_ostream &OS, const DWARFYAML::Data &DI) { -  for (auto Str : DI.DebugStrings) { -    OS.write(Str.data(), Str.size()); -    OS.write('\0'); -  } -} - -void yaml2debug_abbrev(raw_ostream &OS, const DWARFYAML::Data &DI) { -  for (auto AbbrevDecl : DI.AbbrevDecls) { -    encodeULEB128(AbbrevDecl.Code, OS); -    encodeULEB128(AbbrevDecl.Tag, OS); -    OS.write(AbbrevDecl.Children); -    for (auto Attr : AbbrevDecl.Attributes) { -      encodeULEB128(Attr.Attribute, OS); -      encodeULEB128(Attr.Form, OS); -    } -    encodeULEB128(0, OS); -    encodeULEB128(0, OS); -  } -} - -void yaml2debug_aranges(raw_ostream &OS, const DWARFYAML::Data &DI) { -  for (auto Range : DI.ARanges) { -    auto HeaderStart = OS.tell(); -    writeInteger((uint32_t)Range.Length, OS, DI.IsLittleEndian); -    writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian); -    writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian); -    writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian); -    writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian); - -    auto HeaderSize = OS.tell() - HeaderStart; -    auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2); -    ZeroFillBytes(OS, FirstDescriptor - HeaderSize); - -    for (auto Descriptor : Range.Descriptors) { -      writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS, -                                DI.IsLittleEndian); -      writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS, -                                DI.IsLittleEndian); -    } -    ZeroFillBytes(OS, Range.AddrSize * 2); -  } -} - -void yaml2pubsection(raw_ostream &OS, const DWARFYAML::PubSection &Sect, -                     bool IsLittleEndian) { -  writeInteger((uint32_t)Sect.Length, OS, IsLittleEndian); -  writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian); -  writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian); -  writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian); -  for (auto Entry : Sect.Entries) { -    writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian); -    if (Sect.IsGNUStyle) -      writeInteger((uint32_t)Entry.Descriptor, OS, IsLittleEndian); -    OS.write(Entry.Name.data(), Entry.Name.size()); -    OS.write('\0'); -  } -} - -void yaml2debug_info(raw_ostream &OS, const DWARFYAML::Data &DI) { - -  for (auto CU : DI.CompileUnits) { -    writeInteger((uint32_t)CU.Length, OS, DI.IsLittleEndian); -    writeInteger((uint16_t)CU.Version, OS, DI.IsLittleEndian); -    writeInteger((uint32_t)CU.AbbrOffset, OS, DI.IsLittleEndian); -    writeInteger((uint8_t)CU.AddrSize, OS, DI.IsLittleEndian); - -    auto FirstAbbrevCode = CU.Entries[0].AbbrCode; - -    for (auto Entry : CU.Entries) { -      encodeULEB128(Entry.AbbrCode, OS); -      if (Entry.AbbrCode == 0u) -        continue; -      bool Indirect = false; -      assert(Entry.AbbrCode - FirstAbbrevCode < DI.AbbrevDecls.size() && -             "Out of range AbbCode"); -      auto &Abbrev = DI.AbbrevDecls[Entry.AbbrCode - FirstAbbrevCode]; - -      auto FormVal = Entry.Values.begin(); -      auto AbbrForm = Abbrev.Attributes.begin(); -      for (; -           FormVal != Entry.Values.end() && AbbrForm != Abbrev.Attributes.end(); -           ++FormVal, ++AbbrForm) { -        dwarf::Form Form = AbbrForm->Form; -        do { -          Indirect = false; -          switch (Form) { -          case dwarf::DW_FORM_addr: -            writeVariableSizedInteger(FormVal->Value, CU.AddrSize, OS, -                                      DI.IsLittleEndian); -            break; -          case dwarf::DW_FORM_ref_addr: { -            // TODO: Handle DWARF32/DWARF64 after Line Table data is done -            auto writeSize = CU.Version == 2 ? CU.AddrSize : 4; -            writeVariableSizedInteger(FormVal->Value, writeSize, OS, -                                      DI.IsLittleEndian); -            break; -          } -          case dwarf::DW_FORM_exprloc: -          case dwarf::DW_FORM_block: -            encodeULEB128(FormVal->BlockData.size(), OS); -            OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]), -                     FormVal->BlockData.size()); -            break; -          case dwarf::DW_FORM_block1: { -            auto writeSize = FormVal->BlockData.size(); -            writeInteger((uint8_t)writeSize, OS, DI.IsLittleEndian); -            OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]), -                     FormVal->BlockData.size()); -            break; -          } -          case dwarf::DW_FORM_block2: { -            auto writeSize = FormVal->BlockData.size(); -            writeInteger((uint16_t)writeSize, OS, DI.IsLittleEndian); -            OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]), -                     FormVal->BlockData.size()); -            break; -          } -          case dwarf::DW_FORM_block4: { -            auto writeSize = FormVal->BlockData.size(); -            writeInteger((uint32_t)writeSize, OS, DI.IsLittleEndian); -            OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]), -                     FormVal->BlockData.size()); -            break; -          } -          case dwarf::DW_FORM_data1: -          case dwarf::DW_FORM_ref1: -          case dwarf::DW_FORM_flag: -            writeInteger((uint8_t)FormVal->Value, OS, DI.IsLittleEndian); -            break; -          case dwarf::DW_FORM_data2: -          case dwarf::DW_FORM_ref2: -            writeInteger((uint16_t)FormVal->Value, OS, DI.IsLittleEndian); -            break; -          case dwarf::DW_FORM_data4: -          case dwarf::DW_FORM_ref4: -            writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian); -            break; -          case dwarf::DW_FORM_data8: -          case dwarf::DW_FORM_ref8: -            writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian); -            break; -          case dwarf::DW_FORM_sdata: -            encodeSLEB128(FormVal->Value, OS); -            break; -          case dwarf::DW_FORM_udata: -          case dwarf::DW_FORM_ref_udata: -            encodeULEB128(FormVal->Value, OS); -            break; -          case dwarf::DW_FORM_string: -            OS.write(FormVal->CStr.data(), FormVal->CStr.size()); -            OS.write('\0'); -            break; -          case dwarf::DW_FORM_indirect: -            encodeULEB128(FormVal->Value, OS); -            Indirect = true; -            Form = static_cast<dwarf::Form>((uint64_t)FormVal->Value); -            ++FormVal; -            break; -          case dwarf::DW_FORM_strp: -          case dwarf::DW_FORM_sec_offset: -          case dwarf::DW_FORM_GNU_ref_alt: -          case dwarf::DW_FORM_GNU_strp_alt: -          case dwarf::DW_FORM_line_strp: -          case dwarf::DW_FORM_strp_sup: -          case dwarf::DW_FORM_ref_sup: -            // TODO: Handle DWARF32/64 -            writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian); -            break; -          case dwarf::DW_FORM_ref_sig8: -            writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian); -            break; -          case dwarf::DW_FORM_GNU_addr_index: -          case dwarf::DW_FORM_GNU_str_index: -            encodeULEB128(FormVal->Value, OS); -            break; -          default: -            break; -          } -        } while (Indirect); -      } -    } -  } -} - -void yaml2FileEntry(raw_ostream &OS, const DWARFYAML::File &File) { -  OS.write(File.Name.data(), File.Name.size()); -  OS.write('\0'); -  encodeULEB128(File.DirIdx, OS); -  encodeULEB128(File.ModTime, OS); -  encodeULEB128(File.Length, OS); -} - -void yaml2debug_line(raw_ostream &OS, const DWARFYAML::Data &DI) { -  for (const auto LineTable : DI.DebugLines) { -    writeInteger((uint32_t)LineTable.TotalLength, OS, DI.IsLittleEndian); -    uint64_t SizeOfPrologueLength = 4; -    if (LineTable.TotalLength == UINT32_MAX) { -      writeInteger((uint64_t)LineTable.TotalLength64, OS, DI.IsLittleEndian); -      SizeOfPrologueLength = 8; -    } -    writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian); -    writeVariableSizedInteger(LineTable.PrologueLength, SizeOfPrologueLength, -                              OS, DI.IsLittleEndian); -    writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian); -    if (LineTable.Version >= 4) -      writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian); -    writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian); -    writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian); -    writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian); -    writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian); - -    for (auto OpcodeLength : LineTable.StandardOpcodeLengths) -      writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian); - -    for (auto IncludeDir : LineTable.IncludeDirs) { -      OS.write(IncludeDir.data(), IncludeDir.size()); -      OS.write('\0'); -    } -    OS.write('\0'); - -    for (auto File : LineTable.Files) -      yaml2FileEntry(OS, File); -    OS.write('\0'); - -    for (auto Op : LineTable.Opcodes) { -      writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian); -      if (Op.Opcode == 0) { -        encodeULEB128(Op.ExtLen, OS); -        writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian); -        switch (Op.SubOpcode) { -        case dwarf::DW_LNE_set_address: -        case dwarf::DW_LNE_set_discriminator: -          writeVariableSizedInteger(Op.Data, DI.CompileUnits[0].AddrSize, OS, -                                    DI.IsLittleEndian); -          break; -        case dwarf::DW_LNE_define_file: -          yaml2FileEntry(OS, Op.FileEntry); -          break; -        case dwarf::DW_LNE_end_sequence: -          break; -        default: -          for (auto OpByte : Op.UnknownOpcodeData) -            writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian); -        } -      } else if (Op.Opcode < LineTable.OpcodeBase) { -        switch (Op.Opcode) { -        case dwarf::DW_LNS_copy: -        case dwarf::DW_LNS_negate_stmt: -        case dwarf::DW_LNS_set_basic_block: -        case dwarf::DW_LNS_const_add_pc: -        case dwarf::DW_LNS_set_prologue_end: -        case dwarf::DW_LNS_set_epilogue_begin: -          break; - -        case dwarf::DW_LNS_advance_pc: -        case dwarf::DW_LNS_set_file: -        case dwarf::DW_LNS_set_column: -        case dwarf::DW_LNS_set_isa: -          encodeULEB128(Op.Data, OS); -          break; - -        case dwarf::DW_LNS_advance_line: -          encodeSLEB128(Op.SData, OS); -          break; - -        case dwarf::DW_LNS_fixed_advance_pc: -          writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian); -          break; - -        default: -          for (auto OpData : Op.StandardOpcodeData) { -            encodeULEB128(OpData, OS); -          } -        } -      } -    } -  } -} diff --git a/tools/yaml2obj/yaml2macho.cpp b/tools/yaml2obj/yaml2macho.cpp index cbc4d7ff50d5..92b736e5298e 100644 --- a/tools/yaml2obj/yaml2macho.cpp +++ b/tools/yaml2obj/yaml2macho.cpp @@ -14,6 +14,7 @@  #include "yaml2obj.h"  #include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/ObjectYAML/DWARFEmitter.h"  #include "llvm/Support/Error.h"  #include "llvm/Support/LEB128.h"  #include "llvm/Support/MachO.h" @@ -179,6 +180,21 @@ size_t writeLoadCommandData<MachO::rpath_command>(MachOYAML::LoadCommand &LC,    return writePayloadString(LC, OS);  } +template <> +size_t writeLoadCommandData<MachO::build_version_command>( +    MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) { +  size_t BytesWritten = 0; +  for (const auto &T : LC.Tools) { +    struct MachO::build_tool_version tool = T; +    if (IsLittleEndian != sys::IsLittleEndianHost) +      MachO::swapStruct(tool); +    OS.write(reinterpret_cast<const char *>(&tool), +             sizeof(MachO::build_tool_version)); +    BytesWritten += sizeof(MachO::build_tool_version); +  } +  return BytesWritten; +} +  void ZeroFillBytes(raw_ostream &OS, size_t Size) {    std::vector<uint8_t> FillData;    FillData.insert(FillData.begin(), Size, 0); @@ -269,19 +285,21 @@ Error MachOWriter::writeSectionData(raw_ostream &OS) {                 "Wrote too much data somewhere, section offsets don't line up.");          if (0 == strncmp(&Sec.segname[0], "__DWARF", 16)) {            if (0 == strncmp(&Sec.sectname[0], "__debug_str", 16)) { -            yaml2debug_str(OS, Obj.DWARF); +            DWARFYAML::EmitDebugStr(OS, Obj.DWARF);            } else if (0 == strncmp(&Sec.sectname[0], "__debug_abbrev", 16)) { -            yaml2debug_abbrev(OS, Obj.DWARF); +            DWARFYAML::EmitDebugAbbrev(OS, Obj.DWARF);            } else if (0 == strncmp(&Sec.sectname[0], "__debug_aranges", 16)) { -            yaml2debug_aranges(OS, Obj.DWARF); +            DWARFYAML::EmitDebugAranges(OS, Obj.DWARF);            } else if (0 == strncmp(&Sec.sectname[0], "__debug_pubnames", 16)) { -            yaml2pubsection(OS, Obj.DWARF.PubNames, Obj.IsLittleEndian); +            DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubNames, +                                      Obj.IsLittleEndian);            } else if (0 == strncmp(&Sec.sectname[0], "__debug_pubtypes", 16)) { -            yaml2pubsection(OS, Obj.DWARF.PubTypes, Obj.IsLittleEndian); +            DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubTypes, +                                      Obj.IsLittleEndian);            } else if (0 == strncmp(&Sec.sectname[0], "__debug_info", 16)) { -            yaml2debug_info(OS, Obj.DWARF); +            DWARFYAML::EmitDebugInfo(OS, Obj.DWARF);            } else if (0 == strncmp(&Sec.sectname[0], "__debug_line", 16)) { -            yaml2debug_line(OS, Obj.DWARF); +            DWARFYAML::EmitDebugLine(OS, Obj.DWARF);            }          } else {            // Fills section data with 0xDEADBEEF diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp index f746d84a3898..e64e3dc1d179 100644 --- a/tools/yaml2obj/yaml2obj.cpp +++ b/tools/yaml2obj/yaml2obj.cpp @@ -40,31 +40,33 @@ DocNum("docnum", cl::init(1),  static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),                                             cl::value_desc("filename")); +LLVM_ATTRIBUTE_NORETURN static void error(Twine Message) { +  errs() << Message << "\n"; +  exit(1); +} +  static int convertYAML(yaml::Input &YIn, raw_ostream &Out) {    unsigned CurDocNum = 0;    do {      if (++CurDocNum == DocNum) {        yaml::YamlObjectFile Doc;        YIn >> Doc; -      if (YIn.error()) { -        errs() << "yaml2obj: Failed to parse YAML file!\n"; -        return 1; -      } - +      if (YIn.error()) +        error("yaml2obj: Failed to parse YAML file!");        if (Doc.Elf)          return yaml2elf(*Doc.Elf, Out);        if (Doc.Coff)          return yaml2coff(*Doc.Coff, Out);        if (Doc.MachO || Doc.FatMachO)          return yaml2macho(Doc, Out); -      errs() << "yaml2obj: Unknown document type!\n"; -      return 1; +      if (Doc.Wasm) +        return yaml2wasm(*Doc.Wasm, Out); +      error("yaml2obj: Unknown document type!");      }    } while (YIn.nextDocument()); -  errs() << "yaml2obj: Cannot find the " << DocNum -         << llvm::getOrdinalSuffix(DocNum) << " document\n"; -  return 1; +  error("yaml2obj: Cannot find the " + utostr(DocNum) + +        llvm::getOrdinalSuffix(DocNum) + " document");  }  int main(int argc, char **argv) { @@ -79,10 +81,8 @@ int main(int argc, char **argv) {    std::error_code EC;    std::unique_ptr<tool_output_file> Out(        new tool_output_file(OutputFilename, EC, sys::fs::F_None)); -  if (EC) { -    errs() << EC.message() << '\n'; -    return 1; -  } +  if (EC) +    error("yaml2obj: Error opening '" + OutputFilename + "': " + EC.message());    ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =        MemoryBuffer::getFileOrSTDIN(Input); diff --git a/tools/yaml2obj/yaml2obj.h b/tools/yaml2obj/yaml2obj.h index 4a637366e1a1..cb8f11904916 100644 --- a/tools/yaml2obj/yaml2obj.h +++ b/tools/yaml2obj/yaml2obj.h @@ -23,9 +23,8 @@ namespace ELFYAML {  struct Object;  } -namespace DWARFYAML { -struct Data; -struct PubSection; +namespace WasmYAML { +struct Object;  }  namespace yaml { @@ -37,15 +36,6 @@ struct YamlObjectFile;  int yaml2coff(llvm::COFFYAML::Object &Doc, llvm::raw_ostream &Out);  int yaml2elf(llvm::ELFYAML::Object &Doc, llvm::raw_ostream &Out);  int yaml2macho(llvm::yaml::YamlObjectFile &Doc, llvm::raw_ostream &Out); - -void yaml2debug_abbrev(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI); -void yaml2debug_str(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI); - -void yaml2debug_aranges(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI); -void yaml2pubsection(llvm::raw_ostream &OS, -                     const llvm::DWARFYAML::PubSection &Sect, -                     bool IsLittleEndian); -void yaml2debug_info(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI); -void yaml2debug_line(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI); +int yaml2wasm(llvm::WasmYAML::Object &Doc, llvm::raw_ostream &Out);  #endif diff --git a/tools/yaml2obj/yaml2wasm.cpp b/tools/yaml2obj/yaml2wasm.cpp new file mode 100644 index 000000000000..55267ce0392d --- /dev/null +++ b/tools/yaml2obj/yaml2wasm.cpp @@ -0,0 +1,377 @@ +//===- yaml2wasm - Convert YAML to a Wasm object file --------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief The Wasm component of yaml2obj. +/// +//===----------------------------------------------------------------------===// +// +#include "yaml2obj.h" +#include "llvm/Object/Wasm.h" +#include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/LEB128.h" + +using namespace llvm; + +/// This parses a yaml stream that represents a Wasm object file. +/// See docs/yaml2obj for the yaml scheema. +class WasmWriter { +public: +  WasmWriter(WasmYAML::Object &Obj) : Obj(Obj) {} +  int writeWasm(raw_ostream &OS); +  int writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec); +  int writeSectionContent(raw_ostream &OS, WasmYAML::CustomSection &Section); +  int writeSectionContent(raw_ostream &OS, WasmYAML::TypeSection &Section); +  int writeSectionContent(raw_ostream &OS, WasmYAML::ImportSection &Section); +  int writeSectionContent(raw_ostream &OS, WasmYAML::FunctionSection &Section); +  int writeSectionContent(raw_ostream &OS, WasmYAML::TableSection &Section); +  int writeSectionContent(raw_ostream &OS, WasmYAML::MemorySection &Section); +  int writeSectionContent(raw_ostream &OS, WasmYAML::GlobalSection &Section); +  int writeSectionContent(raw_ostream &OS, WasmYAML::ExportSection &Section); +  int writeSectionContent(raw_ostream &OS, WasmYAML::StartSection &Section); +  int writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section); +  int writeSectionContent(raw_ostream &OS, WasmYAML::CodeSection &Section); +  int writeSectionContent(raw_ostream &OS, WasmYAML::DataSection &Section); + +private: +  WasmYAML::Object &Obj; +}; + +static int writeUint64(raw_ostream &OS, uint64_t Value) { +  char Data[sizeof(Value)]; +  support::endian::write64le(Data, Value); +  OS.write(Data, sizeof(Data)); +  return 0; +} + +static int writeUint32(raw_ostream &OS, uint32_t Value) { +  char Data[sizeof(Value)]; +  support::endian::write32le(Data, Value); +  OS.write(Data, sizeof(Data)); +  return 0; +} + +static int writeUint8(raw_ostream &OS, uint8_t Value) { +  char Data[sizeof(Value)]; +  memcpy(Data, &Value, sizeof(Data)); +  OS.write(Data, sizeof(Data)); +  return 0; +} + +static int writeStringRef(StringRef &Str, raw_ostream &OS) { +  encodeULEB128(Str.size(), OS); +  OS << Str; +  return 0; +} + +static int writeLimits(WasmYAML::Limits Lim, raw_ostream &OS) { +  encodeULEB128(Lim.Flags, OS); +  encodeULEB128(Lim.Initial, OS); +  if (Lim.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) +    encodeULEB128(Lim.Maximum, OS); +  return 0; +} + +static int writeInitExpr(wasm::WasmInitExpr InitExpr, raw_ostream &OS) { +  writeUint8(OS, InitExpr.Opcode); +  switch (InitExpr.Opcode) { +  case wasm::WASM_OPCODE_I32_CONST: +    encodeSLEB128(InitExpr.Value.Int32, OS); +    break; +  case wasm::WASM_OPCODE_I64_CONST: +    encodeSLEB128(InitExpr.Value.Int64, OS); +    break; +  case wasm::WASM_OPCODE_F32_CONST: +    writeUint32(OS, InitExpr.Value.Float32); +    break; +  case wasm::WASM_OPCODE_F64_CONST: +    writeUint64(OS, InitExpr.Value.Float64); +    break; +  case wasm::WASM_OPCODE_GET_GLOBAL: +    encodeULEB128(InitExpr.Value.Global, OS); +    break; +  default: +    errs() << "Unknown opcode in init_expr: " << InitExpr.Opcode; +    return 1; +  } +  writeUint8(OS, wasm::WASM_OPCODE_END); +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::CustomSection &Section) { +  // writeStringRef(Section.Name, OS); +  // encodeULEB128(Section.Payload.binary_size(), OS); +  Section.Payload.writeAsBinary(OS); +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::TypeSection &Section) { +  encodeULEB128(Section.Signatures.size(), OS); +  for (auto &Sig : Section.Signatures) { +    encodeSLEB128(Sig.Form, OS); +    encodeULEB128(Sig.ParamTypes.size(), OS); +    for (auto ParamType : Sig.ParamTypes) +      encodeSLEB128(ParamType, OS); +    if (Sig.ReturnType == wasm::WASM_TYPE_NORESULT) { +      encodeSLEB128(0, OS); +    } else { +      encodeULEB128(1, OS); +      encodeSLEB128(Sig.ReturnType, OS); +    } +  } +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::ImportSection &Section) { +  encodeULEB128(Section.Imports.size(), OS); +  for (auto &Import : Section.Imports) { +    writeStringRef(Import.Module, OS); +    writeStringRef(Import.Field, OS); +    encodeULEB128(Import.Kind, OS); +    switch (Import.Kind) { +    case wasm::WASM_EXTERNAL_FUNCTION: +      encodeULEB128(Import.SigIndex, OS); +      break; +    case wasm::WASM_EXTERNAL_GLOBAL: +      encodeSLEB128(Import.GlobalType, OS); +      writeUint8(OS, Import.GlobalMutable); +      break; +    default: +      errs() << "Unknown import type: " << Import.Kind; +      return 1; +    } +  } +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::FunctionSection &Section) { +  encodeULEB128(Section.FunctionTypes.size(), OS); +  for (uint32_t FuncType : Section.FunctionTypes) { +    encodeULEB128(FuncType, OS); +  } +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::ExportSection &Section) { +  encodeULEB128(Section.Exports.size(), OS); +  for (auto &Export : Section.Exports) { +    writeStringRef(Export.Name, OS); +    encodeULEB128(Export.Kind, OS); +    encodeULEB128(Export.Index, OS); +  } +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::StartSection &Section) { +  encodeULEB128(Section.StartFunction, OS); +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::TableSection &Section) { +  encodeULEB128(Section.Tables.size(), OS); +  for (auto &Table : Section.Tables) { +    encodeSLEB128(Table.ElemType, OS); +    writeLimits(Table.TableLimits, OS); +  } +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::MemorySection &Section) { +  encodeULEB128(Section.Memories.size(), OS); +  for (auto &Mem : Section.Memories) { +    writeLimits(Mem, OS); +  } +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::GlobalSection &Section) { +  encodeULEB128(Section.Globals.size(), OS); +  for (auto &Global : Section.Globals) { +    encodeSLEB128(Global.Type, OS); +    writeUint8(OS, Global.Mutable); +    writeInitExpr(Global.InitExpr, OS); +  } +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::ElemSection &Section) { +  encodeULEB128(Section.Segments.size(), OS); +  for (auto &Segment : Section.Segments) { +    encodeULEB128(Segment.TableIndex, OS); +    writeInitExpr(Segment.Offset, OS); + +    encodeULEB128(Segment.Functions.size(), OS); +    for (auto &Function : Segment.Functions) { +      encodeULEB128(Function, OS); +    } +  } +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::CodeSection &Section) { +  encodeULEB128(Section.Functions.size(), OS); +  for (auto &Func : Section.Functions) { +    std::string OutString; +    raw_string_ostream StringStream(OutString); + +    encodeULEB128(Func.Locals.size(), StringStream); +    for (auto &LocalDecl : Func.Locals) { +      encodeULEB128(LocalDecl.Count, StringStream); +      encodeSLEB128(LocalDecl.Type, StringStream); +    } + +    Func.Body.writeAsBinary(StringStream); + +    // Write the section size followed by the content +    StringStream.flush(); +    encodeULEB128(OutString.size(), OS); +    OS << OutString; +  } +  return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, +                                    WasmYAML::DataSection &Section) { +  encodeULEB128(Section.Segments.size(), OS); +  for (auto &Segment : Section.Segments) { +    encodeULEB128(Segment.Index, OS); +    writeInitExpr(Segment.Offset, OS); +    encodeULEB128(Segment.Content.binary_size(), OS); +    Segment.Content.writeAsBinary(OS); +  } +  return 0; +} + +int WasmWriter::writeRelocSection(raw_ostream &OS, +                                  WasmYAML::Section &Sec) { +  StringRef Name; +  switch (Sec.Type) { +    case wasm::WASM_SEC_CODE: +      Name = "reloc.CODE"; +      break; +    case wasm::WASM_SEC_DATA: +      Name = "reloc.DATA"; +      break; +    default: +      llvm_unreachable("not yet implemented"); +      return 1; +  } + +  writeStringRef(Name, OS); +  encodeULEB128(Sec.Type, OS); +  encodeULEB128(Sec.Relocations.size(), OS); + +  for (auto Reloc: Sec.Relocations) { +    encodeULEB128(Reloc.Type, OS); +    encodeULEB128(Reloc.Offset, OS); +    encodeULEB128(Reloc.Index, OS); +    switch (Reloc.Type) { +      case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: +      case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: +      case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: +        encodeULEB128(Reloc.Addend, OS); +    } +  } +  return 0; +} + + +int WasmWriter::writeWasm(raw_ostream &OS) { +  // Write headers +  OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic)); +  writeUint32(OS, Obj.Header.Version); + +  // Write each section +  for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) { +    encodeULEB128(Sec->Type, OS); + +    std::string OutString; +    raw_string_ostream StringStream(OutString); +    if (auto S = dyn_cast<WasmYAML::CustomSection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else if (auto S = dyn_cast<WasmYAML::TypeSection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else if (auto S = dyn_cast<WasmYAML::ImportSection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else if (auto S = dyn_cast<WasmYAML::FunctionSection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else if (auto S = dyn_cast<WasmYAML::TableSection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else if (auto S = dyn_cast<WasmYAML::MemorySection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else if (auto S = dyn_cast<WasmYAML::GlobalSection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else if (auto S = dyn_cast<WasmYAML::ExportSection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else if (auto S = dyn_cast<WasmYAML::StartSection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else if (auto S = dyn_cast<WasmYAML::ElemSection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else if (auto S = dyn_cast<WasmYAML::CodeSection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else if (auto S = dyn_cast<WasmYAML::DataSection>(Sec.get())) { +      if (auto Err = writeSectionContent(StringStream, *S)) +        return Err; +    } else { +      errs() << "Unknown section type: " << Sec->Type << "\n"; +      return 1; +    } +    StringStream.flush(); + +    // Write the section size followed by the content +    encodeULEB128(OutString.size(), OS); +    OS << OutString; +  } + +  // write reloc sections for any section that have relocations +  for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) { +    if (Sec->Relocations.empty()) +      continue; + +    encodeULEB128(wasm::WASM_SEC_CUSTOM, OS); +    std::string OutString; +    raw_string_ostream StringStream(OutString); +    writeRelocSection(StringStream, *Sec); +    StringStream.flush(); + +    encodeULEB128(OutString.size(), OS); +    OS << OutString; +  } + +  return 0; +} + +int yaml2wasm(llvm::WasmYAML::Object &Doc, raw_ostream &Out) { +  WasmWriter Writer(Doc); + +  return Writer.writeWasm(Out); +}  | 
