Coverage Report

Created: 2025-06-24 06:45

/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-2025 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
79
#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
1.55M
{
85
1.55M
  const CGEN_KEYWORD_ENTRY *ke;
86
87
1.55M
  if (kt->name_hash_table == NULL)
88
79
    build_keyword_hash_tables (kt);
89
90
1.55M
  ke = kt->value_hash_table[hash_keyword_value (kt, value)];
91
92
2.14M
  while (ke != NULL)
93
2.06M
    {
94
2.06M
      if (value == ke->value)
95
1.48M
  return ke;
96
583k
      ke = ke->next_value;
97
583k
    }
98
99
72.0k
  return NULL;
100
1.55M
}
101
102
/* Add an entry to a keyword table.  */
103
104
void
105
cgen_keyword_add (CGEN_KEYWORD *kt, CGEN_KEYWORD_ENTRY *ke)
106
2.57k
{
107
2.57k
  unsigned int hash;
108
2.57k
  size_t i;
109
110
2.57k
  if (kt->name_hash_table == NULL)
111
0
    build_keyword_hash_tables (kt);
112
113
2.57k
  hash = hash_keyword_name (kt, ke->name, 0);
114
2.57k
  ke->next_name = kt->name_hash_table[hash];
115
2.57k
  kt->name_hash_table[hash] = ke;
116
117
2.57k
  hash = hash_keyword_value (kt, ke->value);
118
2.57k
  ke->next_value = kt->value_hash_table[hash];
119
2.57k
  kt->value_hash_table[hash] = ke;
120
121
2.57k
  if (ke->name[0] == 0)
122
10
    kt->null_entry = ke;
123
124
11.4k
  for (i = 1; i < strlen (ke->name); i++)
125
8.88k
    if (! ISALNUM (ke->name[i])
126
8.88k
  && ! strchr (kt->nonalpha_chars, ke->name[i]))
127
1
      {
128
1
  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
1
  if (idx >= sizeof (kt->nonalpha_chars) - 1)
134
0
    abort ();
135
1
  kt->nonalpha_chars[idx] = ke->name[i];
136
1
  kt->nonalpha_chars[idx+1] = 0;
137
1
      }
138
2.57k
}
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
2.57k
{
211
2.57k
  unsigned int hash;
212
213
2.57k
  if (case_sensitive_p)
214
0
    for (hash = 0; *name; ++name)
215
0
      hash = (hash * 97) + (unsigned char) *name;
216
2.57k
  else
217
14.0k
    for (hash = 0; *name; ++name)
218
11.4k
      hash = (hash * 97) + (unsigned char) TOLOWER (*name);
219
2.57k
  return hash % kt->hash_table_size;
220
2.57k
}
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
1.56M
{
227
1.56M
  return value % kt->hash_table_size;
228
1.56M
}
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
79
{
237
79
  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
79
  unsigned int size = KEYWORD_HASH_SIZE (kt->num_init_entries);
241
242
79
  kt->hash_table_size = size;
243
79
  kt->name_hash_table = (CGEN_KEYWORD_ENTRY **)
244
79
    xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
245
79
  memset (kt->name_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
246
79
  kt->value_hash_table = (CGEN_KEYWORD_ENTRY **)
247
79
    xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
248
79
  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
2.65k
  for (i = kt->num_init_entries - 1; i >= 0; --i)
253
2.57k
    cgen_keyword_add (kt, &kt->init_entries[i]);
254
79
}
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
49
{
332
49
  int count = cd->insn_table.num_init_entries;
333
49
  CGEN_INSN_LIST *rt_insns = cd->insn_table.new_entries;
334
335
49
  for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
336
0
    ++count;
337
338
49
  return count;
339
49
}
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
49
{
347
49
  int count = cd->macro_insn_table.num_init_entries;
348
49
  CGEN_INSN_LIST *rt_insns = cd->macro_insn_table.new_entries;
349
350
49
  for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
351
0
    ++count;
352
353
49
  return count;
354
49
}
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
2.16M
{
362
2.16M
  int big_p = (endian == CGEN_ENDIAN_BIG);
363
2.16M
  int insn_chunk_bitsize = cd->insn_chunk_bitsize;
364
2.16M
  CGEN_INSN_INT value = 0;
365
366
2.16M
  if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
367
102k
    {
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
102k
      int i;
371
372
      /* Enforce divisibility. */
373
102k
      if ((length % insn_chunk_bitsize) != 0)
374
0
  abort ();
375
376
307k
      for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
377
205k
  {
378
205k
    int bit_index;
379
205k
    bfd_vma this_value;
380
381
205k
    bit_index = i; /* NB: not dependent on endianness; opposite of cgen_put_insn_value! */
382
205k
    this_value = bfd_get_bits (& buf[bit_index / 8], insn_chunk_bitsize, big_p);
383
205k
    value = (value << insn_chunk_bitsize) | this_value;
384
205k
  }
385
102k
    }
386
2.06M
  else
387
2.06M
    {
388
2.06M
      value = bfd_get_bits (buf, length, endian == CGEN_ENDIAN_BIG);
389
2.06M
    }
390
391
2.16M
  return value;
392
2.16M
}
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
}