Coverage Report

Created: 2026-08-14 06:51

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",      "maaac",   "masac",
119
  "msaac",     "mssac",
120
};
121
#endif
122
123
#ifndef CAPSTONE_DIET
124
static const char *getRegName(m68k_reg reg)
125
210k
{
126
210k
  return s_reg_names[(int)reg];
127
210k
}
128
129
static void printRegbits(SStream *O, bool *need_sep, uint32_t data,
130
       const char *prefix)
131
13.7k
{
132
13.7k
  unsigned int first;
133
13.7k
  int i;
134
135
107k
  for (i = 0; i < 8; ++i) {
136
93.3k
    if (!(data & (1 << i)))
137
79.2k
      continue;
138
139
14.1k
    first = i;
140
30.4k
    while (i < 7 && (data & (1 << (i + 1))))
141
16.2k
      i++;
142
143
14.1k
    if (*need_sep)
144
9.59k
      SStream_concat1(O, '/');
145
14.1k
    *need_sep = true;
146
147
14.1k
    SStream_concat(O, "%s%" PRIu32, prefix, first);
148
149
14.1k
    if ((unsigned int)i > first)
150
6.20k
      SStream_concat(O, "-%s%" PRIu32, prefix,
151
6.20k
               (unsigned int)i);
152
14.1k
  }
153
13.7k
}
154
155
static void registerBits(SStream *O, const cs_m68k_op *op)
156
4.73k
{
157
4.73k
  unsigned int data = op->register_bits;
158
4.73k
  bool need_sep = false;
159
160
4.73k
  if (!data) {
161
171
    SStream_concat(O, "%s", "#$0");
162
171
    return;
163
171
  }
164
165
4.56k
  printRegbits(O, &need_sep, data & 0xff, "d");
166
4.56k
  printRegbits(O, &need_sep, (data >> 8) & 0xff, "a");
167
4.56k
  printRegbits(O, &need_sep, (data >> 16) & 0xff, "fp");
168
4.56k
}
169
170
static void registerPair(SStream *O, const cs_m68k_op *op)
171
1.16k
{
172
1.16k
  SStream_concat(O, "%s:%s", s_reg_names[op->reg_pair.reg_0],
173
1.16k
           s_reg_names[op->reg_pair.reg_1]);
174
1.16k
}
175
176
static void printRegisterName(SStream *O, const cs_m68k_op *op)
177
177k
{
178
177k
  SStream_concat(O, "%s", getRegName(op->reg));
179
177k
  if (op->flags & M68K_OP_FLAG_REG_LOWER)
180
0
    SStream_concat0(O, "l");
181
177k
  else if (op->flags & M68K_OP_FLAG_REG_UPPER)
182
0
    SStream_concat0(O, "u");
183
177k
}
184
185
static void printScaleFactor(SStream *O, uint8_t scale, int threshold)
186
20.9k
{
187
20.9k
  if (scale > threshold)
188
12.4k
    SStream_concat(O, "%s*%s%" PRId8, s_spacing, s_spacing, scale);
189
20.9k
}
190
191
static void printIndexReg(SStream *O, const cs_m68k_op *op)
192
18.4k
{
193
18.4k
  SStream_concat(O, "%s.%c", getRegName(op->mem.index_reg),
194
18.4k
           op->mem.index_size ? 'l' : 'w');
195
18.4k
}
196
197
static void printBitfield(SStream *O, const cs_m68k_op *op)
198
404k
{
199
404k
  if (!op->mem.bitfield)
200
402k
    return;
201
1.38k
  SStream_concat0(O, "{");
202
1.38k
  if (M68K_BF_IS_REG(op->mem.offset))
203
746
    SStream_concat(O, "d%" PRId8, M68K_BF_REG_NUM(op->mem.offset));
204
634
  else
205
634
    SStream_concat(O, "%" PRId8, op->mem.offset);
206
1.38k
  SStream_concat0(O, ":");
207
1.38k
  if (M68K_BF_IS_REG(op->mem.width))
208
542
    SStream_concat(O, "d%" PRId8, M68K_BF_REG_NUM(op->mem.width));
209
838
  else
210
838
    SStream_concat(O, "%" PRId8, op->mem.width);
211
1.38k
  SStream_concat0(O, "}");
212
1.38k
}
213
214
static void printImmediate(SStream *O, const cs_m68k *inst,
215
         const cs_m68k_op *op)
216
56.9k
{
217
56.9k
  if (inst->op_size.type == M68K_SIZE_TYPE_FPU) {
218
#if defined(_KERNEL_MODE)
219
    SStream_concat(O, "#<float_point_unsupported>");
220
    return;
221
#else
222
340
    if (inst->op_size.fpu_size == M68K_FPU_SIZE_SINGLE)
223
100
      SStream_concat(O, "#%f", op->simm);
224
240
    else if (inst->op_size.fpu_size == M68K_FPU_SIZE_DOUBLE)
225
65
      SStream_concat(O, "#%f", op->dimm);
226
175
    else
227
175
      SStream_concat(O, "#<unsupported>");
228
340
    return;
229
340
#endif
230
340
  }
231
56.5k
  SStream_concat(O, "#$%" PRIx64, op->imm);
232
56.5k
}
233
234
static void printIndex8BitDisp(SStream *O, uint32_t pc, const cs_m68k_op *op)
235
13.7k
{
236
13.7k
  if (op->address_mode == M68K_AM_PCI_INDEX_8_BIT_DISP) {
237
1.58k
    SStream_concat(O, "$%" PRIx32 "(pc,%s", pc + 2 + op->mem.disp,
238
1.58k
             s_spacing);
239
12.1k
  } else {
240
12.1k
    SStream_concat(O, "%s$%" PRIx16 "(%s,%s",
241
12.1k
             op->mem.disp < 0 ? "-" : "", abs(op->mem.disp),
242
12.1k
             getRegName(op->mem.base_reg), s_spacing);
243
12.1k
  }
244
13.7k
  printIndexReg(O, op);
245
13.7k
  printScaleFactor(O, op->mem.scale, 1);
246
13.7k
  SStream_concat0(O, ")");
247
13.7k
}
248
249
static void printRegAddrMode(SStream *O, uint32_t pc, const cs_m68k_op *op)
250
267k
{
251
267k
  m68k_reg base_reg = op->type == M68K_OP_MEM ? op->mem.base_reg :
252
267k
                  op->reg;
253
254
267k
  switch (op->address_mode) {
255
137k
  case M68K_AM_REG_DIRECT_DATA:
256
137k
    printRegisterName(O, op);
257
137k
    break;
258
19.1k
  case M68K_AM_REG_DIRECT_ADDR:
259
19.1k
    printRegisterName(O, op);
260
19.1k
    break;
261
25.7k
  case M68K_AM_REGI_ADDR:
262
25.7k
    SStream_concat(O, "(a%" PRId32 ")", (base_reg - M68K_REG_A0));
263
25.7k
    break;
264
25.4k
  case M68K_AM_REGI_ADDR_POST_INC:
265
25.4k
    SStream_concat(O, "(a%" PRId32 ")+", (base_reg - M68K_REG_A0));
266
25.4k
    break;
267
39.8k
  case M68K_AM_REGI_ADDR_PRE_DEC:
268
39.8k
    SStream_concat(O, "-(a%" PRId32 ")", (base_reg - M68K_REG_A0));
269
39.8k
    break;
270
17.9k
  case M68K_AM_REGI_ADDR_DISP:
271
17.9k
    SStream_concat(O, "%s$%" PRIx16 "(a%" PRId32 ")",
272
17.9k
             op->mem.disp < 0 ? "-" : "", abs(op->mem.disp),
273
17.9k
             (base_reg - M68K_REG_A0));
274
17.9k
    break;
275
1.90k
  case M68K_AM_PCI_DISP:
276
1.90k
    SStream_concat(O, "$%" PRIx32 "(pc)", pc + 2 + op->mem.disp);
277
1.90k
    break;
278
0
  default:
279
0
    break;
280
267k
  }
281
267k
}
282
283
static void printBaseDisp(SStream *O, uint32_t pc, const cs_m68k_op *op)
284
3.31k
{
285
3.31k
  int is_pc = (op->address_mode == M68K_AM_PCI_INDEX_BASE_DISP);
286
287
3.31k
  if (is_pc) {
288
325
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->mem.in_disp);
289
2.99k
  } else if (op->mem.in_disp != 0) {
290
1.62k
    SStream_concat(O, "%s$%" PRIx32,
291
1.62k
             op->mem.in_disp >= 0 ? "" : "-",
292
1.62k
             abs(op->mem.in_disp));
293
1.62k
  }
294
295
3.31k
  SStream_concat0(O, "(");
296
297
3.31k
  if (is_pc) {
298
325
    SStream_concat0(O, "pc");
299
2.99k
  } else if (op->mem.base_reg != M68K_REG_INVALID) {
300
1.52k
    SStream_concat(O, "a%" PRId32, op->mem.base_reg - M68K_REG_A0);
301
1.52k
  }
302
303
3.31k
  if ((is_pc || op->mem.base_reg != M68K_REG_INVALID) &&
304
1.84k
      op->mem.index_reg != M68K_REG_INVALID)
305
985
    SStream_concat(O, ",%s", s_spacing);
306
307
3.31k
  if (op->mem.index_reg != M68K_REG_INVALID) {
308
1.40k
    printIndexReg(O, op);
309
1.40k
    printScaleFactor(O, op->mem.scale, 0);
310
1.40k
  }
311
312
3.31k
  SStream_concat0(O, ")");
313
3.31k
}
314
315
static void printMemIndirect(SStream *O, uint32_t pc, const cs_m68k_op *op)
316
5.86k
{
317
5.86k
  int is_pc = (op->address_mode == M68K_AM_PC_MEMI_POST_INDEX ||
318
5.47k
         op->address_mode == M68K_AM_PC_MEMI_PRE_INDEX);
319
5.86k
  int is_post = (op->address_mode == M68K_AM_MEMI_POST_INDEX ||
320
3.28k
           op->address_mode == M68K_AM_PC_MEMI_POST_INDEX);
321
5.86k
  int is_pre = (op->address_mode == M68K_AM_MEMI_PRE_INDEX ||
322
3.57k
          op->address_mode == M68K_AM_PC_MEMI_PRE_INDEX);
323
324
5.86k
  SStream_concat0(O, "([");
325
326
5.86k
  if (is_pc) {
327
990
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->mem.in_disp);
328
4.87k
  } else if (op->mem.in_disp != 0) {
329
3.11k
    SStream_concat(O, "%s$%" PRIx32,
330
3.11k
             op->mem.in_disp >= 0 ? "" : "-",
331
3.11k
             abs(op->mem.in_disp));
332
3.11k
  }
333
334
5.86k
  if (op->mem.base_reg != M68K_REG_INVALID) {
335
3.02k
    if (op->mem.in_disp != 0)
336
1.83k
      SStream_concat(O, ",%s%s", s_spacing,
337
1.83k
               getRegName(op->mem.base_reg));
338
1.18k
    else
339
1.18k
      SStream_concat(O, "%s", getRegName(op->mem.base_reg));
340
3.02k
  }
341
342
5.86k
  if (is_post)
343
2.97k
    SStream_concat0(O, "]");
344
345
5.86k
  if (op->mem.index_reg != M68K_REG_INVALID) {
346
3.33k
    SStream_concat(O, ",%s", s_spacing);
347
3.33k
    printIndexReg(O, op);
348
3.33k
  }
349
350
5.86k
  printScaleFactor(O, op->mem.scale, 0);
351
352
5.86k
  if (is_pre)
353
2.89k
    SStream_concat0(O, "]");
354
355
5.86k
  if (op->mem.out_disp != 0) {
356
3.04k
    SStream_concat(O, ",%s%s$%" PRIx32, s_spacing,
357
3.04k
             op->mem.out_disp >= 0 ? "" : "-",
358
3.04k
             abs(op->mem.out_disp));
359
3.04k
  }
360
361
5.86k
  SStream_concat0(O, ")");
362
5.86k
}
363
364
static void printAddressingMode(SStream *O, uint32_t pc, const cs_m68k *inst,
365
        const cs_m68k_op *op)
366
404k
{
367
404k
  switch (op->address_mode) {
368
26.6k
  case M68K_AM_NONE:
369
26.6k
    switch (op->type) {
370
4.73k
    case M68K_OP_REG_BITS:
371
4.73k
      registerBits(O, op);
372
4.73k
      break;
373
1.16k
    case M68K_OP_REG_PAIR:
374
1.16k
      registerPair(O, op);
375
1.16k
      break;
376
20.7k
    case M68K_OP_REG:
377
20.7k
      printRegisterName(O, op);
378
20.7k
      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
0
    default:
386
0
      break;
387
26.6k
    }
388
26.6k
    break;
389
390
137k
  case M68K_AM_REG_DIRECT_DATA:
391
156k
  case M68K_AM_REG_DIRECT_ADDR:
392
182k
  case M68K_AM_REGI_ADDR:
393
207k
  case M68K_AM_REGI_ADDR_POST_INC:
394
247k
  case M68K_AM_REGI_ADDR_PRE_DEC:
395
265k
  case M68K_AM_REGI_ADDR_DISP:
396
267k
  case M68K_AM_PCI_DISP:
397
267k
    printRegAddrMode(O, pc, op);
398
267k
    break;
399
2.89k
  case M68K_AM_ABSOLUTE_DATA_SHORT:
400
2.89k
    SStream_concat(O, "$%" PRIx32 ".w", (uint32_t)op->mem.address);
401
2.89k
    break;
402
2.58k
  case M68K_AM_ABSOLUTE_DATA_LONG:
403
2.58k
    SStream_concat(O, "$%" PRIx64 ".l", (uint64_t)op->mem.address);
404
2.58k
    break;
405
56.9k
  case M68K_AM_IMMEDIATE:
406
56.9k
    printImmediate(O, inst, op);
407
56.9k
    break;
408
1.58k
  case M68K_AM_PCI_INDEX_8_BIT_DISP:
409
13.7k
  case M68K_AM_AREGI_INDEX_8_BIT_DISP:
410
13.7k
    printIndex8BitDisp(O, pc, op);
411
13.7k
    break;
412
325
  case M68K_AM_PCI_INDEX_BASE_DISP:
413
3.31k
  case M68K_AM_AREGI_INDEX_BASE_DISP:
414
3.31k
    printBaseDisp(O, pc, op);
415
3.31k
    break;
416
386
  case M68K_AM_PC_MEMI_POST_INDEX:
417
990
  case M68K_AM_PC_MEMI_PRE_INDEX:
418
3.28k
  case M68K_AM_MEMI_PRE_INDEX:
419
5.86k
  case M68K_AM_MEMI_POST_INDEX:
420
5.86k
    printMemIndirect(O, pc, op);
421
5.86k
    break;
422
24.8k
  case M68K_AM_BRANCH_DISPLACEMENT:
423
24.8k
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->br_disp.disp);
424
24.8k
  default:
425
24.8k
    break;
426
404k
  }
427
428
404k
  printBitfield(O, op);
429
404k
  if (op->flags & M68K_OP_FLAG_MEM_UPDATE)
430
0
    SStream_concat0(O, "&");
431
404k
}
432
433
static void printCAS2(SStream *O, uint32_t pc, const cs_m68k *ext)
434
406
{
435
406
  printAddressingMode(O, pc, ext, &ext->operands[0]);
436
406
  SStream_concat0(O, ",");
437
406
  printAddressingMode(O, pc, ext, &ext->operands[1]);
438
406
  SStream_concat0(O, ",");
439
440
406
  SStream_concat(O, "(%s):(%s)",
441
406
           s_reg_names[ext->operands[2].reg_pair.reg_0],
442
406
           s_reg_names[ext->operands[2].reg_pair.reg_1]);
443
406
}
444
445
static void printCacheOp(SStream *O, uint32_t pc, const cs_m68k *ext)
446
1.10k
{
447
1.10k
  static const char *const cache_names[] = { "nc", "dc", "ic", "bc" };
448
1.10k
  unsigned int sel = (unsigned int)ext->operands[0].imm;
449
1.10k
  int i;
450
451
1.10k
  if (sel < ARR_SIZE(cache_names))
452
1.10k
    SStream_concat0(O, cache_names[sel]);
453
0
  else
454
0
    SStream_concat(O, "#$%" PRIx64, ext->operands[0].imm);
455
456
2.03k
  for (i = 1; i < ext->op_count; ++i) {
457
925
    SStream_concat(O, ",%s", s_spacing);
458
925
    printAddressingMode(O, pc, ext, &ext->operands[i]);
459
925
  }
460
1.10k
}
461
462
#endif
463
464
static void printOpSize(SStream *O, const cs_m68k *ext)
465
226k
{
466
226k
  switch (ext->op_size.type) {
467
0
  case M68K_SIZE_TYPE_INVALID:
468
0
    break;
469
223k
  case M68K_SIZE_TYPE_CPU:
470
223k
    switch (ext->op_size.cpu_size) {
471
76.3k
    case M68K_CPU_SIZE_BYTE:
472
76.3k
      SStream_concat0(O, ".b");
473
76.3k
      break;
474
64.1k
    case M68K_CPU_SIZE_WORD:
475
64.1k
      SStream_concat0(O, ".w");
476
64.1k
      break;
477
54.1k
    case M68K_CPU_SIZE_LONG:
478
54.1k
      SStream_concat0(O, ".l");
479
54.1k
      break;
480
29.0k
    case M68K_CPU_SIZE_NONE:
481
29.0k
      break;
482
223k
    }
483
223k
    break;
484
223k
  case M68K_SIZE_TYPE_FPU:
485
2.37k
    switch (ext->op_size.fpu_size) {
486
739
    case M68K_FPU_SIZE_SINGLE:
487
739
      SStream_concat0(O, ".s");
488
739
      break;
489
309
    case M68K_FPU_SIZE_DOUBLE:
490
309
      SStream_concat0(O, ".d");
491
309
      break;
492
1.32k
    case M68K_FPU_SIZE_EXTENDED:
493
1.32k
      SStream_concat0(O, ".x");
494
1.32k
      break;
495
0
    case M68K_FPU_SIZE_NONE:
496
0
      break;
497
2.37k
    }
498
2.37k
    break;
499
226k
  }
500
226k
}
501
502
void M68K_printInst(MCInst *MI, SStream *O, void *PrinterInfo)
503
282k
{
504
282k
#ifndef CAPSTONE_DIET
505
282k
  m68k_info *info = (m68k_info *)PrinterInfo;
506
282k
  cs_m68k *ext = &info->extension;
507
282k
  cs_detail *detail = NULL;
508
282k
  int i = 0;
509
510
282k
  if (detail_is_set(MI)) {
511
282k
    detail = get_detail(MI);
512
282k
    int regs_read_count = MIN((int)ARR_SIZE(detail->regs_read),
513
282k
            info->regs_read_count);
514
282k
    int regs_write_count = MIN((int)ARR_SIZE(detail->regs_write),
515
282k
             info->regs_write_count);
516
282k
    int groups_count =
517
282k
      MIN((int)ARR_SIZE(detail->groups), info->groups_count);
518
519
282k
    memcpy(&detail->m68k, ext, sizeof(cs_m68k));
520
282k
    memcpy(&detail->regs_read, &info->regs_read,
521
282k
           regs_read_count * sizeof(info->regs_read[0]));
522
282k
    detail->regs_read_count = regs_read_count;
523
524
282k
    memcpy(&detail->regs_write, &info->regs_write,
525
282k
           regs_write_count * sizeof(info->regs_write[0]));
526
282k
    detail->regs_write_count = regs_write_count;
527
528
282k
    memcpy(&detail->groups, &info->groups, groups_count);
529
282k
    detail->groups_count = groups_count;
530
282k
  }
531
532
282k
  if (MI->Opcode == M68K_INS_INVALID) {
533
56.4k
    if (ext->op_count)
534
56.4k
      SStream_concat(O, "dc.w $%" PRIx32,
535
56.4k
               (uint32_t)ext->operands[0].imm);
536
0
    else
537
0
      SStream_concat(O, "dc.w $<unknown>");
538
56.4k
    return;
539
56.4k
  }
540
541
226k
  SStream_concat0(O, (char *)s_instruction_names[MI->Opcode]);
542
226k
  printOpSize(O, ext);
543
226k
  SStream_concat0(O, " ");
544
545
226k
  if (MI->Opcode == M68K_INS_CAS2) {
546
406
    printCAS2(O, info->pc, ext);
547
406
    return;
548
406
  }
549
550
225k
  if (MI->Opcode >= M68K_INS_CINVL && MI->Opcode <= M68K_INS_CPUSHA) {
551
1.10k
    printCacheOp(O, info->pc, ext);
552
1.10k
    return;
553
1.10k
  }
554
555
627k
  for (i = 0; i < ext->op_count; ++i) {
556
402k
    printAddressingMode(O, info->pc, ext, &ext->operands[i]);
557
402k
    if ((i + 1) != ext->op_count)
558
179k
      SStream_concat(O, ",%s", s_spacing);
559
402k
  }
560
224k
#endif
561
224k
}
562
563
const char *M68K_reg_name(csh handle, unsigned int reg)
564
351k
{
565
#ifdef CAPSTONE_DIET
566
  return NULL;
567
#else
568
351k
  if (reg >= ARR_SIZE(s_reg_names)) {
569
0
    return NULL;
570
0
  }
571
351k
  return s_reg_names[(int)reg];
572
351k
#endif
573
351k
}
574
575
void M68K_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
576
282k
{
577
282k
  insn->id = id; // These id's matches for 68k
578
282k
}
579
580
const char *M68K_insn_name(csh handle, unsigned int id)
581
282k
{
582
#ifdef CAPSTONE_DIET
583
  return NULL;
584
#else
585
282k
  if (id >= ARR_SIZE(s_instruction_names)) {
586
0
    return NULL;
587
0
  }
588
282k
  return s_instruction_names[id];
589
282k
#endif
590
282k
}
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
52.1k
{
604
52.1k
#ifndef CAPSTONE_DIET
605
52.1k
  return id2name(group_name_maps, ARR_SIZE(group_name_maps), id);
606
#else
607
  return NULL;
608
#endif
609
52.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