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