Coverage Report

Created: 2026-05-30 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/capstonenext/arch/M68K/M68KInstPrinter.c
Line
Count
Source
1
/* Capstone Disassembly Engine */
2
/* M68K Backend by Daniel Collin <daniel@collin.com> 2015-2016 */
3
4
#include <stdio.h>
5
#include <stdlib.h>
6
#include <string.h>
7
8
#include "M68KInstPrinter.h"
9
10
#include "M68KDisassembler.h"
11
12
#include "../../Mapping.h"
13
#include "../../cs_priv.h"
14
#include "../../utils.h"
15
16
#include "../../MCInst.h"
17
#include "../../MCInstrDesc.h"
18
#include "../../MCRegisterInfo.h"
19
20
#ifndef CAPSTONE_DIET
21
static const char s_spacing[] = " ";
22
23
static const char *const s_reg_names[] = {
24
  "invalid",  "d0", "d1",  "d2",   "d3",   "d4",   "d5",   "d6",
25
  "d7",     "a0", "a1",  "a2",   "a3",   "a4",   "a5",   "a6",
26
  "a7",     "fp0",  "fp1",   "fp2",  "fp3",  "fp4",  "fp5",  "fp6",
27
  "fp7",      "pc", "sr",  "ccr",  "sfc",  "dfc",  "usp",  "vbr",
28
  "cacr",     "caar", "msp",   "isp",  "tc",   "itt0", "itt1", "dtt0",
29
  "dtt1",     "mmusr",  "urp",   "srp",
30
31
  "fpcr",     "fpsr", "fpiar",
32
33
  "tt0",      "tt1",  "crp",   "acc",  "acc0", "acc1", "acc2", "acc3",
34
  "accext01", "accext23", "macsr", "mask",
35
};
36
37
static const char *const s_instruction_names[] = {
38
  "invalid",   "abcd",   "add",      "adda",    "addi",
39
  "addq",      "addx",   "and",      "andi",    "asl",
40
  "asr",       "bhs",  "blo",      "bhi",   "bls",
41
  "bcc",       "bcs",  "bne",      "beq",   "bvc",
42
  "bvs",       "bpl",  "bmi",      "bge",   "blt",
43
  "bgt",       "ble",  "bra",      "bsr",   "bchg",
44
  "bclr",      "bset",   "btst",     "bitrev",    "byterev",
45
  "bfchg",     "bfclr",  "bfexts",   "bfextu",    "bfffo",
46
  "bfins",     "bfset",  "bftst",    "bkpt",    "callm",
47
  "cas",       "cas2",   "chk",      "chk2",    "clr",
48
  "cmp",       "cmpa",   "cmpi",     "cmpm",    "cmp2",
49
  "cinvl",     "cinvp",  "cinva",    "cpushl",    "cpushp",
50
  "cpusha",    "dbt",  "dbf",      "dbhi",    "dbls",
51
  "dbcc",      "dbcs",   "dbne",     "dbeq",    "dbvc",
52
  "dbvs",      "dbpl",   "dbmi",     "dbge",    "dblt",
53
  "dbgt",      "dble",   "dbra",     "divs",    "divsl",
54
  "divu",      "divul",  "eor",      "eori",    "exg",
55
  "ext",       "extb",   "ff1",      "fabs",    "fsabs",
56
  "fdabs",     "facos",  "fadd",     "fsadd",   "fdadd",
57
  "fasin",     "fatan",  "fatanh",   "fbf",   "fbeq",
58
  "fbogt",     "fboge",  "fbolt",    "fbole",   "fbogl",
59
  "fbor",      "fbun",   "fbueq",    "fbugt",   "fbuge",
60
  "fbult",     "fbule",  "fbne",     "fbt",   "fbsf",
61
  "fbseq",     "fbgt",   "fbge",     "fblt",    "fble",
62
  "fbgl",      "fbgle",  "fbngle",   "fbngl",   "fbnle",
63
  "fbnlt",     "fbnge",  "fbngt",    "fbsne",   "fbst",
64
  "fcmp",      "fcos",   "fcosh",    "fdbf",    "fdbeq",
65
  "fdbogt",    "fdboge",   "fdbolt",   "fdbole",    "fdbogl",
66
  "fdbor",     "fdbun",  "fdbueq",   "fdbugt",    "fdbuge",
67
  "fdbult",    "fdbule",   "fdbne",    "fdbt",    "fdbsf",
68
  "fdbseq",    "fdbgt",  "fdbge",    "fdblt",   "fdble",
69
  "fdbgl",     "fdbgle",   "fdbngle",  "fdbngl",    "fdbnle",
70
  "fdbnlt",    "fdbnge",   "fdbngt",   "fdbsne",    "fdbst",
71
  "fdiv",      "fsdiv",  "fddiv",    "fetox",   "fetoxm1",
72
  "fgetexp",   "fgetman",  "fint",     "fintrz",    "flog10",
73
  "flog2",     "flogn",  "flognp1",  "fmod",    "fmove",
74
  "fsmove",    "fdmove",   "fmovecr",  "fmovem",    "fmul",
75
  "fsmul",     "fdmul",  "fneg",     "fsneg",   "fdneg",
76
  "fnop",      "frem",   "frestore", "fsave",   "fscale",
77
  "fsgldiv",   "fsglmul",  "fsin",     "fsincos",   "fsinh",
78
  "fsqrt",     "fssqrt",   "fdsqrt",   "fsf",   "fseq",
79
  "fsogt",     "fsoge",  "fsolt",    "fsole",   "fsogl",
80
  "fsor",      "fsun",   "fsueq",    "fsugt",   "fsuge",
81
  "fsult",     "fsule",  "fsne",     "fst",   "fssf",
82
  "fsseq",     "fsgt",   "fsge",     "fslt",    "fsle",
83
  "fsgl",      "fsgle",  "fsngle",   "fsngl",   "fsnle",
84
  "fsnlt",     "fsnge",  "fsngt",    "fssne",   "fsst",
85
  "fsub",      "fssub",  "fdsub",    "ftan",    "ftanh",
86
  "ftentox",   "ftrapf",   "ftrapeq",  "ftrapogt",  "ftrapoge",
87
  "ftrapolt",  "ftrapole", "ftrapogl", "ftrapor",   "ftrapun",
88
  "ftrapueq",  "ftrapugt", "ftrapuge", "ftrapult",  "ftrapule",
89
  "ftrapne",   "ftrapt",   "ftrapsf",  "ftrapseq",  "ftrapgt",
90
  "ftrapge",   "ftraplt",  "ftraple",  "ftrapgl",   "ftrapgle",
91
  "ftrapngle", "ftrapngl", "ftrapnle", "ftrapnlt",  "ftrapnge",
92
  "ftrapngt",  "ftrapsne", "ftrapst",  "ftst",    "ftwotox",
93
  "halt",      "illegal",  "intouch",  "jmp",   "jsr",
94
  "lea",       "link",   "lpstop",   "lsl",   "lsr",
95
  "mac",       "move",   "movea",    "movec",   "movem",
96
  "movep",     "moveq",  "moves",    "move16",    "mov3q",
97
  "movclr",    "msac",   "muls",     "mulu",    "mvs",
98
  "mvz",       "nbcd",   "neg",      "negx",    "nop",
99
  "not",       "or",   "ori",      "pack",    "pea",
100
  "pflush",    "pflusha",  "pflushan", "pflushn",   "ploadr",
101
  "ploadw",    "plpar",  "plpaw",    "pmove",   "pmovefd",
102
  "ptestr",    "ptestw",   "pulse",    "rems",    "remu",
103
  "reset",     "rol",  "ror",      "roxl",    "roxr",
104
  "rtd",       "rte",  "rtm",      "rtr",   "rts",
105
  "sats",      "sbcd",   "st",       "sf",    "shi",
106
  "sls",       "scc",  "shs",      "scs",   "slo",
107
  "sne",       "seq",  "svc",      "svs",   "spl",
108
  "smi",       "sge",  "slt",      "sgt",   "sle",
109
  "stop",      "strldsr",  "sub",      "suba",    "subi",
110
  "subq",      "subx",   "swap",     "tas",   "trap",
111
  "trapv",     "trapt",  "trapf",    "traphi",    "trapls",
112
  "trapcc",    "traphs",   "trapcs",   "traplo",    "trapne",
113
  "trapeq",    "trapvc",   "trapvs",   "trappl",    "trapmi",
114
  "trapge",    "traplt",   "trapgt",   "traple",    "tst",
115
  "unlk",      "unpk",   "wddata",   "wdebug",    "bgnd",
116
  "tbls",      "tblu",   "tblsn",    "tblun",   "cp0bcbusy",
117
  "cp0ld",     "cp0nop",   "cp0st",    "cp1bcbusy", "cp1ld",
118
  "cp1nop",    "cp1st",  "tpf",
119
};
120
#endif
121
122
#ifndef CAPSTONE_DIET
123
static const char *getRegName(m68k_reg reg)
124
148k
{
125
148k
  return s_reg_names[(int)reg];
126
148k
}
127
128
static void printRegbits(SStream *O, bool *need_sep, uint32_t data,
129
       const char *prefix)
130
7.36k
{
131
7.36k
  unsigned int first;
132
7.36k
  int i;
133
134
59.6k
  for (i = 0; i < 8; ++i) {
135
52.3k
    if (!(data & (1 << i)))
136
42.8k
      continue;
137
138
9.45k
    first = i;
139
16.0k
    while (i < 7 && (data & (1 << (i + 1))))
140
6.60k
      i++;
141
142
9.45k
    if (*need_sep)
143
6.99k
      SStream_concat1(O, '/');
144
9.45k
    *need_sep = true;
145
146
9.45k
    SStream_concat(O, "%s%" PRIu32, prefix, first);
147
148
9.45k
    if ((unsigned int)i > first)
149
2.92k
      SStream_concat(O, "-%s%" PRIu32, prefix,
150
2.92k
               (unsigned int)i);
151
9.45k
  }
152
7.36k
}
153
154
static void registerBits(SStream *O, const cs_m68k_op *op)
155
2.64k
{
156
2.64k
  unsigned int data = op->register_bits;
157
2.64k
  bool need_sep = false;
158
159
2.64k
  if (!data) {
160
186
    SStream_concat(O, "%s", "#$0");
161
186
    return;
162
186
  }
163
164
2.45k
  printRegbits(O, &need_sep, data & 0xff, "d");
165
2.45k
  printRegbits(O, &need_sep, (data >> 8) & 0xff, "a");
166
2.45k
  printRegbits(O, &need_sep, (data >> 16) & 0xff, "fp");
167
2.45k
}
168
169
static void registerPair(SStream *O, const cs_m68k_op *op)
170
398
{
171
398
  SStream_concat(O, "%s:%s", s_reg_names[op->reg_pair.reg_0],
172
398
           s_reg_names[op->reg_pair.reg_1]);
173
398
}
174
175
static void printRegisterName(SStream *O, const cs_m68k_op *op)
176
129k
{
177
129k
  SStream_concat(O, "%s", getRegName(op->reg));
178
129k
  if (op->flags & M68K_OP_FLAG_REG_LOWER)
179
0
    SStream_concat0(O, "l");
180
129k
  else if (op->flags & M68K_OP_FLAG_REG_UPPER)
181
0
    SStream_concat0(O, "u");
182
129k
}
183
184
static void printScaleFactor(SStream *O, uint8_t scale, int threshold)
185
12.0k
{
186
12.0k
  if (scale > threshold)
187
6.32k
    SStream_concat(O, "%s*%s%" PRId8, s_spacing, s_spacing, scale);
188
12.0k
}
189
190
static void printIndexReg(SStream *O, const cs_m68k_op *op)
191
10.7k
{
192
10.7k
  SStream_concat(O, "%s.%c", getRegName(op->mem.index_reg),
193
10.7k
           op->mem.index_size ? 'l' : 'w');
194
10.7k
}
195
196
static void printBitfield(SStream *O, const cs_m68k_op *op)
197
286k
{
198
286k
  if (!op->mem.bitfield)
199
284k
    return;
200
1.16k
  SStream_concat0(O, "{");
201
1.16k
  if (M68K_BF_IS_REG(op->mem.offset))
202
722
    SStream_concat(O, "d%" PRId8, M68K_BF_REG_NUM(op->mem.offset));
203
447
  else
204
447
    SStream_concat(O, "%" PRId8, op->mem.offset);
205
1.16k
  SStream_concat0(O, ":");
206
1.16k
  if (M68K_BF_IS_REG(op->mem.width))
207
434
    SStream_concat(O, "d%" PRId8, M68K_BF_REG_NUM(op->mem.width));
208
735
  else
209
735
    SStream_concat(O, "%" PRId8, op->mem.width);
210
1.16k
  SStream_concat0(O, "}");
211
1.16k
}
212
213
static void printImmediate(SStream *O, const cs_m68k *inst,
214
         const cs_m68k_op *op)
215
45.2k
{
216
45.2k
  if (inst->op_size.type == M68K_SIZE_TYPE_FPU) {
217
#if defined(_KERNEL_MODE)
218
    SStream_concat(O, "#<float_point_unsupported>");
219
    return;
220
#else
221
118
    if (inst->op_size.fpu_size == M68K_FPU_SIZE_SINGLE)
222
3
      SStream_concat(O, "#%f", op->simm);
223
115
    else if (inst->op_size.fpu_size == M68K_FPU_SIZE_DOUBLE)
224
28
      SStream_concat(O, "#%f", op->dimm);
225
87
    else
226
87
      SStream_concat(O, "#<unsupported>");
227
118
    return;
228
118
#endif
229
118
  }
230
45.1k
  SStream_concat(O, "#$%" PRIx64, op->imm);
231
45.1k
}
232
233
static void printIndex8BitDisp(SStream *O, unsigned int pc,
234
             const cs_m68k_op *op)
235
6.74k
{
236
6.74k
  if (op->address_mode == M68K_AM_PCI_INDEX_8_BIT_DISP) {
237
747
    SStream_concat(O, "$%" PRIx32 "(pc,%s", pc + 2 + op->mem.disp,
238
747
             s_spacing);
239
5.99k
  } else {
240
5.99k
    SStream_concat(O, "%s$%" PRIx16 "(%s,%s",
241
5.99k
             op->mem.disp < 0 ? "-" : "", abs(op->mem.disp),
242
5.99k
             getRegName(op->mem.base_reg), s_spacing);
243
5.99k
  }
244
6.74k
  printIndexReg(O, op);
245
6.74k
  printScaleFactor(O, op->mem.scale, 1);
246
6.74k
  SStream_concat0(O, ")");
247
6.74k
}
248
249
static void printRegAddrMode(SStream *O, unsigned int pc, const cs_m68k_op *op)
250
192k
{
251
192k
  m68k_reg base_reg = op->type == M68K_OP_MEM ? op->mem.base_reg :
252
192k
                  op->reg;
253
254
192k
  switch (op->address_mode) {
255
99.5k
  case M68K_AM_REG_DIRECT_DATA:
256
99.5k
    printRegisterName(O, op);
257
99.5k
    break;
258
13.7k
  case M68K_AM_REG_DIRECT_ADDR:
259
13.7k
    printRegisterName(O, op);
260
13.7k
    break;
261
16.4k
  case M68K_AM_REGI_ADDR:
262
16.4k
    SStream_concat(O, "(a%" PRId32 ")", (base_reg - M68K_REG_A0));
263
16.4k
    break;
264
16.7k
  case M68K_AM_REGI_ADDR_POST_INC:
265
16.7k
    SStream_concat(O, "(a%" PRId32 ")+", (base_reg - M68K_REG_A0));
266
16.7k
    break;
267
31.6k
  case M68K_AM_REGI_ADDR_PRE_DEC:
268
31.6k
    SStream_concat(O, "-(a%" PRId32 ")", (base_reg - M68K_REG_A0));
269
31.6k
    break;
270
12.8k
  case M68K_AM_REGI_ADDR_DISP:
271
12.8k
    SStream_concat(O, "%s$%" PRIx16 "(a%" PRId32 ")",
272
12.8k
             op->mem.disp < 0 ? "-" : "", abs(op->mem.disp),
273
12.8k
             (base_reg - M68K_REG_A0));
274
12.8k
    break;
275
1.59k
  case M68K_AM_PCI_DISP:
276
1.59k
    SStream_concat(O, "$%" PRIx32 "(pc)", pc + 2 + op->mem.disp);
277
1.59k
    break;
278
0
  default:
279
0
    break;
280
192k
  }
281
192k
}
282
283
static void printBaseDisp(SStream *O, unsigned int pc, const cs_m68k_op *op)
284
2.48k
{
285
2.48k
  int is_pc = (op->address_mode == M68K_AM_PCI_INDEX_BASE_DISP);
286
287
2.48k
  if (is_pc) {
288
391
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->mem.in_disp);
289
2.09k
  } else if (op->mem.in_disp != 0) {
290
1.20k
    SStream_concat(O, "%s$%" PRIx32,
291
1.20k
             op->mem.in_disp >= 0 ? "" : "-",
292
1.20k
             abs(op->mem.in_disp));
293
1.20k
  }
294
295
2.48k
  SStream_concat0(O, "(");
296
297
2.48k
  if (is_pc) {
298
391
    SStream_concat0(O, "pc");
299
2.09k
  } else if (op->mem.base_reg != M68K_REG_INVALID) {
300
1.43k
    SStream_concat(O, "a%" PRId32, op->mem.base_reg - M68K_REG_A0);
301
1.43k
  }
302
303
2.48k
  if ((is_pc || op->mem.base_reg != M68K_REG_INVALID) &&
304
1.82k
      op->mem.index_reg != M68K_REG_INVALID)
305
1.44k
    SStream_concat(O, ",%s", s_spacing);
306
307
2.48k
  if (op->mem.index_reg != M68K_REG_INVALID) {
308
1.55k
    printIndexReg(O, op);
309
1.55k
    printScaleFactor(O, op->mem.scale, 0);
310
1.55k
  }
311
312
2.48k
  SStream_concat0(O, ")");
313
2.48k
}
314
315
static void printMemIndirect(SStream *O, unsigned int pc, const cs_m68k_op *op)
316
3.74k
{
317
3.74k
  int is_pc = (op->address_mode == M68K_AM_PC_MEMI_POST_INDEX ||
318
3.33k
         op->address_mode == M68K_AM_PC_MEMI_PRE_INDEX);
319
3.74k
  int is_post = (op->address_mode == M68K_AM_MEMI_POST_INDEX ||
320
2.13k
           op->address_mode == M68K_AM_PC_MEMI_POST_INDEX);
321
3.74k
  int is_pre = (op->address_mode == M68K_AM_MEMI_PRE_INDEX ||
322
2.34k
          op->address_mode == M68K_AM_PC_MEMI_PRE_INDEX);
323
324
3.74k
  SStream_concat0(O, "([");
325
326
3.74k
  if (is_pc) {
327
731
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->mem.in_disp);
328
3.01k
  } else if (op->mem.in_disp != 0) {
329
2.04k
    SStream_concat(O, "%s$%" PRIx32,
330
2.04k
             op->mem.in_disp >= 0 ? "" : "-",
331
2.04k
             abs(op->mem.in_disp));
332
2.04k
  }
333
334
3.74k
  if (op->mem.base_reg != M68K_REG_INVALID) {
335
2.29k
    if (op->mem.in_disp != 0)
336
1.44k
      SStream_concat(O, ",%s%s", s_spacing,
337
1.44k
               getRegName(op->mem.base_reg));
338
847
    else
339
847
      SStream_concat(O, "%s", getRegName(op->mem.base_reg));
340
2.29k
  }
341
342
3.74k
  if (is_post)
343
2.01k
    SStream_concat0(O, "]");
344
345
3.74k
  if (op->mem.index_reg != M68K_REG_INVALID) {
346
2.43k
    SStream_concat(O, ",%s", s_spacing);
347
2.43k
    printIndexReg(O, op);
348
2.43k
  }
349
350
3.74k
  printScaleFactor(O, op->mem.scale, 0);
351
352
3.74k
  if (is_pre)
353
1.73k
    SStream_concat0(O, "]");
354
355
3.74k
  if (op->mem.out_disp != 0) {
356
2.06k
    SStream_concat(O, ",%s%s$%" PRIx32, s_spacing,
357
2.06k
             op->mem.out_disp >= 0 ? "" : "-",
358
2.06k
             abs(op->mem.out_disp));
359
2.06k
  }
360
361
3.74k
  SStream_concat0(O, ")");
362
3.74k
}
363
364
static void printAddressingMode(SStream *O, unsigned int pc,
365
        const cs_m68k *inst, const cs_m68k_op *op)
366
286k
{
367
286k
  switch (op->address_mode) {
368
19.5k
  case M68K_AM_NONE:
369
19.5k
    switch (op->type) {
370
2.64k
    case M68K_OP_REG_BITS:
371
2.64k
      registerBits(O, op);
372
2.64k
      break;
373
398
    case M68K_OP_REG_PAIR:
374
398
      registerPair(O, op);
375
398
      break;
376
16.4k
    case M68K_OP_REG:
377
16.4k
      printRegisterName(O, op);
378
16.4k
      break;
379
0
    case M68K_OP_SHIFT:
380
0
      if (op->flags & M68K_OP_FLAG_SHIFT_LEFT)
381
0
        SStream_concat0(O, "<<");
382
0
      else if (op->flags & M68K_OP_FLAG_SHIFT_RIGHT)
383
0
        SStream_concat0(O, ">>");
384
0
      break;
385
67
    default:
386
67
      break;
387
19.5k
    }
388
19.5k
    break;
389
390
99.5k
  case M68K_AM_REG_DIRECT_DATA:
391
113k
  case M68K_AM_REG_DIRECT_ADDR:
392
129k
  case M68K_AM_REGI_ADDR:
393
146k
  case M68K_AM_REGI_ADDR_POST_INC:
394
178k
  case M68K_AM_REGI_ADDR_PRE_DEC:
395
191k
  case M68K_AM_REGI_ADDR_DISP:
396
192k
  case M68K_AM_PCI_DISP:
397
192k
    printRegAddrMode(O, pc, op);
398
192k
    break;
399
2.61k
  case M68K_AM_ABSOLUTE_DATA_SHORT:
400
2.61k
    SStream_concat(O, "$%" PRIx32 ".w", (uint32_t)op->mem.address);
401
2.61k
    break;
402
1.25k
  case M68K_AM_ABSOLUTE_DATA_LONG:
403
1.25k
    SStream_concat(O, "$%" PRIx64 ".l", (uint64_t)op->mem.address);
404
1.25k
    break;
405
45.2k
  case M68K_AM_IMMEDIATE:
406
45.2k
    printImmediate(O, inst, op);
407
45.2k
    break;
408
747
  case M68K_AM_PCI_INDEX_8_BIT_DISP:
409
6.74k
  case M68K_AM_AREGI_INDEX_8_BIT_DISP:
410
6.74k
    printIndex8BitDisp(O, pc, op);
411
6.74k
    break;
412
391
  case M68K_AM_PCI_INDEX_BASE_DISP:
413
2.48k
  case M68K_AM_AREGI_INDEX_BASE_DISP:
414
2.48k
    printBaseDisp(O, pc, op);
415
2.48k
    break;
416
406
  case M68K_AM_PC_MEMI_POST_INDEX:
417
731
  case M68K_AM_PC_MEMI_PRE_INDEX:
418
2.13k
  case M68K_AM_MEMI_PRE_INDEX:
419
3.74k
  case M68K_AM_MEMI_POST_INDEX:
420
3.74k
    printMemIndirect(O, pc, op);
421
3.74k
    break;
422
11.6k
  case M68K_AM_BRANCH_DISPLACEMENT:
423
11.6k
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->br_disp.disp);
424
11.6k
  default:
425
11.6k
    break;
426
286k
  }
427
428
286k
  printBitfield(O, op);
429
286k
  if (op->flags & M68K_OP_FLAG_MEM_UPDATE)
430
0
    SStream_concat0(O, "&");
431
286k
}
432
433
static void printCAS2(SStream *O, unsigned int pc, const cs_m68k *ext)
434
88
{
435
88
  printAddressingMode(O, pc, ext, &ext->operands[0]);
436
88
  SStream_concat0(O, ",");
437
88
  printAddressingMode(O, pc, ext, &ext->operands[1]);
438
88
  SStream_concat0(O, ",");
439
440
88
  SStream_concat(O, "(%s):(%s)",
441
88
           s_reg_names[ext->operands[2].reg_pair.reg_0],
442
88
           s_reg_names[ext->operands[2].reg_pair.reg_1]);
443
88
}
444
445
static void printCacheOp(SStream *O, unsigned int pc, const cs_m68k *ext)
446
524
{
447
524
  static const char *const cache_names[] = { "nc", "dc", "ic", "bc" };
448
524
  unsigned int sel = (unsigned int)ext->operands[0].imm;
449
524
  int i;
450
451
524
  if (sel < ARR_SIZE(cache_names))
452
524
    SStream_concat0(O, cache_names[sel]);
453
0
  else
454
0
    SStream_concat(O, "#$%" PRIx64, ext->operands[0].imm);
455
456
928
  for (i = 1; i < ext->op_count; ++i) {
457
404
    SStream_concat(O, ",%s", s_spacing);
458
404
    printAddressingMode(O, pc, ext, &ext->operands[i]);
459
404
  }
460
524
}
461
462
#endif
463
464
static void printOpSize(SStream *O, const cs_m68k *ext)
465
158k
{
466
158k
  switch (ext->op_size.type) {
467
0
  case M68K_SIZE_TYPE_INVALID:
468
0
    break;
469
157k
  case M68K_SIZE_TYPE_CPU:
470
157k
    switch (ext->op_size.cpu_size) {
471
53.7k
    case M68K_CPU_SIZE_BYTE:
472
53.7k
      SStream_concat0(O, ".b");
473
53.7k
      break;
474
43.6k
    case M68K_CPU_SIZE_WORD:
475
43.6k
      SStream_concat0(O, ".w");
476
43.6k
      break;
477
38.6k
    case M68K_CPU_SIZE_LONG:
478
38.6k
      SStream_concat0(O, ".l");
479
38.6k
      break;
480
21.4k
    case M68K_CPU_SIZE_NONE:
481
21.4k
      break;
482
157k
    }
483
157k
    break;
484
157k
  case M68K_SIZE_TYPE_FPU:
485
745
    switch (ext->op_size.fpu_size) {
486
302
    case M68K_FPU_SIZE_SINGLE:
487
302
      SStream_concat0(O, ".s");
488
302
      break;
489
74
    case M68K_FPU_SIZE_DOUBLE:
490
74
      SStream_concat0(O, ".d");
491
74
      break;
492
369
    case M68K_FPU_SIZE_EXTENDED:
493
369
      SStream_concat0(O, ".x");
494
369
      break;
495
0
    case M68K_FPU_SIZE_NONE:
496
0
      break;
497
745
    }
498
745
    break;
499
158k
  }
500
158k
}
501
502
void M68K_printInst(MCInst *MI, SStream *O, void *PrinterInfo)
503
191k
{
504
191k
#ifndef CAPSTONE_DIET
505
191k
  m68k_info *info = (m68k_info *)PrinterInfo;
506
191k
  cs_m68k *ext = &info->extension;
507
191k
  cs_detail *detail = NULL;
508
191k
  int i = 0;
509
510
191k
  if (detail_is_set(MI)) {
511
191k
    detail = get_detail(MI);
512
191k
    int regs_read_count = MIN((int)ARR_SIZE(detail->regs_read),
513
191k
            info->regs_read_count);
514
191k
    int regs_write_count = MIN((int)ARR_SIZE(detail->regs_write),
515
191k
             info->regs_write_count);
516
191k
    int groups_count =
517
191k
      MIN((int)ARR_SIZE(detail->groups), info->groups_count);
518
519
191k
    memcpy(&detail->m68k, ext, sizeof(cs_m68k));
520
191k
    memcpy(&detail->regs_read, &info->regs_read,
521
191k
           regs_read_count * sizeof(info->regs_read[0]));
522
191k
    detail->regs_read_count = regs_read_count;
523
524
191k
    memcpy(&detail->regs_write, &info->regs_write,
525
191k
           regs_write_count * sizeof(info->regs_write[0]));
526
191k
    detail->regs_write_count = regs_write_count;
527
528
191k
    memcpy(&detail->groups, &info->groups, groups_count);
529
191k
    detail->groups_count = groups_count;
530
191k
  }
531
532
191k
  if (MI->Opcode == M68K_INS_INVALID) {
533
33.5k
    if (ext->op_count)
534
33.5k
      SStream_concat(O, "dc.w $%" PRIx32,
535
33.5k
               (uint32_t)ext->operands[0].imm);
536
0
    else
537
0
      SStream_concat(O, "dc.w $<unknown>");
538
33.5k
    return;
539
33.5k
  }
540
541
158k
  SStream_concat0(O, (char *)s_instruction_names[MI->Opcode]);
542
158k
  printOpSize(O, ext);
543
158k
  SStream_concat0(O, " ");
544
545
158k
  if (MI->Opcode == M68K_INS_CAS2) {
546
88
    printCAS2(O, info->pc, ext);
547
88
    return;
548
88
  }
549
550
158k
  if (MI->Opcode >= M68K_INS_CINVL && MI->Opcode <= M68K_INS_CPUSHA) {
551
524
    printCacheOp(O, info->pc, ext);
552
524
    return;
553
524
  }
554
555
443k
  for (i = 0; i < ext->op_count; ++i) {
556
285k
    printAddressingMode(O, info->pc, ext, &ext->operands[i]);
557
285k
    if ((i + 1) != ext->op_count)
558
128k
      SStream_concat(O, ",%s", s_spacing);
559
285k
  }
560
157k
#endif
561
157k
}
562
563
const char *M68K_reg_name(csh handle, unsigned int reg)
564
243k
{
565
#ifdef CAPSTONE_DIET
566
  return NULL;
567
#else
568
243k
  if (reg >= ARR_SIZE(s_reg_names)) {
569
0
    return NULL;
570
0
  }
571
243k
  return s_reg_names[(int)reg];
572
243k
#endif
573
243k
}
574
575
void M68K_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
576
191k
{
577
191k
  insn->id = id; // These id's matches for 68k
578
191k
}
579
580
const char *M68K_insn_name(csh handle, unsigned int id)
581
191k
{
582
#ifdef CAPSTONE_DIET
583
  return NULL;
584
#else
585
191k
  if (id > ARR_SIZE(s_instruction_names)) {
586
0
    return NULL;
587
0
  }
588
191k
  return s_instruction_names[id];
589
191k
#endif
590
191k
}
591
592
#ifndef CAPSTONE_DIET
593
static const name_map group_name_maps[] = {
594
  { M68K_GRP_INVALID, NULL },
595
  { M68K_GRP_JUMP, "jump" },
596
  { M68K_GRP_RET, "ret" },
597
  { M68K_GRP_IRET, "iret" },
598
  { M68K_GRP_BRANCH_RELATIVE, "branch_relative" },
599
};
600
#endif
601
602
const char *M68K_group_name(csh handle, unsigned int id)
603
26.1k
{
604
26.1k
#ifndef CAPSTONE_DIET
605
26.1k
  return id2name(group_name_maps, ARR_SIZE(group_name_maps), id);
606
#else
607
  return NULL;
608
#endif
609
26.1k
}
610
611
#ifndef CAPSTONE_DIET
612
void M68K_reg_access(const cs_insn *insn, cs_regs regs_read,
613
         uint8_t *regs_read_count, cs_regs regs_write,
614
         uint8_t *regs_write_count)
615
0
{
616
0
  uint8_t read_count, write_count;
617
618
0
  read_count = insn->detail->regs_read_count;
619
0
  write_count = insn->detail->regs_write_count;
620
621
  // implicit registers
622
0
  memcpy(regs_read, insn->detail->regs_read,
623
0
         read_count * sizeof(insn->detail->regs_read[0]));
624
0
  memcpy(regs_write, insn->detail->regs_write,
625
0
         write_count * sizeof(insn->detail->regs_write[0]));
626
627
0
  *regs_read_count = read_count;
628
0
  *regs_write_count = write_count;
629
0
}
630
#endif