Coverage Report

Created: 2024-05-21 06:29

/src/binutils-gdb/opcodes/mmix-dis.c
Line
Count
Source (jump to first uncovered line)
1
/* mmix-dis.c -- Disassemble MMIX instructions.
2
   Copyright (C) 2000-2024 Free Software Foundation, Inc.
3
   Written by Hans-Peter Nilsson (hp@bitrange.com)
4
5
   This file is part of the GNU opcodes library.
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
18
   along with this file; see the file COPYING.  If not, write to the Free
19
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20
   MA 02110-1301, USA.  */
21
22
#include "sysdep.h"
23
#include <stdio.h>
24
#include "opcode/mmix.h"
25
#include "disassemble.h"
26
#include "libiberty.h"
27
#include "bfd.h"
28
#include "opintl.h"
29
30
#define BAD_CASE(x)           \
31
0
  do                \
32
0
   {               \
33
0
     opcodes_error_handler (_("bad case %d (%s) in %s:%d"),  \
34
0
          x, #x, __FILE__, __LINE__);   \
35
0
     abort ();              \
36
0
   }                \
37
0
 while (0)
38
39
#define FATAL_DEBUG           \
40
0
 do                \
41
0
   {               \
42
0
     opcodes_error_handler (_("internal: non-debugged code " \
43
0
            "(test-case missing): %s:%d"),  \
44
0
          __FILE__, __LINE__);    \
45
0
     abort ();              \
46
0
   }                \
47
0
 while (0)
48
49
#define ROUND_MODE(n)         \
50
446
 ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" :  \
51
271
  (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" :  \
52
75
  _("(unknown)"))
53
54
66.3k
#define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24)
55
12.6k
#define INSN_BACKWARD_OFFSET_BIT (1 << 24)
56
57
269k
#define MAX_REG_NAME_LEN       256
58
665
#define MAX_SPEC_REG_NAME_LEN  32
59
struct mmix_dis_info
60
 {
61
   const char *reg_name[MAX_REG_NAME_LEN];
62
   const char *spec_reg_name[MAX_SPEC_REG_NAME_LEN];
63
64
   /* Waste a little memory so we don't have to allocate each separately.
65
      We could have an array with static contents for these, but on the
66
      other hand, we don't have to.  */
67
   char basic_reg_name[MAX_REG_NAME_LEN][sizeof ("$255")];
68
 };
69
70
/* Initialize a target-specific array in INFO.  */
71
72
static bool
73
initialize_mmix_dis_info (struct disassemble_info *info)
74
233
{
75
233
  struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info));
76
233
  long i;
77
78
233
  if (minfop == NULL)
79
0
    return false;
80
81
233
  memset (minfop, 0, sizeof (*minfop));
82
83
  /* Initialize register names from register symbols.  If there's no
84
     register section, then there are no register symbols.  */
85
233
  if ((info->section != NULL && info->section->owner != NULL)
86
233
      || (info->symbols != NULL
87
130
    && info->symbols[0] != NULL
88
130
    && bfd_asymbol_bfd (info->symbols[0]) != NULL))
89
103
    {
90
103
      bfd *abfd = info->section && info->section->owner != NULL
91
103
  ? info->section->owner
92
103
  : bfd_asymbol_bfd (info->symbols[0]);
93
103
      asection *reg_section = bfd_get_section_by_name (abfd, "*REG*");
94
95
103
      if (reg_section != NULL)
96
14
  {
97
    /* The returned symcount *does* include the ending NULL.  */
98
14
    long symsize = bfd_get_symtab_upper_bound (abfd);
99
14
    asymbol **syms = malloc (symsize);
100
14
    long nsyms;
101
102
14
    if (syms == NULL)
103
0
      {
104
0
        FATAL_DEBUG;
105
0
        free (minfop);
106
0
        return false;
107
0
      }
108
14
    nsyms = bfd_canonicalize_symtab (abfd, syms);
109
110
    /* We use the first name for a register.  If this is MMO, then
111
       it's the name with the first sequence number, presumably the
112
       first in the source.  */
113
512
    for (i = 0; i < nsyms && syms[i] != NULL; i++)
114
498
      {
115
498
        if (syms[i]->section == reg_section
116
498
      && syms[i]->value < MAX_REG_NAME_LEN
117
498
      && minfop->reg_name[syms[i]->value] == NULL)
118
28
    minfop->reg_name[syms[i]->value] = syms[i]->name;
119
498
      }
120
14
    free (syms);
121
14
  }
122
103
    }
123
124
  /* Fill in the rest with the canonical names.  */
125
59.8k
  for (i = 0; i < MAX_REG_NAME_LEN; i++)
126
59.6k
    if (minfop->reg_name[i] == NULL)
127
59.6k
      {
128
59.6k
  sprintf (minfop->basic_reg_name[i], "$%ld", i);
129
59.6k
  minfop->reg_name[i] = minfop->basic_reg_name[i];
130
59.6k
      }
131
132
  /* We assume it's actually a one-to-one mapping of number-to-name.  */
133
7.68k
  for (i = 0; mmix_spec_regs[i].name != NULL; i++)
134
7.45k
    minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name;
135
136
233
  info->private_data = (void *) minfop;
137
233
  return true;
138
233
}
139
140
/* A table indexed by the first byte is constructed as we disassemble each
141
   tetrabyte.  The contents is a pointer into mmix_insns reflecting the
142
   first found entry with matching match-bits and lose-bits.  Further
143
   entries are considered one after one until the operand constraints
144
   match or the match-bits and lose-bits do not match.  Normally a
145
   "further entry" will just show that there was no other match.  */
146
147
static const struct mmix_opcode *
148
get_opcode (unsigned long insn)
149
180k
{
150
180k
  static const struct mmix_opcode **opcodes = NULL;
151
180k
  const struct mmix_opcode *opcodep = mmix_opcodes;
152
180k
  unsigned int opcode_part = (insn >> 24) & 255;
153
154
180k
  if (opcodes == NULL)
155
2
    opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
156
157
180k
  opcodep = opcodes[opcode_part];
158
180k
  if (opcodep == NULL
159
180k
      || (opcodep->match & insn) != opcodep->match
160
180k
      || (opcodep->lose & insn) != 0)
161
121k
    {
162
      /* Search through the table.  */
163
9.62M
      for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
164
9.62M
  {
165
    /* FIXME: Break out this into an initialization function.  */
166
9.62M
    if ((opcodep->match & (opcode_part << 24)) == opcode_part
167
9.62M
        && (opcodep->lose & (opcode_part << 24)) == 0)
168
2
      opcodes[opcode_part] = opcodep;
169
170
9.62M
    if ((opcodep->match & insn) == opcodep->match
171
9.62M
        && (opcodep->lose & insn) == 0)
172
117k
      break;
173
9.62M
  }
174
121k
    }
175
176
180k
  if (opcodep->name == NULL)
177
4.08k
    return NULL;
178
179
  /* Check constraints.  If they don't match, loop through the next opcode
180
     entries.  */
181
176k
  do
182
176k
    {
183
176k
      switch (opcodep->operands)
184
176k
  {
185
    /* These have no restraint on what can be in the lower three
186
       bytes.  */
187
10.5k
  case mmix_operands_regs:
188
15.2k
  case mmix_operands_reg_yz:
189
29.6k
  case mmix_operands_regs_z_opt:
190
72.8k
  case mmix_operands_regs_z:
191
73.8k
  case mmix_operands_jmp:
192
74.2k
  case mmix_operands_pushgo:
193
74.8k
  case mmix_operands_pop:
194
77.0k
  case mmix_operands_sync:
195
79.9k
  case mmix_operands_x_regs_z:
196
81.6k
  case mmix_operands_neg:
197
83.4k
  case mmix_operands_pushj:
198
93.2k
  case mmix_operands_regaddr:
199
93.4k
  case mmix_operands_get:
200
93.4k
  case mmix_operands_set:
201
93.4k
  case mmix_operands_save:
202
93.5k
  case mmix_operands_unsave:
203
167k
  case mmix_operands_xyz_opt:
204
167k
    return opcodep;
205
206
    /* For a ROUND_MODE, the middle byte must be 0..4.  */
207
6.00k
  case mmix_operands_roundregs_z:
208
7.98k
  case mmix_operands_roundregs:
209
7.98k
    {
210
7.98k
      int midbyte = (insn >> 8) & 255;
211
212
7.98k
      if (midbyte <= 4)
213
3.64k
        return opcodep;
214
7.98k
    }
215
4.33k
  break;
216
217
4.33k
  case mmix_operands_put:
218
    /* A "PUT".  If it is "immediate", then no restrictions,
219
       otherwise we have to make sure the register number is < 32.  */
220
545
    if ((insn & INSN_IMMEDIATE_BIT)
221
545
        || ((insn >> 16) & 255) < 32)
222
493
      return opcodep;
223
52
    break;
224
225
52
  case mmix_operands_resume:
226
    /* Middle bytes must be zero.  */
227
27
    if ((insn & 0x00ffff00) == 0)
228
27
      return opcodep;
229
0
    break;
230
231
0
  default:
232
0
    BAD_CASE (opcodep->operands);
233
176k
  }
234
235
4.38k
      opcodep++;
236
4.38k
    }
237
176k
  while ((opcodep->match & insn) == opcodep->match
238
4.38k
   && (opcodep->lose & insn) == 0);
239
240
  /* If we got here, we had no match.  */
241
4.38k
  return NULL;
242
176k
}
243
244
static inline const char *
245
get_reg_name (const struct mmix_dis_info * minfop, unsigned int x)
246
208k
{
247
208k
  if (x >= MAX_REG_NAME_LEN)
248
0
    return _("*illegal*");
249
208k
  return minfop->reg_name[x];
250
208k
}
251
252
static inline const char *
253
get_spec_reg_name (const struct mmix_dis_info * minfop, unsigned int x)
254
665
{
255
665
  if (x >= MAX_SPEC_REG_NAME_LEN)
256
16
    return _("*illegal*");
257
649
  return minfop->spec_reg_name[x];
258
665
}
259
260
/* The main disassembly function.  */
261
262
int
263
print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
264
180k
{
265
180k
  unsigned char buffer[4];
266
180k
  unsigned long insn;
267
180k
  unsigned int x, y, z;
268
180k
  const struct mmix_opcode *opcodep;
269
180k
  int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
270
180k
  struct mmix_dis_info *minfop;
271
272
180k
  if (status != 0)
273
92
    {
274
92
      (*info->memory_error_func) (status, memaddr, info);
275
92
      return -1;
276
92
    }
277
278
  /* FIXME: Is -1 suitable?  */
279
180k
  if (info->private_data == NULL
280
180k
      && ! initialize_mmix_dis_info (info))
281
0
    return -1;
282
283
180k
  minfop = (struct mmix_dis_info *) info->private_data;
284
180k
  x = buffer[1];
285
180k
  y = buffer[2];
286
180k
  z = buffer[3];
287
288
180k
  insn = bfd_getb32 (buffer);
289
290
180k
  opcodep = get_opcode (insn);
291
292
180k
  if (opcodep == NULL)
293
8.47k
    {
294
8.47k
      (*info->fprintf_func) (info->stream, _("*unknown*"));
295
8.47k
      return 4;
296
8.47k
    }
297
298
171k
  (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
299
300
  /* Present bytes in the order they are laid out in memory.  */
301
171k
  info->display_endian = BFD_ENDIAN_BIG;
302
303
171k
  info->insn_info_valid = 1;
304
171k
  info->bytes_per_chunk = 4;
305
171k
  info->branch_delay_insns = 0;
306
171k
  info->target = 0;
307
171k
  switch (opcodep->type)
308
171k
    {
309
69.3k
    case mmix_type_normal:
310
71.7k
    case mmix_type_memaccess_block:
311
71.7k
      info->insn_type = dis_nonbranch;
312
71.7k
      break;
313
314
2.16k
    case mmix_type_branch:
315
2.16k
      info->insn_type = dis_branch;
316
2.16k
      break;
317
318
9.14k
    case mmix_type_condbranch:
319
9.14k
      info->insn_type = dis_condbranch;
320
9.14k
      break;
321
322
3.93k
    case mmix_type_memaccess_octa:
323
3.93k
      info->insn_type = dis_dref;
324
3.93k
      info->data_size = 8;
325
3.93k
      break;
326
327
4.09k
    case mmix_type_memaccess_tetra:
328
4.09k
      info->insn_type = dis_dref;
329
4.09k
      info->data_size = 4;
330
4.09k
      break;
331
332
2.01k
    case mmix_type_memaccess_wyde:
333
2.01k
      info->insn_type = dis_dref;
334
2.01k
      info->data_size = 2;
335
2.01k
      break;
336
337
3.39k
    case mmix_type_memaccess_byte:
338
3.39k
      info->insn_type = dis_dref;
339
3.39k
      info->data_size = 1;
340
3.39k
      break;
341
342
75.2k
    case mmix_type_jsr:
343
75.2k
      info->insn_type = dis_jsr;
344
75.2k
      break;
345
346
0
    default:
347
0
      BAD_CASE(opcodep->type);
348
171k
    }
349
350
171k
  switch (opcodep->operands)
351
171k
    {
352
10.5k
    case mmix_operands_regs:
353
      /*  All registers: "$X,$Y,$Z".  */
354
10.5k
      (*info->fprintf_func) (info->stream, "%s,%s,%s",
355
10.5k
           get_reg_name (minfop, x),
356
10.5k
           get_reg_name (minfop, y),
357
10.5k
           get_reg_name (minfop, z));
358
10.5k
      break;
359
360
4.72k
    case mmix_operands_reg_yz:
361
      /* Like SETH - "$X,YZ".  */
362
4.72k
      (*info->fprintf_func) (info->stream, "%s,0x%x",
363
4.72k
           get_reg_name (minfop, x), y * 256 + z);
364
4.72k
      break;
365
366
14.4k
    case mmix_operands_regs_z_opt:
367
57.5k
    case mmix_operands_regs_z:
368
57.9k
    case mmix_operands_pushgo:
369
      /* The regular "$X,$Y,$Z|Z".  */
370
57.9k
      if (insn & INSN_IMMEDIATE_BIT)
371
26.9k
  (*info->fprintf_func) (info->stream, "%s,%s,%d",
372
26.9k
             get_reg_name (minfop, x),
373
26.9k
             get_reg_name (minfop, y), z);
374
31.0k
      else
375
31.0k
  (*info->fprintf_func) (info->stream, "%s,%s,%s",
376
31.0k
             get_reg_name (minfop, x),
377
31.0k
             get_reg_name (minfop, y),
378
31.0k
             get_reg_name (minfop, z));
379
57.9k
      break;
380
381
1.01k
    case mmix_operands_jmp:
382
      /* Address; only JMP.  */
383
1.01k
      {
384
1.01k
  bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
385
386
1.01k
  if (insn & INSN_BACKWARD_OFFSET_BIT)
387
250
    offset -= (256 * 65536) * 4;
388
389
1.01k
  info->target = memaddr + offset;
390
1.01k
  (*info->print_address_func) (memaddr + offset, info);
391
1.01k
      }
392
1.01k
      break;
393
394
2.72k
    case mmix_operands_roundregs_z:
395
      /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
396
   "$X,ROUND_MODE,$Z|Z".  */
397
2.72k
      if (y != 0)
398
254
  {
399
254
    if (insn & INSN_IMMEDIATE_BIT)
400
180
      (*info->fprintf_func) (info->stream, "%s,%s,%d",
401
180
           get_reg_name (minfop, x),
402
180
           ROUND_MODE (y), z);
403
74
    else
404
74
      (*info->fprintf_func) (info->stream, "%s,%s,%s",
405
74
           get_reg_name (minfop, x),
406
74
           ROUND_MODE (y),
407
74
           get_reg_name (minfop, z));
408
254
  }
409
2.47k
      else
410
2.47k
  {
411
2.47k
    if (insn & INSN_IMMEDIATE_BIT)
412
735
      (*info->fprintf_func) (info->stream, "%s,%d",
413
735
           get_reg_name (minfop, x), z);
414
1.73k
    else
415
1.73k
      (*info->fprintf_func) (info->stream, "%s,%s",
416
1.73k
           get_reg_name (minfop, x),
417
1.73k
           get_reg_name (minfop, z));
418
2.47k
  }
419
2.72k
      break;
420
421
603
    case mmix_operands_pop:
422
      /* Like POP - "X,YZ".  */
423
603
      (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
424
603
      break;
425
426
918
    case mmix_operands_roundregs:
427
      /* Two registers, possibly with rounding: "$X,$Z" or
428
   "$X,ROUND_MODE,$Z".  */
429
918
      if (y != 0)
430
192
  (*info->fprintf_func) (info->stream, "%s,%s,%s",
431
192
             get_reg_name (minfop, x),
432
192
             ROUND_MODE (y),
433
192
             get_reg_name (minfop, z));
434
726
      else
435
726
  (*info->fprintf_func) (info->stream, "%s,%s",
436
726
             get_reg_name (minfop, x),
437
726
             get_reg_name (minfop, z));
438
918
      break;
439
440
2.14k
    case mmix_operands_sync:
441
  /* Like SYNC - "XYZ".  */
442
2.14k
      (*info->fprintf_func) (info->stream, "%u",
443
2.14k
           x * 65536 + y * 256 + z);
444
2.14k
      break;
445
446
2.91k
    case mmix_operands_x_regs_z:
447
      /* Like SYNCD - "X,$Y,$Z|Z".  */
448
2.91k
      if (insn & INSN_IMMEDIATE_BIT)
449
1.52k
  (*info->fprintf_func) (info->stream, "%d,%s,%d",
450
1.52k
             x, get_reg_name (minfop, y), z);
451
1.38k
      else
452
1.38k
  (*info->fprintf_func) (info->stream, "%d,%s,%s",
453
1.38k
             x, get_reg_name (minfop, y),
454
1.38k
             get_reg_name (minfop, z));
455
2.91k
      break;
456
457
1.72k
    case mmix_operands_neg:
458
      /* Like NEG and NEGU - "$X,Y,$Z|Z".  */
459
1.72k
      if (insn & INSN_IMMEDIATE_BIT)
460
620
  (*info->fprintf_func) (info->stream, "%s,%d,%d",
461
620
             get_reg_name (minfop, x), y, z);
462
1.10k
      else
463
1.10k
  (*info->fprintf_func) (info->stream, "%s,%d,%s",
464
1.10k
             get_reg_name (minfop, x), y,
465
1.10k
             get_reg_name (minfop, z));
466
1.72k
      break;
467
468
1.79k
    case mmix_operands_pushj:
469
11.6k
    case mmix_operands_regaddr:
470
      /* Like GETA or branches - "$X,Address".  */
471
11.6k
      {
472
11.6k
  bfd_signed_vma offset = (y * 256 + z) * 4;
473
474
11.6k
  if (insn & INSN_BACKWARD_OFFSET_BIT)
475
5.40k
    offset -= 65536 * 4;
476
477
11.6k
  info->target = memaddr + offset;
478
479
11.6k
  (*info->fprintf_func) (info->stream, "%s,", get_reg_name (minfop, x));
480
11.6k
  (*info->print_address_func) (memaddr + offset, info);
481
11.6k
      }
482
11.6k
      break;
483
484
172
    case mmix_operands_get:
485
      /* GET - "X,spec_reg".  */
486
172
      (*info->fprintf_func) (info->stream, "%s,%s",
487
172
           get_reg_name (minfop, x),
488
172
           get_spec_reg_name (minfop, z));
489
172
      break;
490
491
493
    case mmix_operands_put:
492
      /* PUT - "spec_reg,$Z|Z".  */
493
493
      if (insn & INSN_IMMEDIATE_BIT)
494
240
  (*info->fprintf_func) (info->stream, "%s,%d",
495
240
             get_spec_reg_name (minfop, x), z);
496
253
      else
497
253
  (*info->fprintf_func) (info->stream, "%s,%s",
498
253
             get_spec_reg_name (minfop, x),
499
253
             get_reg_name (minfop, z));
500
493
      break;
501
502
23
    case mmix_operands_set:
503
      /*  Two registers, "$X,$Y".  */
504
23
      (*info->fprintf_func) (info->stream, "%s,%s",
505
23
           get_reg_name (minfop, x),
506
23
           get_reg_name (minfop, y));
507
23
      break;
508
509
19
    case mmix_operands_save:
510
      /* SAVE - "$X,0".  */
511
19
      (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
512
19
      break;
513
514
6
    case mmix_operands_unsave:
515
      /* UNSAVE - "0,$Z".  */
516
6
      (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
517
6
      break;
518
519
74.1k
    case mmix_operands_xyz_opt:
520
      /* Like SWYM or TRAP - "X,Y,Z".  */
521
74.1k
      (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
522
74.1k
      break;
523
524
27
    case mmix_operands_resume:
525
      /* Just "Z", like RESUME.  */
526
27
      (*info->fprintf_func) (info->stream, "%d", z);
527
27
      break;
528
529
0
    default:
530
0
      (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),
531
0
           opcodep->operands);
532
0
      break;
533
171k
    }
534
535
171k
  return 4;
536
171k
}