mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-21 04:42:53 +08:00
08dedd6631
bfd/ChangeLog: * bfd-in.h (startswith): Add startswith function. (CONST_STRNEQ): Remove. * bfd-in2.h (startswith): Regenerate with make headers. * archive.c (bfd_slurp_armap): Replace usage of CONST_STRNEQ with startswith. (_bfd_slurp_extended_name_table): Likewise. * archive64.c (_bfd_archive_64_bit_slurp_armap): Likewise. * bfd.c (bfd_get_sign_extend_vma): Likewise. (bfd_convert_section_size): Likewise. (bfd_convert_section_contents): Likewise. * coff-stgo32.c (go32exe_create_stub): Likewise. (go32exe_check_format): Likewise. * coffcode.h (styp_to_sec_flags): Likewise. (GNU_DEBUGALTLINK): Likewise. * coffgen.c (_bfd_coff_section_already_linked): Likewise. (coff_gc_sweep): Likewise. (bfd_coff_gc_sections): Likewise. * cofflink.c (coff_link_add_symbols): Likewise. (process_embedded_commands): Likewise. * compress.c (bfd_is_section_compressed_with_header): Likewise. (bfd_init_section_decompress_status): Likewise. * dwarf2.c (find_debug_info): Likewise. (place_sections): Likewise. * ecoff.c (_bfd_ecoff_slurp_armap): Likewise. * elf-m10300.c (_bfd_mn10300_elf_size_dynamic_sections): Likewise. * elf.c (_bfd_elf_make_section_from_shdr): Likewise. (assign_section_numbers): Likewise. (elfcore_grok_win32pstatus): Likewise. * elf32-arm.c (cmse_scan): Likewise. (elf32_arm_gc_mark_extra_sections): Likewise. (elf32_arm_size_dynamic_sections): Likewise. (is_arm_elf_unwind_section_name): Likewise. * elf32-bfin.c (bfin_size_dynamic_sections): Likewise. * elf32-cr16.c (_bfd_cr16_elf_size_dynamic_sections): Likewise. * elf32-cris.c (elf_cris_size_dynamic_sections): Likewise. * elf32-csky.c (csky_elf_size_dynamic_sections): Likewise. * elf32-hppa.c (elf32_hppa_size_dynamic_sections): Likewise. * elf32-iq2000.c (iq2000_elf_check_relocs): Likewise. * elf32-lm32.c (lm32_elf_size_dynamic_sections): Likewise. * elf32-m32r.c (m32r_elf_size_dynamic_sections): Likewise. * elf32-m68k.c (elf_m68k_size_dynamic_sections): Likewise. * elf32-metag.c (elf_metag_size_dynamic_sections): Likewise. * elf32-msp430.c (msp430_elf_relax_delete_bytes): Likewise. * elf32-nios2.c (nios2_elf32_size_dynamic_sections): Likewise. * elf32-or1k.c (or1k_elf_size_dynamic_sections): Likewise. * elf32-ppc.c (ppc_elf_size_dynamic_sections): Likewise. * elf32-s390.c (elf_s390_size_dynamic_sections): Likewise. * elf32-score.c (s3_bfd_score_elf_size_dynamic_sections): Likewise. * elf32-score7.c (s7_bfd_score_elf_size_dynamic_sections): Likewise. * elf32-sh.c (sh_elf_size_dynamic_sections): Likewise. * elf32-tic6x.c (is_tic6x_elf_unwind_section_name): Likewise. (elf32_tic6x_size_dynamic_sections): Likewise. * elf32-vax.c (elf_vax_size_dynamic_sections): Likewise. * elf32-xtensa.c (elf_xtensa_size_dynamic_sections): Likewise. (xtensa_is_insntable_section): Likewise. (xtensa_is_littable_section): Likewise. (xtensa_is_proptable_section): Likewise. (xtensa_property_section_name): Likewise. (xtensa_callback_required_dependence): Likewise. * elf64-alpha.c (elf64_alpha_size_dynamic_sections): Likewise. * elf64-hppa.c (elf64_hppa_size_dynamic_sections): Likewise. * elf64-ia64-vms.c (is_unwind_section_name): Likewise. (get_reloc_section): Likewise. (elf64_ia64_size_dynamic_sections): Likewise. (elf64_ia64_object_p): Likewise. * elf64-mmix.c (mmix_elf_add_symbol_hook): Likewise. * elf64-ppc.c (ppc64_elf_size_dynamic_sections): Likewise. * elf64-s390.c (elf_s390_size_dynamic_sections): Likewise. * elflink.c (elf_link_add_object_symbols): Likewise. (_bfd_elf_gc_mark_extra_sections): Likewise. (bfd_elf_parse_eh_frame_entries): Likewise. (_bfd_elf_section_already_linked): Likewise. * elfnn-aarch64.c (elfNN_aarch64_size_dynamic_sections): Likewise. * elfnn-ia64.c (is_unwind_section_name): Likewise. (elfNN_ia64_size_dynamic_sections): Likewise. (elfNN_ia64_object_p): Likewise. * elfxx-mips.c (FN_STUB_P): Likewise. (CALL_STUB_P): Likewise. (CALL_FP_STUB_P): Likewise. (_bfd_mips_elf_section_from_shdr): Likewise. (_bfd_mips_elf_fake_sections): Likewise. (_bfd_mips_elf_size_dynamic_sections): Likewise. (_bfd_mips_final_write_processing): Likewise. (_bfd_mips_elf_final_link): Likewise. * elfxx-sparc.c (_bfd_sparc_elf_size_dynamic_sections): Likewise. * elfxx-x86.c (elf_i386_is_reloc_section): Likewise. (elf_x86_64_is_reloc_section): Likewise. * hpux-core.c (thread_section_p): Likewise. * libcoff.h (bfd_pei_p): Likewise. * linker.c (REAL): Likewise. (unwrap_hash_lookup): Likewise. (_bfd_generic_link_add_one_symbol): Likewise. * mmo.c (mmo_internal_write_section): Likewise. * osf-core.c (osf_core_core_file_p): Likewise. * pef.c (bfd_pef_print_symbol): Likewise. * pei-x86_64.c (pex64_print_all_pdata_sections): Likewise. * som.c (som_slurp_symbol_table): Likewise. (som_slurp_armap): Likewise. * wasm-module.c (wasm_compute_custom_section_file_position): Likewise. binutils/ChangeLog: * dlltool.c (scan_drectve_symbols): Replace usage of CONST_STRNEQ with startswith. * emul_aix.c (ar_emul_aix_parse_arg): Likewise. * objcopy.c (is_mergeable_note_section): Likewise. * objdump.c (dump_dwarf_section): Likewise. * prdbg.c (pr_method_type): Likewise. (pr_class_baseclass): Likewise. (tg_class_baseclass): Likewise. * readelf.c (process_lto_symbol_tables): Likewise. * stabs.c (ULLHIGH): Likewise. (parse_stab_argtypes): Likewise. (stab_demangle_function_name): Likewise. gas/ChangeLog: * config/tc-i386.c (md_parse_option): Replace usage of CONST_STRNEQ with startswith. (x86_64_section_word): Likewise. * config/tc-sparc.c (md_parse_option): Likewise. gdb/ChangeLog: * arm-tdep.c (show_disassembly_style_sfunc): Replace usage of CONST_STRNEQ with startswith. (_initialize_arm_tdep): Likewise. ld/ChangeLog: * emultempl/aix.em: Replace usage of CONST_STRNEQ with startswith. * emultempl/beos.em: Likewise. * emultempl/elf.em: Likewise. * emultempl/pe.em: Likewise. * emultempl/pep.em: Likewise. * emultempl/xtensaelf.em: Likewise. * ldctor.c (ctor_prio): Likewise. * ldelf.c (ldelf_try_needed): Likewise. (ldelf_parse_ld_so_conf): Likewise. (ldelf_after_open): Likewise. (output_rel_find): Likewise. (ldelf_place_orphan): Likewise. * ldfile.c (ldfile_add_library_path): Likewise. * ldlang.c (lang_add_input_file): Likewise. * ldmain.c (get_sysroot): Likewise. (get_emulation): Likewise. (add_archive_element): Likewise. * ldwrite.c (unsplittable_name): Likewise. (clone_section): Likewise. * lexsup.c (parse_args): Likewise. * pe-dll.c (is_import): Likewise. (pe_implied_import_dll): Likewise. opcodes/ChangeLog: * aarch64-dis.c (parse_aarch64_dis_option): Replace usage of CONST_STRNEQ with startswith. * arc-dis.c (parse_option): Likewise. * arm-dis.c (parse_arm_disassembler_options): Likewise. * cris-dis.c (print_with_operands): Likewise. * h8300-dis.c (bfd_h8_disassemble): Likewise. * i386-dis.c (print_insn): Likewise. * ia64-gen.c (fetch_insn_class): Likewise. (parse_resource_users): Likewise. (in_iclass): Likewise. (lookup_specifier): Likewise. (insert_opcode_dependencies): Likewise. * mips-dis.c (parse_mips_ase_option): Likewise. (parse_mips_dis_option): Likewise. * s390-dis.c (disassemble_init_s390): Likewise. * wasm32-dis.c (parse_wasm32_disassembler_options): Likewise.
569 lines
13 KiB
C
569 lines
13 KiB
C
/* Opcode printing code for the WebAssembly target
|
|
Copyright (C) 2017-2021 Free Software Foundation, Inc.
|
|
|
|
This file is part of libopcodes.
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
It is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "sysdep.h"
|
|
#include "disassemble.h"
|
|
#include "opintl.h"
|
|
#include "safe-ctype.h"
|
|
#include "floatformat.h"
|
|
#include "libiberty.h"
|
|
#include "elf-bfd.h"
|
|
#include "elf/internal.h"
|
|
#include "elf/wasm32.h"
|
|
#include "bfd_stdint.h"
|
|
|
|
#ifdef HAVE_LIMITS_H
|
|
#include <limits.h>
|
|
#endif
|
|
#ifndef CHAR_BIT
|
|
#define CHAR_BIT 8
|
|
#endif
|
|
|
|
/* Type names for blocks and signatures. */
|
|
#define BLOCK_TYPE_NONE 0x40
|
|
#define BLOCK_TYPE_I32 0x7f
|
|
#define BLOCK_TYPE_I64 0x7e
|
|
#define BLOCK_TYPE_F32 0x7d
|
|
#define BLOCK_TYPE_F64 0x7c
|
|
|
|
enum wasm_class
|
|
{
|
|
wasm_typed,
|
|
wasm_special,
|
|
wasm_break,
|
|
wasm_break_if,
|
|
wasm_break_table,
|
|
wasm_return,
|
|
wasm_call,
|
|
wasm_call_import,
|
|
wasm_call_indirect,
|
|
wasm_get_local,
|
|
wasm_set_local,
|
|
wasm_tee_local,
|
|
wasm_drop,
|
|
wasm_constant_i32,
|
|
wasm_constant_i64,
|
|
wasm_constant_f32,
|
|
wasm_constant_f64,
|
|
wasm_unary,
|
|
wasm_binary,
|
|
wasm_conv,
|
|
wasm_load,
|
|
wasm_store,
|
|
wasm_select,
|
|
wasm_relational,
|
|
wasm_eqz,
|
|
wasm_current_memory,
|
|
wasm_grow_memory,
|
|
wasm_signature
|
|
};
|
|
|
|
struct wasm32_private_data
|
|
{
|
|
bfd_boolean print_registers;
|
|
bfd_boolean print_well_known_globals;
|
|
|
|
/* Limit valid symbols to those with a given prefix. */
|
|
const char *section_prefix;
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
const char *name;
|
|
const char *description;
|
|
} wasm32_options_t;
|
|
|
|
static const wasm32_options_t options[] =
|
|
{
|
|
{ "registers", N_("Disassemble \"register\" names") },
|
|
{ "globals", N_("Name well-known globals") },
|
|
};
|
|
|
|
#define WASM_OPCODE(opcode, name, intype, outtype, clas, signedness) \
|
|
{ name, wasm_ ## clas, opcode },
|
|
|
|
struct wasm32_opcode_s
|
|
{
|
|
const char *name;
|
|
enum wasm_class clas;
|
|
unsigned char opcode;
|
|
} wasm32_opcodes[] =
|
|
{
|
|
#include "opcode/wasm.h"
|
|
{ NULL, 0, 0 }
|
|
};
|
|
|
|
/* Parse the disassembler options in OPTS and initialize INFO. */
|
|
|
|
static void
|
|
parse_wasm32_disassembler_options (struct disassemble_info *info,
|
|
const char *opts)
|
|
{
|
|
struct wasm32_private_data *private = info->private_data;
|
|
|
|
while (opts != NULL)
|
|
{
|
|
if (startswith (opts, "registers"))
|
|
private->print_registers = TRUE;
|
|
else if (startswith (opts, "globals"))
|
|
private->print_well_known_globals = TRUE;
|
|
|
|
opts = strchr (opts, ',');
|
|
if (opts)
|
|
opts++;
|
|
}
|
|
}
|
|
|
|
/* Check whether SYM is valid. Special-case absolute symbols, which
|
|
are unhelpful to print, and arguments to a "call" insn, which we
|
|
want to be in a section matching a given prefix. */
|
|
|
|
static bfd_boolean
|
|
wasm32_symbol_is_valid (asymbol *sym,
|
|
struct disassemble_info *info)
|
|
{
|
|
struct wasm32_private_data *private_data = info->private_data;
|
|
|
|
if (sym == NULL)
|
|
return FALSE;
|
|
|
|
if (strcmp(sym->section->name, "*ABS*") == 0)
|
|
return FALSE;
|
|
|
|
if (private_data && private_data->section_prefix != NULL
|
|
&& strncmp (sym->section->name, private_data->section_prefix,
|
|
strlen (private_data->section_prefix)))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Initialize the disassembler structures for INFO. */
|
|
|
|
void
|
|
disassemble_init_wasm32 (struct disassemble_info *info)
|
|
{
|
|
if (info->private_data == NULL)
|
|
{
|
|
static struct wasm32_private_data private;
|
|
|
|
private.print_registers = FALSE;
|
|
private.print_well_known_globals = FALSE;
|
|
private.section_prefix = NULL;
|
|
|
|
info->private_data = &private;
|
|
}
|
|
|
|
if (info->disassembler_options)
|
|
{
|
|
parse_wasm32_disassembler_options (info, info->disassembler_options);
|
|
|
|
info->disassembler_options = NULL;
|
|
}
|
|
|
|
info->symbol_is_valid = wasm32_symbol_is_valid;
|
|
}
|
|
|
|
/* Read an LEB128-encoded integer from INFO at address PC, reading one
|
|
byte at a time. Set ERROR_RETURN if no complete integer could be
|
|
read, LENGTH_RETURN to the number oof bytes read (including bytes
|
|
in incomplete numbers). SIGN means interpret the number as
|
|
SLEB128. Unfortunately, this is a duplicate of wasm-module.c's
|
|
wasm_read_leb128 (). */
|
|
|
|
static uint64_t
|
|
wasm_read_leb128 (bfd_vma pc,
|
|
struct disassemble_info * info,
|
|
bfd_boolean * error_return,
|
|
unsigned int * length_return,
|
|
bfd_boolean sign)
|
|
{
|
|
uint64_t result = 0;
|
|
unsigned int num_read = 0;
|
|
unsigned int shift = 0;
|
|
unsigned char byte = 0;
|
|
unsigned char lost, mask;
|
|
int status = 1;
|
|
|
|
while (info->read_memory_func (pc + num_read, &byte, 1, info) == 0)
|
|
{
|
|
num_read++;
|
|
|
|
if (shift < CHAR_BIT * sizeof (result))
|
|
{
|
|
result |= ((uint64_t) (byte & 0x7f)) << shift;
|
|
/* These bits overflowed. */
|
|
lost = byte ^ (result >> shift);
|
|
/* And this is the mask of possible overflow bits. */
|
|
mask = 0x7f ^ ((uint64_t) 0x7f << shift >> shift);
|
|
shift += 7;
|
|
}
|
|
else
|
|
{
|
|
lost = byte;
|
|
mask = 0x7f;
|
|
}
|
|
if ((lost & mask) != (sign && (int64_t) result < 0 ? mask : 0))
|
|
status |= 2;
|
|
|
|
if ((byte & 0x80) == 0)
|
|
{
|
|
status &= ~1;
|
|
if (sign && shift < CHAR_BIT * sizeof (result) && (byte & 0x40))
|
|
result |= -((uint64_t) 1 << shift);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (length_return != NULL)
|
|
*length_return = num_read;
|
|
if (error_return != NULL)
|
|
*error_return = status != 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
/* Read a 32-bit IEEE float from PC using INFO, convert it to a host
|
|
double, and store it at VALUE. */
|
|
|
|
static int
|
|
read_f32 (double *value, bfd_vma pc, struct disassemble_info *info)
|
|
{
|
|
bfd_byte buf[4];
|
|
|
|
if (info->read_memory_func (pc, buf, sizeof (buf), info))
|
|
return -1;
|
|
|
|
floatformat_to_double (&floatformat_ieee_single_little, buf,
|
|
value);
|
|
|
|
return sizeof (buf);
|
|
}
|
|
|
|
/* Read a 64-bit IEEE float from PC using INFO, convert it to a host
|
|
double, and store it at VALUE. */
|
|
|
|
static int
|
|
read_f64 (double *value, bfd_vma pc, struct disassemble_info *info)
|
|
{
|
|
bfd_byte buf[8];
|
|
|
|
if (info->read_memory_func (pc, buf, sizeof (buf), info))
|
|
return -1;
|
|
|
|
floatformat_to_double (&floatformat_ieee_double_little, buf,
|
|
value);
|
|
|
|
return sizeof (buf);
|
|
}
|
|
|
|
/* Main disassembly routine. Disassemble insn at PC using INFO. */
|
|
|
|
int
|
|
print_insn_wasm32 (bfd_vma pc, struct disassemble_info *info)
|
|
{
|
|
unsigned char opcode;
|
|
struct wasm32_opcode_s *op;
|
|
bfd_byte buffer[16];
|
|
void *stream = info->stream;
|
|
fprintf_ftype prin = info->fprintf_func;
|
|
struct wasm32_private_data *private_data = info->private_data;
|
|
uint64_t val;
|
|
int len;
|
|
unsigned int bytes_read;
|
|
bfd_boolean error;
|
|
|
|
if (info->read_memory_func (pc, buffer, 1, info))
|
|
return -1;
|
|
|
|
opcode = buffer[0];
|
|
|
|
for (op = wasm32_opcodes; op->name; op++)
|
|
if (op->opcode == opcode)
|
|
break;
|
|
|
|
if (!op->name)
|
|
{
|
|
prin (stream, "\t.byte 0x%02x\n", buffer[0]);
|
|
return 1;
|
|
}
|
|
|
|
len = 1;
|
|
|
|
prin (stream, "\t");
|
|
prin (stream, "%s", op->name);
|
|
|
|
if (op->clas == wasm_typed)
|
|
{
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read, FALSE);
|
|
if (error)
|
|
return -1;
|
|
len += bytes_read;
|
|
switch (val)
|
|
{
|
|
case BLOCK_TYPE_NONE:
|
|
prin (stream, "[]");
|
|
break;
|
|
case BLOCK_TYPE_I32:
|
|
prin (stream, "[i]");
|
|
break;
|
|
case BLOCK_TYPE_I64:
|
|
prin (stream, "[l]");
|
|
break;
|
|
case BLOCK_TYPE_F32:
|
|
prin (stream, "[f]");
|
|
break;
|
|
case BLOCK_TYPE_F64:
|
|
prin (stream, "[d]");
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
switch (op->clas)
|
|
{
|
|
case wasm_special:
|
|
case wasm_eqz:
|
|
case wasm_binary:
|
|
case wasm_unary:
|
|
case wasm_conv:
|
|
case wasm_relational:
|
|
case wasm_drop:
|
|
case wasm_signature:
|
|
case wasm_call_import:
|
|
case wasm_typed:
|
|
case wasm_select:
|
|
break;
|
|
|
|
case wasm_break_table:
|
|
{
|
|
uint32_t target_count, i;
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
|
|
FALSE);
|
|
target_count = val;
|
|
if (error || target_count != val || target_count == (uint32_t) -1)
|
|
return -1;
|
|
len += bytes_read;
|
|
prin (stream, " %u", target_count);
|
|
for (i = 0; i < target_count + 1; i++)
|
|
{
|
|
uint32_t target;
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
|
|
FALSE);
|
|
target = val;
|
|
if (error || target != val)
|
|
return -1;
|
|
len += bytes_read;
|
|
prin (stream, " %u", target);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case wasm_break:
|
|
case wasm_break_if:
|
|
{
|
|
uint32_t depth;
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
|
|
FALSE);
|
|
depth = val;
|
|
if (error || depth != val)
|
|
return -1;
|
|
len += bytes_read;
|
|
prin (stream, " %u", depth);
|
|
}
|
|
break;
|
|
|
|
case wasm_return:
|
|
break;
|
|
|
|
case wasm_constant_i32:
|
|
case wasm_constant_i64:
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read, TRUE);
|
|
if (error)
|
|
return -1;
|
|
len += bytes_read;
|
|
prin (stream, " %" PRId64, val);
|
|
break;
|
|
|
|
case wasm_constant_f32:
|
|
{
|
|
double fconstant;
|
|
int ret;
|
|
/* This appears to be the best we can do, even though we're
|
|
using host doubles for WebAssembly floats. */
|
|
ret = read_f32 (&fconstant, pc + len, info);
|
|
if (ret < 0)
|
|
return -1;
|
|
len += ret;
|
|
prin (stream, " %.9g", fconstant);
|
|
}
|
|
break;
|
|
|
|
case wasm_constant_f64:
|
|
{
|
|
double fconstant;
|
|
int ret;
|
|
ret = read_f64 (&fconstant, pc + len, info);
|
|
if (ret < 0)
|
|
return -1;
|
|
len += ret;
|
|
prin (stream, " %.17g", fconstant);
|
|
}
|
|
break;
|
|
|
|
case wasm_call:
|
|
{
|
|
uint32_t function_index;
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
|
|
FALSE);
|
|
function_index = val;
|
|
if (error || function_index != val)
|
|
return -1;
|
|
len += bytes_read;
|
|
prin (stream, " ");
|
|
private_data->section_prefix = ".space.function_index";
|
|
(*info->print_address_func) ((bfd_vma) function_index, info);
|
|
private_data->section_prefix = NULL;
|
|
}
|
|
break;
|
|
|
|
case wasm_call_indirect:
|
|
{
|
|
uint32_t type_index, xtra_index;
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
|
|
FALSE);
|
|
type_index = val;
|
|
if (error || type_index != val)
|
|
return -1;
|
|
len += bytes_read;
|
|
prin (stream, " %u", type_index);
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
|
|
FALSE);
|
|
xtra_index = val;
|
|
if (error || xtra_index != val)
|
|
return -1;
|
|
len += bytes_read;
|
|
prin (stream, " %u", xtra_index);
|
|
}
|
|
break;
|
|
|
|
case wasm_get_local:
|
|
case wasm_set_local:
|
|
case wasm_tee_local:
|
|
{
|
|
uint32_t local_index;
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
|
|
FALSE);
|
|
local_index = val;
|
|
if (error || local_index != val)
|
|
return -1;
|
|
len += bytes_read;
|
|
prin (stream, " %u", local_index);
|
|
if (strcmp (op->name + 4, "local") == 0)
|
|
{
|
|
static const char *locals[] =
|
|
{
|
|
"$dpc", "$sp1", "$r0", "$r1", "$rpc", "$pc0",
|
|
"$rp", "$fp", "$sp",
|
|
"$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
|
|
"$i0", "$i1", "$i2", "$i3", "$i4", "$i5", "$i6", "$i7",
|
|
"$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
|
|
};
|
|
if (private_data->print_registers
|
|
&& local_index < ARRAY_SIZE (locals))
|
|
prin (stream, " <%s>", locals[local_index]);
|
|
}
|
|
else
|
|
{
|
|
static const char *globals[] =
|
|
{
|
|
"$got", "$plt", "$gpo"
|
|
};
|
|
if (private_data->print_well_known_globals
|
|
&& local_index < ARRAY_SIZE (globals))
|
|
prin (stream, " <%s>", globals[local_index]);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case wasm_grow_memory:
|
|
case wasm_current_memory:
|
|
{
|
|
uint32_t reserved_size;
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
|
|
FALSE);
|
|
reserved_size = val;
|
|
if (error || reserved_size != val)
|
|
return -1;
|
|
len += bytes_read;
|
|
prin (stream, " %u", reserved_size);
|
|
}
|
|
break;
|
|
|
|
case wasm_load:
|
|
case wasm_store:
|
|
{
|
|
uint32_t flags, offset;
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
|
|
FALSE);
|
|
flags = val;
|
|
if (error || flags != val)
|
|
return -1;
|
|
len += bytes_read;
|
|
val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
|
|
FALSE);
|
|
offset = val;
|
|
if (error || offset != val)
|
|
return -1;
|
|
len += bytes_read;
|
|
prin (stream, " a=%u %u", flags, offset);
|
|
}
|
|
break;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
/* Print valid disassembler options to STREAM. */
|
|
|
|
void
|
|
print_wasm32_disassembler_options (FILE *stream)
|
|
{
|
|
unsigned int i, max_len = 0;
|
|
|
|
fprintf (stream, _("\
|
|
The following WebAssembly-specific disassembler options are supported for use\n\
|
|
with the -M switch:\n"));
|
|
|
|
for (i = 0; i < ARRAY_SIZE (options); i++)
|
|
{
|
|
unsigned int len = strlen (options[i].name);
|
|
|
|
if (max_len < len)
|
|
max_len = len;
|
|
}
|
|
|
|
for (i = 0, max_len++; i < ARRAY_SIZE (options); i++)
|
|
fprintf (stream, " %s%*c %s\n",
|
|
options[i].name,
|
|
(int)(max_len - strlen (options[i].name)), ' ',
|
|
_(options[i].description));
|
|
}
|