xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/bpf-asm.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1867d70fcSchristos /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
2867d70fcSchristos /* Assembler interface for targets using CGEN. -*- C -*-
3867d70fcSchristos    CGEN: Cpu tools GENerator
4867d70fcSchristos 
5867d70fcSchristos    THIS FILE IS MACHINE GENERATED WITH CGEN.
6867d70fcSchristos    - the resultant file is machine generated, cgen-asm.in isn't
7867d70fcSchristos 
8*c42dbd0eSchristos    Copyright (C) 1996-2022 Free Software Foundation, Inc.
9867d70fcSchristos 
10867d70fcSchristos    This file is part of libopcodes.
11867d70fcSchristos 
12867d70fcSchristos    This library is free software; you can redistribute it and/or modify
13867d70fcSchristos    it under the terms of the GNU General Public License as published by
14867d70fcSchristos    the Free Software Foundation; either version 3, or (at your option)
15867d70fcSchristos    any later version.
16867d70fcSchristos 
17867d70fcSchristos    It is distributed in the hope that it will be useful, but WITHOUT
18867d70fcSchristos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19867d70fcSchristos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
20867d70fcSchristos    License for more details.
21867d70fcSchristos 
22867d70fcSchristos    You should have received a copy of the GNU General Public License
23867d70fcSchristos    along with this program; if not, write to the Free Software Foundation, Inc.,
24867d70fcSchristos    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
25867d70fcSchristos 
26867d70fcSchristos 
27867d70fcSchristos /* ??? Eventually more and more of this stuff can go to cpu-independent files.
28867d70fcSchristos    Keep that in mind.  */
29867d70fcSchristos 
30867d70fcSchristos #include "sysdep.h"
31867d70fcSchristos #include <stdio.h>
32867d70fcSchristos #include "ansidecl.h"
33867d70fcSchristos #include "bfd.h"
34867d70fcSchristos #include "symcat.h"
35867d70fcSchristos #include "bpf-desc.h"
36867d70fcSchristos #include "bpf-opc.h"
37867d70fcSchristos #include "opintl.h"
38867d70fcSchristos #include "xregex.h"
39867d70fcSchristos #include "libiberty.h"
40867d70fcSchristos #include "safe-ctype.h"
41867d70fcSchristos 
42867d70fcSchristos #undef  min
43867d70fcSchristos #define min(a,b) ((a) < (b) ? (a) : (b))
44867d70fcSchristos #undef  max
45867d70fcSchristos #define max(a,b) ((a) > (b) ? (a) : (b))
46867d70fcSchristos 
47867d70fcSchristos static const char * parse_insn_normal
48867d70fcSchristos   (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
49867d70fcSchristos 
50867d70fcSchristos /* -- assembler routines inserted here.  */
51867d70fcSchristos 
52867d70fcSchristos /* -- asm.c */
53867d70fcSchristos 
54867d70fcSchristos /* Parse a signed 64-bit immediate.  */
55867d70fcSchristos 
56867d70fcSchristos static const char *
parse_imm64(CGEN_CPU_DESC cd,const char ** strp,int opindex,int64_t * valuep)57867d70fcSchristos parse_imm64 (CGEN_CPU_DESC cd,
58867d70fcSchristos              const char **strp,
59867d70fcSchristos              int opindex,
60867d70fcSchristos              int64_t *valuep)
61867d70fcSchristos {
62867d70fcSchristos   bfd_vma value;
63867d70fcSchristos   enum cgen_parse_operand_result result;
64867d70fcSchristos   const char *errmsg;
65867d70fcSchristos 
66867d70fcSchristos   errmsg = (* cd->parse_operand_fn)
67867d70fcSchristos     (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE,
68867d70fcSchristos      &result, &value);
69867d70fcSchristos   if (!errmsg)
70867d70fcSchristos     *valuep = value;
71867d70fcSchristos 
72867d70fcSchristos   return errmsg;
73867d70fcSchristos }
74867d70fcSchristos 
75867d70fcSchristos /* Endianness size operands are integer immediates whose values can be
76867d70fcSchristos    16, 32 or 64.  */
77867d70fcSchristos 
78867d70fcSchristos static const char *
parse_endsize(CGEN_CPU_DESC cd,const char ** strp,int opindex,unsigned long * valuep)79867d70fcSchristos parse_endsize (CGEN_CPU_DESC cd,
80867d70fcSchristos                const char **strp,
81867d70fcSchristos                int opindex,
82867d70fcSchristos                unsigned long *valuep)
83867d70fcSchristos {
84867d70fcSchristos   const char *errmsg;
85867d70fcSchristos 
86867d70fcSchristos   errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
87867d70fcSchristos   if (errmsg)
88867d70fcSchristos     return errmsg;
89867d70fcSchristos 
90867d70fcSchristos   switch (*valuep)
91867d70fcSchristos     {
92867d70fcSchristos     case 16:
93867d70fcSchristos     case 32:
94867d70fcSchristos     case 64:
95867d70fcSchristos       break;
96867d70fcSchristos     default:
97867d70fcSchristos       return _("expected 16, 32 or 64 in");
98867d70fcSchristos     }
99867d70fcSchristos 
100867d70fcSchristos   return NULL;
101867d70fcSchristos }
102867d70fcSchristos 
103867d70fcSchristos /* Special check to ensure that the right instruction variant is used
104867d70fcSchristos    for the given endianness induced by the ISA selected in the CPU.
105867d70fcSchristos    See bpf.cpu for a discussion on how eBPF is really two instruction
106867d70fcSchristos    sets.  */
107867d70fcSchristos 
108867d70fcSchristos int
bpf_cgen_insn_supported(CGEN_CPU_DESC cd,const CGEN_INSN * insn)109867d70fcSchristos bpf_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
110867d70fcSchristos {
111867d70fcSchristos   CGEN_BITSET isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA);
112867d70fcSchristos 
113867d70fcSchristos   return cgen_bitset_intersect_p (&isas, cd->isas);
114867d70fcSchristos }
115867d70fcSchristos 
116867d70fcSchristos 
117867d70fcSchristos /* -- dis.c */
118867d70fcSchristos 
119867d70fcSchristos const char * bpf_cgen_parse_operand
120867d70fcSchristos   (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
121867d70fcSchristos 
122867d70fcSchristos /* Main entry point for operand parsing.
123867d70fcSchristos 
124867d70fcSchristos    This function is basically just a big switch statement.  Earlier versions
125867d70fcSchristos    used tables to look up the function to use, but
126867d70fcSchristos    - if the table contains both assembler and disassembler functions then
127867d70fcSchristos      the disassembler contains much of the assembler and vice-versa,
128867d70fcSchristos    - there's a lot of inlining possibilities as things grow,
129867d70fcSchristos    - using a switch statement avoids the function call overhead.
130867d70fcSchristos 
131867d70fcSchristos    This function could be moved into `parse_insn_normal', but keeping it
132867d70fcSchristos    separate makes clear the interface between `parse_insn_normal' and each of
133867d70fcSchristos    the handlers.  */
134867d70fcSchristos 
135867d70fcSchristos const char *
bpf_cgen_parse_operand(CGEN_CPU_DESC cd,int opindex,const char ** strp,CGEN_FIELDS * fields)136867d70fcSchristos bpf_cgen_parse_operand (CGEN_CPU_DESC cd,
137867d70fcSchristos 			   int opindex,
138867d70fcSchristos 			   const char ** strp,
139867d70fcSchristos 			   CGEN_FIELDS * fields)
140867d70fcSchristos {
141867d70fcSchristos   const char * errmsg = NULL;
142867d70fcSchristos   /* Used by scalar operands that still need to be parsed.  */
143867d70fcSchristos   long junk ATTRIBUTE_UNUSED;
144867d70fcSchristos 
145867d70fcSchristos   switch (opindex)
146867d70fcSchristos     {
147867d70fcSchristos     case BPF_OPERAND_DISP16 :
148867d70fcSchristos       errmsg = cgen_parse_signed_integer (cd, strp, BPF_OPERAND_DISP16, (long *) (& fields->f_offset16));
149867d70fcSchristos       break;
150867d70fcSchristos     case BPF_OPERAND_DISP32 :
151867d70fcSchristos       errmsg = cgen_parse_signed_integer (cd, strp, BPF_OPERAND_DISP32, (long *) (& fields->f_imm32));
152867d70fcSchristos       break;
153867d70fcSchristos     case BPF_OPERAND_DSTBE :
154867d70fcSchristos       errmsg = cgen_parse_keyword (cd, strp, & bpf_cgen_opval_h_gpr, & fields->f_dstbe);
155867d70fcSchristos       break;
156867d70fcSchristos     case BPF_OPERAND_DSTLE :
157867d70fcSchristos       errmsg = cgen_parse_keyword (cd, strp, & bpf_cgen_opval_h_gpr, & fields->f_dstle);
158867d70fcSchristos       break;
159867d70fcSchristos     case BPF_OPERAND_ENDSIZE :
160867d70fcSchristos       errmsg = parse_endsize (cd, strp, BPF_OPERAND_ENDSIZE, (unsigned long *) (& fields->f_imm32));
161867d70fcSchristos       break;
162867d70fcSchristos     case BPF_OPERAND_IMM32 :
163867d70fcSchristos       errmsg = cgen_parse_signed_integer (cd, strp, BPF_OPERAND_IMM32, (long *) (& fields->f_imm32));
164867d70fcSchristos       break;
165867d70fcSchristos     case BPF_OPERAND_IMM64 :
166867d70fcSchristos       errmsg = parse_imm64 (cd, strp, BPF_OPERAND_IMM64, (int64_t *) (& fields->f_imm64));
167867d70fcSchristos       break;
168867d70fcSchristos     case BPF_OPERAND_OFFSET16 :
169867d70fcSchristos       errmsg = cgen_parse_signed_integer (cd, strp, BPF_OPERAND_OFFSET16, (long *) (& fields->f_offset16));
170867d70fcSchristos       break;
171867d70fcSchristos     case BPF_OPERAND_SRCBE :
172867d70fcSchristos       errmsg = cgen_parse_keyword (cd, strp, & bpf_cgen_opval_h_gpr, & fields->f_srcbe);
173867d70fcSchristos       break;
174867d70fcSchristos     case BPF_OPERAND_SRCLE :
175867d70fcSchristos       errmsg = cgen_parse_keyword (cd, strp, & bpf_cgen_opval_h_gpr, & fields->f_srcle);
176867d70fcSchristos       break;
177867d70fcSchristos 
178867d70fcSchristos     default :
179867d70fcSchristos       /* xgettext:c-format */
180867d70fcSchristos       opcodes_error_handler
181867d70fcSchristos 	(_("internal error: unrecognized field %d while parsing"),
182867d70fcSchristos 	 opindex);
183867d70fcSchristos       abort ();
184867d70fcSchristos   }
185867d70fcSchristos 
186867d70fcSchristos   return errmsg;
187867d70fcSchristos }
188867d70fcSchristos 
189867d70fcSchristos cgen_parse_fn * const bpf_cgen_parse_handlers[] =
190867d70fcSchristos {
191867d70fcSchristos   parse_insn_normal,
192867d70fcSchristos };
193867d70fcSchristos 
194867d70fcSchristos void
bpf_cgen_init_asm(CGEN_CPU_DESC cd)195867d70fcSchristos bpf_cgen_init_asm (CGEN_CPU_DESC cd)
196867d70fcSchristos {
197867d70fcSchristos   bpf_cgen_init_opcode_table (cd);
198867d70fcSchristos   bpf_cgen_init_ibld_table (cd);
199867d70fcSchristos   cd->parse_handlers = & bpf_cgen_parse_handlers[0];
200867d70fcSchristos   cd->parse_operand = bpf_cgen_parse_operand;
201867d70fcSchristos #ifdef CGEN_ASM_INIT_HOOK
202867d70fcSchristos CGEN_ASM_INIT_HOOK
203867d70fcSchristos #endif
204867d70fcSchristos }
205867d70fcSchristos 
206867d70fcSchristos 
207867d70fcSchristos 
208867d70fcSchristos /* Regex construction routine.
209867d70fcSchristos 
210867d70fcSchristos    This translates an opcode syntax string into a regex string,
211867d70fcSchristos    by replacing any non-character syntax element (such as an
212867d70fcSchristos    opcode) with the pattern '.*'
213867d70fcSchristos 
214867d70fcSchristos    It then compiles the regex and stores it in the opcode, for
215867d70fcSchristos    later use by bpf_cgen_assemble_insn
216867d70fcSchristos 
217867d70fcSchristos    Returns NULL for success, an error message for failure.  */
218867d70fcSchristos 
219867d70fcSchristos char *
bpf_cgen_build_insn_regex(CGEN_INSN * insn)220867d70fcSchristos bpf_cgen_build_insn_regex (CGEN_INSN *insn)
221867d70fcSchristos {
222867d70fcSchristos   CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
223867d70fcSchristos   const char *mnem = CGEN_INSN_MNEMONIC (insn);
224867d70fcSchristos   char rxbuf[CGEN_MAX_RX_ELEMENTS];
225867d70fcSchristos   char *rx = rxbuf;
226867d70fcSchristos   const CGEN_SYNTAX_CHAR_TYPE *syn;
227867d70fcSchristos   int reg_err;
228867d70fcSchristos 
229867d70fcSchristos   syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
230867d70fcSchristos 
231867d70fcSchristos   /* Mnemonics come first in the syntax string.  */
232867d70fcSchristos   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
233867d70fcSchristos     return _("missing mnemonic in syntax string");
234867d70fcSchristos   ++syn;
235867d70fcSchristos 
236867d70fcSchristos   /* Generate a case sensitive regular expression that emulates case
237867d70fcSchristos      insensitive matching in the "C" locale.  We cannot generate a case
238867d70fcSchristos      insensitive regular expression because in Turkish locales, 'i' and 'I'
239867d70fcSchristos      are not equal modulo case conversion.  */
240867d70fcSchristos 
241867d70fcSchristos   /* Copy the literal mnemonic out of the insn.  */
242867d70fcSchristos   for (; *mnem; mnem++)
243867d70fcSchristos     {
244867d70fcSchristos       char c = *mnem;
245867d70fcSchristos 
246867d70fcSchristos       if (ISALPHA (c))
247867d70fcSchristos 	{
248867d70fcSchristos 	  *rx++ = '[';
249867d70fcSchristos 	  *rx++ = TOLOWER (c);
250867d70fcSchristos 	  *rx++ = TOUPPER (c);
251867d70fcSchristos 	  *rx++ = ']';
252867d70fcSchristos 	}
253867d70fcSchristos       else
254867d70fcSchristos 	*rx++ = c;
255867d70fcSchristos     }
256867d70fcSchristos 
257867d70fcSchristos   /* Copy any remaining literals from the syntax string into the rx.  */
258867d70fcSchristos   for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
259867d70fcSchristos     {
260867d70fcSchristos       if (CGEN_SYNTAX_CHAR_P (* syn))
261867d70fcSchristos 	{
262867d70fcSchristos 	  char c = CGEN_SYNTAX_CHAR (* syn);
263867d70fcSchristos 
264867d70fcSchristos 	  switch (c)
265867d70fcSchristos 	    {
266867d70fcSchristos 	      /* Escape any regex metacharacters in the syntax.  */
267867d70fcSchristos 	    case '.': case '[': case '\\':
268867d70fcSchristos 	    case '*': case '^': case '$':
269867d70fcSchristos 
270867d70fcSchristos #ifdef CGEN_ESCAPE_EXTENDED_REGEX
271867d70fcSchristos 	    case '?': case '{': case '}':
272867d70fcSchristos 	    case '(': case ')': case '*':
273867d70fcSchristos 	    case '|': case '+': case ']':
274867d70fcSchristos #endif
275867d70fcSchristos 	      *rx++ = '\\';
276867d70fcSchristos 	      *rx++ = c;
277867d70fcSchristos 	      break;
278867d70fcSchristos 
279867d70fcSchristos 	    default:
280867d70fcSchristos 	      if (ISALPHA (c))
281867d70fcSchristos 		{
282867d70fcSchristos 		  *rx++ = '[';
283867d70fcSchristos 		  *rx++ = TOLOWER (c);
284867d70fcSchristos 		  *rx++ = TOUPPER (c);
285867d70fcSchristos 		  *rx++ = ']';
286867d70fcSchristos 		}
287867d70fcSchristos 	      else
288867d70fcSchristos 		*rx++ = c;
289867d70fcSchristos 	      break;
290867d70fcSchristos 	    }
291867d70fcSchristos 	}
292867d70fcSchristos       else
293867d70fcSchristos 	{
294867d70fcSchristos 	  /* Replace non-syntax fields with globs.  */
295867d70fcSchristos 	  *rx++ = '.';
296867d70fcSchristos 	  *rx++ = '*';
297867d70fcSchristos 	}
298867d70fcSchristos     }
299867d70fcSchristos 
300867d70fcSchristos   /* Trailing whitespace ok.  */
301867d70fcSchristos   * rx++ = '[';
302867d70fcSchristos   * rx++ = ' ';
303867d70fcSchristos   * rx++ = '\t';
304867d70fcSchristos   * rx++ = ']';
305867d70fcSchristos   * rx++ = '*';
306867d70fcSchristos 
307867d70fcSchristos   /* But anchor it after that.  */
308867d70fcSchristos   * rx++ = '$';
309867d70fcSchristos   * rx = '\0';
310867d70fcSchristos 
311867d70fcSchristos   CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
312867d70fcSchristos   reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
313867d70fcSchristos 
314867d70fcSchristos   if (reg_err == 0)
315867d70fcSchristos     return NULL;
316867d70fcSchristos   else
317867d70fcSchristos     {
318867d70fcSchristos       static char msg[80];
319867d70fcSchristos 
320867d70fcSchristos       regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
321867d70fcSchristos       regfree ((regex_t *) CGEN_INSN_RX (insn));
322867d70fcSchristos       free (CGEN_INSN_RX (insn));
323867d70fcSchristos       (CGEN_INSN_RX (insn)) = NULL;
324867d70fcSchristos       return msg;
325867d70fcSchristos     }
326867d70fcSchristos }
327867d70fcSchristos 
328867d70fcSchristos 
329867d70fcSchristos /* Default insn parser.
330867d70fcSchristos 
331867d70fcSchristos    The syntax string is scanned and operands are parsed and stored in FIELDS.
332867d70fcSchristos    Relocs are queued as we go via other callbacks.
333867d70fcSchristos 
334867d70fcSchristos    ??? Note that this is currently an all-or-nothing parser.  If we fail to
335867d70fcSchristos    parse the instruction, we return 0 and the caller will start over from
336867d70fcSchristos    the beginning.  Backtracking will be necessary in parsing subexpressions,
337867d70fcSchristos    but that can be handled there.  Not handling backtracking here may get
338867d70fcSchristos    expensive in the case of the m68k.  Deal with later.
339867d70fcSchristos 
340867d70fcSchristos    Returns NULL for success, an error message for failure.  */
341867d70fcSchristos 
342867d70fcSchristos static const char *
parse_insn_normal(CGEN_CPU_DESC cd,const CGEN_INSN * insn,const char ** strp,CGEN_FIELDS * fields)343867d70fcSchristos parse_insn_normal (CGEN_CPU_DESC cd,
344867d70fcSchristos 		   const CGEN_INSN *insn,
345867d70fcSchristos 		   const char **strp,
346867d70fcSchristos 		   CGEN_FIELDS *fields)
347867d70fcSchristos {
348867d70fcSchristos   /* ??? Runtime added insns not handled yet.  */
349867d70fcSchristos   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
350867d70fcSchristos   const char *str = *strp;
351867d70fcSchristos   const char *errmsg;
352867d70fcSchristos   const char *p;
353867d70fcSchristos   const CGEN_SYNTAX_CHAR_TYPE * syn;
354867d70fcSchristos #ifdef CGEN_MNEMONIC_OPERANDS
355867d70fcSchristos   /* FIXME: wip */
356867d70fcSchristos   int past_opcode_p;
357867d70fcSchristos #endif
358867d70fcSchristos 
359867d70fcSchristos   /* For now we assume the mnemonic is first (there are no leading operands).
360867d70fcSchristos      We can parse it without needing to set up operand parsing.
361867d70fcSchristos      GAS's input scrubber will ensure mnemonics are lowercase, but we may
362867d70fcSchristos      not be called from GAS.  */
363867d70fcSchristos   p = CGEN_INSN_MNEMONIC (insn);
364867d70fcSchristos   while (*p && TOLOWER (*p) == TOLOWER (*str))
365867d70fcSchristos     ++p, ++str;
366867d70fcSchristos 
367867d70fcSchristos   if (* p)
368867d70fcSchristos     return _("unrecognized instruction");
369867d70fcSchristos 
370867d70fcSchristos #ifndef CGEN_MNEMONIC_OPERANDS
371867d70fcSchristos   if (* str && ! ISSPACE (* str))
372867d70fcSchristos     return _("unrecognized instruction");
373867d70fcSchristos #endif
374867d70fcSchristos 
375867d70fcSchristos   CGEN_INIT_PARSE (cd);
376867d70fcSchristos   cgen_init_parse_operand (cd);
377867d70fcSchristos #ifdef CGEN_MNEMONIC_OPERANDS
378867d70fcSchristos   past_opcode_p = 0;
379867d70fcSchristos #endif
380867d70fcSchristos 
381867d70fcSchristos   /* We don't check for (*str != '\0') here because we want to parse
382867d70fcSchristos      any trailing fake arguments in the syntax string.  */
383867d70fcSchristos   syn = CGEN_SYNTAX_STRING (syntax);
384867d70fcSchristos 
385867d70fcSchristos   /* Mnemonics come first for now, ensure valid string.  */
386867d70fcSchristos   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
387867d70fcSchristos     abort ();
388867d70fcSchristos 
389867d70fcSchristos   ++syn;
390867d70fcSchristos 
391867d70fcSchristos   while (* syn != 0)
392867d70fcSchristos     {
393867d70fcSchristos       /* Non operand chars must match exactly.  */
394867d70fcSchristos       if (CGEN_SYNTAX_CHAR_P (* syn))
395867d70fcSchristos 	{
396867d70fcSchristos 	  /* FIXME: While we allow for non-GAS callers above, we assume the
397867d70fcSchristos 	     first char after the mnemonic part is a space.  */
398867d70fcSchristos 	  /* FIXME: We also take inappropriate advantage of the fact that
399867d70fcSchristos 	     GAS's input scrubber will remove extraneous blanks.  */
400867d70fcSchristos 	  if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
401867d70fcSchristos 	    {
402867d70fcSchristos #ifdef CGEN_MNEMONIC_OPERANDS
403867d70fcSchristos 	      if (CGEN_SYNTAX_CHAR(* syn) == ' ')
404867d70fcSchristos 		past_opcode_p = 1;
405867d70fcSchristos #endif
406867d70fcSchristos 	      ++ syn;
407867d70fcSchristos 	      ++ str;
408867d70fcSchristos 	    }
409867d70fcSchristos 	  else if (*str)
410867d70fcSchristos 	    {
411867d70fcSchristos 	      /* Syntax char didn't match.  Can't be this insn.  */
412867d70fcSchristos 	      static char msg [80];
413867d70fcSchristos 
414867d70fcSchristos 	      /* xgettext:c-format */
415867d70fcSchristos 	      sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
416867d70fcSchristos 		       CGEN_SYNTAX_CHAR(*syn), *str);
417867d70fcSchristos 	      return msg;
418867d70fcSchristos 	    }
419867d70fcSchristos 	  else
420867d70fcSchristos 	    {
421867d70fcSchristos 	      /* Ran out of input.  */
422867d70fcSchristos 	      static char msg [80];
423867d70fcSchristos 
424867d70fcSchristos 	      /* xgettext:c-format */
425867d70fcSchristos 	      sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
426867d70fcSchristos 		       CGEN_SYNTAX_CHAR(*syn));
427867d70fcSchristos 	      return msg;
428867d70fcSchristos 	    }
429867d70fcSchristos 	  continue;
430867d70fcSchristos 	}
431867d70fcSchristos 
432867d70fcSchristos #ifdef CGEN_MNEMONIC_OPERANDS
433867d70fcSchristos       (void) past_opcode_p;
434867d70fcSchristos #endif
435867d70fcSchristos       /* We have an operand of some sort.  */
436867d70fcSchristos       errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), &str, fields);
437867d70fcSchristos       if (errmsg)
438867d70fcSchristos 	return errmsg;
439867d70fcSchristos 
440867d70fcSchristos       /* Done with this operand, continue with next one.  */
441867d70fcSchristos       ++ syn;
442867d70fcSchristos     }
443867d70fcSchristos 
444867d70fcSchristos   /* If we're at the end of the syntax string, we're done.  */
445867d70fcSchristos   if (* syn == 0)
446867d70fcSchristos     {
447867d70fcSchristos       /* FIXME: For the moment we assume a valid `str' can only contain
448867d70fcSchristos 	 blanks now.  IE: We needn't try again with a longer version of
449867d70fcSchristos 	 the insn and it is assumed that longer versions of insns appear
450867d70fcSchristos 	 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
451867d70fcSchristos       while (ISSPACE (* str))
452867d70fcSchristos 	++ str;
453867d70fcSchristos 
454867d70fcSchristos       if (* str != '\0')
455867d70fcSchristos 	return _("junk at end of line"); /* FIXME: would like to include `str' */
456867d70fcSchristos 
457867d70fcSchristos       return NULL;
458867d70fcSchristos     }
459867d70fcSchristos 
460867d70fcSchristos   /* We couldn't parse it.  */
461867d70fcSchristos   return _("unrecognized instruction");
462867d70fcSchristos }
463867d70fcSchristos 
464867d70fcSchristos /* Main entry point.
465867d70fcSchristos    This routine is called for each instruction to be assembled.
466867d70fcSchristos    STR points to the insn to be assembled.
467867d70fcSchristos    We assume all necessary tables have been initialized.
468867d70fcSchristos    The assembled instruction, less any fixups, is stored in BUF.
469867d70fcSchristos    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
470867d70fcSchristos    still needs to be converted to target byte order, otherwise BUF is an array
471867d70fcSchristos    of bytes in target byte order.
472867d70fcSchristos    The result is a pointer to the insn's entry in the opcode table,
473867d70fcSchristos    or NULL if an error occured (an error message will have already been
474867d70fcSchristos    printed).
475867d70fcSchristos 
476867d70fcSchristos    Note that when processing (non-alias) macro-insns,
477867d70fcSchristos    this function recurses.
478867d70fcSchristos 
479867d70fcSchristos    ??? It's possible to make this cpu-independent.
480867d70fcSchristos    One would have to deal with a few minor things.
481867d70fcSchristos    At this point in time doing so would be more of a curiosity than useful
482867d70fcSchristos    [for example this file isn't _that_ big], but keeping the possibility in
483867d70fcSchristos    mind helps keep the design clean.  */
484867d70fcSchristos 
485867d70fcSchristos const CGEN_INSN *
bpf_cgen_assemble_insn(CGEN_CPU_DESC cd,const char * str,CGEN_FIELDS * fields,CGEN_INSN_BYTES_PTR buf,char ** errmsg)486867d70fcSchristos bpf_cgen_assemble_insn (CGEN_CPU_DESC cd,
487867d70fcSchristos 			   const char *str,
488867d70fcSchristos 			   CGEN_FIELDS *fields,
489867d70fcSchristos 			   CGEN_INSN_BYTES_PTR buf,
490867d70fcSchristos 			   char **errmsg)
491867d70fcSchristos {
492867d70fcSchristos   const char *start;
493867d70fcSchristos   CGEN_INSN_LIST *ilist;
494867d70fcSchristos   const char *parse_errmsg = NULL;
495867d70fcSchristos   const char *insert_errmsg = NULL;
496867d70fcSchristos   int recognized_mnemonic = 0;
497867d70fcSchristos 
498867d70fcSchristos   /* Skip leading white space.  */
499867d70fcSchristos   while (ISSPACE (* str))
500867d70fcSchristos     ++ str;
501867d70fcSchristos 
502867d70fcSchristos   /* The instructions are stored in hashed lists.
503867d70fcSchristos      Get the first in the list.  */
504867d70fcSchristos   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
505867d70fcSchristos 
506867d70fcSchristos   /* Keep looking until we find a match.  */
507867d70fcSchristos   start = str;
508867d70fcSchristos   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
509867d70fcSchristos     {
510867d70fcSchristos       const CGEN_INSN *insn = ilist->insn;
511867d70fcSchristos       recognized_mnemonic = 1;
512867d70fcSchristos 
513867d70fcSchristos #ifdef CGEN_VALIDATE_INSN_SUPPORTED
514867d70fcSchristos       /* Not usually needed as unsupported opcodes
515867d70fcSchristos 	 shouldn't be in the hash lists.  */
516867d70fcSchristos       /* Is this insn supported by the selected cpu?  */
517867d70fcSchristos       if (! bpf_cgen_insn_supported (cd, insn))
518867d70fcSchristos 	continue;
519867d70fcSchristos #endif
520867d70fcSchristos       /* If the RELAXED attribute is set, this is an insn that shouldn't be
521867d70fcSchristos 	 chosen immediately.  Instead, it is used during assembler/linker
522867d70fcSchristos 	 relaxation if possible.  */
523867d70fcSchristos       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
524867d70fcSchristos 	continue;
525867d70fcSchristos 
526867d70fcSchristos       str = start;
527867d70fcSchristos 
528867d70fcSchristos       /* Skip this insn if str doesn't look right lexically.  */
529867d70fcSchristos       if (CGEN_INSN_RX (insn) != NULL &&
530867d70fcSchristos 	  regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
531867d70fcSchristos 	continue;
532867d70fcSchristos 
533867d70fcSchristos       /* Allow parse/insert handlers to obtain length of insn.  */
534867d70fcSchristos       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
535867d70fcSchristos 
536867d70fcSchristos       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
537867d70fcSchristos       if (parse_errmsg != NULL)
538867d70fcSchristos 	continue;
539867d70fcSchristos 
540867d70fcSchristos       /* ??? 0 is passed for `pc'.  */
541867d70fcSchristos       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
542867d70fcSchristos 						 (bfd_vma) 0);
543867d70fcSchristos       if (insert_errmsg != NULL)
544867d70fcSchristos         continue;
545867d70fcSchristos 
546867d70fcSchristos       /* It is up to the caller to actually output the insn and any
547867d70fcSchristos          queued relocs.  */
548867d70fcSchristos       return insn;
549867d70fcSchristos     }
550867d70fcSchristos 
551867d70fcSchristos   {
552867d70fcSchristos     static char errbuf[150];
553867d70fcSchristos     const char *tmp_errmsg;
554867d70fcSchristos #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
555867d70fcSchristos #define be_verbose 1
556867d70fcSchristos #else
557867d70fcSchristos #define be_verbose 0
558867d70fcSchristos #endif
559867d70fcSchristos 
560867d70fcSchristos     if (be_verbose)
561867d70fcSchristos       {
562867d70fcSchristos 	/* If requesting verbose error messages, use insert_errmsg.
563867d70fcSchristos 	   Failing that, use parse_errmsg.  */
564867d70fcSchristos 	tmp_errmsg = (insert_errmsg ? insert_errmsg :
565867d70fcSchristos 		      parse_errmsg ? parse_errmsg :
566867d70fcSchristos 		      recognized_mnemonic ?
567867d70fcSchristos 		      _("unrecognized form of instruction") :
568867d70fcSchristos 		      _("unrecognized instruction"));
569867d70fcSchristos 
570867d70fcSchristos 	if (strlen (start) > 50)
571867d70fcSchristos 	  /* xgettext:c-format */
572867d70fcSchristos 	  sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
573867d70fcSchristos 	else
574867d70fcSchristos 	  /* xgettext:c-format */
575867d70fcSchristos 	  sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
576867d70fcSchristos       }
577867d70fcSchristos     else
578867d70fcSchristos       {
579867d70fcSchristos 	if (strlen (start) > 50)
580867d70fcSchristos 	  /* xgettext:c-format */
581867d70fcSchristos 	  sprintf (errbuf, _("bad instruction `%.50s...'"), start);
582867d70fcSchristos 	else
583867d70fcSchristos 	  /* xgettext:c-format */
584867d70fcSchristos 	  sprintf (errbuf, _("bad instruction `%.50s'"), start);
585867d70fcSchristos       }
586867d70fcSchristos 
587867d70fcSchristos     *errmsg = errbuf;
588867d70fcSchristos     return NULL;
589867d70fcSchristos   }
590867d70fcSchristos }
591