Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/wasm2c/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 79 kB image not shown  

Quelle  binary-reader-objdump.cc   Sprache: C

 
/*
 * Copyright 2016 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "wabt/binary-reader-objdump.h"

#include <algorithm>
#include <cassert>
#include <cinttypes>
#include <cstdio>
#include <cstring>
#include <vector>

#if HAVE_STRCASECMP
#include <strings.h>
#endif

#include "wabt/binary-reader-nop.h"
#include "wabt/filenames.h"
#include "wabt/literal.h"
#include "wabt/string-util.h"

namespace wabt {

namespace {

class BinaryReaderObjdumpBase : public BinaryReaderNop {
 public:
  BinaryReaderObjdumpBase(const uint8_t* data,
                          size_t size,
                          ObjdumpOptions* options,
                          ObjdumpState* state);

  bool OnError(const Error&) override;

  Result BeginModule(uint32_t version) override;
  Result BeginSection(Index section_index,
                      BinarySection section_type,
                      Offset size) override;

  Result OnOpcode(Opcode Opcode) override;
  Result OnRelocCount(Index count, Index section_index) override;

 protected:
  std::string_view GetTypeName(Index index) const;
  std::string_view GetFunctionName(Index index) const;
  std::string_view GetGlobalName(Index index) const;
  std::string_view GetLocalName(Index function_index, Index local_index) const;
  std::string_view GetSectionName(Index index) const;
  std::string_view GetTagName(Index index) const;
  std::string_view GetSymbolName(Index index) const;
  std::string_view GetSegmentName(Index index) const;
  std::string_view GetTableName(Index index) const;
  void PrintRelocation(const Reloc& reloc, Offset offset) const;
  Offset GetPrintOffset(Offset offset) const;
  Offset GetSectionStart(BinarySection section_code) const {
    return section_starts_[static_cast<size_t>(section_code)];
  }

  ObjdumpOptions* options_;
  ObjdumpState* objdump_state_;
  const uint8_t* data_;
  size_t size_;
  bool print_details_ = false;
  BinarySection reloc_section_ = BinarySection::Invalid;
  Offset section_starts_[kBinarySectionCount];
  // Map of section index to section type
  std::vector<BinarySection> section_types_;
  bool section_found_ = false;
  std::string module_name_;
  Opcode current_opcode = Opcode::Unreachable;

  std::unique_ptr<FileStream> err_stream_;
};

BinaryReaderObjdumpBase::BinaryReaderObjdumpBase(const uint8_t* data,
                                                 size_t size,
                                                 ObjdumpOptions* options,
                                                 ObjdumpState* objdump_state)
    : options_(options),
      objdump_state_(objdump_state),
      data_(data),
      size_(size),
      err_stream_(FileStream::CreateStderr()) {
  ZeroMemory(section_starts_);
}

Result BinaryReaderObjdumpBase::BeginSection(Index section_index,
                                             BinarySection section_code,
                                             Offset size) {
  section_starts_[static_cast<size_t>(section_code)] = state->offset;
  section_types_.push_back(section_code);
  return Result::Ok;
}

bool BinaryReaderObjdumpBase::OnError(const Error&) {
  // Tell the BinaryReader that this error is "handled" for all passes other
  // than the prepass. When the error is handled the default message will be
  // suppressed.
  return options_->mode != ObjdumpMode::Prepass;
}

Result BinaryReaderObjdumpBase::BeginModule(uint32_t version) {
  switch (options_->mode) {
    case ObjdumpMode::Headers:
      printf("\n");
      printf("Sections:\n\n");
      break;
    case ObjdumpMode::Details:
      printf("\n");
      printf("Section Details:\n\n");
      break;
    case ObjdumpMode::Disassemble:
      printf("\n");
      printf("Code Disassembly:\n\n");
      break;
    case ObjdumpMode::Prepass: {
      std::string_view basename = GetBasename(options_->filename);
      if (basename == "-") {
        basename = "";
      }
      printf("%s:\tfile format wasm %#x\n", std::string(basename).c_str(),
             version);
      break;
    }
    case ObjdumpMode::RawData:
      break;
  }

  return Result::Ok;
}

std::string_view BinaryReaderObjdumpBase::GetTypeName(Index index) const {
  return objdump_state_->type_names.Get(index);
}

std::string_view BinaryReaderObjdumpBase::GetFunctionName(Index index) const {
  return objdump_state_->function_names.Get(index);
}

std::string_view BinaryReaderObjdumpBase::GetGlobalName(Index index) const {
  return objdump_state_->global_names.Get(index);
}

std::string_view BinaryReaderObjdumpBase::GetLocalName(
    Index function_index,
    Index local_index) const {
  return objdump_state_->local_names.Get(function_index, local_index);
}

std::string_view BinaryReaderObjdumpBase::GetSectionName(Index index) const {
  return objdump_state_->section_names.Get(index);
}

std::string_view BinaryReaderObjdumpBase::GetTagName(Index index) const {
  return objdump_state_->tag_names.Get(index);
}

std::string_view BinaryReaderObjdumpBase::GetSegmentName(Index index) const {
  return objdump_state_->segment_names.Get(index);
}

std::string_view BinaryReaderObjdumpBase::GetTableName(Index index) const {
  return objdump_state_->table_names.Get(index);
}

std::string_view BinaryReaderObjdumpBase::GetSymbolName(
    Index symbol_index) const {
  if (symbol_index >= objdump_state_->symtab.size())
    return "";
  ObjdumpSymbol& sym = objdump_state_->symtab[symbol_index];
  switch (sym.kind) {
    case SymbolType::Function:
      return GetFunctionName(sym.index);
    case SymbolType::Data:
      return sym.name;
    case SymbolType::Global:
      return GetGlobalName(sym.index);
    case SymbolType::Section:
      return GetSectionName(sym.index);
    case SymbolType::Tag:
      return GetTagName(sym.index);
    case SymbolType::Table:
      return GetTableName(sym.index);
  }
  WABT_UNREACHABLE;
}

void BinaryReaderObjdumpBase::PrintRelocation(const Reloc& reloc,
                                              Offset offset) const {
  printf(" %06" PRIzx ": %-18s %" PRIindex, offset,
         GetRelocTypeName(reloc.type), reloc.index);
  if (reloc.addend) {
    printf(" + %d", reloc.addend);
  }
  if (reloc.type != RelocType::TypeIndexLEB) {
    printf(" <" PRIstringview ">",
           WABT_PRINTF_STRING_VIEW_ARG(GetSymbolName(reloc.index)));
  }
  printf("\n");
}

Offset BinaryReaderObjdumpBase::GetPrintOffset(Offset offset) const {
  return options_->section_offsets
             ? offset - GetSectionStart(BinarySection::Code)
             : offset;
}

Result BinaryReaderObjdumpBase::OnOpcode(Opcode opcode) {
  current_opcode = opcode;
  return Result::Ok;
}

Result BinaryReaderObjdumpBase::OnRelocCount(Index count, Index section_index) {
  if (section_index >= section_types_.size()) {
    err_stream_->Writef("invalid relocation section index: %" PRIindex "\n",
                        section_index);
    reloc_section_ = BinarySection::Invalid;
    return Result::Error;
  }
  reloc_section_ = section_types_[section_index];
  return Result::Ok;
}

class BinaryReaderObjdumpPrepass : public BinaryReaderObjdumpBase {
 public:
  using BinaryReaderObjdumpBase::BinaryReaderObjdumpBase;

  Result BeginSection(Index section_index,
                      BinarySection section_code,
                      Offset size) override {
    BinaryReaderObjdumpBase::BeginSection(section_index, section_code, size);
    if (section_code != BinarySection::Custom) {
      objdump_state_->section_names.Set(section_index,
                                        wabt::GetSectionName(section_code));
    }
    return Result::Ok;
  }

  Result BeginCustomSection(Index section_index,
                            Offset size,
                            std::string_view section_name) override {
    objdump_state_->section_names.Set(section_index, section_name);
    return Result::Ok;
  }

  Result OnFunctionName(Index index, std::string_view name) override {
    SetFunctionName(index, name);
    return Result::Ok;
  }

  Result OnFuncType(Index index,
                    Index param_count,
                    Type* param_types,
                    Index result_count,
                    Type* result_types) override {
    objdump_state_->function_param_counts[index] = param_count;
    return Result::Ok;
  }

  Result OnNameEntry(NameSectionSubsection type,
                     Index index,
                     std::string_view name) override {
    switch (type) {
      // TODO(sbc): remove OnFunctionName in favor of just using
      // OnNameEntry so that this works
      /*
      case NameSectionSubsection::Function:
        SetFunctionName(index, name);
        break;
      */

      case NameSectionSubsection::Type:
        SetTypeName(index, name);
        break;
      case NameSectionSubsection::Global:
        SetGlobalName(index, name);
        break;
      case NameSectionSubsection::Table:
        SetTableName(index, name);
        break;
      case NameSectionSubsection::DataSegment:
        SetSegmentName(index, name);
        break;
      case NameSectionSubsection::Tag:
        SetTagName(index, name);
        break;
      default:
        break;
    }
    return Result::Ok;
  }

  Result OnLocalName(Index function_index,
                     Index local_index,
                     std::string_view local_name) override {
    SetLocalName(function_index, local_index, local_name);
    return Result::Ok;
  }

  Result OnSymbolCount(Index count) override {
    objdump_state_->symtab.resize(count);
    return Result::Ok;
  }

  Result OnDataSymbol(Index index,
                      uint32_t flags,
                      std::string_view name,
                      Index segment,
                      uint32_t offset,
                      uint32_t size) override {
    objdump_state_->symtab[index] = {SymbolType::Data, std::string(name), 0};
    return Result::Ok;
  }

  Result OnFunctionSymbol(Index index,
                          uint32_t flags,
                          std::string_view name,
                          Index func_index) override {
    if (!name.empty()) {
      SetFunctionName(func_index, name);
    }
    objdump_state_->symtab[index] = {SymbolType::Function, std::string(name),
                                     func_index};
    return Result::Ok;
  }

  Result OnGlobalSymbol(Index index,
                        uint32_t flags,
                        std::string_view name,
                        Index global_index) override {
    if (!name.empty()) {
      SetGlobalName(global_index, name);
    }
    objdump_state_->symtab[index] = {SymbolType::Global, std::string(name),
                                     global_index};
    return Result::Ok;
  }

  Result OnSectionSymbol(Index index,
                         uint32_t flags,
                         Index section_index) override {
    objdump_state_->symtab[index] = {SymbolType::Section,
                                     std::string(GetSectionName(section_index)),
                                     section_index};
    return Result::Ok;
  }

  Result OnTagSymbol(Index index,
                     uint32_t flags,
                     std::string_view name,
                     Index tag_index) override {
    if (!name.empty()) {
      SetTagName(tag_index, name);
    }
    objdump_state_->symtab[index] = {SymbolType::Tag, std::string(name),
                                     tag_index};
    return Result::Ok;
  }

  Result OnTableSymbol(Index index,
                       uint32_t flags,
                       std::string_view name,
                       Index table_index) override {
    if (!name.empty()) {
      SetTableName(table_index, name);
    }
    objdump_state_->symtab[index] = {SymbolType::Table, std::string(name),
                                     table_index};
    return Result::Ok;
  }

  Result OnImportFunc(Index import_index,
                      std::string_view module_name,
                      std::string_view field_name,
                      Index func_index,
                      Index sig_index) override {
    SetFunctionName(func_index, module_name + "." + field_name);
    return Result::Ok;
  }

  Result OnImportTag(Index import_index,
                     std::string_view module_name,
                     std::string_view field_name,
                     Index tag_index,
                     Index sig_index) override {
    SetTagName(tag_index, module_name + "." + field_name);
    return Result::Ok;
  }

  Result OnImportGlobal(Index import_index,
                        std::string_view module_name,
                        std::string_view field_name,
                        Index global_index,
                        Type type,
                        bool mutable_) override {
    SetGlobalName(global_index, module_name + "." + field_name);
    return Result::Ok;
  }

  Result OnImportTable(Index import_index,
                       std::string_view module_name,
                       std::string_view field_name,
                       Index table_index,
                       Type elem_type,
                       const Limits* elem_limits) override {
    SetTableName(table_index, module_name + "." + field_name);
    return Result::Ok;
  }

  Result OnExport(Index index,
                  ExternalKind kind,
                  Index item_index,
                  std::string_view name) override {
    if (kind == ExternalKind::Func) {
      SetFunctionName(item_index, name);
    } else if (kind == ExternalKind::Global) {
      SetGlobalName(item_index, name);
    }
    return Result::Ok;
  }

  Result OnReloc(RelocType type,
                 Offset offset,
                 Index index,
                 uint32_t addend) override;

  Result OnModuleName(std::string_view name) override {
    if (options_->mode == ObjdumpMode::Prepass) {
      printf("module name: <" PRIstringview ">\n",
             WABT_PRINTF_STRING_VIEW_ARG(name));
    }
    return Result::Ok;
  }

  Result OnSegmentInfo(Index index,
                       std::string_view name,
                       Address alignment_log2,
                       uint32_t flags) override {
    SetSegmentName(index, name);
    return Result::Ok;
  }

 protected:
  void SetTypeName(Index index, std::string_view name);
  void SetFunctionName(Index index, std::string_view name);
  void SetGlobalName(Index index, std::string_view name);
  void SetLocalName(Index function_index,
                    Index local_index,
                    std::string_view name);
  void SetTagName(Index index, std::string_view name);
  void SetTableName(Index index, std::string_view name);
  void SetSegmentName(Index index, std::string_view name);
};

void BinaryReaderObjdumpPrepass::SetTypeName(Index index,
                                             std::string_view name) {
  objdump_state_->type_names.Set(index, name);
}

void BinaryReaderObjdumpPrepass::SetFunctionName(Index index,
                                                 std::string_view name) {
  objdump_state_->function_names.Set(index, name);
}

void BinaryReaderObjdumpPrepass::SetGlobalName(Index index,
                                               std::string_view name) {
  objdump_state_->global_names.Set(index, name);
}

void BinaryReaderObjdumpPrepass::SetLocalName(Index function_index,
                                              Index local_index,
                                              std::string_view name) {
  objdump_state_->local_names.Set(function_index, local_index, name);
}

void BinaryReaderObjdumpPrepass::SetTagName(Index index,
                                            std::string_view name) {
  objdump_state_->tag_names.Set(index, name);
}

void BinaryReaderObjdumpPrepass::SetTableName(Index index,
                                              std::string_view name) {
  objdump_state_->table_names.Set(index, name);
}

void BinaryReaderObjdumpPrepass::SetSegmentName(Index index,
                                                std::string_view name) {
  objdump_state_->segment_names.Set(index, name);
}

Result BinaryReaderObjdumpPrepass::OnReloc(RelocType type,
                                           Offset offset,
                                           Index index,
                                           uint32_t addend) {
  BinaryReaderObjdumpBase::OnReloc(type, offset, index, addend);
  if (reloc_section_ == BinarySection::Code) {
    objdump_state_->code_relocations.emplace_back(type, offset, index, addend);
  } else if (reloc_section_ == BinarySection::Data) {
    objdump_state_->data_relocations.emplace_back(type, offset, index, addend);
  }
  return Result::Ok;
}

class BinaryReaderObjdumpDisassemble : public BinaryReaderObjdumpBase {
 public:
  using BinaryReaderObjdumpBase::BinaryReaderObjdumpBase;

  std::string BlockSigToString(Type type) const;

  Result OnFunction(Index index, Index sig_index) override;

  Result BeginFunctionBody(Index index, Offset size) override;
  Result EndFunctionBody(Index index) override;

  Result OnLocalDeclCount(Index count) override;
  Result OnLocalDecl(Index decl_index, Index count, Type type) override;

  Result OnOpcode(Opcode Opcode) override;
  Result OnOpcodeBare() override;
  Result OnOpcodeIndex(Index value) override;
  Result OnOpcodeIndexIndex(Index value, Index value2) override;
  Result OnOpcodeUint32(uint32_t value) override;
  Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override;
  Result OnCallIndirectExpr(uint32_t sig_indix, uint32_t table_index) override;
  Result OnOpcodeUint32Uint32Uint32(uint32_t value,
                                    uint32_t value2,
                                    uint32_t value3) override;
  Result OnOpcodeUint32Uint32Uint32Uint32(uint32_t value,
                                          uint32_t value2,
                                          uint32_t value3,
                                          uint32_t value4) override;
  Result OnOpcodeUint64(uint64_t value) override;
  Result OnOpcodeF32(uint32_t value) override;
  Result OnOpcodeF64(uint64_t value) override;
  Result OnOpcodeV128(v128 value) override;
  Result OnOpcodeBlockSig(Type sig_type) override;
  Result OnOpcodeType(Type type) override;

  Result OnBrTableExpr(Index num_targets,
                       Index* target_depths,
                       Index default_target_depth) override;
  Result OnDelegateExpr(Index) override;
  Result OnEndExpr() override;

 private:
  void LogOpcode(const char* fmt, ...);

  Offset current_opcode_offset = 0;
  Offset last_opcode_end = 0;
  int indent_level = 0;
  Index next_reloc = 0;
  Index current_function_index = 0;
  Index local_index_ = 0;
  bool in_function_body = false;
  bool skip_next_opcode_ = false;
};

std::string BinaryReaderObjdumpDisassemble::BlockSigToString(Type type) const {
  if (type.IsIndex()) {
    return StringPrintf("type[%d]", type.GetIndex());
  } else if (type == Type::Void) {
    return "";
  } else {
    return type.GetName();
  }
}

Result BinaryReaderObjdumpDisassemble::OnOpcode(Opcode opcode) {
  BinaryReaderObjdumpBase::OnOpcode(opcode);
  if (!in_function_body) {
    return Result::Ok;
  }
  if (options_->debug) {
    const char* opcode_name = opcode.GetName();
    err_stream_->Writef("on_opcode: %#" PRIzx ": %s\n", state->offset,
                        opcode_name);
  }

  if (last_opcode_end) {
    // Takes care of cases where opcode's bytes was a non-canonical leb128
    // encoding. In this case, opcode.GetLength() under-reports the length,
    // since it canonicalizes the opcode.
    if (state->offset < last_opcode_end + opcode.GetLength()) {
      Opcode missing_opcode = Opcode::FromCode(data_[last_opcode_end]);
      const char* opcode_name = missing_opcode.GetName();
      fprintf(stderr,
              "error: %#" PRIzx " missing opcode callback at %#" PRIzx
              " (%#02x=%s)\n",
              state->offset, last_opcode_end + 1, data_[last_opcode_end],
              opcode_name);
      return Result::Error;
    }
  }

  current_opcode_offset = state->offset;
  return Result::Ok;
}

#define IMMEDIATE_OCTET_COUNT 9

Result BinaryReaderObjdumpDisassemble::OnLocalDeclCount(Index count) {
  if (!in_function_body) {
    return Result::Ok;
  }
  current_opcode_offset = state->offset;
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnLocalDecl(Index decl_index,
                                                   Index count,
                                                   Type type) {
  if (!in_function_body) {
    return Result::Ok;
  }
  Offset offset = current_opcode_offset;
  size_t data_size = state->offset - offset;

  printf(" %06" PRIzx ":", GetPrintOffset(offset));
  for (size_t i = 0; i < data_size && i < IMMEDIATE_OCTET_COUNT;
       i++, offset++) {
    printf(" %02x", data_[offset]);
  }
  for (size_t i = data_size; i < IMMEDIATE_OCTET_COUNT; i++) {
    printf(" ");
  }
  printf(" | local[");
  if (count > 0) {
    printf("%" PRIindex, local_index_);

    if (count != 1) {
      printf("..%" PRIindex "", local_index_ + count - 1);
    }
    local_index_ += count;
  }
  printf("] type=%s\n", type.GetName().c_str());

  last_opcode_end = current_opcode_offset + data_size;
  current_opcode_offset = last_opcode_end;

  return Result::Ok;
}

void BinaryReaderObjdumpDisassemble::LogOpcode(const char* fmt, ...) {
  // BinaryReaderObjdumpDisassemble is only used to disassembly function bodies
  // so this should never be called for instructions outside of function bodies
  // (i.e. init expresions).
  assert(in_function_body);
  if (skip_next_opcode_) {
    skip_next_opcode_ = false;
    return;
  }
  const Offset immediate_len = state->offset - current_opcode_offset;
  const Offset opcode_size = current_opcode.GetLength();
  const Offset total_size = opcode_size + immediate_len;
  // current_opcode_offset has already read past this opcode; rewind it by the
  // size of this opcode, which may be more than one byte.
  Offset offset = current_opcode_offset - opcode_size;
  const Offset offset_end = offset + total_size;

  bool first_line = true;
  while (offset < offset_end) {
    // Print bytes, but only display a maximum of IMMEDIATE_OCTET_COUNT on each
    // line.
    printf(" %06" PRIzx ":", GetPrintOffset(offset));
    size_t i;
    for (i = 0; offset < offset_end && i < IMMEDIATE_OCTET_COUNT;
         ++i, ++offset) {
      printf(" %02x", data_[offset]);
    }
    // Fill the rest of the remaining space with spaces.
    for (; i < IMMEDIATE_OCTET_COUNT; ++i) {
      printf(" ");
    }
    printf(" | ");

    if (first_line) {
      first_line = false;

      // Print disassembly.
      int indent_level = this->indent_level;
      switch (current_opcode) {
        case Opcode::Else:
        case Opcode::Catch:
        case Opcode::CatchAll:
          indent_level--;
          break;
        default:
          break;
      }
      for (int j = 0; j < indent_level; j++) {
        printf(" ");
      }

      const char* opcode_name = current_opcode.GetName();
      printf("%s", opcode_name);
      if (fmt) {
        printf(" ");
        va_list args;
        va_start(args, fmt);
        vprintf(fmt, args);
        va_end(args);
      }
    }

    printf("\n");
  }

  last_opcode_end = state->offset;

  // Print relocation after then full (potentially multi-line) instruction.
  if (options_->relocs &&
      next_reloc < objdump_state_->code_relocations.size()) {
    const Reloc& reloc = objdump_state_->code_relocations[next_reloc];
    Offset code_start = GetSectionStart(BinarySection::Code);
    Offset abs_offset = code_start + reloc.offset;
    if (last_opcode_end > abs_offset) {
      PrintRelocation(reloc, abs_offset);
      next_reloc++;
    }
  }
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeBare() {
  if (!in_function_body) {
    return Result::Ok;
  }
  LogOpcode(0, nullptr);
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeIndex(Index value) {
  if (!in_function_body) {
    return Result::Ok;
  }
  std::string_view name;
  if (current_opcode == Opcode::Call &&
      !(name = GetFunctionName(value)).empty()) {
    LogOpcode("%d <" PRIstringview ">", value,
              WABT_PRINTF_STRING_VIEW_ARG(name));
  } else if (current_opcode == Opcode::Throw &&
             !(name = GetTagName(value)).empty()) {
    LogOpcode("%d <" PRIstringview ">", value,
              WABT_PRINTF_STRING_VIEW_ARG(name));
  } else if ((current_opcode == Opcode::GlobalGet ||
              current_opcode == Opcode::GlobalSet) &&
             !(name = GetGlobalName(value)).empty()) {
    LogOpcode("%d <" PRIstringview ">", value,
              WABT_PRINTF_STRING_VIEW_ARG(name));
  } else if ((current_opcode == Opcode::LocalGet ||
              current_opcode == Opcode::LocalSet) &&
             !(name = GetLocalName(current_function_index, value)).empty()) {
    LogOpcode("%d <" PRIstringview ">", value,
              WABT_PRINTF_STRING_VIEW_ARG(name));
  } else {
    LogOpcode("%d", value);
  }
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeIndexIndex(Index value,
                                                          Index value2) {
  if (!in_function_body) {
    return Result::Ok;
  }
  LogOpcode("%" PRIindex " %" PRIindex, value, value2);
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeUint32(uint32_t value) {
  if (!in_function_body) {
    return Result::Ok;
  }
  std::string_view name;
  if (current_opcode == Opcode::DataDrop &&
      !(name = GetSegmentName(value)).empty()) {
    LogOpcode("%d <" PRIstringview ">", value,
              WABT_PRINTF_STRING_VIEW_ARG(name));
  } else {
    LogOpcode("%u", value);
  }
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeUint32Uint32(uint32_t value,
                                                            uint32_t value2) {
  if (!in_function_body)
    return Result::Ok;
  std::string_view name;
  if (current_opcode == Opcode::MemoryInit &&
      !(name = GetSegmentName(value)).empty()) {
    LogOpcode("%u %u <" PRIstringview ">", value, value2,
              WABT_PRINTF_STRING_VIEW_ARG(name));
  } else {
    LogOpcode("%u %u", value, value2);
  }
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnCallIndirectExpr(
    uint32_t sig_index,
    uint32_t table_index) {
  std::string_view table_name = GetTableName(table_index);
  std::string_view type_name = GetTypeName(sig_index);
  if (!type_name.empty() && !table_name.empty()) {
    LogOpcode("%u <" PRIstringview "> (type %u <" PRIstringview ">)",
              table_index, WABT_PRINTF_STRING_VIEW_ARG(table_name), sig_index,
              WABT_PRINTF_STRING_VIEW_ARG(type_name));
  } else if (!table_name.empty()) {
    LogOpcode("%u <" PRIstringview "> (type %u)", table_index,
              WABT_PRINTF_STRING_VIEW_ARG(table_name), sig_index);
  } else if (!type_name.empty()) {
    LogOpcode("%u (type %u <" PRIstringview ">)", table_index, sig_index,
              WABT_PRINTF_STRING_VIEW_ARG(type_name));
  } else {
    LogOpcode("%u (type %u)", table_index, sig_index);
  }
  skip_next_opcode_ = true;
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeUint32Uint32Uint32(
    uint32_t value,
    uint32_t value2,
    uint32_t value3) {
  if (!in_function_body) {
    return Result::Ok;
  }
  LogOpcode("%u %u %u", value, value2, value3);
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeUint32Uint32Uint32Uint32(
    uint32_t value,
    uint32_t value2,
    uint32_t value3,
    uint32_t value4) {
  if (!in_function_body) {
    return Result::Ok;
  }
  LogOpcode("%u %u %u %u", value, value2, value3, value4);
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeUint64(uint64_t value) {
  if (!in_function_body) {
    return Result::Ok;
  }
  LogOpcode("%" PRIu64, value);
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeF32(uint32_t value) {
  if (!in_function_body) {
    return Result::Ok;
  }
  char buffer[WABT_MAX_FLOAT_HEX];
  WriteFloatHex(buffer, sizeof(buffer), value);
  LogOpcode(buffer);
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeF64(uint64_t value) {
  if (!in_function_body) {
    return Result::Ok;
  }
  char buffer[WABT_MAX_DOUBLE_HEX];
  WriteDoubleHex(buffer, sizeof(buffer), value);
  LogOpcode(buffer);
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeV128(v128 value) {
  if (!in_function_body) {
    return Result::Ok;
  }
  // v128 is always dumped as i32x4:
  LogOpcode("0x%08x 0x%08x 0x%08x 0x%08x", value.u32(0), value.u32(1),
            value.u32(2), value.u32(3));
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeType(Type type) {
  if (!in_function_body) {
    return Result::Ok;
  }
  if (current_opcode == Opcode::SelectT) {
    LogOpcode(type.GetName().c_str());
  } else {
    LogOpcode(type.GetRefKindName());
  }
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnBrTableExpr(
    Index num_targets,
    Index* target_depths,
    Index default_target_depth) {
  if (!in_function_body) {
    return Result::Ok;
  }

  std::string buffer = std::string();
  for (Index i = 0; i < num_targets; i++) {
    buffer.append(std::to_string(target_depths[i])).append(" ");
  }
  buffer.append(std::to_string(default_target_depth));

  LogOpcode("%s", buffer.c_str());
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnDelegateExpr(Index depth) {
  if (!in_function_body) {
    return Result::Ok;
  }
  // Because `delegate` ends the block we need to dedent here, and
  // we don't need to dedent it in LogOpcode.
  if (indent_level > 0) {
    indent_level--;
  }
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnEndExpr() {
  if (!in_function_body) {
    return Result::Ok;
  }
  if (indent_level > 0) {
    indent_level--;
  }
  LogOpcode(0, nullptr);
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnFunction(Index index,
                                                  Index sig_index) {
  objdump_state_->function_types[index] = sig_index;
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::BeginFunctionBody(Index index,
                                                         Offset size) {
  printf("%06" PRIzx " func[%" PRIindex "]", GetPrintOffset(state->offset),
         index);
  auto name = GetFunctionName(index);
  if (!name.empty()) {
    printf(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
  }
  printf(":\n");

  last_opcode_end = 0;
  in_function_body = true;
  current_function_index = index;
  auto type_index = objdump_state_->function_types[index];
  local_index_ = objdump_state_->function_param_counts[type_index];
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::EndFunctionBody(Index index) {
  assert(in_function_body);
  in_function_body = false;
  return Result::Ok;
}

Result BinaryReaderObjdumpDisassemble::OnOpcodeBlockSig(Type sig_type) {
  if (!in_function_body) {
    return Result::Ok;
  }
  if (sig_type != Type::Void) {
    LogOpcode("%s", BlockSigToString(sig_type).c_str());
  } else {
    LogOpcode(nullptr);
  }
  indent_level++;
  return Result::Ok;
}

enum class InitExprType {
  Invalid,
  I32,
  F32,
  I64,
  F64,
  V128,
  Global,
  FuncRef,
  // TODO: There isn't a nullref anymore, this just represents ref.null of some
  // type T.
  NullRef,
};

struct InitInst {
  Opcode opcode;
  union {
    Index index;
    uint32_t i32;
    uint32_t f32;
    uint64_t i64;
    uint64_t f64;
    v128 v128_v;
    Type type;
  } imm;
};

struct InitExpr {
  InitExprType type;
  std::vector<InitInst> insts;
};

class BinaryReaderObjdump : public BinaryReaderObjdumpBase {
 public:
  BinaryReaderObjdump(const uint8_t* data,
                      size_t size,
                      ObjdumpOptions* options,
                      ObjdumpState* state);

  Result EndModule() override;
  Result BeginSection(Index section_index,
                      BinarySection section_type,
                      Offset size) override;
  Result BeginCustomSection(Index section_index,
                            Offset size,
                            std::string_view section_name) override;

  Result OnTypeCount(Index count) override;
  Result OnFuncType(Index index,
                    Index param_count,
                    Type* param_types,
                    Index result_count,
                    Type* result_types) override;
  Result OnStructType(Index index, Index field_count, TypeMut* fields) override;
  Result OnArrayType(Index index, TypeMut field) override;

  Result OnImportCount(Index count) override;
  Result OnImportFunc(Index import_index,
                      std::string_view module_name,
                      std::string_view field_name,
                      Index func_index,
                      Index sig_index) override;
  Result OnImportTable(Index import_index,
                       std::string_view module_name,
                       std::string_view field_name,
                       Index table_index,
                       Type elem_type,
                       const Limits* elem_limits) override;
  Result OnImportMemory(Index import_index,
                        std::string_view module_name,
                        std::string_view field_name,
                        Index memory_index,
                        const Limits* page_limits,
                        uint32_t page_size) override;
  Result OnImportGlobal(Index import_index,
                        std::string_view module_name,
                        std::string_view field_name,
                        Index global_index,
                        Type type,
                        bool mutable_) override;
  Result OnImportTag(Index import_index,
                     std::string_view module_name,
                     std::string_view field_name,
                     Index tag_index,
                     Index sig_index) override;

  Result OnFunctionCount(Index count) override;
  Result OnFunction(Index index, Index sig_index) override;

  Result OnTableCount(Index count) override;
  Result OnTable(Index index,
                 Type elem_type,
                 const Limits* elem_limits) override;

  Result OnMemoryCount(Index count) override;
  Result OnMemory(Index index,
                  const Limits* limits,
                  uint32_t page_size) override;

  Result OnGlobalCount(Index count) override;
  Result BeginGlobal(Index index, Type type, bool mutable_) override;

  Result OnExportCount(Index count) override;
  Result OnExport(Index index,
                  ExternalKind kind,
                  Index item_index,
                  std::string_view name) override;

  Result OnStartFunction(Index func_index) override;
  Result OnDataCount(Index count) override;

  Result OnFunctionBodyCount(Index count) override;
  Result BeginFunctionBody(Index index, Offset size) override;

  Result OnElemSegmentCount(Index count) override;
  Result BeginElemSegment(Index index,
                          Index table_index,
                          uint8_t flags) override;
  Result OnElemSegmentElemType(Index index, Type elem_type) override;
  Result OnElemSegmentElemExprCount(Index index, Index count) override;

  void BeginInitExpr() { current_init_expr_.insts.clear(); }

  Result BeginElemSegmentInitExpr(Index index) override {
    reading_elem_init_expr_ = true;
    BeginInitExpr();
    return Result::Ok;
  }

  Result EndElemSegmentInitExpr(Index index) override { return EndInitExpr(); }

  Result BeginDataSegmentInitExpr(Index index) override {
    reading_data_init_expr_ = true;
    BeginInitExpr();
    return Result::Ok;
  }

  Result EndDataSegmentInitExpr(Index index) override { return EndInitExpr(); }

  Result BeginGlobalInitExpr(Index index) override {
    reading_global_init_expr_ = true;
    BeginInitExpr();
    return Result::Ok;
  }

  Result EndGlobalInitExpr(Index index) override { return EndInitExpr(); }

  Result BeginElemExpr(Index elem_index, Index expr_index) override {
    reading_elem_expr_ = true;
    elem_index_ = expr_index;
    BeginInitExpr();
    return Result::Ok;
  }

  Result EndElemExpr(Index elem_index, Index expr_index) override {
    assert(expr_index == elem_index_);
    return EndInitExpr();
  }

  Result OnDataSegmentCount(Index count) override;
  Result BeginDataSegment(Index index,
                          Index memory_index,
                          uint8_t flags) override;
  Result OnDataSegmentData(Index index,
                           const void* data,
                           Address size) override;

  Result OnModuleName(std::string_view name) override;
  Result OnFunctionName(Index function_index,
                        std::string_view function_name) override;
  Result OnLocalName(Index function_index,
                     Index local_index,
                     std::string_view local_name) override;
  Result OnNameEntry(NameSectionSubsection type,
                     Index index,
                     std::string_view name) override;

  Result OnDylinkInfo(uint32_t mem_size,
                      uint32_t mem_align_log2,
                      uint32_t table_size,
                      uint32_t table_align_log2) override;
  Result OnDylinkNeededCount(Index count) override;
  Result OnDylinkNeeded(std::string_view so_name) override;
  Result OnDylinkImportCount(Index count) override;
  Result OnDylinkExportCount(Index count) override;
  Result OnDylinkImport(std::string_view module,
                        std::string_view name,
                        uint32_t flags) override;
  Result OnDylinkExport(std::string_view name, uint32_t flags) override;

  Result OnRelocCount(Index count, Index section_index) override;
  Result OnReloc(RelocType type,
                 Offset offset,
                 Index index,
                 uint32_t addend) override;

  Result OnFeature(uint8_t prefix, std::string_view name) override;

  Result OnSymbolCount(Index count) override;
  Result OnDataSymbol(Index index,
                      uint32_t flags,
                      std::string_view name,
                      Index segment,
                      uint32_t offset,
                      uint32_t size) override;
  Result OnFunctionSymbol(Index index,
                          uint32_t flags,
                          std::string_view name,
                          Index func_index) override;
  Result OnGlobalSymbol(Index index,
                        uint32_t flags,
                        std::string_view name,
                        Index global_index) override;
  Result OnSectionSymbol(Index index,
                         uint32_t flags,
                         Index section_index) override;
  Result OnTagSymbol(Index index,
                     uint32_t flags,
                     std::string_view name,
                     Index tag_index) override;
  Result OnTableSymbol(Index index,
                       uint32_t flags,
                       std::string_view name,
                       Index table_index) override;
  Result OnSegmentInfoCount(Index count) override;
  Result OnSegmentInfo(Index index,
                       std::string_view name,
                       Address alignment_log2,
                       uint32_t flags) override;
  Result OnInitFunctionCount(Index count) override;
  Result OnInitFunction(uint32_t priority, Index symbol_index) override;
  Result OnComdatCount(Index count) override;
  Result OnComdatBegin(std::string_view name,
                       uint32_t flags,
                       Index count) override;
  Result OnComdatEntry(ComdatType kind, Index index) override;

  Result OnTagCount(Index count) override;
  Result OnTagType(Index index, Index sig_index) override;

  Result OnOpcode(Opcode Opcode) override;
  Result OnI32ConstExpr(uint32_t value) override;
  Result OnI64ConstExpr(uint64_t value) override;
  Result OnF32ConstExpr(uint32_t value) override;
  Result OnF64ConstExpr(uint64_t value) override;
  Result OnRefFuncExpr(Index func_index) override;
  Result OnRefNullExpr(Type type) override;
  Result OnGlobalGetExpr(Index global_index) override;
  Result OnCodeMetadataCount(Index function_index, Index count) override;
  Result OnCodeMetadata(Offset code_offset,
                        const void* data,
                        Address size) override;

 private:
  Result EndInitExpr();
  bool ShouldPrintDetails();
  void PrintDetails(const char* fmt, ...);
  Result PrintSymbolFlags(uint32_t flags);
  Result PrintSegmentFlags(uint32_t flags);
  void PrintInitExpr(const InitExpr& expr,
                     bool as_unsigned = false,
                     bool with_prefix = true);
  Result OnCount(Index count);

  std::unique_ptr<FileStream> out_stream_;
  Index elem_index_ = 0;
  Index table_index_ = 0;
  Index next_data_reloc_ = 0;
  bool reading_elem_init_expr_ = false;
  bool reading_data_init_expr_ = false;
  bool reading_global_init_expr_ = false;
  bool reading_elem_expr_ = false;
  InitExpr current_init_expr_{};
  uint8_t data_flags_ = 0;
  uint8_t elem_flags_ = 0;
  Index data_mem_index_ = 0;
  uint64_t data_offset_ = 0;
  uint64_t elem_offset_ = 0;

  bool ReadingInitExpr() {
    return reading_elem_init_expr_ || reading_data_init_expr_ ||
           reading_global_init_expr_ || reading_elem_expr_;
  }
};

BinaryReaderObjdump::BinaryReaderObjdump(const uint8_t* data,
                                         size_t size,
                                         ObjdumpOptions* options,
                                         ObjdumpState* objdump_state)
    : BinaryReaderObjdumpBase(data, size, options, objdump_state),
      out_stream_(FileStream::CreateStdout()) {}

Result BinaryReaderObjdump::BeginCustomSection(Index section_index,
                                               Offset size,
                                               std::string_view section_name) {
  PrintDetails(" - name: \"" PRIstringview "\"\n",
               WABT_PRINTF_STRING_VIEW_ARG(section_name));
  if (options_->mode == ObjdumpMode::Headers) {
    printf("\"" PRIstringview "\"\n",
           WABT_PRINTF_STRING_VIEW_ARG(section_name));
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::BeginSection(Index section_index,
                                         BinarySection section_code,
                                         Offset size) {
  BinaryReaderObjdumpBase::BeginSection(section_index, section_code, size);

  // |section_name| and |match_name| are identical for known sections. For
  // custom sections, |section_name| is "Custom", but |match_name| is the name
  // of the custom section.
  const char* section_name = wabt::GetSectionName(section_code);
  std::string match_name(GetSectionName(section_index));

  bool section_match = !options_->section_name ||
                       !strcasecmp(options_->section_name, match_name.c_str());
  if (section_match) {
    section_found_ = true;
  }

  switch (options_->mode) {
    case ObjdumpMode::Headers:
      printf("%9s start=%#010" PRIzx " end=%#010" PRIzx " (size=%#010" PRIoffset
             ") ",
             section_name, state->offset, state->offset + size, size);
      break;
    case ObjdumpMode::Details:
      if (section_match) {
        printf("%s", section_name);
        // All known section types except the Start and DataCount sections have
        // a count in which case this line gets completed in OnCount().
        if (section_code == BinarySection::Start ||
            section_code == BinarySection::DataCount ||
            section_code == BinarySection::Custom) {
          printf(":\n");
        }
        print_details_ = true;
      } else {
        print_details_ = false;
      }
      break;
    case ObjdumpMode::RawData:
      if (section_match) {
        printf("\nContents of section %s:\n", section_name);
        out_stream_->WriteMemoryDump(data_ + state->offset, size, state->offset,
                                     PrintChars::Yes);
      }
      break;
    case ObjdumpMode::Prepass:
    case ObjdumpMode::Disassemble:
      break;
  }
  return Result::Ok;
}

bool BinaryReaderObjdump::ShouldPrintDetails() {
  if (options_->mode != ObjdumpMode::Details) {
    return false;
  }
  return print_details_;
}

void WABT_PRINTF_FORMAT(2, 3) BinaryReaderObjdump::PrintDetails(const char* fmt,
                                                                ...) {
  if (!ShouldPrintDetails()) {
    return;
  }
  va_list args;
  va_start(args, fmt);
  vprintf(fmt, args);
  va_end(args);
}

Result BinaryReaderObjdump::OnCount(Index count) {
  if (options_->mode == ObjdumpMode::Headers) {
    printf("count: %" PRIindex "\n", count);
  } else if (options_->mode == ObjdumpMode::Details && print_details_) {
    printf("[%" PRIindex "]:\n", count);
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::EndModule() {
  if (options_->section_name && !section_found_) {
    err_stream_->Writef("Section not found: %s\n", options_->section_name);
    return Result::Error;
  }

  if (options_->relocs && ShouldPrintDetails()) {
    if (next_data_reloc_ != objdump_state_->data_relocations.size()) {
      err_stream_->Writef("Data reloctions outside of segments!:\n");
      for (size_t i = next_data_reloc_;
           i < objdump_state_->data_relocations.size(); i++) {
        const Reloc& reloc = objdump_state_->data_relocations[i];
        PrintRelocation(reloc, reloc.offset);
      }

      return Result::Error;
    }
  }

  return Result::Ok;
}

Result BinaryReaderObjdump::OnTypeCount(Index count) {
  return OnCount(count);
}

Result BinaryReaderObjdump::OnFuncType(Index index,
                                       Index param_count,
                                       Type* param_types,
                                       Index result_count,
                                       Type* result_types) {
  if (!ShouldPrintDetails()) {
    return Result::Ok;
  }
  printf(" - type[%" PRIindex "] (", index);
  for (Index i = 0; i < param_count; i++) {
    if (i != 0) {
      printf(", ");
    }
    printf("%s", param_types[i].GetName().c_str());
  }
  printf(") -> ");
  switch (result_count) {
    case 0:
      printf("nil");
      break;
    case 1:
      printf("%s", result_types[0].GetName().c_str());
      break;
    default:
      printf("(");
      for (Index i = 0; i < result_count; i++) {
        if (i != 0) {
          printf(", ");
        }
        printf("%s", result_types[i].GetName().c_str());
      }
      printf(")");
      break;
  }
  printf("\n");
  return Result::Ok;
}

Result BinaryReaderObjdump::OnStructType(Index index,
                                         Index field_count,
                                         TypeMut* fields) {
  if (!ShouldPrintDetails()) {
    return Result::Ok;
  }
  printf(" - type[%" PRIindex "] (struct", index);
  for (Index i = 0; i < field_count; i++) {
    if (fields[i].mutable_) {
      printf(" (mut");
    }
    printf(" %s", fields[i].type.GetName().c_str());
    if (fields[i].mutable_) {
      printf(")");
    }
  }
  printf(")\n");
  return Result::Ok;
}

Result BinaryReaderObjdump::OnArrayType(Index index, TypeMut field) {
  if (!ShouldPrintDetails()) {
    return Result::Ok;
  }
  printf(" - type[%" PRIindex "] (array", index);
  if (field.mutable_) {
    printf(" (mut");
  }
  printf(" %s", field.type.GetName().c_str());
  if (field.mutable_) {
    printf(")");
  }
  printf(")\n");
  return Result::Ok;
}

Result BinaryReaderObjdump::OnFunctionCount(Index count) {
  return OnCount(count);
}

Result BinaryReaderObjdump::OnFunction(Index index, Index sig_index) {
  PrintDetails(" - func[%" PRIindex "] sig=%" PRIindex, index, sig_index);
  auto name = GetFunctionName(index);
  if (!name.empty()) {
    PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
  }
  PrintDetails("\n");
  objdump_state_->function_types[index] = sig_index;
  return Result::Ok;
}

Result BinaryReaderObjdump::OnFunctionBodyCount(Index count) {
  return OnCount(count);
}

Result BinaryReaderObjdump::BeginFunctionBody(Index index, Offset size) {
  PrintDetails(" - func[%" PRIindex "] size=%" PRIzd, index, size);
  auto name = GetFunctionName(index);
  if (!name.empty()) {
    PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
  }
  PrintDetails("\n");
  return Result::Ok;
}

Result BinaryReaderObjdump::OnStartFunction(Index func_index) {
  if (options_->mode == ObjdumpMode::Headers) {
    printf("start: %" PRIindex "\n", func_index);
  } else {
    PrintDetails(" - start function: %" PRIindex, func_index);
    auto name = GetFunctionName(func_index);
    if (!name.empty()) {
      PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
    }
    PrintDetails("\n");
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnDataCount(Index count) {
  if (options_->mode == ObjdumpMode::Headers) {
    printf("count: %" PRIindex "\n", count);
  } else {
    PrintDetails(" - data count: %" PRIindex "\n", count);
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnImportCount(Index count) {
  return OnCount(count);
}

Result BinaryReaderObjdump::OnImportFunc(Index import_index,
                                         std::string_view module_name,
                                         std::string_view field_name,
                                         Index func_index,
                                         Index sig_index) {
  PrintDetails(" - func[%" PRIindex "] sig=%" PRIindex, func_index, sig_index);
  auto name = GetFunctionName(func_index);
  if (!name.empty()) {
    PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
  }
  PrintDetails(" <- " PRIstringview "." PRIstringview "\n",
               WABT_PRINTF_STRING_VIEW_ARG(module_name),
               WABT_PRINTF_STRING_VIEW_ARG(field_name));
  return Result::Ok;
}

Result BinaryReaderObjdump::OnImportTable(Index import_index,
                                          std::string_view module_name,
                                          std::string_view field_name,
                                          Index table_index,
                                          Type elem_type,
                                          const Limits* elem_limits) {
  PrintDetails(" - table[%" PRIindex "] type=%s initial=%" PRId64, table_index,
               elem_type.GetName().c_str(), elem_limits->initial);
  if (elem_limits->has_max) {
    PrintDetails(" max=%" PRId64, elem_limits->max);
  }
  if (elem_limits->is_64) {
    PrintDetails(" i64");
  }
  PrintDetails(" <- " PRIstringview "." PRIstringview "\n",
               WABT_PRINTF_STRING_VIEW_ARG(module_name),
               WABT_PRINTF_STRING_VIEW_ARG(field_name));
  return Result::Ok;
}

Result BinaryReaderObjdump::OnImportMemory(Index import_index,
                                           std::string_view module_name,
                                           std::string_view field_name,
                                           Index memory_index,
                                           const Limits* page_limits,
                                           uint32_t page_size) {
  PrintDetails(" - memory[%" PRIindex "] pages: initial=%" PRId64, memory_index,
               page_limits->initial);
  if (page_limits->has_max) {
    PrintDetails(" max=%" PRId64, page_limits->max);
  }
  if (page_limits->is_shared) {
    PrintDetails(" shared");
  }
  if (page_limits->is_64) {
    PrintDetails(" i64");
  }
  if (page_size != WABT_DEFAULT_PAGE_SIZE) {
    PrintDetails(" (pagesize %u)", page_size);
  }
  PrintDetails(" <- " PRIstringview "." PRIstringview "\n",
               WABT_PRINTF_STRING_VIEW_ARG(module_name),
               WABT_PRINTF_STRING_VIEW_ARG(field_name));
  return Result::Ok;
}

Result BinaryReaderObjdump::OnImportGlobal(Index import_index,
                                           std::string_view module_name,
                                           std::string_view field_name,
                                           Index global_index,
                                           Type type,
                                           bool mutable_) {
  PrintDetails(" - global[%" PRIindex "] %s mutable=%d", global_index,
               type.GetName().c_str(), mutable_);
  PrintDetails(" <- " PRIstringview "." PRIstringview "\n",
               WABT_PRINTF_STRING_VIEW_ARG(module_name),
               WABT_PRINTF_STRING_VIEW_ARG(field_name));
  return Result::Ok;
}

Result BinaryReaderObjdump::OnImportTag(Index import_index,
                                        std::string_view module_name,
                                        std::string_view field_name,
                                        Index tag_index,
                                        Index sig_index) {
  PrintDetails(" - tag[%" PRIindex "] sig=%" PRIindex, tag_index, sig_index);
  auto name = GetTagName(tag_index);
  if (!name.empty()) {
    PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
  }
  PrintDetails(" <- " PRIstringview "." PRIstringview "\n",
               WABT_PRINTF_STRING_VIEW_ARG(module_name),
               WABT_PRINTF_STRING_VIEW_ARG(field_name));
  return Result::Ok;
}

Result BinaryReaderObjdump::OnMemoryCount(Index count) {
  return OnCount(count);
}

Result BinaryReaderObjdump::OnMemory(Index index,
                                     const Limits* page_limits,
                                     uint32_t page_size) {
  PrintDetails(" - memory[%" PRIindex "] pages: initial=%" PRId64, index,
               page_limits->initial);
  if (page_limits->has_max) {
    PrintDetails(" max=%" PRId64, page_limits->max);
  }
  if (page_limits->is_shared) {
    PrintDetails(" shared");
  }
  if (page_limits->is_64) {
    PrintDetails(" i64");
  }
  if (page_size != WABT_DEFAULT_PAGE_SIZE) {
    PrintDetails(" (pagesize %u)", page_size);
  }
  PrintDetails("\n");
  return Result::Ok;
}

Result BinaryReaderObjdump::OnTableCount(Index count) {
  return OnCount(count);
}

Result BinaryReaderObjdump::OnTable(Index index,
                                    Type elem_type,
                                    const Limits* elem_limits) {
  PrintDetails(" - table[%" PRIindex "] type=%s initial=%" PRId64, index,
               elem_type.GetName().c_str(), elem_limits->initial);
  if (elem_limits->has_max) {
    PrintDetails(" max=%" PRId64, elem_limits->max);
  }
  auto name = GetTableName(index);
  if (!name.empty()) {
    PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
  }
  if (elem_limits->is_64) {
    PrintDetails(" i64");
  }
  PrintDetails("\n");
  return Result::Ok;
}

Result BinaryReaderObjdump::OnExportCount(Index count) {
  return OnCount(count);
}

Result BinaryReaderObjdump::OnExport(Index index,
                                     ExternalKind kind,
                                     Index item_index,
                                     std::string_view name) {
  PrintDetails(" - %s[%" PRIindex "]", GetKindName(kind), item_index);
  if (kind == ExternalKind::Func) {
    auto name = GetFunctionName(item_index);
    if (!name.empty()) {
      PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
    }
  }

  PrintDetails(" -> \"" PRIstringview "\"\n",
               WABT_PRINTF_STRING_VIEW_ARG(name));
  return Result::Ok;
}

Result BinaryReaderObjdump::OnElemSegmentCount(Index count) {
  return OnCount(count);
}

Result BinaryReaderObjdump::BeginElemSegment(Index index,
                                             Index table_index,
                                             uint8_t flags) {
  table_index_ = table_index;
  elem_index_ = 0;
  elem_flags_ = flags;
  return Result::Ok;
}

Result BinaryReaderObjdump::OnElemSegmentElemType(Index index, Type elem_type) {
  // TODO: Add support for this.
  return Result::Ok;
}

Result BinaryReaderObjdump::OnElemSegmentElemExprCount(Index index,
                                                       Index count) {
  PrintDetails(" - segment[%" PRIindex "] flags=%d table=%" PRIindex
               " count=%" PRIindex,
               index, elem_flags_, table_index_, count);
  if (elem_flags_ & SegPassive) {
    PrintDetails("\n");
  } else {
    PrintInitExpr(current_init_expr_, /*as_unsigned=*/true);
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnGlobalCount(Index count) {
  return OnCount(count);
}

Result BinaryReaderObjdump::BeginGlobal(Index index, Type type, bool mutable_) {
  PrintDetails(" - global[%" PRIindex "] %s mutable=%d", index,
               type.GetName().c_str(), mutable_);
  std::string_view name = GetGlobalName(index);
  if (!name.empty()) {
    PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
  }
  return Result::Ok;
}

void BinaryReaderObjdump::PrintInitExpr(const InitExpr& expr,
                                        bool as_unsigned,
                                        bool with_prefix) {
  if (with_prefix) {
    PrintDetails(" - init ");
  }

  if (expr.insts.empty()) {
    PrintDetails("\n");
    return;
  }

  // We have two different way to print init expressions.  One for
  // extended expressions involving more than one instruction, and
  // a short form for the more traditional single instruction form.
  if (expr.insts.size() > 1) {
    PrintDetails("(");
    bool first = true;
    for (auto& inst : expr.insts) {
      if (!first) {
        PrintDetails(", ");
      }
      first = false;
      PrintDetails("%s", inst.opcode.GetName());
      switch (inst.opcode) {
        case Opcode::I32Const:
          PrintDetails(" %d", inst.imm.i32);
          break;
        case Opcode::I64Const:
          PrintDetails(" %" PRId64, inst.imm.i64);
          break;
        case Opcode::F32Const: {
          char buffer[WABT_MAX_FLOAT_HEX];
          WriteFloatHex(buffer, sizeof(buffer), inst.imm.f32);
          PrintDetails(" %s\n", buffer);
          break;
        }
        case Opcode::F64Const: {
          char buffer[WABT_MAX_DOUBLE_HEX];
          WriteDoubleHex(buffer, sizeof(buffer), inst.imm.f64);
          PrintDetails(" %s\n", buffer);
          break;
        }
        case Opcode::GlobalGet: {
          PrintDetails(" %" PRIindex, inst.imm.index);
          std::string_view name = GetGlobalName(inst.imm.index);
          if (!name.empty()) {
            PrintDetails(" <" PRIstringview ">",
                         WABT_PRINTF_STRING_VIEW_ARG(name));
          }
          break;
        }
        default:
          break;
      }
    }
    PrintDetails(")\n");
    return;
  }

  switch (expr.type) {
    case InitExprType::I32:
      if (as_unsigned) {
        PrintDetails("i32=%u\n", expr.insts[0].imm.i32);
      } else {
        PrintDetails("i32=%d\n", expr.insts[0].imm.i32);
      }
      break;
    case InitExprType::I64:
      if (as_unsigned) {
        PrintDetails("i64=%" PRIu64 "\n", expr.insts[0].imm.i64);
      } else {
        PrintDetails("i64=%" PRId64 "\n", expr.insts[0].imm.i64);
      }
      break;
    case InitExprType::F64: {
      char buffer[WABT_MAX_DOUBLE_HEX];
      WriteDoubleHex(buffer, sizeof(buffer), expr.insts[0].imm.f64);
      PrintDetails("f64=%s\n", buffer);
      break;
    }
    case InitExprType::F32: {
      char buffer[WABT_MAX_FLOAT_HEX];
      WriteFloatHex(buffer, sizeof(buffer), expr.insts[0].imm.f32);
      PrintDetails("f32=%s\n", buffer);
      break;
    }
    case InitExprType::V128: {
      PrintDetails(
          "v128=0x%08x 0x%08x 0x%08x 0x%08x \n",
          expr.insts[0].imm.v128_v.u32(0), expr.insts[0].imm.v128_v.u32(1),
          expr.insts[0].imm.v128_v.u32(2), expr.insts[0].imm.v128_v.u32(3));
      break;
    }
    case InitExprType::Global: {
      PrintDetails("global=%" PRIindex, expr.insts[0].imm.index);
      std::string_view name = GetGlobalName(expr.insts[0].imm.index);
      if (!name.empty()) {
        PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
      }
      PrintDetails("\n");
      break;
    }
    case InitExprType::FuncRef: {
      PrintDetails("ref.func:%" PRIindex, expr.insts[0].imm.index);
      std::string_view name = GetFunctionName(expr.insts[0].imm.index);
      if (!name.empty()) {
        PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
      }
      PrintDetails("\n");
      break;
    }
    case InitExprType::NullRef:
      PrintDetails("ref.null %s\n", expr.insts[0].imm.type.GetName().c_str());
      break;
    case InitExprType::Invalid:
      PrintDetails("\n");
      break;
  }
}

static void InitExprToConstOffset(const InitExpr& expr, uint64_t* out_offset) {
  if (expr.insts.size() == 1) {
    switch (expr.type) {
      case InitExprType::I32:
        *out_offset = expr.insts[0].imm.i32;
        break;
      case InitExprType::I64:
        *out_offset = expr.insts[0].imm.i64;
        break;
      default:
        break;
    }
  }
}

Result BinaryReaderObjdump::EndInitExpr() {
  if (reading_data_init_expr_) {
    reading_data_init_expr_ = false;
    InitExprToConstOffset(current_init_expr_, &data_offset_);
  } else if (reading_elem_init_expr_) {
    reading_elem_init_expr_ = false;
    InitExprToConstOffset(current_init_expr_, &elem_offset_);
  } else if (reading_global_init_expr_) {
    reading_global_init_expr_ = false;
    PrintInitExpr(current_init_expr_);
  } else if (reading_elem_expr_) {
    reading_elem_expr_ = false;
    PrintDetails(" - elem[%" PRIu64 "] = ", elem_offset_ + elem_index_);
    PrintInitExpr(current_init_expr_, /*as_unsigned=*/false,
                  /*with_prefix=*/false);
  } else {
    WABT_UNREACHABLE;
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnI32ConstExpr(uint32_t value) {
  if (ReadingInitExpr()) {
    current_init_expr_.type = InitExprType::I32;
    current_init_expr_.insts.back().imm.i32 = value;
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnI64ConstExpr(uint64_t value) {
  if (ReadingInitExpr()) {
    current_init_expr_.type = InitExprType::I64;
    current_init_expr_.insts.back().imm.i64 = value;
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnF32ConstExpr(uint32_t value) {
  if (ReadingInitExpr()) {
    current_init_expr_.type = InitExprType::F32;
    current_init_expr_.insts.back().imm.f32 = value;
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnF64ConstExpr(uint64_t value) {
  if (ReadingInitExpr()) {
    current_init_expr_.type = InitExprType::F64;
    current_init_expr_.insts.back().imm.f64 = value;
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnRefFuncExpr(Index func_index) {
  if (ReadingInitExpr()) {
    current_init_expr_.type = InitExprType::FuncRef;
    current_init_expr_.insts.back().imm.index = func_index;
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnRefNullExpr(Type type) {
  if (ReadingInitExpr()) {
    current_init_expr_.type = InitExprType::NullRef;
    current_init_expr_.insts.back().imm.type = type;
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnOpcode(Opcode opcode) {
  BinaryReaderObjdumpBase::OnOpcode(opcode);
  if (ReadingInitExpr() && opcode != Opcode::End) {
    InitInst i;
    i.opcode = current_opcode;
    current_init_expr_.insts.push_back(i);
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnGlobalGetExpr(Index global_index) {
  if (ReadingInitExpr()) {
    current_init_expr_.type = InitExprType::Global;
    current_init_expr_.insts.back().imm.index = global_index;
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnModuleName(std::string_view name) {
  PrintDetails(" - module <" PRIstringview ">\n",
               WABT_PRINTF_STRING_VIEW_ARG(name));
  return Result::Ok;
}

Result BinaryReaderObjdump::OnFunctionName(Index index, std::string_view name) {
  PrintDetails(" - func[%" PRIindex "] <" PRIstringview ">\n", index,
               WABT_PRINTF_STRING_VIEW_ARG(name));
  return Result::Ok;
}

Result BinaryReaderObjdump::OnNameEntry(NameSectionSubsection type,
                                        Index index,
                                        std::string_view name) {
  PrintDetails(" - %s[%" PRIindex "] <" PRIstringview ">\n",
               GetNameSectionSubsectionName(type), index,
               WABT_PRINTF_STRING_VIEW_ARG(name));
  return Result::Ok;
}

Result BinaryReaderObjdump::OnLocalName(Index func_index,
                                        Index local_index,
                                        std::string_view name) {
  if (!name.empty()) {
    PrintDetails(" - func[%" PRIindex "] local[%" PRIindex "] <" PRIstringview
                 ">\n",
                 func_index, local_index, WABT_PRINTF_STRING_VIEW_ARG(name));
  }
  return Result::Ok;
}

Result BinaryReaderObjdump::OnDataSegmentCount(Index count) {
  return OnCount(count);
}

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=97 G=95

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.