(root)/
binutils-2.41/
opcodes/
bpf-ibld.c
       1  /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
       2  /* Instruction building/extraction support for bpf. -*- C -*-
       3  
       4     THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
       5     - the resultant file is machine generated, cgen-ibld.in isn't
       6  
       7     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       8  
       9     This file is part of libopcodes.
      10  
      11     This library is free software; you can redistribute it and/or modify
      12     it under the terms of the GNU General Public License as published by
      13     the Free Software Foundation; either version 3, or (at your option)
      14     any later version.
      15  
      16     It is distributed in the hope that it will be useful, but WITHOUT
      17     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      18     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      19     License for more details.
      20  
      21     You should have received a copy of the GNU General Public License
      22     along with this program; if not, write to the Free Software Foundation, Inc.,
      23     51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
      24  
      25  /* ??? Eventually more and more of this stuff can go to cpu-independent files.
      26     Keep that in mind.  */
      27  
      28  #include "sysdep.h"
      29  #include <stdio.h>
      30  #include "ansidecl.h"
      31  #include "dis-asm.h"
      32  #include "bfd.h"
      33  #include "symcat.h"
      34  #include "bpf-desc.h"
      35  #include "bpf-opc.h"
      36  #include "cgen/basic-modes.h"
      37  #include "opintl.h"
      38  #include "safe-ctype.h"
      39  
      40  #undef  min
      41  #define min(a,b) ((a) < (b) ? (a) : (b))
      42  #undef  max
      43  #define max(a,b) ((a) > (b) ? (a) : (b))
      44  
      45  /* Used by the ifield rtx function.  */
      46  #define FLD(f) (fields->f)
      47  
      48  static const char * insert_normal
      49    (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
      50     unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
      51  static const char * insert_insn_normal
      52    (CGEN_CPU_DESC, const CGEN_INSN *,
      53     CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
      54  static int extract_normal
      55    (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
      56     unsigned int, unsigned int, unsigned int, unsigned int,
      57     unsigned int, unsigned int, bfd_vma, long *);
      58  static int extract_insn_normal
      59    (CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
      60     CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
      61  #if CGEN_INT_INSN_P
      62  static void put_insn_int_value
      63    (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
      64  #endif
      65  #if ! CGEN_INT_INSN_P
      66  static CGEN_INLINE void insert_1
      67    (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
      68  static CGEN_INLINE int fill_cache
      69    (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *,  int, int, bfd_vma);
      70  static CGEN_INLINE long extract_1
      71    (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
      72  #endif
      73  
      74  /* Operand insertion.  */
      75  
      76  #if ! CGEN_INT_INSN_P
      77  
      78  /* Subroutine of insert_normal.  */
      79  
      80  static CGEN_INLINE void
      81  insert_1 (CGEN_CPU_DESC cd,
      82  	  unsigned long value,
      83  	  int start,
      84  	  int length,
      85  	  int word_length,
      86  	  unsigned char *bufp)
      87  {
      88    unsigned long x, mask;
      89    int shift;
      90  
      91    x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
      92  
      93    /* Written this way to avoid undefined behaviour.  */
      94    mask = (1UL << (length - 1) << 1) - 1;
      95    if (CGEN_INSN_LSB0_P)
      96      shift = (start + 1) - length;
      97    else
      98      shift = (word_length - (start + length));
      99    x = (x & ~(mask << shift)) | ((value & mask) << shift);
     100  
     101    cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x, cd->endian);
     102  }
     103  
     104  #endif /* ! CGEN_INT_INSN_P */
     105  
     106  /* Default insertion routine.
     107  
     108     ATTRS is a mask of the boolean attributes.
     109     WORD_OFFSET is the offset in bits from the start of the insn of the value.
     110     WORD_LENGTH is the length of the word in bits in which the value resides.
     111     START is the starting bit number in the word, architecture origin.
     112     LENGTH is the length of VALUE in bits.
     113     TOTAL_LENGTH is the total length of the insn in bits.
     114  
     115     The result is an error message or NULL if success.  */
     116  
     117  /* ??? This duplicates functionality with bfd's howto table and
     118     bfd_install_relocation.  */
     119  /* ??? This doesn't handle bfd_vma's.  Create another function when
     120     necessary.  */
     121  
     122  static const char *
     123  insert_normal (CGEN_CPU_DESC cd,
     124  	       long value,
     125  	       unsigned int attrs,
     126  	       unsigned int word_offset,
     127  	       unsigned int start,
     128  	       unsigned int length,
     129  	       unsigned int word_length,
     130  	       unsigned int total_length,
     131  	       CGEN_INSN_BYTES_PTR buffer)
     132  {
     133    static char errbuf[100];
     134    unsigned long mask;
     135  
     136    /* If LENGTH is zero, this operand doesn't contribute to the value.  */
     137    if (length == 0)
     138      return NULL;
     139  
     140    /* Written this way to avoid undefined behaviour.  */
     141    mask = (1UL << (length - 1) << 1) - 1;
     142  
     143    if (word_length > 8 * sizeof (CGEN_INSN_INT))
     144      abort ();
     145  
     146    /* For architectures with insns smaller than the base-insn-bitsize,
     147       word_length may be too big.  */
     148    if (cd->min_insn_bitsize < cd->base_insn_bitsize)
     149      {
     150        if (word_offset == 0
     151  	  && word_length > total_length)
     152  	word_length = total_length;
     153      }
     154  
     155    /* Ensure VALUE will fit.  */
     156    if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
     157      {
     158        long minval = - (1UL << (length - 1));
     159        unsigned long maxval = mask;
     160  
     161        if ((value > 0 && (unsigned long) value > maxval)
     162  	  || value < minval)
     163  	{
     164  	  /* xgettext:c-format */
     165  	  sprintf (errbuf,
     166  		   _("operand out of range (%ld not between %ld and %lu)"),
     167  		   value, minval, maxval);
     168  	  return errbuf;
     169  	}
     170      }
     171    else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
     172      {
     173        unsigned long maxval = mask;
     174        unsigned long val = (unsigned long) value;
     175  
     176        /* For hosts with a word size > 32 check to see if value has been sign
     177  	 extended beyond 32 bits.  If so then ignore these higher sign bits
     178  	 as the user is attempting to store a 32-bit signed value into an
     179  	 unsigned 32-bit field which is allowed.  */
     180        if (sizeof (unsigned long) > 4 && ((value >> 32) == -1))
     181  	val &= 0xFFFFFFFF;
     182  
     183        if (val > maxval)
     184  	{
     185  	  /* xgettext:c-format */
     186  	  sprintf (errbuf,
     187  		   _("operand out of range (0x%lx not between 0 and 0x%lx)"),
     188  		   val, maxval);
     189  	  return errbuf;
     190  	}
     191      }
     192    else
     193      {
     194        if (! cgen_signed_overflow_ok_p (cd))
     195  	{
     196  	  long minval = - (1UL << (length - 1));
     197  	  long maxval =   (1UL << (length - 1)) - 1;
     198  
     199  	  if (value < minval || value > maxval)
     200  	    {
     201  	      sprintf
     202  		/* xgettext:c-format */
     203  		(errbuf, _("operand out of range (%ld not between %ld and %ld)"),
     204  		 value, minval, maxval);
     205  	      return errbuf;
     206  	    }
     207  	}
     208      }
     209  
     210  #if CGEN_INT_INSN_P
     211  
     212    {
     213      int shift_within_word, shift_to_word, shift;
     214  
     215      /* How to shift the value to BIT0 of the word.  */
     216      shift_to_word = total_length - (word_offset + word_length);
     217  
     218      /* How to shift the value to the field within the word.  */
     219      if (CGEN_INSN_LSB0_P)
     220        shift_within_word = start + 1 - length;
     221      else
     222        shift_within_word = word_length - start - length;
     223  
     224      /* The total SHIFT, then mask in the value.  */
     225      shift = shift_to_word + shift_within_word;
     226      *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
     227    }
     228  
     229  #else /* ! CGEN_INT_INSN_P */
     230  
     231    {
     232      unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
     233  
     234      insert_1 (cd, value, start, length, word_length, bufp);
     235    }
     236  
     237  #endif /* ! CGEN_INT_INSN_P */
     238  
     239    return NULL;
     240  }
     241  
     242  /* Default insn builder (insert handler).
     243     The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
     244     that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
     245     recorded in host byte order, otherwise BUFFER is an array of bytes
     246     and the value is recorded in target byte order).
     247     The result is an error message or NULL if success.  */
     248  
     249  static const char *
     250  insert_insn_normal (CGEN_CPU_DESC cd,
     251  		    const CGEN_INSN * insn,
     252  		    CGEN_FIELDS * fields,
     253  		    CGEN_INSN_BYTES_PTR buffer,
     254  		    bfd_vma pc)
     255  {
     256    const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
     257    unsigned long value;
     258    const CGEN_SYNTAX_CHAR_TYPE * syn;
     259  
     260    CGEN_INIT_INSERT (cd);
     261    value = CGEN_INSN_BASE_VALUE (insn);
     262  
     263    /* If we're recording insns as numbers (rather than a string of bytes),
     264       target byte order handling is deferred until later.  */
     265  
     266  #if CGEN_INT_INSN_P
     267  
     268    put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
     269  		      CGEN_FIELDS_BITSIZE (fields), value);
     270  
     271  #else
     272  
     273    cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
     274                                          (unsigned) CGEN_FIELDS_BITSIZE (fields)),
     275  		       value, cd->insn_endian);
     276  
     277  #endif /* ! CGEN_INT_INSN_P */
     278  
     279    /* ??? It would be better to scan the format's fields.
     280       Still need to be able to insert a value based on the operand though;
     281       e.g. storing a branch displacement that got resolved later.
     282       Needs more thought first.  */
     283  
     284    for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
     285      {
     286        const char *errmsg;
     287  
     288        if (CGEN_SYNTAX_CHAR_P (* syn))
     289  	continue;
     290  
     291        errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
     292  				       fields, buffer, pc);
     293        if (errmsg)
     294  	return errmsg;
     295      }
     296  
     297    return NULL;
     298  }
     299  
     300  #if CGEN_INT_INSN_P
     301  /* Cover function to store an insn value into an integral insn.  Must go here
     302     because it needs <prefix>-desc.h for CGEN_INT_INSN_P.  */
     303  
     304  static void
     305  put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     306  		    CGEN_INSN_BYTES_PTR buf,
     307  		    int length,
     308  		    int insn_length,
     309  		    CGEN_INSN_INT value)
     310  {
     311    /* For architectures with insns smaller than the base-insn-bitsize,
     312       length may be too big.  */
     313    if (length > insn_length)
     314      *buf = value;
     315    else
     316      {
     317        int shift = insn_length - length;
     318        /* Written this way to avoid undefined behaviour.  */
     319        CGEN_INSN_INT mask = length == 0 ? 0 : (1UL << (length - 1) << 1) - 1;
     320  
     321        *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
     322      }
     323  }
     324  #endif
     325  
     326  /* Operand extraction.  */
     327  
     328  #if ! CGEN_INT_INSN_P
     329  
     330  /* Subroutine of extract_normal.
     331     Ensure sufficient bytes are cached in EX_INFO.
     332     OFFSET is the offset in bytes from the start of the insn of the value.
     333     BYTES is the length of the needed value.
     334     Returns 1 for success, 0 for failure.  */
     335  
     336  static CGEN_INLINE int
     337  fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     338  	    CGEN_EXTRACT_INFO *ex_info,
     339  	    int offset,
     340  	    int bytes,
     341  	    bfd_vma pc)
     342  {
     343    /* It's doubtful that the middle part has already been fetched so
     344       we don't optimize that case.  kiss.  */
     345    unsigned int mask;
     346    disassemble_info *info = (disassemble_info *) ex_info->dis_info;
     347  
     348    /* First do a quick check.  */
     349    mask = (1 << bytes) - 1;
     350    if (((ex_info->valid >> offset) & mask) == mask)
     351      return 1;
     352  
     353    /* Search for the first byte we need to read.  */
     354    for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
     355      if (! (mask & ex_info->valid))
     356        break;
     357  
     358    if (bytes)
     359      {
     360        int status;
     361  
     362        pc += offset;
     363        status = (*info->read_memory_func)
     364  	(pc, ex_info->insn_bytes + offset, bytes, info);
     365  
     366        if (status != 0)
     367  	{
     368  	  (*info->memory_error_func) (status, pc, info);
     369  	  return 0;
     370  	}
     371  
     372        ex_info->valid |= ((1 << bytes) - 1) << offset;
     373      }
     374  
     375    return 1;
     376  }
     377  
     378  /* Subroutine of extract_normal.  */
     379  
     380  static CGEN_INLINE long
     381  extract_1 (CGEN_CPU_DESC cd,
     382  	   CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
     383  	   int start,
     384  	   int length,
     385  	   int word_length,
     386  	   unsigned char *bufp,
     387  	   bfd_vma pc ATTRIBUTE_UNUSED)
     388  {
     389    unsigned long x;
     390    int shift;
     391  
     392    x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
     393  
     394    if (CGEN_INSN_LSB0_P)
     395      shift = (start + 1) - length;
     396    else
     397      shift = (word_length - (start + length));
     398    return x >> shift;
     399  }
     400  
     401  #endif /* ! CGEN_INT_INSN_P */
     402  
     403  /* Default extraction routine.
     404  
     405     INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
     406     or sometimes less for cases like the m32r where the base insn size is 32
     407     but some insns are 16 bits.
     408     ATTRS is a mask of the boolean attributes.  We only need `SIGNED',
     409     but for generality we take a bitmask of all of them.
     410     WORD_OFFSET is the offset in bits from the start of the insn of the value.
     411     WORD_LENGTH is the length of the word in bits in which the value resides.
     412     START is the starting bit number in the word, architecture origin.
     413     LENGTH is the length of VALUE in bits.
     414     TOTAL_LENGTH is the total length of the insn in bits.
     415  
     416     Returns 1 for success, 0 for failure.  */
     417  
     418  /* ??? The return code isn't properly used.  wip.  */
     419  
     420  /* ??? This doesn't handle bfd_vma's.  Create another function when
     421     necessary.  */
     422  
     423  static int
     424  extract_normal (CGEN_CPU_DESC cd,
     425  #if ! CGEN_INT_INSN_P
     426  		CGEN_EXTRACT_INFO *ex_info,
     427  #else
     428  		CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
     429  #endif
     430  		CGEN_INSN_INT insn_value,
     431  		unsigned int attrs,
     432  		unsigned int word_offset,
     433  		unsigned int start,
     434  		unsigned int length,
     435  		unsigned int word_length,
     436  		unsigned int total_length,
     437  #if ! CGEN_INT_INSN_P
     438  		bfd_vma pc,
     439  #else
     440  		bfd_vma pc ATTRIBUTE_UNUSED,
     441  #endif
     442  		long *valuep)
     443  {
     444    long value, mask;
     445  
     446    /* If LENGTH is zero, this operand doesn't contribute to the value
     447       so give it a standard value of zero.  */
     448    if (length == 0)
     449      {
     450        *valuep = 0;
     451        return 1;
     452      }
     453  
     454    if (word_length > 8 * sizeof (CGEN_INSN_INT))
     455      abort ();
     456  
     457    /* For architectures with insns smaller than the insn-base-bitsize,
     458       word_length may be too big.  */
     459    if (cd->min_insn_bitsize < cd->base_insn_bitsize)
     460      {
     461        if (word_offset + word_length > total_length)
     462  	word_length = total_length - word_offset;
     463      }
     464  
     465    /* Does the value reside in INSN_VALUE, and at the right alignment?  */
     466  
     467    if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
     468      {
     469        if (CGEN_INSN_LSB0_P)
     470  	value = insn_value >> ((word_offset + start + 1) - length);
     471        else
     472  	value = insn_value >> (total_length - ( word_offset + start + length));
     473      }
     474  
     475  #if ! CGEN_INT_INSN_P
     476  
     477    else
     478      {
     479        unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
     480  
     481        if (word_length > 8 * sizeof (CGEN_INSN_INT))
     482  	abort ();
     483  
     484        if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
     485  	{
     486  	  *valuep = 0;
     487  	  return 0;
     488  	}
     489  
     490        value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
     491      }
     492  
     493  #endif /* ! CGEN_INT_INSN_P */
     494  
     495    /* Written this way to avoid undefined behaviour.  */
     496    mask = (1UL << (length - 1) << 1) - 1;
     497  
     498    value &= mask;
     499    /* sign extend? */
     500    if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
     501        && (value & (1UL << (length - 1))))
     502      value |= ~mask;
     503  
     504    *valuep = value;
     505  
     506    return 1;
     507  }
     508  
     509  /* Default insn extractor.
     510  
     511     INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
     512     The extracted fields are stored in FIELDS.
     513     EX_INFO is used to handle reading variable length insns.
     514     Return the length of the insn in bits, or 0 if no match,
     515     or -1 if an error occurs fetching data (memory_error_func will have
     516     been called).  */
     517  
     518  static int
     519  extract_insn_normal (CGEN_CPU_DESC cd,
     520  		     const CGEN_INSN *insn,
     521  		     CGEN_EXTRACT_INFO *ex_info,
     522  		     CGEN_INSN_INT insn_value,
     523  		     CGEN_FIELDS *fields,
     524  		     bfd_vma pc)
     525  {
     526    const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
     527    const CGEN_SYNTAX_CHAR_TYPE *syn;
     528  
     529    CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
     530  
     531    CGEN_INIT_EXTRACT (cd);
     532  
     533    for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
     534      {
     535        int length;
     536  
     537        if (CGEN_SYNTAX_CHAR_P (*syn))
     538  	continue;
     539  
     540        length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
     541  					ex_info, insn_value, fields, pc);
     542        if (length <= 0)
     543  	return length;
     544      }
     545  
     546    /* We recognized and successfully extracted this insn.  */
     547    return CGEN_INSN_BITSIZE (insn);
     548  }
     549  
     550  /* Machine generated code added here.  */
     551  
     552  const char * bpf_cgen_insert_operand
     553    (CGEN_CPU_DESC, int, CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
     554  
     555  /* Main entry point for operand insertion.
     556  
     557     This function is basically just a big switch statement.  Earlier versions
     558     used tables to look up the function to use, but
     559     - if the table contains both assembler and disassembler functions then
     560       the disassembler contains much of the assembler and vice-versa,
     561     - there's a lot of inlining possibilities as things grow,
     562     - using a switch statement avoids the function call overhead.
     563  
     564     This function could be moved into `parse_insn_normal', but keeping it
     565     separate makes clear the interface between `parse_insn_normal' and each of
     566     the handlers.  It's also needed by GAS to insert operands that couldn't be
     567     resolved during parsing.  */
     568  
     569  const char *
     570  bpf_cgen_insert_operand (CGEN_CPU_DESC cd,
     571  			     int opindex,
     572  			     CGEN_FIELDS * fields,
     573  			     CGEN_INSN_BYTES_PTR buffer,
     574  			     bfd_vma pc ATTRIBUTE_UNUSED)
     575  {
     576    const char * errmsg = NULL;
     577    unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
     578  
     579    switch (opindex)
     580      {
     581      case BPF_OPERAND_DISP16 :
     582        errmsg = insert_normal (cd, fields->f_offset16, 0|(1<<CGEN_IFLD_SIGNED), 16, 15, 16, 16, total_length, buffer);
     583        break;
     584      case BPF_OPERAND_DISP32 :
     585        errmsg = insert_normal (cd, fields->f_imm32, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, buffer);
     586        break;
     587      case BPF_OPERAND_DSTBE :
     588        errmsg = insert_normal (cd, fields->f_dstbe, 0, 8, 7, 4, 8, total_length, buffer);
     589        break;
     590      case BPF_OPERAND_DSTLE :
     591        errmsg = insert_normal (cd, fields->f_dstle, 0, 8, 3, 4, 8, total_length, buffer);
     592        break;
     593      case BPF_OPERAND_ENDSIZE :
     594        errmsg = insert_normal (cd, fields->f_imm32, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, buffer);
     595        break;
     596      case BPF_OPERAND_IMM32 :
     597        errmsg = insert_normal (cd, fields->f_imm32, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, buffer);
     598        break;
     599      case BPF_OPERAND_IMM64 :
     600        {
     601  {
     602    FLD (f_imm64_b) = 0;
     603    FLD (f_imm64_c) = ((UDI) (FLD (f_imm64)) >> (32));
     604    FLD (f_imm64_a) = ((FLD (f_imm64)) & (MAKEDI (0, 0xffffffff)));
     605  }
     606          errmsg = insert_normal (cd, fields->f_imm64_a, 0, 32, 31, 32, 32, total_length, buffer);
     607          if (errmsg)
     608            break;
     609          errmsg = insert_normal (cd, fields->f_imm64_b, 0, 64, 31, 32, 32, total_length, buffer);
     610          if (errmsg)
     611            break;
     612          errmsg = insert_normal (cd, fields->f_imm64_c, 0, 96, 31, 32, 32, total_length, buffer);
     613          if (errmsg)
     614            break;
     615        }
     616        break;
     617      case BPF_OPERAND_OFFSET16 :
     618        errmsg = insert_normal (cd, fields->f_offset16, 0|(1<<CGEN_IFLD_SIGNED), 16, 15, 16, 16, total_length, buffer);
     619        break;
     620      case BPF_OPERAND_SRCBE :
     621        errmsg = insert_normal (cd, fields->f_srcbe, 0, 8, 3, 4, 8, total_length, buffer);
     622        break;
     623      case BPF_OPERAND_SRCLE :
     624        errmsg = insert_normal (cd, fields->f_srcle, 0, 8, 7, 4, 8, total_length, buffer);
     625        break;
     626  
     627      default :
     628        /* xgettext:c-format */
     629        opcodes_error_handler
     630  	(_("internal error: unrecognized field %d while building insn"),
     631  	 opindex);
     632        abort ();
     633    }
     634  
     635    return errmsg;
     636  }
     637  
     638  int bpf_cgen_extract_operand
     639    (CGEN_CPU_DESC, int, CGEN_EXTRACT_INFO *, CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
     640  
     641  /* Main entry point for operand extraction.
     642     The result is <= 0 for error, >0 for success.
     643     ??? Actual values aren't well defined right now.
     644  
     645     This function is basically just a big switch statement.  Earlier versions
     646     used tables to look up the function to use, but
     647     - if the table contains both assembler and disassembler functions then
     648       the disassembler contains much of the assembler and vice-versa,
     649     - there's a lot of inlining possibilities as things grow,
     650     - using a switch statement avoids the function call overhead.
     651  
     652     This function could be moved into `print_insn_normal', but keeping it
     653     separate makes clear the interface between `print_insn_normal' and each of
     654     the handlers.  */
     655  
     656  int
     657  bpf_cgen_extract_operand (CGEN_CPU_DESC cd,
     658  			     int opindex,
     659  			     CGEN_EXTRACT_INFO *ex_info,
     660  			     CGEN_INSN_INT insn_value,
     661  			     CGEN_FIELDS * fields,
     662  			     bfd_vma pc)
     663  {
     664    /* Assume success (for those operands that are nops).  */
     665    int length = 1;
     666    unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
     667  
     668    switch (opindex)
     669      {
     670      case BPF_OPERAND_DISP16 :
     671        length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 16, 15, 16, 16, total_length, pc, & fields->f_offset16);
     672        break;
     673      case BPF_OPERAND_DISP32 :
     674        length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, pc, & fields->f_imm32);
     675        break;
     676      case BPF_OPERAND_DSTBE :
     677        length = extract_normal (cd, ex_info, insn_value, 0, 8, 7, 4, 8, total_length, pc, & fields->f_dstbe);
     678        break;
     679      case BPF_OPERAND_DSTLE :
     680        length = extract_normal (cd, ex_info, insn_value, 0, 8, 3, 4, 8, total_length, pc, & fields->f_dstle);
     681        break;
     682      case BPF_OPERAND_ENDSIZE :
     683        length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, pc, & fields->f_imm32);
     684        break;
     685      case BPF_OPERAND_IMM32 :
     686        length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, pc, & fields->f_imm32);
     687        break;
     688      case BPF_OPERAND_IMM64 :
     689        {
     690          length = extract_normal (cd, ex_info, insn_value, 0, 32, 31, 32, 32, total_length, pc, & fields->f_imm64_a);
     691          if (length <= 0) break;
     692          length = extract_normal (cd, ex_info, insn_value, 0, 64, 31, 32, 32, total_length, pc, & fields->f_imm64_b);
     693          if (length <= 0) break;
     694          length = extract_normal (cd, ex_info, insn_value, 0, 96, 31, 32, 32, total_length, pc, & fields->f_imm64_c);
     695          if (length <= 0) break;
     696  {
     697    FLD (f_imm64) = ((((((UDI) (UINT) (FLD (f_imm64_c)))) << (32))) | (((UDI) (UINT) (FLD (f_imm64_a)))));
     698  }
     699        }
     700        break;
     701      case BPF_OPERAND_OFFSET16 :
     702        length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 16, 15, 16, 16, total_length, pc, & fields->f_offset16);
     703        break;
     704      case BPF_OPERAND_SRCBE :
     705        length = extract_normal (cd, ex_info, insn_value, 0, 8, 3, 4, 8, total_length, pc, & fields->f_srcbe);
     706        break;
     707      case BPF_OPERAND_SRCLE :
     708        length = extract_normal (cd, ex_info, insn_value, 0, 8, 7, 4, 8, total_length, pc, & fields->f_srcle);
     709        break;
     710  
     711      default :
     712        /* xgettext:c-format */
     713        opcodes_error_handler
     714  	(_("internal error: unrecognized field %d while decoding insn"),
     715  	 opindex);
     716        abort ();
     717      }
     718  
     719    return length;
     720  }
     721  
     722  cgen_insert_fn * const bpf_cgen_insert_handlers[] =
     723  {
     724    insert_insn_normal,
     725  };
     726  
     727  cgen_extract_fn * const bpf_cgen_extract_handlers[] =
     728  {
     729    extract_insn_normal,
     730  };
     731  
     732  int bpf_cgen_get_int_operand     (CGEN_CPU_DESC, int, const CGEN_FIELDS *);
     733  bfd_vma bpf_cgen_get_vma_operand (CGEN_CPU_DESC, int, const CGEN_FIELDS *);
     734  
     735  /* Getting values from cgen_fields is handled by a collection of functions.
     736     They are distinguished by the type of the VALUE argument they return.
     737     TODO: floating point, inlining support, remove cases where result type
     738     not appropriate.  */
     739  
     740  int
     741  bpf_cgen_get_int_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     742  			     int opindex,
     743  			     const CGEN_FIELDS * fields)
     744  {
     745    int value;
     746  
     747    switch (opindex)
     748      {
     749      case BPF_OPERAND_DISP16 :
     750        value = fields->f_offset16;
     751        break;
     752      case BPF_OPERAND_DISP32 :
     753        value = fields->f_imm32;
     754        break;
     755      case BPF_OPERAND_DSTBE :
     756        value = fields->f_dstbe;
     757        break;
     758      case BPF_OPERAND_DSTLE :
     759        value = fields->f_dstle;
     760        break;
     761      case BPF_OPERAND_ENDSIZE :
     762        value = fields->f_imm32;
     763        break;
     764      case BPF_OPERAND_IMM32 :
     765        value = fields->f_imm32;
     766        break;
     767      case BPF_OPERAND_IMM64 :
     768        value = fields->f_imm64;
     769        break;
     770      case BPF_OPERAND_OFFSET16 :
     771        value = fields->f_offset16;
     772        break;
     773      case BPF_OPERAND_SRCBE :
     774        value = fields->f_srcbe;
     775        break;
     776      case BPF_OPERAND_SRCLE :
     777        value = fields->f_srcle;
     778        break;
     779  
     780      default :
     781        /* xgettext:c-format */
     782        opcodes_error_handler
     783  	(_("internal error: unrecognized field %d while getting int operand"),
     784  	 opindex);
     785        abort ();
     786    }
     787  
     788    return value;
     789  }
     790  
     791  bfd_vma
     792  bpf_cgen_get_vma_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     793  			     int opindex,
     794  			     const CGEN_FIELDS * fields)
     795  {
     796    bfd_vma value;
     797  
     798    switch (opindex)
     799      {
     800      case BPF_OPERAND_DISP16 :
     801        value = fields->f_offset16;
     802        break;
     803      case BPF_OPERAND_DISP32 :
     804        value = fields->f_imm32;
     805        break;
     806      case BPF_OPERAND_DSTBE :
     807        value = fields->f_dstbe;
     808        break;
     809      case BPF_OPERAND_DSTLE :
     810        value = fields->f_dstle;
     811        break;
     812      case BPF_OPERAND_ENDSIZE :
     813        value = fields->f_imm32;
     814        break;
     815      case BPF_OPERAND_IMM32 :
     816        value = fields->f_imm32;
     817        break;
     818      case BPF_OPERAND_IMM64 :
     819        value = fields->f_imm64;
     820        break;
     821      case BPF_OPERAND_OFFSET16 :
     822        value = fields->f_offset16;
     823        break;
     824      case BPF_OPERAND_SRCBE :
     825        value = fields->f_srcbe;
     826        break;
     827      case BPF_OPERAND_SRCLE :
     828        value = fields->f_srcle;
     829        break;
     830  
     831      default :
     832        /* xgettext:c-format */
     833        opcodes_error_handler
     834  	(_("internal error: unrecognized field %d while getting vma operand"),
     835  	 opindex);
     836        abort ();
     837    }
     838  
     839    return value;
     840  }
     841  
     842  void bpf_cgen_set_int_operand  (CGEN_CPU_DESC, int, CGEN_FIELDS *, int);
     843  void bpf_cgen_set_vma_operand  (CGEN_CPU_DESC, int, CGEN_FIELDS *, bfd_vma);
     844  
     845  /* Stuffing values in cgen_fields is handled by a collection of functions.
     846     They are distinguished by the type of the VALUE argument they accept.
     847     TODO: floating point, inlining support, remove cases where argument type
     848     not appropriate.  */
     849  
     850  void
     851  bpf_cgen_set_int_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     852  			     int opindex,
     853  			     CGEN_FIELDS * fields,
     854  			     int value)
     855  {
     856    switch (opindex)
     857      {
     858      case BPF_OPERAND_DISP16 :
     859        fields->f_offset16 = value;
     860        break;
     861      case BPF_OPERAND_DISP32 :
     862        fields->f_imm32 = value;
     863        break;
     864      case BPF_OPERAND_DSTBE :
     865        fields->f_dstbe = value;
     866        break;
     867      case BPF_OPERAND_DSTLE :
     868        fields->f_dstle = value;
     869        break;
     870      case BPF_OPERAND_ENDSIZE :
     871        fields->f_imm32 = value;
     872        break;
     873      case BPF_OPERAND_IMM32 :
     874        fields->f_imm32 = value;
     875        break;
     876      case BPF_OPERAND_IMM64 :
     877        fields->f_imm64 = value;
     878        break;
     879      case BPF_OPERAND_OFFSET16 :
     880        fields->f_offset16 = value;
     881        break;
     882      case BPF_OPERAND_SRCBE :
     883        fields->f_srcbe = value;
     884        break;
     885      case BPF_OPERAND_SRCLE :
     886        fields->f_srcle = value;
     887        break;
     888  
     889      default :
     890        /* xgettext:c-format */
     891        opcodes_error_handler
     892  	(_("internal error: unrecognized field %d while setting int operand"),
     893  	 opindex);
     894        abort ();
     895    }
     896  }
     897  
     898  void
     899  bpf_cgen_set_vma_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     900  			     int opindex,
     901  			     CGEN_FIELDS * fields,
     902  			     bfd_vma value)
     903  {
     904    switch (opindex)
     905      {
     906      case BPF_OPERAND_DISP16 :
     907        fields->f_offset16 = value;
     908        break;
     909      case BPF_OPERAND_DISP32 :
     910        fields->f_imm32 = value;
     911        break;
     912      case BPF_OPERAND_DSTBE :
     913        fields->f_dstbe = value;
     914        break;
     915      case BPF_OPERAND_DSTLE :
     916        fields->f_dstle = value;
     917        break;
     918      case BPF_OPERAND_ENDSIZE :
     919        fields->f_imm32 = value;
     920        break;
     921      case BPF_OPERAND_IMM32 :
     922        fields->f_imm32 = value;
     923        break;
     924      case BPF_OPERAND_IMM64 :
     925        fields->f_imm64 = value;
     926        break;
     927      case BPF_OPERAND_OFFSET16 :
     928        fields->f_offset16 = value;
     929        break;
     930      case BPF_OPERAND_SRCBE :
     931        fields->f_srcbe = value;
     932        break;
     933      case BPF_OPERAND_SRCLE :
     934        fields->f_srcle = value;
     935        break;
     936  
     937      default :
     938        /* xgettext:c-format */
     939        opcodes_error_handler
     940  	(_("internal error: unrecognized field %d while setting vma operand"),
     941  	 opindex);
     942        abort ();
     943    }
     944  }
     945  
     946  /* Function to call before using the instruction builder tables.  */
     947  
     948  void
     949  bpf_cgen_init_ibld_table (CGEN_CPU_DESC cd)
     950  {
     951    cd->insert_handlers = & bpf_cgen_insert_handlers[0];
     952    cd->extract_handlers = & bpf_cgen_extract_handlers[0];
     953  
     954    cd->insert_operand = bpf_cgen_insert_operand;
     955    cd->extract_operand = bpf_cgen_extract_operand;
     956  
     957    cd->get_int_operand = bpf_cgen_get_int_operand;
     958    cd->set_int_operand = bpf_cgen_set_int_operand;
     959    cd->get_vma_operand = bpf_cgen_get_vma_operand;
     960    cd->set_vma_operand = bpf_cgen_set_vma_operand;
     961  }