cpu,gas,opcodes: support for eBPF JMP32 instruction class
[deliverable/binutils-gdb.git] / opcodes / wasm32-dis.c
index dbb18973a6dc0261e8cdc33383bb96ecc9177464..946ce5fb68bcb13057c42d6872c11fae6ad16fc2 100644 (file)
@@ -1,5 +1,5 @@
 /* Opcode printing code for the WebAssembly target
-   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+   Copyright (C) 2017-2020 Free Software Foundation, Inc.
 
    This file is part of libopcodes.
 
@@ -27,7 +27,7 @@
 #include "elf-bfd.h"
 #include "elf/internal.h"
 #include "elf/wasm32.h"
-#include <stdint.h>
+#include "bfd_stdint.h"
 
 /* Type names for blocks and signatures.  */
 #define BLOCK_TYPE_NONE              0x40
@@ -192,29 +192,36 @@ wasm_read_leb128 (bfd_vma                   pc,
   unsigned int num_read = 0;
   unsigned int shift = 0;
   unsigned char byte = 0;
-  bfd_boolean success = FALSE;
+  int status = 1;
 
   while (info->read_memory_func (pc + num_read, &byte, 1, info) == 0)
     {
       num_read++;
 
-      result |= ((bfd_vma) (byte & 0x7f)) << shift;
+      if (shift < sizeof (result) * 8)
+       {
+         result |= ((uint64_t) (byte & 0x7f)) << shift;
+         if ((result >> shift) != (byte & 0x7f))
+           /* Overflow.  */
+           status |= 2;
+         shift += 7;
+       }
+      else if ((byte & 0x7f) != 0)
+       status |= 2;
 
-      shift += 7;
       if ((byte & 0x80) == 0)
-        {
-          success = TRUE;
-          break;
-        }
+       {
+         status &= ~1;
+         if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
+           result |= -((uint64_t) 1 << shift);
+         break;
+       }
     }
 
   if (length_return != NULL)
     *length_return = num_read;
   if (error_return != NULL)
-    *error_return = ! success;
-
-  if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
-    result |= -((uint64_t) 1 << shift);
+    *error_return = status != 0;
 
   return result;
 }
@@ -264,33 +271,10 @@ print_insn_wasm32 (bfd_vma pc, struct disassemble_info *info)
   void *stream = info->stream;
   fprintf_ftype prin = info->fprintf_func;
   struct wasm32_private_data *private_data = info->private_data;
-  long long constant = 0;
-  double fconstant = 0.0;
-  long flags = 0;
-  long offset = 0;
-  long depth = 0;
-  long index = 0;
-  long target_count = 0;
-  long block_type = 0;
-  int len = 1;
-  int ret = 0;
-  unsigned int bytes_read = 0;
-  int i;
-  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",
-    };
-  int nlocals = ARRAY_SIZE (locals);
-  const char *globals[] =
-    {
-      "$got", "$plt", "$gpo"
-    };
-  int nglobals = ARRAY_SIZE (globals);
-  bfd_boolean error = FALSE;
+  uint64_t val;
+  int len;
+  unsigned int bytes_read;
+  bfd_boolean error;
 
   if (info->read_memory_func (pc, buffer, 1, info))
     return -1;
@@ -306,189 +290,239 @@ print_insn_wasm32 (bfd_vma pc, struct disassemble_info *info)
       prin (stream, "\t.byte 0x%02x\n", buffer[0]);
       return 1;
     }
-  else
+
+  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)
     {
-      len = 1;
-
-      prin (stream, "\t");
-      prin (stream, "%s", op->name);
-
-      if (op->clas == wasm_typed)
-        {
-          block_type = wasm_read_leb128
-            (pc + len, info, &error, &bytes_read, FALSE);
-          if (error)
-            return -1;
-          len += bytes_read;
-          switch (block_type)
-            {
-            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;
-            }
-        }
-
-      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:
-          target_count = wasm_read_leb128
-            (pc + len, info, &error, &bytes_read, FALSE);
-          if (error)
-            return -1;
-          len += bytes_read;
-          prin (stream, " %ld", target_count);
-          for (i = 0; i < target_count + 1; i++)
-            {
-              long target = 0;
-              target = wasm_read_leb128
-                (pc + len, info, &error, &bytes_read, FALSE);
-              if (error)
-                return -1;
-              len += bytes_read;
-              prin (stream, " %ld", target);
-            }
-          break;
-
-        case wasm_break:
-        case wasm_break_if:
-          depth = wasm_read_leb128
-            (pc + len, info, &error, &bytes_read, FALSE);
-          if (error)
-            return -1;
-          len += bytes_read;
-          prin (stream, " %ld", depth);
-          break;
-
-        case wasm_return:
-          break;
-
-        case wasm_constant_i32:
-        case wasm_constant_i64:
-          constant = wasm_read_leb128
-            (pc + len, info, &error, &bytes_read, TRUE);
-          if (error)
-            return -1;
-          len += bytes_read;
-          prin (stream, " %lld", constant);
-          break;
-
-        case wasm_constant_f32:
-          /* 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:
-          ret = read_f64 (&fconstant, pc + len, info);
-          if (ret < 0)
-            return -1;
-          len += ret;
-         prin (stream, " %.17g", fconstant);
-          break;
-
-        case wasm_call:
-          index = wasm_read_leb128
-            (pc + len, info, &error, &bytes_read, FALSE);
-          if (error)
-            return -1;
-          len += bytes_read;
-          prin (stream, " ");
-          private_data->section_prefix = ".space.function_index";
-          (*info->print_address_func) ((bfd_vma) index, info);
-          private_data->section_prefix = NULL;
-          break;
-
-        case wasm_call_indirect:
-          constant = wasm_read_leb128
-            (pc + len, info, &error, &bytes_read, FALSE);
-          if (error)
-            return -1;
-          len += bytes_read;
-          prin (stream, " %lld", constant);
-          constant = wasm_read_leb128
-            (pc + len, info, &error, &bytes_read, FALSE);
-          if (error)
-            return -1;
-          len += bytes_read;
-          prin (stream, " %lld", constant);
-          break;
-
-        case wasm_get_local:
-        case wasm_set_local:
-        case wasm_tee_local:
-          constant = wasm_read_leb128
-            (pc + len, info, &error, &bytes_read, FALSE);
-          if (error)
-            return -1;
-          len += bytes_read;
-          prin (stream, " %lld", constant);
-          if (strcmp (op->name + 4, "local") == 0)
-            {
-              if (private_data->print_registers
-                  && constant >= 0 && constant < nlocals)
-                prin (stream, " <%s>", locals[constant]);
-            }
-          else
-            {
-              if (private_data->print_well_known_globals
-                  && constant >= 0 && constant < nglobals)
-                prin (stream, " <%s>", globals[constant]);
-            }
-          break;
-
-        case wasm_grow_memory:
-        case wasm_current_memory:
-          constant = wasm_read_leb128
-            (pc + len, info, &error, &bytes_read, FALSE);
-          if (error)
-            return -1;
-          len += bytes_read;
-          prin (stream, " %lld", constant);
-          break;
-
-        case wasm_load:
-        case wasm_store:
-          flags = wasm_read_leb128
-            (pc + len, info, &error, &bytes_read, FALSE);
-          if (error)
-            return -1;
-          len += bytes_read;
-          offset = wasm_read_leb128
-            (pc + len, info, &error, &bytes_read, FALSE);
-          if (error)
-            return -1;
-          len += bytes_read;
-          prin (stream, " a=%ld %ld", flags, offset);
-        }
+    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;
 }
This page took 0.028176 seconds and 4 git commands to generate.