xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/wasm32-dis.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1e6c7e151Schristos /* Opcode printing code for the WebAssembly target
2*c42dbd0eSchristos    Copyright (C) 2017-2022 Free Software Foundation, Inc.
3e6c7e151Schristos 
4e6c7e151Schristos    This file is part of libopcodes.
5e6c7e151Schristos 
6e6c7e151Schristos    This library is free software; you can redistribute it and/or modify
7e6c7e151Schristos    it under the terms of the GNU General Public License as published by
8e6c7e151Schristos    the Free Software Foundation; either version 3 of the License, or
9e6c7e151Schristos    (at your option) any later version.
10e6c7e151Schristos 
11e6c7e151Schristos    It is distributed in the hope that it will be useful, but WITHOUT
12e6c7e151Schristos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13e6c7e151Schristos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14e6c7e151Schristos    License for more details.
15e6c7e151Schristos 
16e6c7e151Schristos    You should have received a copy of the GNU General Public License
17e6c7e151Schristos    along with this program; if not, write to the Free Software
18e6c7e151Schristos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19e6c7e151Schristos    MA 02110-1301, USA.  */
20e6c7e151Schristos 
21e6c7e151Schristos #include "sysdep.h"
22e6c7e151Schristos #include "disassemble.h"
23e6c7e151Schristos #include "opintl.h"
24e6c7e151Schristos #include "safe-ctype.h"
25e6c7e151Schristos #include "floatformat.h"
26e6c7e151Schristos #include "libiberty.h"
27e6c7e151Schristos #include "elf-bfd.h"
28e6c7e151Schristos #include "elf/internal.h"
29e6c7e151Schristos #include "elf/wasm32.h"
30*c42dbd0eSchristos #include <stdint.h>
31*c42dbd0eSchristos 
32*c42dbd0eSchristos #include <limits.h>
33*c42dbd0eSchristos #ifndef CHAR_BIT
34*c42dbd0eSchristos #define CHAR_BIT 8
35*c42dbd0eSchristos #endif
36e6c7e151Schristos 
37e6c7e151Schristos /* Type names for blocks and signatures.  */
38e6c7e151Schristos #define BLOCK_TYPE_NONE              0x40
39e6c7e151Schristos #define BLOCK_TYPE_I32               0x7f
40e6c7e151Schristos #define BLOCK_TYPE_I64               0x7e
41e6c7e151Schristos #define BLOCK_TYPE_F32               0x7d
42e6c7e151Schristos #define BLOCK_TYPE_F64               0x7c
43e6c7e151Schristos 
44e6c7e151Schristos enum wasm_class
45e6c7e151Schristos {
46e6c7e151Schristos   wasm_typed,
47e6c7e151Schristos   wasm_special,
48e6c7e151Schristos   wasm_break,
49e6c7e151Schristos   wasm_break_if,
50e6c7e151Schristos   wasm_break_table,
51e6c7e151Schristos   wasm_return,
52e6c7e151Schristos   wasm_call,
53e6c7e151Schristos   wasm_call_import,
54e6c7e151Schristos   wasm_call_indirect,
55e6c7e151Schristos   wasm_get_local,
56e6c7e151Schristos   wasm_set_local,
57e6c7e151Schristos   wasm_tee_local,
58e6c7e151Schristos   wasm_drop,
59e6c7e151Schristos   wasm_constant_i32,
60e6c7e151Schristos   wasm_constant_i64,
61e6c7e151Schristos   wasm_constant_f32,
62e6c7e151Schristos   wasm_constant_f64,
63e6c7e151Schristos   wasm_unary,
64e6c7e151Schristos   wasm_binary,
65e6c7e151Schristos   wasm_conv,
66e6c7e151Schristos   wasm_load,
67e6c7e151Schristos   wasm_store,
68e6c7e151Schristos   wasm_select,
69e6c7e151Schristos   wasm_relational,
70e6c7e151Schristos   wasm_eqz,
71e6c7e151Schristos   wasm_current_memory,
72e6c7e151Schristos   wasm_grow_memory,
73e6c7e151Schristos   wasm_signature
74e6c7e151Schristos };
75e6c7e151Schristos 
76e6c7e151Schristos struct wasm32_private_data
77e6c7e151Schristos {
78*c42dbd0eSchristos   bool print_registers;
79*c42dbd0eSchristos   bool print_well_known_globals;
80e6c7e151Schristos 
81e6c7e151Schristos   /* Limit valid symbols to those with a given prefix.  */
82e6c7e151Schristos   const char *section_prefix;
83e6c7e151Schristos };
84e6c7e151Schristos 
85e6c7e151Schristos typedef struct
86e6c7e151Schristos {
87e6c7e151Schristos   const char *name;
88e6c7e151Schristos   const char *description;
89e6c7e151Schristos } wasm32_options_t;
90e6c7e151Schristos 
91e6c7e151Schristos static const wasm32_options_t options[] =
92e6c7e151Schristos {
93e6c7e151Schristos   { "registers", N_("Disassemble \"register\" names") },
94e6c7e151Schristos   { "globals",   N_("Name well-known globals") },
95e6c7e151Schristos };
96e6c7e151Schristos 
97e6c7e151Schristos #define WASM_OPCODE(opcode, name, intype, outtype, clas, signedness)     \
98e6c7e151Schristos   { name, wasm_ ## clas, opcode },
99e6c7e151Schristos 
100e6c7e151Schristos struct wasm32_opcode_s
101e6c7e151Schristos {
102e6c7e151Schristos   const char *name;
103e6c7e151Schristos   enum wasm_class clas;
104e6c7e151Schristos   unsigned char opcode;
105e6c7e151Schristos } wasm32_opcodes[] =
106e6c7e151Schristos {
107e6c7e151Schristos #include "opcode/wasm.h"
108e6c7e151Schristos   { NULL, 0, 0 }
109e6c7e151Schristos };
110e6c7e151Schristos 
111e6c7e151Schristos /* Parse the disassembler options in OPTS and initialize INFO.  */
112e6c7e151Schristos 
113e6c7e151Schristos static void
parse_wasm32_disassembler_options(struct disassemble_info * info,const char * opts)114e6c7e151Schristos parse_wasm32_disassembler_options (struct disassemble_info *info,
115e6c7e151Schristos                                    const char *opts)
116e6c7e151Schristos {
117e6c7e151Schristos   struct wasm32_private_data *private = info->private_data;
118e6c7e151Schristos 
119e6c7e151Schristos   while (opts != NULL)
120e6c7e151Schristos     {
121*c42dbd0eSchristos       if (startswith (opts, "registers"))
122*c42dbd0eSchristos         private->print_registers = true;
123*c42dbd0eSchristos       else if (startswith (opts, "globals"))
124*c42dbd0eSchristos         private->print_well_known_globals = true;
125e6c7e151Schristos 
126e6c7e151Schristos       opts = strchr (opts, ',');
127e6c7e151Schristos       if (opts)
128e6c7e151Schristos         opts++;
129e6c7e151Schristos     }
130e6c7e151Schristos }
131e6c7e151Schristos 
132e6c7e151Schristos /* Check whether SYM is valid.  Special-case absolute symbols, which
133e6c7e151Schristos    are unhelpful to print, and arguments to a "call" insn, which we
134e6c7e151Schristos    want to be in a section matching a given prefix.  */
135e6c7e151Schristos 
136*c42dbd0eSchristos static bool
wasm32_symbol_is_valid(asymbol * sym,struct disassemble_info * info)137e6c7e151Schristos wasm32_symbol_is_valid (asymbol *sym,
138e6c7e151Schristos                         struct disassemble_info *info)
139e6c7e151Schristos {
140e6c7e151Schristos   struct wasm32_private_data *private_data = info->private_data;
141e6c7e151Schristos 
142e6c7e151Schristos   if (sym == NULL)
143*c42dbd0eSchristos     return false;
144e6c7e151Schristos 
145e6c7e151Schristos   if (strcmp(sym->section->name, "*ABS*") == 0)
146*c42dbd0eSchristos     return false;
147e6c7e151Schristos 
148e6c7e151Schristos   if (private_data && private_data->section_prefix != NULL
149e6c7e151Schristos       && strncmp (sym->section->name, private_data->section_prefix,
150e6c7e151Schristos                   strlen (private_data->section_prefix)))
151*c42dbd0eSchristos     return false;
152e6c7e151Schristos 
153*c42dbd0eSchristos   return true;
154e6c7e151Schristos }
155e6c7e151Schristos 
156e6c7e151Schristos /* Initialize the disassembler structures for INFO.  */
157e6c7e151Schristos 
158e6c7e151Schristos void
disassemble_init_wasm32(struct disassemble_info * info)159e6c7e151Schristos disassemble_init_wasm32 (struct disassemble_info *info)
160e6c7e151Schristos {
161e6c7e151Schristos   if (info->private_data == NULL)
162e6c7e151Schristos     {
163e6c7e151Schristos       static struct wasm32_private_data private;
164e6c7e151Schristos 
165*c42dbd0eSchristos       private.print_registers = false;
166*c42dbd0eSchristos       private.print_well_known_globals = false;
167e6c7e151Schristos       private.section_prefix = NULL;
168e6c7e151Schristos 
169e6c7e151Schristos       info->private_data = &private;
170e6c7e151Schristos     }
171e6c7e151Schristos 
172e6c7e151Schristos   if (info->disassembler_options)
173e6c7e151Schristos     {
174e6c7e151Schristos       parse_wasm32_disassembler_options (info, info->disassembler_options);
175e6c7e151Schristos 
176e6c7e151Schristos       info->disassembler_options = NULL;
177e6c7e151Schristos     }
178e6c7e151Schristos 
179e6c7e151Schristos   info->symbol_is_valid = wasm32_symbol_is_valid;
180e6c7e151Schristos }
181e6c7e151Schristos 
182e6c7e151Schristos /* Read an LEB128-encoded integer from INFO at address PC, reading one
183e6c7e151Schristos    byte at a time.  Set ERROR_RETURN if no complete integer could be
184e6c7e151Schristos    read, LENGTH_RETURN to the number oof bytes read (including bytes
185e6c7e151Schristos    in incomplete numbers).  SIGN means interpret the number as
186e6c7e151Schristos    SLEB128.  Unfortunately, this is a duplicate of wasm-module.c's
187e6c7e151Schristos    wasm_read_leb128 ().  */
188e6c7e151Schristos 
189e6c7e151Schristos static uint64_t
wasm_read_leb128(bfd_vma pc,struct disassemble_info * info,bool * error_return,unsigned int * length_return,bool sign)190e6c7e151Schristos wasm_read_leb128 (bfd_vma pc,
191e6c7e151Schristos                   struct disassemble_info *info,
192*c42dbd0eSchristos                   bool *error_return,
193e6c7e151Schristos                   unsigned int *length_return,
194*c42dbd0eSchristos                   bool sign)
195e6c7e151Schristos {
196e6c7e151Schristos   uint64_t result = 0;
197e6c7e151Schristos   unsigned int num_read = 0;
198e6c7e151Schristos   unsigned int shift = 0;
199e6c7e151Schristos   unsigned char byte = 0;
200*c42dbd0eSchristos   unsigned char lost, mask;
201867d70fcSchristos   int status = 1;
202e6c7e151Schristos 
203e6c7e151Schristos   while (info->read_memory_func (pc + num_read, &byte, 1, info) == 0)
204e6c7e151Schristos     {
205e6c7e151Schristos       num_read++;
206e6c7e151Schristos 
207*c42dbd0eSchristos       if (shift < CHAR_BIT * sizeof (result))
208867d70fcSchristos 	{
209867d70fcSchristos 	  result |= ((uint64_t) (byte & 0x7f)) << shift;
210*c42dbd0eSchristos 	  /* These bits overflowed.  */
211*c42dbd0eSchristos 	  lost = byte ^ (result >> shift);
212*c42dbd0eSchristos 	  /* And this is the mask of possible overflow bits.  */
213*c42dbd0eSchristos 	  mask = 0x7f ^ ((uint64_t) 0x7f << shift >> shift);
214e6c7e151Schristos 	  shift += 7;
215867d70fcSchristos 	}
216*c42dbd0eSchristos       else
217*c42dbd0eSchristos 	{
218*c42dbd0eSchristos 	  lost = byte;
219*c42dbd0eSchristos 	  mask = 0x7f;
220*c42dbd0eSchristos 	}
221*c42dbd0eSchristos       if ((lost & mask) != (sign && (int64_t) result < 0 ? mask : 0))
222867d70fcSchristos 	status |= 2;
223867d70fcSchristos 
224e6c7e151Schristos       if ((byte & 0x80) == 0)
225e6c7e151Schristos 	{
226867d70fcSchristos 	  status &= ~1;
227*c42dbd0eSchristos 	  if (sign && shift < CHAR_BIT * sizeof (result) && (byte & 0x40))
228867d70fcSchristos 	    result |= -((uint64_t) 1 << shift);
229e6c7e151Schristos 	  break;
230e6c7e151Schristos 	}
231e6c7e151Schristos     }
232e6c7e151Schristos 
233e6c7e151Schristos   if (length_return != NULL)
234e6c7e151Schristos     *length_return = num_read;
235e6c7e151Schristos   if (error_return != NULL)
236867d70fcSchristos     *error_return = status != 0;
237e6c7e151Schristos 
238e6c7e151Schristos   return result;
239e6c7e151Schristos }
240e6c7e151Schristos 
241e6c7e151Schristos /* Read a 32-bit IEEE float from PC using INFO, convert it to a host
242e6c7e151Schristos    double, and store it at VALUE.  */
243e6c7e151Schristos 
244e6c7e151Schristos static int
read_f32(double * value,bfd_vma pc,struct disassemble_info * info)245e6c7e151Schristos read_f32 (double *value, bfd_vma pc, struct disassemble_info *info)
246e6c7e151Schristos {
247e6c7e151Schristos   bfd_byte buf[4];
248e6c7e151Schristos 
249e6c7e151Schristos   if (info->read_memory_func (pc, buf, sizeof (buf), info))
250e6c7e151Schristos     return -1;
251e6c7e151Schristos 
252e6c7e151Schristos   floatformat_to_double (&floatformat_ieee_single_little, buf,
253e6c7e151Schristos                          value);
254e6c7e151Schristos 
255e6c7e151Schristos   return sizeof (buf);
256e6c7e151Schristos }
257e6c7e151Schristos 
258e6c7e151Schristos /* Read a 64-bit IEEE float from PC using INFO, convert it to a host
259e6c7e151Schristos    double, and store it at VALUE.  */
260e6c7e151Schristos 
261e6c7e151Schristos static int
read_f64(double * value,bfd_vma pc,struct disassemble_info * info)262e6c7e151Schristos read_f64 (double *value, bfd_vma pc, struct disassemble_info *info)
263e6c7e151Schristos {
264e6c7e151Schristos   bfd_byte buf[8];
265e6c7e151Schristos 
266e6c7e151Schristos   if (info->read_memory_func (pc, buf, sizeof (buf), info))
267e6c7e151Schristos     return -1;
268e6c7e151Schristos 
269e6c7e151Schristos   floatformat_to_double (&floatformat_ieee_double_little, buf,
270e6c7e151Schristos                          value);
271e6c7e151Schristos 
272e6c7e151Schristos   return sizeof (buf);
273e6c7e151Schristos }
274e6c7e151Schristos 
275e6c7e151Schristos /* Main disassembly routine.  Disassemble insn at PC using INFO.  */
276e6c7e151Schristos 
277e6c7e151Schristos int
print_insn_wasm32(bfd_vma pc,struct disassemble_info * info)278e6c7e151Schristos print_insn_wasm32 (bfd_vma pc, struct disassemble_info *info)
279e6c7e151Schristos {
280e6c7e151Schristos   unsigned char opcode;
281e6c7e151Schristos   struct wasm32_opcode_s *op;
282e6c7e151Schristos   bfd_byte buffer[16];
283e6c7e151Schristos   void *stream = info->stream;
284e6c7e151Schristos   fprintf_ftype prin = info->fprintf_func;
285e6c7e151Schristos   struct wasm32_private_data *private_data = info->private_data;
286867d70fcSchristos   uint64_t val;
287867d70fcSchristos   int len;
288867d70fcSchristos   unsigned int bytes_read;
289*c42dbd0eSchristos   bool error;
290e6c7e151Schristos 
291e6c7e151Schristos   if (info->read_memory_func (pc, buffer, 1, info))
292e6c7e151Schristos     return -1;
293e6c7e151Schristos 
294e6c7e151Schristos   opcode = buffer[0];
295e6c7e151Schristos 
296e6c7e151Schristos   for (op = wasm32_opcodes; op->name; op++)
297e6c7e151Schristos     if (op->opcode == opcode)
298e6c7e151Schristos       break;
299e6c7e151Schristos 
300e6c7e151Schristos   if (!op->name)
301e6c7e151Schristos     {
302e6c7e151Schristos       prin (stream, "\t.byte 0x%02x\n", buffer[0]);
303e6c7e151Schristos       return 1;
304e6c7e151Schristos     }
305867d70fcSchristos 
306e6c7e151Schristos   len = 1;
307e6c7e151Schristos 
308e6c7e151Schristos   prin (stream, "\t");
309e6c7e151Schristos   prin (stream, "%s", op->name);
310e6c7e151Schristos 
311e6c7e151Schristos   if (op->clas == wasm_typed)
312e6c7e151Schristos     {
313*c42dbd0eSchristos       val = wasm_read_leb128 (pc + len, info, &error, &bytes_read, false);
314e6c7e151Schristos       if (error)
315e6c7e151Schristos 	return -1;
316e6c7e151Schristos       len += bytes_read;
317867d70fcSchristos       switch (val)
318e6c7e151Schristos 	{
319e6c7e151Schristos 	case BLOCK_TYPE_NONE:
320e6c7e151Schristos 	  prin (stream, "[]");
321e6c7e151Schristos 	  break;
322e6c7e151Schristos 	case BLOCK_TYPE_I32:
323e6c7e151Schristos 	  prin (stream, "[i]");
324e6c7e151Schristos 	  break;
325e6c7e151Schristos 	case BLOCK_TYPE_I64:
326e6c7e151Schristos 	  prin (stream, "[l]");
327e6c7e151Schristos 	  break;
328e6c7e151Schristos 	case BLOCK_TYPE_F32:
329e6c7e151Schristos 	  prin (stream, "[f]");
330e6c7e151Schristos 	  break;
331e6c7e151Schristos 	case BLOCK_TYPE_F64:
332e6c7e151Schristos 	  prin (stream, "[d]");
333e6c7e151Schristos 	  break;
334867d70fcSchristos 	default:
335867d70fcSchristos 	  return -1;
336e6c7e151Schristos 	}
337e6c7e151Schristos     }
338e6c7e151Schristos 
339e6c7e151Schristos   switch (op->clas)
340e6c7e151Schristos     {
341e6c7e151Schristos     case wasm_special:
342e6c7e151Schristos     case wasm_eqz:
343e6c7e151Schristos     case wasm_binary:
344e6c7e151Schristos     case wasm_unary:
345e6c7e151Schristos     case wasm_conv:
346e6c7e151Schristos     case wasm_relational:
347e6c7e151Schristos     case wasm_drop:
348e6c7e151Schristos     case wasm_signature:
349e6c7e151Schristos     case wasm_call_import:
350e6c7e151Schristos     case wasm_typed:
351e6c7e151Schristos     case wasm_select:
352e6c7e151Schristos       break;
353e6c7e151Schristos 
354e6c7e151Schristos     case wasm_break_table:
355867d70fcSchristos       {
356867d70fcSchristos 	uint32_t target_count, i;
357867d70fcSchristos 	val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
358*c42dbd0eSchristos 				false);
359867d70fcSchristos 	target_count = val;
360867d70fcSchristos 	if (error || target_count != val || target_count == (uint32_t) -1)
361e6c7e151Schristos 	  return -1;
362e6c7e151Schristos 	len += bytes_read;
363867d70fcSchristos 	prin (stream, " %u", target_count);
364e6c7e151Schristos 	for (i = 0; i < target_count + 1; i++)
365e6c7e151Schristos 	  {
366867d70fcSchristos 	    uint32_t target;
367867d70fcSchristos 	    val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
368*c42dbd0eSchristos 				    false);
369867d70fcSchristos 	    target = val;
370867d70fcSchristos 	    if (error || target != val)
371e6c7e151Schristos 	      return -1;
372e6c7e151Schristos 	    len += bytes_read;
373867d70fcSchristos 	    prin (stream, " %u", target);
374867d70fcSchristos 	  }
375e6c7e151Schristos       }
376e6c7e151Schristos       break;
377e6c7e151Schristos 
378e6c7e151Schristos     case wasm_break:
379e6c7e151Schristos     case wasm_break_if:
380867d70fcSchristos       {
381867d70fcSchristos 	uint32_t depth;
382867d70fcSchristos 	val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
383*c42dbd0eSchristos 				false);
384867d70fcSchristos 	depth = val;
385867d70fcSchristos 	if (error || depth != val)
386e6c7e151Schristos 	  return -1;
387e6c7e151Schristos 	len += bytes_read;
388867d70fcSchristos 	prin (stream, " %u", depth);
389867d70fcSchristos       }
390e6c7e151Schristos       break;
391e6c7e151Schristos 
392e6c7e151Schristos     case wasm_return:
393e6c7e151Schristos       break;
394e6c7e151Schristos 
395e6c7e151Schristos     case wasm_constant_i32:
396e6c7e151Schristos     case wasm_constant_i64:
397*c42dbd0eSchristos       val = wasm_read_leb128 (pc + len, info, &error, &bytes_read, true);
398e6c7e151Schristos       if (error)
399e6c7e151Schristos 	return -1;
400e6c7e151Schristos       len += bytes_read;
401867d70fcSchristos       prin (stream, " %" PRId64, val);
402e6c7e151Schristos       break;
403e6c7e151Schristos 
404e6c7e151Schristos     case wasm_constant_f32:
405867d70fcSchristos       {
406867d70fcSchristos 	double fconstant;
407867d70fcSchristos 	int ret;
408e6c7e151Schristos 	/* This appears to be the best we can do, even though we're
409e6c7e151Schristos 	   using host doubles for WebAssembly floats.  */
410e6c7e151Schristos 	ret = read_f32 (&fconstant, pc + len, info);
411e6c7e151Schristos 	if (ret < 0)
412e6c7e151Schristos 	  return -1;
413e6c7e151Schristos 	len += ret;
414e6c7e151Schristos 	prin (stream, " %.9g", fconstant);
415867d70fcSchristos       }
416e6c7e151Schristos       break;
417e6c7e151Schristos 
418e6c7e151Schristos     case wasm_constant_f64:
419867d70fcSchristos       {
420867d70fcSchristos 	double fconstant;
421867d70fcSchristos 	int ret;
422e6c7e151Schristos 	ret = read_f64 (&fconstant, pc + len, info);
423e6c7e151Schristos 	if (ret < 0)
424e6c7e151Schristos 	  return -1;
425e6c7e151Schristos 	len += ret;
426e6c7e151Schristos 	prin (stream, " %.17g", fconstant);
427867d70fcSchristos       }
428e6c7e151Schristos       break;
429e6c7e151Schristos 
430e6c7e151Schristos     case wasm_call:
431867d70fcSchristos       {
432867d70fcSchristos 	uint32_t function_index;
433867d70fcSchristos 	val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
434*c42dbd0eSchristos 				false);
435867d70fcSchristos 	function_index = val;
436867d70fcSchristos 	if (error || function_index != val)
437e6c7e151Schristos 	  return -1;
438e6c7e151Schristos 	len += bytes_read;
439e6c7e151Schristos 	prin (stream, " ");
440e6c7e151Schristos 	private_data->section_prefix = ".space.function_index";
441e6c7e151Schristos 	(*info->print_address_func) ((bfd_vma) function_index, info);
442e6c7e151Schristos 	private_data->section_prefix = NULL;
443867d70fcSchristos       }
444e6c7e151Schristos       break;
445e6c7e151Schristos 
446e6c7e151Schristos     case wasm_call_indirect:
447867d70fcSchristos       {
448867d70fcSchristos 	uint32_t type_index, xtra_index;
449867d70fcSchristos 	val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
450*c42dbd0eSchristos 				false);
451867d70fcSchristos 	type_index = val;
452867d70fcSchristos 	if (error || type_index != val)
453e6c7e151Schristos 	  return -1;
454e6c7e151Schristos 	len += bytes_read;
455867d70fcSchristos 	prin (stream, " %u", type_index);
456867d70fcSchristos 	val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
457*c42dbd0eSchristos 				false);
458867d70fcSchristos 	xtra_index = val;
459867d70fcSchristos 	if (error || xtra_index != val)
460e6c7e151Schristos 	  return -1;
461e6c7e151Schristos 	len += bytes_read;
462867d70fcSchristos 	prin (stream, " %u", xtra_index);
463867d70fcSchristos       }
464e6c7e151Schristos       break;
465e6c7e151Schristos 
466e6c7e151Schristos     case wasm_get_local:
467e6c7e151Schristos     case wasm_set_local:
468e6c7e151Schristos     case wasm_tee_local:
469867d70fcSchristos       {
470867d70fcSchristos 	uint32_t local_index;
471867d70fcSchristos 	val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
472*c42dbd0eSchristos 				false);
473867d70fcSchristos 	local_index = val;
474867d70fcSchristos 	if (error || local_index != val)
475e6c7e151Schristos 	  return -1;
476e6c7e151Schristos 	len += bytes_read;
477867d70fcSchristos 	prin (stream, " %u", local_index);
478e6c7e151Schristos 	if (strcmp (op->name + 4, "local") == 0)
479e6c7e151Schristos 	  {
480867d70fcSchristos 	    static const char *locals[] =
481867d70fcSchristos 	      {
482867d70fcSchristos 		"$dpc", "$sp1", "$r0", "$r1", "$rpc", "$pc0",
483867d70fcSchristos 		"$rp", "$fp", "$sp",
484867d70fcSchristos 		"$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
485867d70fcSchristos 		"$i0", "$i1", "$i2", "$i3", "$i4", "$i5", "$i6", "$i7",
486867d70fcSchristos 		"$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
487867d70fcSchristos 	      };
488e6c7e151Schristos 	    if (private_data->print_registers
489867d70fcSchristos 		&& local_index < ARRAY_SIZE (locals))
490867d70fcSchristos 	      prin (stream, " <%s>", locals[local_index]);
491e6c7e151Schristos 	  }
492e6c7e151Schristos 	else
493e6c7e151Schristos 	  {
494867d70fcSchristos 	    static const char *globals[] =
495867d70fcSchristos 	      {
496867d70fcSchristos 		"$got", "$plt", "$gpo"
497867d70fcSchristos 	      };
498e6c7e151Schristos 	    if (private_data->print_well_known_globals
499867d70fcSchristos 		&& local_index < ARRAY_SIZE (globals))
500867d70fcSchristos 	      prin (stream, " <%s>", globals[local_index]);
501867d70fcSchristos 	  }
502e6c7e151Schristos       }
503e6c7e151Schristos       break;
504e6c7e151Schristos 
505e6c7e151Schristos     case wasm_grow_memory:
506e6c7e151Schristos     case wasm_current_memory:
507867d70fcSchristos       {
508867d70fcSchristos 	uint32_t reserved_size;
509867d70fcSchristos 	val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
510*c42dbd0eSchristos 				false);
511867d70fcSchristos 	reserved_size = val;
512867d70fcSchristos 	if (error || reserved_size != val)
513e6c7e151Schristos 	  return -1;
514e6c7e151Schristos 	len += bytes_read;
515867d70fcSchristos 	prin (stream, " %u", reserved_size);
516867d70fcSchristos       }
517e6c7e151Schristos       break;
518e6c7e151Schristos 
519e6c7e151Schristos     case wasm_load:
520e6c7e151Schristos     case wasm_store:
521867d70fcSchristos       {
522867d70fcSchristos 	uint32_t flags, offset;
523867d70fcSchristos 	val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
524*c42dbd0eSchristos 				false);
525867d70fcSchristos 	flags = val;
526867d70fcSchristos 	if (error || flags != val)
527e6c7e151Schristos 	  return -1;
528e6c7e151Schristos 	len += bytes_read;
529867d70fcSchristos 	val = wasm_read_leb128 (pc + len, info, &error, &bytes_read,
530*c42dbd0eSchristos 				false);
531867d70fcSchristos 	offset = val;
532867d70fcSchristos 	if (error || offset != val)
533e6c7e151Schristos 	  return -1;
534e6c7e151Schristos 	len += bytes_read;
535867d70fcSchristos 	prin (stream, " a=%u %u", flags, offset);
536e6c7e151Schristos       }
537867d70fcSchristos       break;
538e6c7e151Schristos     }
539e6c7e151Schristos   return len;
540e6c7e151Schristos }
541e6c7e151Schristos 
542e6c7e151Schristos /* Print valid disassembler options to STREAM.  */
543e6c7e151Schristos 
544e6c7e151Schristos void
print_wasm32_disassembler_options(FILE * stream)545e6c7e151Schristos print_wasm32_disassembler_options (FILE *stream)
546e6c7e151Schristos {
547e6c7e151Schristos   unsigned int i, max_len = 0;
548e6c7e151Schristos 
549e6c7e151Schristos   fprintf (stream, _("\
550e6c7e151Schristos The following WebAssembly-specific disassembler options are supported for use\n\
551e6c7e151Schristos with the -M switch:\n"));
552e6c7e151Schristos 
553e6c7e151Schristos   for (i = 0; i < ARRAY_SIZE (options); i++)
554e6c7e151Schristos     {
555e6c7e151Schristos       unsigned int len = strlen (options[i].name);
556e6c7e151Schristos 
557e6c7e151Schristos       if (max_len < len)
558e6c7e151Schristos 	max_len = len;
559e6c7e151Schristos     }
560e6c7e151Schristos 
561e6c7e151Schristos   for (i = 0, max_len++; i < ARRAY_SIZE (options); i++)
562e6c7e151Schristos     fprintf (stream, "  %s%*c %s\n",
563e6c7e151Schristos 	     options[i].name,
564e6c7e151Schristos 	     (int)(max_len - strlen (options[i].name)), ' ',
565e6c7e151Schristos 	     _(options[i].description));
566e6c7e151Schristos }
567