Coverage Report

Created: 2025-07-08 11:15

/src/binutils-gdb/opcodes/s12z-dis.c
Line
Count
Source (jump to first uncovered line)
1
/* s12z-dis.c -- Freescale S12Z disassembly
2
   Copyright (C) 2018-2025 Free Software Foundation, Inc.
3
4
   This file is part of the GNU opcodes library.
5
6
   This library is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3, or (at your option)
9
   any later version.
10
11
   It is distributed in the hope that it will be useful, but WITHOUT
12
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14
   License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program; if not, write to the Free Software
18
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19
   MA 02110-1301, USA.  */
20
21
#include "sysdep.h"
22
#include <stdio.h>
23
#include <stdint.h>
24
#include <stdbool.h>
25
#include <assert.h>
26
27
#include "opcode/s12z.h"
28
#include "bfd.h"
29
#include "dis-asm.h"
30
#include "disassemble.h"
31
#include "s12z-opc.h"
32
#include "opintl.h"
33
34
struct mem_read_abstraction
35
{
36
  struct mem_read_abstraction_base base;
37
  bfd_vma memaddr;
38
  struct disassemble_info* info;
39
};
40
41
static void
42
advance (struct mem_read_abstraction_base *b)
43
299k
{
44
299k
  struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
45
299k
  mra->memaddr ++;
46
299k
}
47
48
static bfd_vma
49
posn (struct mem_read_abstraction_base *b)
50
20.9k
{
51
20.9k
  struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
52
20.9k
  return mra->memaddr;
53
20.9k
}
54
55
static int
56
abstract_read_memory (struct mem_read_abstraction_base *b,
57
          int offset,
58
          size_t n, bfd_byte *bytes)
59
882k
{
60
882k
  struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
61
62
882k
  int status = (*mra->info->read_memory_func) (mra->memaddr + offset,
63
882k
                 bytes, n, mra->info);
64
882k
  if (status != 0)
65
651
    (*mra->info->memory_error_func) (status, mra->memaddr + offset,
66
651
                                     mra->info);
67
882k
  return status != 0 ? -1 : 0;
68
882k
}
69
70
/* Start of disassembly file.  */
71
const struct reg registers[S12Z_N_REGISTERS] =
72
  {
73
    {"d2", 2},
74
    {"d3", 2},
75
    {"d4", 2},
76
    {"d5", 2},
77
78
    {"d0", 1},
79
    {"d1", 1},
80
81
    {"d6", 4},
82
    {"d7", 4},
83
84
    {"x", 3},
85
    {"y", 3},
86
    {"s", 3},
87
    {"p", 3},
88
    {"cch", 1},
89
    {"ccl", 1},
90
    {"ccw", 2}
91
  };
92
93
static const char *mnemonics[] =
94
  {
95
    "!!invalid!!",
96
    "psh",
97
    "pul",
98
    "tbne", "tbeq", "tbpl", "tbmi", "tbgt", "tble",
99
    "dbne", "dbeq", "dbpl", "dbmi", "dbgt", "dble",
100
    "sex",
101
    "exg",
102
    "lsl", "lsr",
103
    "asl", "asr",
104
    "rol", "ror",
105
    "bfins", "bfext",
106
107
    "trap",
108
109
    "ld",
110
    "st",
111
    "cmp",
112
113
    "stop",
114
    "wai",
115
    "sys",
116
117
    "minu",
118
    "mins",
119
    "maxu",
120
    "maxs",
121
122
    "abs",
123
    "adc",
124
    "bit",
125
    "sbc",
126
    "rti",
127
    "clb",
128
    "eor",
129
130
    "sat",
131
132
    "nop",
133
    "bgnd",
134
    "brclr",
135
    "brset",
136
    "rts",
137
    "lea",
138
    "mov",
139
140
    "bra",
141
    "bsr",
142
    "bhi",
143
    "bls",
144
    "bcc",
145
    "bcs",
146
    "bne",
147
    "beq",
148
    "bvc",
149
    "bvs",
150
    "bpl",
151
    "bmi",
152
    "bge",
153
    "blt",
154
    "bgt",
155
    "ble",
156
    "inc",
157
    "clr",
158
    "dec",
159
160
    "add",
161
    "sub",
162
    "and",
163
    "or",
164
165
    "tfr",
166
    "jmp",
167
    "jsr",
168
    "com",
169
    "andcc",
170
    "neg",
171
    "orcc",
172
    "bclr",
173
    "bset",
174
    "btgl",
175
    "swi",
176
177
    "mulu",
178
    "divu",
179
    "modu",
180
    "macu",
181
    "qmulu",
182
183
    "muls",
184
    "divs",
185
    "mods",
186
    "macs",
187
    "qmuls",
188
189
    NULL
190
  };
191
192
193
static void
194
operand_separator (struct disassemble_info *info)
195
339k
{
196
339k
  if ((info->flags & 0x2))
197
338k
    (*info->fprintf_func) (info->stream, ",");
198
199
339k
  (*info->fprintf_func) (info->stream, " ");
200
201
339k
  info->flags |= 0x2;
202
339k
}
203
204
/* Render the symbol name whose value is ADDR + BASE or the adddress itself if
205
   there is no symbol.  If BASE is non zero, then the a PC relative adddress is
206
   assumend (ie BASE is the value in the PC.  */
207
static void
208
decode_possible_symbol (bfd_signed_vma addr, bfd_vma base,
209
                        struct disassemble_info *info, bool relative)
210
57.4k
{
211
57.4k
  const char *fmt = relative ? "*%+" PRId64 : "%" PRId64;
212
57.4k
  asymbol *sym = info->symbol_at_address_func (addr + base, info);
213
214
57.4k
  if (!sym)
215
57.4k
    (*info->fprintf_func) (info->stream, fmt, (int64_t) addr);
216
0
  else
217
0
    (*info->fprintf_func) (info->stream, "%s", bfd_asymbol_name (sym));
218
57.4k
}
219
220
221
/* Emit the disassembled text for OPR */
222
static void
223
opr_emit_disassembly (const struct operand *opr,
224
          struct disassemble_info *info)
225
339k
{
226
339k
  operand_separator (info);
227
228
339k
  switch (opr->cl)
229
339k
    {
230
53.9k
    case OPND_CL_IMMEDIATE:
231
53.9k
      (*info->fprintf_func) (info->stream, "#%d",
232
53.9k
           ((struct immediate_operand *) opr)->value);
233
53.9k
      break;
234
174k
    case OPND_CL_REGISTER:
235
174k
      {
236
174k
        int r = ((struct register_operand*) opr)->reg;
237
238
174k
  if (r < 0 || r >= S12Z_N_REGISTERS)
239
159
    (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
240
174k
  else
241
174k
    (*info->fprintf_func) (info->stream, "%s", registers[r].name);
242
174k
      }
243
174k
      break;
244
1.38k
    case OPND_CL_REGISTER_ALL16:
245
1.38k
      (*info->fprintf_func) (info->stream, "%s", "ALL16b");
246
1.38k
      break;
247
512
    case OPND_CL_REGISTER_ALL:
248
512
      (*info->fprintf_func) (info->stream, "%s", "ALL");
249
512
      break;
250
1.16k
    case OPND_CL_BIT_FIELD:
251
1.16k
      (*info->fprintf_func) (info->stream, "#%d:%d",
252
1.16k
                             ((struct bitfield_operand*)opr)->width,
253
1.16k
                             ((struct bitfield_operand*)opr)->offset);
254
1.16k
      break;
255
57.4k
    case OPND_CL_SIMPLE_MEMORY:
256
57.4k
      {
257
57.4k
        struct simple_memory_operand *mo =
258
57.4k
    (struct simple_memory_operand *) opr;
259
57.4k
  decode_possible_symbol (mo->addr, mo->base, info, mo->relative);
260
57.4k
      }
261
57.4k
      break;
262
50.0k
    case OPND_CL_MEMORY:
263
50.0k
      {
264
50.0k
        int used_reg = 0;
265
50.0k
        struct memory_operand *mo = (struct memory_operand *) opr;
266
50.0k
  (*info->fprintf_func) (info->stream, "%c", mo->indirect ? '[' : '(');
267
268
50.0k
  const char *fmt;
269
50.0k
  assert (mo->mutation == OPND_RM_NONE || mo->n_regs == 1);
270
50.0k
  switch (mo->mutation)
271
50.0k
    {
272
942
    case OPND_RM_PRE_DEC:
273
942
      fmt = "-%s";
274
942
      break;
275
2.28k
    case OPND_RM_PRE_INC:
276
2.28k
      fmt = "+%s";
277
2.28k
      break;
278
976
    case OPND_RM_POST_DEC:
279
976
      fmt = "%s-";
280
976
      break;
281
4.69k
    case OPND_RM_POST_INC:
282
4.69k
      fmt = "%s+";
283
4.69k
      break;
284
41.1k
    case OPND_RM_NONE:
285
41.1k
    default:
286
41.1k
      if (mo->n_regs < 2)
287
33.6k
        (*info->fprintf_func) (info->stream, (mo->n_regs == 0) ? "%d" : "%d,", mo->base_offset);
288
41.1k
      fmt = "%s";
289
41.1k
      break;
290
50.0k
    }
291
50.0k
  if (mo->n_regs > 0)
292
49.2k
    {
293
49.2k
      int r = mo->regs[0];
294
295
49.2k
      if (r < 0 || r >= S12Z_N_REGISTERS)
296
0
        (*info->fprintf_func) (info->stream, fmt, _("<illegal reg num>"));
297
49.2k
      else
298
49.2k
        (*info->fprintf_func) (info->stream, fmt, registers[r].name);
299
49.2k
    }
300
50.0k
  used_reg = 1;
301
302
50.0k
        if (mo->n_regs > used_reg)
303
7.52k
          {
304
7.52k
      int r = mo->regs[used_reg];
305
306
7.52k
      if (r < 0 || r >= S12Z_N_REGISTERS)
307
0
        (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
308
7.52k
      else
309
7.52k
        (*info->fprintf_func) (info->stream, ",%s",
310
7.52k
             registers[r].name);
311
7.52k
          }
312
313
50.0k
  (*info->fprintf_func) (info->stream, "%c",
314
50.0k
             mo->indirect ? ']' : ')');
315
50.0k
      }
316
0
      break;
317
339k
    };
318
339k
}
319
320
27.4k
#define S12Z_N_SIZES 4
321
static const char shift_size_table[S12Z_N_SIZES] =
322
{
323
  'b', 'w', 'p', 'l'
324
};
325
326
int
327
print_insn_s12z (bfd_vma memaddr, struct disassemble_info* info)
328
295k
{
329
295k
  int o;
330
295k
  enum optr operator = OP_INVALID;
331
295k
  int n_operands = 0;
332
333
  /* The longest instruction in S12Z can have 6 operands.
334
     (Most have 3 or less.  Only PSH and PUL have so many.  */
335
295k
  struct operand *operands[6];
336
337
295k
  struct mem_read_abstraction mra;
338
295k
  mra.base.read = (void *) abstract_read_memory ;
339
295k
  mra.base.advance = advance ;
340
295k
  mra.base.posn = posn;
341
295k
  mra.memaddr = memaddr;
342
295k
  mra.info = info;
343
344
295k
  short osize = -1;
345
295k
  int n_bytes =
346
295k
    decode_s12z (&operator, &osize, &n_operands, operands,
347
295k
     (struct mem_read_abstraction_base *) &mra);
348
349
295k
  (info->fprintf_func) (info->stream, "%s", mnemonics[(long)operator]);
350
351
  /* Ship out size sufficies for those instructions which
352
     need them.  */
353
295k
  if (osize == -1)
354
285k
    {
355
285k
      bool suffix = false;
356
357
609k
      for (o = 0; o < n_operands; ++o)
358
323k
  {
359
323k
    if (operands[o] && operands[o]->osize != -1)
360
16.6k
      {
361
16.6k
        if (!suffix)
362
15.5k
    {
363
15.5k
      (*mra.info->fprintf_func) (mra.info->stream, "%c", '.');
364
15.5k
      suffix = true;
365
15.5k
    }
366
367
16.6k
        osize = operands[o]->osize;
368
369
16.6k
        if (osize < 0 || osize >= S12Z_N_SIZES)
370
0
    (*mra.info->fprintf_func) (mra.info->stream, _("<bad>"));
371
16.6k
        else
372
16.6k
    (*mra.info->fprintf_func) (mra.info->stream, "%c",
373
16.6k
             shift_size_table[osize]);
374
16.6k
      }
375
323k
  }
376
285k
    }
377
10.8k
  else
378
10.8k
    {
379
10.8k
      if (osize < 0 || osize >= S12Z_N_SIZES)
380
0
  (*mra.info->fprintf_func) (mra.info->stream, _(".<bad>"));
381
10.8k
      else
382
10.8k
  (*mra.info->fprintf_func) (mra.info->stream, ".%c",
383
10.8k
           shift_size_table[osize]);
384
10.8k
    }
385
386
  /* Ship out the operands.  */
387
635k
  for (o = 0; o < n_operands; ++o)
388
339k
    {
389
339k
      if (operands[o])
390
339k
  opr_emit_disassembly (operands[o], mra.info);
391
339k
      free (operands[o]);
392
339k
    }
393
394
295k
  return n_bytes;
395
295k
}