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