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