Coverage Report

Created: 2023-08-28 06:30

/src/binutils-gdb/opcodes/cgen-opc.c
Line
Count
Source (jump to first uncovered line)
1
/* CGEN generic opcode support.
2
3
   Copyright (C) 1996-2023 Free Software Foundation, Inc.
4
5
   This file is part of libopcodes.
6
7
   This library is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3, or (at your option)
10
   any later version.
11
12
   It is distributed in the hope that it will be useful, but WITHOUT
13
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15
   License for more details.
16
17
   You should have received a copy of the GNU General Public License along
18
   with this program; if not, write to the Free Software Foundation, Inc.,
19
   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
20
21
#include "sysdep.h"
22
#include <stdio.h>
23
#include "ansidecl.h"
24
#include "libiberty.h"
25
#include "safe-ctype.h"
26
#include "bfd.h"
27
#include "symcat.h"
28
#include "opcode/cgen.h"
29
30
static unsigned int hash_keyword_name
31
  (const CGEN_KEYWORD *, const char *, int);
32
static unsigned int hash_keyword_value
33
  (const CGEN_KEYWORD *, unsigned int);
34
static void build_keyword_hash_tables
35
  (CGEN_KEYWORD *);
36
37
/* Return number of hash table entries to use for N elements.  */
38
16
#define KEYWORD_HASH_SIZE(n) ((n) <= 31 ? 17 : 31)
39
40
/* Look up *NAMEP in the keyword table KT.
41
   The result is the keyword entry or NULL if not found.  */
42
43
const CGEN_KEYWORD_ENTRY *
44
cgen_keyword_lookup_name (CGEN_KEYWORD *kt, const char *name)
45
0
{
46
0
  const CGEN_KEYWORD_ENTRY *ke;
47
0
  const char *p,*n;
48
49
0
  if (kt->name_hash_table == NULL)
50
0
    build_keyword_hash_tables (kt);
51
52
0
  ke = kt->name_hash_table[hash_keyword_name (kt, name, 0)];
53
54
  /* We do case insensitive comparisons.
55
     If that ever becomes a problem, add an attribute that denotes
56
     "do case sensitive comparisons".  */
57
58
0
  while (ke != NULL)
59
0
    {
60
0
      n = name;
61
0
      p = ke->name;
62
63
0
      while (*p
64
0
       && (*p == *n
65
0
     || (ISALPHA (*p) && (TOLOWER (*p) == TOLOWER (*n)))))
66
0
  ++n, ++p;
67
68
0
      if (!*p && !*n)
69
0
  return ke;
70
71
0
      ke = ke->next_name;
72
0
    }
73
74
0
  if (kt->null_entry)
75
0
    return kt->null_entry;
76
0
  return NULL;
77
0
}
78
79
/* Look up VALUE in the keyword table KT.
80
   The result is the keyword entry or NULL if not found.  */
81
82
const CGEN_KEYWORD_ENTRY *
83
cgen_keyword_lookup_value (CGEN_KEYWORD *kt, int value)
84
559k
{
85
559k
  const CGEN_KEYWORD_ENTRY *ke;
86
87
559k
  if (kt->name_hash_table == NULL)
88
16
    build_keyword_hash_tables (kt);
89
90
559k
  ke = kt->value_hash_table[hash_keyword_value (kt, value)];
91
92
594k
  while (ke != NULL)
93
592k
    {
94
592k
      if (value == ke->value)
95
557k
  return ke;
96
35.2k
      ke = ke->next_value;
97
35.2k
    }
98
99
1.90k
  return NULL;
100
559k
}
101
102
/* Add an entry to a keyword table.  */
103
104
void
105
cgen_keyword_add (CGEN_KEYWORD *kt, CGEN_KEYWORD_ENTRY *ke)
106
364
{
107
364
  unsigned int hash;
108
364
  size_t i;
109
110
364
  if (kt->name_hash_table == NULL)
111
0
    build_keyword_hash_tables (kt);
112
113
364
  hash = hash_keyword_name (kt, ke->name, 0);
114
364
  ke->next_name = kt->name_hash_table[hash];
115
364
  kt->name_hash_table[hash] = ke;
116
117
364
  hash = hash_keyword_value (kt, ke->value);
118
364
  ke->next_value = kt->value_hash_table[hash];
119
364
  kt->value_hash_table[hash] = ke;
120
121
364
  if (ke->name[0] == 0)
122
0
    kt->null_entry = ke;
123
124
1.35k
  for (i = 1; i < strlen (ke->name); i++)
125
988
    if (! ISALNUM (ke->name[i])
126
988
  && ! strchr (kt->nonalpha_chars, ke->name[i]))
127
0
      {
128
0
  size_t idx = strlen (kt->nonalpha_chars);
129
130
  /* If you hit this limit, please don't just
131
     increase the size of the field, instead
132
     look for a better algorithm.  */
133
0
  if (idx >= sizeof (kt->nonalpha_chars) - 1)
134
0
    abort ();
135
0
  kt->nonalpha_chars[idx] = ke->name[i];
136
0
  kt->nonalpha_chars[idx+1] = 0;
137
0
      }
138
364
}
139
140
/* FIXME: Need function to return count of keywords.  */
141
142
/* Initialize a keyword table search.
143
   SPEC is a specification of what to search for.
144
   A value of NULL means to find every keyword.
145
   Currently NULL is the only acceptable value [further specification
146
   deferred].
147
   The result is an opaque data item used to record the search status.
148
   It is passed to each call to cgen_keyword_search_next.  */
149
150
CGEN_KEYWORD_SEARCH
151
cgen_keyword_search_init (CGEN_KEYWORD *kt, const char *spec)
152
0
{
153
0
  CGEN_KEYWORD_SEARCH search;
154
155
  /* FIXME: Need to specify format of params.  */
156
0
  if (spec != NULL)
157
0
    abort ();
158
159
0
  if (kt->name_hash_table == NULL)
160
0
    build_keyword_hash_tables (kt);
161
162
0
  search.table = kt;
163
0
  search.spec = spec;
164
0
  search.current_hash = 0;
165
0
  search.current_entry = NULL;
166
0
  return search;
167
0
}
168
169
/* Return the next keyword specified by SEARCH.
170
   The result is the next entry or NULL if there are no more.  */
171
172
const CGEN_KEYWORD_ENTRY *
173
cgen_keyword_search_next (CGEN_KEYWORD_SEARCH *search)
174
0
{
175
  /* Has search finished?  */
176
0
  if (search->current_hash == search->table->hash_table_size)
177
0
    return NULL;
178
179
  /* Search in progress?  */
180
0
  if (search->current_entry != NULL
181
      /* Anything left on this hash chain?  */
182
0
      && search->current_entry->next_name != NULL)
183
0
    {
184
0
      search->current_entry = search->current_entry->next_name;
185
0
      return search->current_entry;
186
0
    }
187
188
  /* Move to next hash chain [unless we haven't started yet].  */
189
0
  if (search->current_entry != NULL)
190
0
    ++search->current_hash;
191
192
0
  while (search->current_hash < search->table->hash_table_size)
193
0
    {
194
0
      search->current_entry = search->table->name_hash_table[search->current_hash];
195
0
      if (search->current_entry != NULL)
196
0
  return search->current_entry;
197
0
      ++search->current_hash;
198
0
    }
199
200
0
  return NULL;
201
0
}
202
203
/* Return first entry in hash chain for NAME.
204
   If CASE_SENSITIVE_P is non-zero, return a case sensitive hash.  */
205
206
static unsigned int
207
hash_keyword_name (const CGEN_KEYWORD *kt,
208
       const char *name,
209
       int case_sensitive_p)
210
364
{
211
364
  unsigned int hash;
212
213
364
  if (case_sensitive_p)
214
0
    for (hash = 0; *name; ++name)
215
0
      hash = (hash * 97) + (unsigned char) *name;
216
364
  else
217
1.71k
    for (hash = 0; *name; ++name)
218
1.35k
      hash = (hash * 97) + (unsigned char) TOLOWER (*name);
219
364
  return hash % kt->hash_table_size;
220
364
}
221
222
/* Return first entry in hash chain for VALUE.  */
223
224
static unsigned int
225
hash_keyword_value (const CGEN_KEYWORD *kt, unsigned int value)
226
559k
{
227
559k
  return value % kt->hash_table_size;
228
559k
}
229
230
/* Build a keyword table's hash tables.
231
   We probably needn't build the value hash table for the assembler when
232
   we're using the disassembler, but we keep things simple.  */
233
234
static void
235
build_keyword_hash_tables (CGEN_KEYWORD *kt)
236
16
{
237
16
  int i;
238
  /* Use the number of compiled in entries as an estimate for the
239
     typical sized table [not too many added at runtime].  */
240
16
  unsigned int size = KEYWORD_HASH_SIZE (kt->num_init_entries);
241
242
16
  kt->hash_table_size = size;
243
16
  kt->name_hash_table = (CGEN_KEYWORD_ENTRY **)
244
16
    xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
245
16
  memset (kt->name_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
246
16
  kt->value_hash_table = (CGEN_KEYWORD_ENTRY **)
247
16
    xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
248
16
  memset (kt->value_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
249
250
  /* The table is scanned backwards as we want keywords appearing earlier to
251
     be prefered over later ones.  */
252
380
  for (i = kt->num_init_entries - 1; i >= 0; --i)
253
364
    cgen_keyword_add (kt, &kt->init_entries[i]);
254
16
}
255

256
/* Hardware support.  */
257
258
/* Lookup a hardware element by its name.
259
   Returns NULL if NAME is not supported by the currently selected
260
   mach/isa.  */
261
262
const CGEN_HW_ENTRY *
263
cgen_hw_lookup_by_name (CGEN_CPU_DESC cd, const char *name)
264
0
{
265
0
  unsigned int i;
266
0
  const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
267
268
0
  for (i = 0; i < cd->hw_table.num_entries; ++i)
269
0
    if (hw[i] && strcmp (name, hw[i]->name) == 0)
270
0
      return hw[i];
271
272
0
  return NULL;
273
0
}
274
275
/* Lookup a hardware element by its number.
276
   Hardware elements are enumerated, however it may be possible to add some
277
   at runtime, thus HWNUM is not an enum type but rather an int.
278
   Returns NULL if HWNUM is not supported by the currently selected mach.  */
279
280
const CGEN_HW_ENTRY *
281
cgen_hw_lookup_by_num (CGEN_CPU_DESC cd, unsigned int hwnum)
282
0
{
283
0
  unsigned int i;
284
0
  const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
285
286
  /* ??? This can be speeded up.  */
287
0
  for (i = 0; i < cd->hw_table.num_entries; ++i)
288
0
    if (hw[i] && hwnum == hw[i]->type)
289
0
      return hw[i];
290
291
0
  return NULL;
292
0
}
293

294
/* Operand support.  */
295
296
/* Lookup an operand by its name.
297
   Returns NULL if NAME is not supported by the currently selected
298
   mach/isa.  */
299
300
const CGEN_OPERAND *
301
cgen_operand_lookup_by_name (CGEN_CPU_DESC cd, const char *name)
302
0
{
303
0
  unsigned int i;
304
0
  const CGEN_OPERAND **op = cd->operand_table.entries;
305
306
0
  for (i = 0; i < cd->operand_table.num_entries; ++i)
307
0
    if (op[i] && strcmp (name, op[i]->name) == 0)
308
0
      return op[i];
309
310
0
  return NULL;
311
0
}
312
313
/* Lookup an operand by its number.
314
   Operands are enumerated, however it may be possible to add some
315
   at runtime, thus OPNUM is not an enum type but rather an int.
316
   Returns NULL if OPNUM is not supported by the currently selected
317
   mach/isa.  */
318
319
const CGEN_OPERAND *
320
cgen_operand_lookup_by_num (CGEN_CPU_DESC cd, int opnum)
321
0
{
322
0
  return cd->operand_table.entries[opnum];
323
0
}
324

325
/* Instruction support.  */
326
327
/* Return number of instructions.  This includes any added at runtime.  */
328
329
int
330
cgen_insn_count (CGEN_CPU_DESC cd)
331
10
{
332
10
  int count = cd->insn_table.num_init_entries;
333
10
  CGEN_INSN_LIST *rt_insns = cd->insn_table.new_entries;
334
335
10
  for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
336
0
    ++count;
337
338
10
  return count;
339
10
}
340
341
/* Return number of macro-instructions.
342
   This includes any added at runtime.  */
343
344
int
345
cgen_macro_insn_count (CGEN_CPU_DESC cd)
346
10
{
347
10
  int count = cd->macro_insn_table.num_init_entries;
348
10
  CGEN_INSN_LIST *rt_insns = cd->macro_insn_table.new_entries;
349
350
10
  for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
351
0
    ++count;
352
353
10
  return count;
354
10
}
355
356
/* Cover function to read and properly byteswap an insn value.  */
357
358
CGEN_INSN_INT
359
cgen_get_insn_value (CGEN_CPU_DESC cd, unsigned char *buf, int length,
360
                     int endian)
361
544k
{
362
544k
  int big_p = (endian == CGEN_ENDIAN_BIG);
363
544k
  int insn_chunk_bitsize = cd->insn_chunk_bitsize;
364
544k
  CGEN_INSN_INT value = 0;
365
366
544k
  if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
367
0
    {
368
      /* We need to divide up the incoming value into insn_chunk_bitsize-length
369
   segments, and endian-convert them, one at a time. */
370
0
      int i;
371
372
      /* Enforce divisibility. */
373
0
      if ((length % insn_chunk_bitsize) != 0)
374
0
  abort ();
375
376
0
      for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
377
0
  {
378
0
    int bit_index;
379
0
    bfd_vma this_value;
380
381
0
    bit_index = i; /* NB: not dependent on endianness; opposite of cgen_put_insn_value! */
382
0
    this_value = bfd_get_bits (& buf[bit_index / 8], insn_chunk_bitsize, big_p);
383
0
    value = (value << insn_chunk_bitsize) | this_value;
384
0
  }
385
0
    }
386
544k
  else
387
544k
    {
388
544k
      value = bfd_get_bits (buf, length, endian == CGEN_ENDIAN_BIG);
389
544k
    }
390
391
544k
  return value;
392
544k
}
393
394
/* Cover function to store an insn value properly byteswapped.  */
395
396
void
397
cgen_put_insn_value (CGEN_CPU_DESC cd,
398
         unsigned char *buf,
399
         int length,
400
         CGEN_INSN_INT value,
401
                     int endian)
402
0
{
403
0
  int big_p = (endian == CGEN_ENDIAN_BIG);
404
0
  int insn_chunk_bitsize = cd->insn_chunk_bitsize;
405
406
0
  if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
407
0
    {
408
      /* We need to divide up the incoming value into insn_chunk_bitsize-length
409
   segments, and endian-convert them, one at a time. */
410
0
      int i;
411
412
      /* Enforce divisibility. */
413
0
      if ((length % insn_chunk_bitsize) != 0)
414
0
  abort ();
415
416
0
      for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
417
0
  {
418
0
    int bit_index;
419
420
0
    bit_index = (length - insn_chunk_bitsize - i); /* NB: not dependent on endianness! */
421
0
    bfd_put_bits ((bfd_vma) value, & buf[bit_index / 8], insn_chunk_bitsize, big_p);
422
0
    value >>= insn_chunk_bitsize;
423
0
  }
424
0
    }
425
0
  else
426
0
    {
427
0
      bfd_put_bits ((bfd_vma) value, buf, length, big_p);
428
0
    }
429
0
}
430

431
/* Look up instruction INSN_*_VALUE and extract its fields.
432
   INSN_INT_VALUE is used if CGEN_INT_INSN_P.
433
   Otherwise INSN_BYTES_VALUE is used.
434
   INSN, if non-null, is the insn table entry.
435
   Otherwise INSN_*_VALUE is examined to compute it.
436
   LENGTH is the bit length of INSN_*_VALUE if known, otherwise 0.
437
   0 is only valid if `insn == NULL && ! CGEN_INT_INSN_P'.
438
   If INSN != NULL, LENGTH must be valid.
439
   ALIAS_P is non-zero if alias insns are to be included in the search.
440
441
   The result is a pointer to the insn table entry, or NULL if the instruction
442
   wasn't recognized.  */
443
444
/* ??? Will need to be revisited for VLIW architectures.  */
445
446
const CGEN_INSN *
447
cgen_lookup_insn (CGEN_CPU_DESC cd,
448
      const CGEN_INSN *insn,
449
      CGEN_INSN_INT insn_int_value,
450
      /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
451
      unsigned char *insn_bytes_value,
452
      int length,
453
      CGEN_FIELDS *fields,
454
      int alias_p)
455
0
{
456
0
  CGEN_EXTRACT_INFO ex_info;
457
0
  CGEN_EXTRACT_INFO *info;
458
459
0
  if (cd->int_insn_p)
460
0
    {
461
0
      info = NULL;
462
0
      insn_bytes_value = (unsigned char *) xmalloc (cd->max_insn_bitsize / 8);
463
0
      cgen_put_insn_value (cd, insn_bytes_value, length, insn_int_value,
464
0
                           cd->insn_endian);
465
0
    }
466
0
  else
467
0
    {
468
0
      info = &ex_info;
469
0
      ex_info.dis_info = NULL;
470
0
      ex_info.insn_bytes = insn_bytes_value;
471
0
      ex_info.valid = -1;
472
0
      insn_int_value = cgen_get_insn_value (cd, insn_bytes_value, length,
473
0
                                            cd->insn_endian);
474
0
    }
475
476
0
  if (!insn)
477
0
    {
478
0
      const CGEN_INSN_LIST *insn_list;
479
480
      /* The instructions are stored in hash lists.
481
   Pick the first one and keep trying until we find the right one.  */
482
483
0
      insn_list = cgen_dis_lookup_insn (cd, (char *) insn_bytes_value,
484
0
          insn_int_value);
485
0
      while (insn_list != NULL)
486
0
  {
487
0
    insn = insn_list->insn;
488
489
0
    if (alias_p
490
        /* FIXME: Ensure ALIAS attribute always has same index.  */
491
0
        || ! CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
492
0
      {
493
        /* Basic bit mask must be correct.  */
494
        /* ??? May wish to allow target to defer this check until the
495
     extract handler.  */
496
0
        if ((insn_int_value & CGEN_INSN_BASE_MASK (insn))
497
0
      == CGEN_INSN_BASE_VALUE (insn))
498
0
    {
499
      /* ??? 0 is passed for `pc' */
500
0
      int elength = CGEN_EXTRACT_FN (cd, insn)
501
0
        (cd, insn, info, insn_int_value, fields, (bfd_vma) 0);
502
0
      if (elength > 0)
503
0
        {
504
          /* sanity check */
505
0
          if (length != 0 && length != elength)
506
0
      abort ();
507
0
          break;
508
0
        }
509
0
    }
510
0
      }
511
512
0
    insn_list = insn_list->next;
513
0
  }
514
0
    }
515
0
  else
516
0
    {
517
      /* Sanity check: can't pass an alias insn if ! alias_p.  */
518
0
      if (! alias_p
519
0
    && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
520
0
  abort ();
521
      /* Sanity check: length must be correct.  */
522
0
      if (length != CGEN_INSN_BITSIZE (insn))
523
0
  abort ();
524
525
      /* ??? 0 is passed for `pc' */
526
0
      length = CGEN_EXTRACT_FN (cd, insn)
527
0
  (cd, insn, info, insn_int_value, fields, (bfd_vma) 0);
528
      /* Sanity check: must succeed.
529
   Could relax this later if it ever proves useful.  */
530
0
      if (length == 0)
531
0
  abort ();
532
0
    }
533
534
0
  if (cd->int_insn_p)
535
0
    free (insn_bytes_value);
536
537
0
  return insn;
538
0
}
539
540
/* Fill in the operand instances used by INSN whose operands are FIELDS.
541
   INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
542
   in.  */
543
544
void
545
cgen_get_insn_operands (CGEN_CPU_DESC cd,
546
      const CGEN_INSN *insn,
547
      const CGEN_FIELDS *fields,
548
      int *indices)
549
0
{
550
0
  const CGEN_OPINST *opinst;
551
0
  int i;
552
553
0
  if (insn->opinst == NULL)
554
0
    abort ();
555
0
  for (i = 0, opinst = insn->opinst; opinst->type != CGEN_OPINST_END; ++i, ++opinst)
556
0
    {
557
0
      enum cgen_operand_type op_type = opinst->op_type;
558
0
      if (op_type == CGEN_OPERAND_NIL)
559
0
  indices[i] = opinst->index;
560
0
      else
561
0
  indices[i] = (*cd->get_int_operand) (cd, op_type, fields);
562
0
    }
563
0
}
564
565
/* Cover function to cgen_get_insn_operands when either INSN or FIELDS
566
   isn't known.
567
   The INSN, INSN_*_VALUE, and LENGTH arguments are passed to
568
   cgen_lookup_insn unchanged.
569
   INSN_INT_VALUE is used if CGEN_INT_INSN_P.
570
   Otherwise INSN_BYTES_VALUE is used.
571
572
   The result is the insn table entry or NULL if the instruction wasn't
573
   recognized.  */
574
575
const CGEN_INSN *
576
cgen_lookup_get_insn_operands (CGEN_CPU_DESC cd,
577
             const CGEN_INSN *insn,
578
             CGEN_INSN_INT insn_int_value,
579
             /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
580
             unsigned char *insn_bytes_value,
581
             int length,
582
             int *indices,
583
             CGEN_FIELDS *fields)
584
0
{
585
  /* Pass non-zero for ALIAS_P only if INSN != NULL.
586
     If INSN == NULL, we want a real insn.  */
587
0
  insn = cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value,
588
0
         length, fields, insn != NULL);
589
0
  if (! insn)
590
0
    return NULL;
591
592
0
  cgen_get_insn_operands (cd, insn, fields, indices);
593
0
  return insn;
594
0
}
595
596
/* Allow signed overflow of instruction fields.  */
597
void
598
cgen_set_signed_overflow_ok (CGEN_CPU_DESC cd)
599
0
{
600
0
  cd->signed_overflow_ok_p = 1;
601
0
}
602
603
/* Generate an error message if a signed field in an instruction overflows.  */
604
void
605
cgen_clear_signed_overflow_ok (CGEN_CPU_DESC cd)
606
0
{
607
0
  cd->signed_overflow_ok_p = 0;
608
0
}
609
610
/* Will an error message be generated if a signed field in an instruction overflows ? */
611
unsigned int
612
cgen_signed_overflow_ok_p (CGEN_CPU_DESC cd)
613
0
{
614
0
  return cd->signed_overflow_ok_p;
615
0
}