Coverage Report

Created: 2026-10-17 07:17

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
#include "../../MathExtras.h"
20
21
#ifndef CAPSTONE_DIET
22
static const char s_spacing[] = " ";
23
24
static const char *const s_reg_names[] = {
25
  "invalid",  "d0", "d1",  "d2",   "d3",   "d4",   "d5",   "d6",
26
  "d7",     "a0", "a1",  "a2",   "a3",   "a4",   "a5",   "a6",
27
  "a7",     "fp0",  "fp1",   "fp2",  "fp3",  "fp4",  "fp5",  "fp6",
28
  "fp7",      "pc", "sr",  "ccr",  "sfc",  "dfc",  "usp",  "vbr",
29
  "cacr",     "caar", "msp",   "isp",  "tc",   "itt0", "itt1", "dtt0",
30
  "dtt1",     "mmusr",  "urp",   "srp",
31
32
  "fpcr",     "fpsr", "fpiar",
33
34
  "tt0",      "tt1",  "crp",   "acc",  "acc0", "acc1", "acc2", "acc3",
35
  "accext01", "accext23", "macsr", "mask",
36
};
37
38
static const char *const s_instruction_names[] = {
39
  "invalid",   "abcd",   "add",      "adda",    "addi",
40
  "addq",      "addx",   "and",      "andi",    "asl",
41
  "asr",       "bhs",  "blo",      "bhi",   "bls",
42
  "bcc",       "bcs",  "bne",      "beq",   "bvc",
43
  "bvs",       "bpl",  "bmi",      "bge",   "blt",
44
  "bgt",       "ble",  "bra",      "bsr",   "bchg",
45
  "bclr",      "bset",   "btst",     "bitrev",    "byterev",
46
  "bfchg",     "bfclr",  "bfexts",   "bfextu",    "bfffo",
47
  "bfins",     "bfset",  "bftst",    "bkpt",    "callm",
48
  "cas",       "cas2",   "chk",      "chk2",    "clr",
49
  "cmp",       "cmpa",   "cmpi",     "cmpm",    "cmp2",
50
  "cinvl",     "cinvp",  "cinva",    "cpushl",    "cpushp",
51
  "cpusha",    "dbt",  "dbf",      "dbhi",    "dbls",
52
  "dbcc",      "dbcs",   "dbne",     "dbeq",    "dbvc",
53
  "dbvs",      "dbpl",   "dbmi",     "dbge",    "dblt",
54
  "dbgt",      "dble",   "dbra",     "divs",    "divsl",
55
  "divu",      "divul",  "eor",      "eori",    "exg",
56
  "ext",       "extb",   "ff1",      "fabs",    "fsabs",
57
  "fdabs",     "facos",  "fadd",     "fsadd",   "fdadd",
58
  "fasin",     "fatan",  "fatanh",   "fbf",   "fbeq",
59
  "fbogt",     "fboge",  "fbolt",    "fbole",   "fbogl",
60
  "fbor",      "fbun",   "fbueq",    "fbugt",   "fbuge",
61
  "fbult",     "fbule",  "fbne",     "fbt",   "fbsf",
62
  "fbseq",     "fbgt",   "fbge",     "fblt",    "fble",
63
  "fbgl",      "fbgle",  "fbngle",   "fbngl",   "fbnle",
64
  "fbnlt",     "fbnge",  "fbngt",    "fbsne",   "fbst",
65
  "fcmp",      "fcos",   "fcosh",    "fdbf",    "fdbeq",
66
  "fdbogt",    "fdboge",   "fdbolt",   "fdbole",    "fdbogl",
67
  "fdbor",     "fdbun",  "fdbueq",   "fdbugt",    "fdbuge",
68
  "fdbult",    "fdbule",   "fdbne",    "fdbt",    "fdbsf",
69
  "fdbseq",    "fdbgt",  "fdbge",    "fdblt",   "fdble",
70
  "fdbgl",     "fdbgle",   "fdbngle",  "fdbngl",    "fdbnle",
71
  "fdbnlt",    "fdbnge",   "fdbngt",   "fdbsne",    "fdbst",
72
  "fdiv",      "fsdiv",  "fddiv",    "fetox",   "fetoxm1",
73
  "fgetexp",   "fgetman",  "fint",     "fintrz",    "flog10",
74
  "flog2",     "flogn",  "flognp1",  "fmod",    "fmove",
75
  "fsmove",    "fdmove",   "fmovecr",  "fmovem",    "fmul",
76
  "fsmul",     "fdmul",  "fneg",     "fsneg",   "fdneg",
77
  "fnop",      "frem",   "frestore", "fsave",   "fscale",
78
  "fsgldiv",   "fsglmul",  "fsin",     "fsincos",   "fsinh",
79
  "fsqrt",     "fssqrt",   "fdsqrt",   "fsf",   "fseq",
80
  "fsogt",     "fsoge",  "fsolt",    "fsole",   "fsogl",
81
  "fsor",      "fsun",   "fsueq",    "fsugt",   "fsuge",
82
  "fsult",     "fsule",  "fsne",     "fst",   "fssf",
83
  "fsseq",     "fsgt",   "fsge",     "fslt",    "fsle",
84
  "fsgl",      "fsgle",  "fsngle",   "fsngl",   "fsnle",
85
  "fsnlt",     "fsnge",  "fsngt",    "fssne",   "fsst",
86
  "fsub",      "fssub",  "fdsub",    "ftan",    "ftanh",
87
  "ftentox",   "ftrapf",   "ftrapeq",  "ftrapogt",  "ftrapoge",
88
  "ftrapolt",  "ftrapole", "ftrapogl", "ftrapor",   "ftrapun",
89
  "ftrapueq",  "ftrapugt", "ftrapuge", "ftrapult",  "ftrapule",
90
  "ftrapne",   "ftrapt",   "ftrapsf",  "ftrapseq",  "ftrapgt",
91
  "ftrapge",   "ftraplt",  "ftraple",  "ftrapgl",   "ftrapgle",
92
  "ftrapngle", "ftrapngl", "ftrapnle", "ftrapnlt",  "ftrapnge",
93
  "ftrapngt",  "ftrapsne", "ftrapst",  "ftst",    "ftwotox",
94
  "halt",      "illegal",  "intouch",  "jmp",   "jsr",
95
  "lea",       "link",   "lpstop",   "lsl",   "lsr",
96
  "mac",       "move",   "movea",    "movec",   "movem",
97
  "movep",     "moveq",  "moves",    "move16",    "mov3q",
98
  "movclr",    "msac",   "muls",     "mulu",    "mvs",
99
  "mvz",       "nbcd",   "neg",      "negx",    "nop",
100
  "not",       "or",   "ori",      "pack",    "pea",
101
  "pflush",    "pflusha",  "pflushan", "pflushn",   "ploadr",
102
  "ploadw",    "plpar",  "plpaw",    "pmove",   "pmovefd",
103
  "ptestr",    "ptestw",   "pulse",    "rems",    "remu",
104
  "reset",     "rol",  "ror",      "roxl",    "roxr",
105
  "rtd",       "rte",  "rtm",      "rtr",   "rts",
106
  "sats",      "sbcd",   "st",       "sf",    "shi",
107
  "sls",       "scc",  "shs",      "scs",   "slo",
108
  "sne",       "seq",  "svc",      "svs",   "spl",
109
  "smi",       "sge",  "slt",      "sgt",   "sle",
110
  "stop",      "strldsr",  "sub",      "suba",    "subi",
111
  "subq",      "subx",   "swap",     "tas",   "trap",
112
  "trapv",     "trapt",  "trapf",    "traphi",    "trapls",
113
  "trapcc",    "traphs",   "trapcs",   "traplo",    "trapne",
114
  "trapeq",    "trapvc",   "trapvs",   "trappl",    "trapmi",
115
  "trapge",    "traplt",   "trapgt",   "traple",    "tst",
116
  "unlk",      "unpk",   "wddata",   "wdebug",    "bgnd",
117
  "tbls",      "tblu",   "tblsn",    "tblun",   "cp0bcbusy",
118
  "cp0ld",     "cp0nop",   "cp0st",    "cp1bcbusy", "cp1ld",
119
  "cp1nop",    "cp1st",  "tpf",      "maaac",   "masac",
120
  "msaac",     "mssac",
121
};
122
#endif
123
124
#ifndef CAPSTONE_DIET
125
static const char *getRegName(m68k_reg reg)
126
230k
{
127
230k
  return s_reg_names[(int)reg];
128
230k
}
129
130
static void printRegbits(SStream *O, bool *need_sep, uint32_t data,
131
       const char *prefix)
132
16.0k
{
133
16.0k
  unsigned int first;
134
16.0k
  int i;
135
136
129k
  for (i = 0; i < 8; ++i) {
137
113k
    if (!(data & (1 << i)))
138
97.2k
      continue;
139
140
16.6k
    first = i;
141
31.4k
    while (i < 7 && (data & (1 << (i + 1))))
142
14.8k
      i++;
143
144
16.6k
    if (*need_sep)
145
11.3k
      SStream_concat1(O, '/');
146
16.6k
    *need_sep = true;
147
148
16.6k
    SStream_concat(O, "%s%" PRIu32, prefix, first);
149
150
16.6k
    if ((unsigned int)i > first)
151
6.08k
      SStream_concat(O, "-%s%" PRIu32, prefix,
152
6.08k
               (unsigned int)i);
153
16.6k
  }
154
16.0k
}
155
156
static void registerBits(SStream *O, const cs_m68k_op *op)
157
5.68k
{
158
5.68k
  unsigned int data = op->register_bits;
159
5.68k
  bool need_sep = false;
160
161
5.68k
  if (!data) {
162
322
    SStream_concat(O, "%s", "#$0");
163
322
    return;
164
322
  }
165
166
5.36k
  printRegbits(O, &need_sep, data & 0xff, "d");
167
5.36k
  printRegbits(O, &need_sep, (data >> 8) & 0xff, "a");
168
5.36k
  printRegbits(O, &need_sep, (data >> 16) & 0xff, "fp");
169
5.36k
}
170
171
static void registerPair(SStream *O, const cs_m68k_op *op)
172
3.26k
{
173
3.26k
  SStream_concat(O, "%s:%s", s_reg_names[op->reg_pair.reg_0],
174
3.26k
           s_reg_names[op->reg_pair.reg_1]);
175
3.26k
}
176
177
static void printRegisterName(SStream *O, const cs_m68k_op *op)
178
196k
{
179
196k
  SStream_concat(O, "%s", getRegName(op->reg));
180
196k
  if (op->flags & M68K_OP_FLAG_REG_LOWER)
181
0
    SStream_concat0(O, "l");
182
196k
  else if (op->flags & M68K_OP_FLAG_REG_UPPER)
183
0
    SStream_concat0(O, "u");
184
196k
}
185
186
static void printScaleFactor(SStream *O, uint8_t scale, int threshold)
187
21.4k
{
188
21.4k
  if (scale > threshold)
189
12.4k
    SStream_concat(O, "%s*%s%" PRId8, s_spacing, s_spacing, scale);
190
21.4k
}
191
192
static void printIndexReg(SStream *O, const cs_m68k_op *op)
193
19.1k
{
194
19.1k
  SStream_concat(O, "%s.%c", getRegName(op->mem.index_reg),
195
19.1k
           op->mem.index_size ? 'l' : 'w');
196
19.1k
}
197
198
static void printBitfield(SStream *O, const cs_m68k_op *op)
199
440k
{
200
440k
  if (!op->mem.bitfield)
201
438k
    return;
202
2.10k
  SStream_concat0(O, "{");
203
2.10k
  if (M68K_BF_IS_REG(op->mem.offset))
204
1.13k
    SStream_concat(O, "d%" PRId8, M68K_BF_REG_NUM(op->mem.offset));
205
971
  else
206
971
    SStream_concat(O, "%" PRId8, op->mem.offset);
207
2.10k
  SStream_concat0(O, ":");
208
2.10k
  if (M68K_BF_IS_REG(op->mem.width))
209
782
    SStream_concat(O, "d%" PRId8, M68K_BF_REG_NUM(op->mem.width));
210
1.32k
  else
211
1.32k
    SStream_concat(O, "%" PRId8, op->mem.width);
212
2.10k
  SStream_concat0(O, "}");
213
2.10k
}
214
215
static bool packed_bcd_to_string(uint64_t packed, char digits[17])
216
659
{
217
659
  unsigned int i;
218
219
3.81k
  for (i = 0; i < 16; ++i) {
220
3.72k
    unsigned int digit =
221
3.72k
      (unsigned int)((packed >> ((15 - i) * 4)) & 0xf);
222
3.72k
    if (digit > 9)
223
569
      return false;
224
3.15k
    digits[i] = (char)('0' + digit);
225
3.15k
  }
226
90
  digits[16] = '\0';
227
90
  return true;
228
659
}
229
230
static bool packed_exponent_to_string(uint16_t packed, char digits[4])
231
787
{
232
787
  unsigned int i;
233
234
2.89k
  for (i = 0; i < 3; ++i) {
235
2.23k
    unsigned int digit =
236
2.23k
      (unsigned int)((packed >> ((2 - i) * 4)) & 0xf);
237
2.23k
    if (digit > 9)
238
128
      return false;
239
2.10k
    digits[i] = (char)('0' + digit);
240
2.10k
  }
241
659
  digits[3] = '\0';
242
659
  return true;
243
787
}
244
245
static void printPackedImmediate(SStream *O, const m68k_op_fp_packed *value)
246
1.03k
{
247
1.03k
  const uint32_t header = value->header;
248
1.03k
  const bool negative = (header & 0x80000000U) != 0;
249
1.03k
  const bool negative_exponent = (header & 0x40000000U) != 0;
250
1.03k
  const uint16_t exponent = (uint16_t)((header >> 16) & 0x0fff);
251
1.03k
  const unsigned int integer_digit = header & 0xf;
252
1.03k
  char exponent_digits[4];
253
1.03k
  char fraction_digits[17];
254
255
  /* SE=1, y=3, and exponent=FFF encode infinity or NaN. */
256
1.03k
  if (((header >> 16) & 0x7fff) == 0x7fff) {
257
105
    SStream_concat(O, "#0e%s%s", negative ? "-" : "",
258
105
             value->fraction == 0 ? "inf" : "nan");
259
105
    return;
260
105
  }
261
262
928
  if (integer_digit == 0 && value->fraction == 0) {
263
56
    SStream_concat(O, "#0e%s0", negative ? "-" : "");
264
56
    return;
265
56
  }
266
267
872
  if (integer_digit > 9 ||
268
787
      !packed_exponent_to_string(exponent, exponent_digits) ||
269
782
      !packed_bcd_to_string(value->fraction, fraction_digits)) {
270
782
    SStream_concat0(O, "#<invalid-packed>");
271
782
    return;
272
782
  }
273
274
90
  SStream_concat(O, "#0e%s%u.%se%c%s", negative ? "-" : "", integer_digit,
275
90
           fraction_digits, negative_exponent ? '-' : '+',
276
90
           exponent_digits);
277
90
}
278
279
/* Issue #681: Windows kernel printf-style functions do not support
280
 * floating-point format specifiers, so the text conversion is unused there. */
281
#if !defined(_KERNEL_MODE)
282
/* Round `value >> shift` to nearest, ties to even.  Requires 1 <= shift <= 64. */
283
static uint64_t round_right_to_even(uint64_t value, unsigned int shift)
284
1.42k
{
285
1.42k
  if (shift < 64) {
286
1.22k
    uint64_t quotient = value >> shift;
287
1.22k
    uint64_t remainder = value & ((1ULL << shift) - 1);
288
1.22k
    uint64_t halfway = 1ULL << (shift - 1);
289
1.22k
    if (remainder > halfway ||
290
818
        (remainder == halfway && (quotient & 1)))
291
635
      return quotient + 1;
292
585
    return quotient;
293
1.22k
  }
294
201
  if (value > 0x8000000000000000ULL)
295
120
    return 1;
296
81
  return 0;
297
201
}
298
299
/* Convert only for assembly-text rendering.  The detail operand retains the
300
 * complete external representation in fp_extended. */
301
static double extended_to_double(const m68k_op_fp_extended *value)
302
2.10k
{
303
2.10k
  const uint16_t sign_exp = value->sign_exp;
304
2.10k
  const uint64_t significand = value->significand;
305
2.10k
  const uint64_t sign = ((uint64_t)(sign_exp & 0x8000)) << 48;
306
2.10k
  const unsigned int E = sign_exp & 0x7fff;
307
308
2.10k
  if (E == 0x7fff) {
309
176
    uint64_t fraction = significand & 0x7fffffffffffffffULL;
310
176
    if (fraction == 0)
311
65
      return BitsToDouble(sign | 0x7ff0000000000000ULL);
312
111
    return BitsToDouble(sign | 0x7ff0000000000000ULL |
313
111
            ((fraction >> 11) | 0x0008000000000000ULL));
314
176
  }
315
316
1.92k
  if (E == 0 || significand == 0)
317
136
    return BitsToDouble(sign);
318
319
1.78k
  {
320
1.78k
    unsigned int leading = CountLeadingZeros_64(significand);
321
1.78k
    uint64_t normalized = significand << leading;
322
1.78k
    int64_t e = (int64_t)E - 16383 - (int64_t)leading;
323
324
1.78k
    if (e > 1023)
325
94
      return BitsToDouble(sign | 0x7ff0000000000000ULL);
326
327
1.69k
    if (e >= -1022) {
328
657
      uint64_t rounded = round_right_to_even(normalized, 11);
329
657
      if (rounded == (1ULL << 53)) {
330
143
        rounded >>= 1;
331
143
        ++e;
332
143
        if (e > 1023)
333
72
          return BitsToDouble(
334
72
            sign | 0x7ff0000000000000ULL);
335
143
      }
336
585
      return BitsToDouble(sign |
337
585
              ((uint64_t)(e + 1023) << 52) |
338
585
              (rounded & 0x000fffffffffffffULL));
339
657
    }
340
341
1.03k
    {
342
1.03k
      uint64_t shift = (uint64_t)(-e - 1011);
343
1.03k
      uint64_t fraction =
344
1.03k
        shift > 64 ? 0 :
345
1.03k
               round_right_to_even(
346
764
                 normalized,
347
764
                 (unsigned int)shift);
348
1.03k
      return BitsToDouble(sign | fraction);
349
1.69k
    }
350
1.69k
  }
351
1.69k
}
352
#endif
353
354
static void printImmediate(SStream *O, const cs_m68k *inst,
355
         const cs_m68k_op *op)
356
66.4k
{
357
66.4k
  if (inst->op_size.type == M68K_SIZE_TYPE_FPU) {
358
3.83k
    if (op->type == M68K_OP_FP_PACKED) {
359
1.03k
      printPackedImmediate(O, &op->fp_packed);
360
1.03k
      return;
361
1.03k
    }
362
#if defined(_KERNEL_MODE)
363
    SStream_concat(O, "#<float_point_unsupported>");
364
    return;
365
#else
366
    /* Dispatch on the operand storage type.  Extended immediates
367
     * are converted only for GNU-compatible assembly text. */
368
2.80k
    if (op->type == M68K_OP_FP_SINGLE)
369
370
      SStream_concat(O, "#%f", op->simm);
370
2.43k
    else if (op->type == M68K_OP_FP_DOUBLE)
371
76
      SStream_concat(O, "#%f", op->dimm);
372
2.35k
    else if (op->type == M68K_OP_FP_EXTENDED)
373
2.10k
      SStream_concat(O, "#0e%g",
374
2.10k
               extended_to_double(&op->fp_extended));
375
255
    else
376
255
      SStream_concat(O, "#<unsupported>");
377
2.80k
    return;
378
3.83k
#endif
379
3.83k
  }
380
62.6k
  SStream_concat(O, "#$%" PRIx64, op->imm);
381
62.6k
}
382
383
static void printIndex8BitDisp(SStream *O, uint32_t pc, const cs_m68k_op *op)
384
13.5k
{
385
13.5k
  if (op->address_mode == M68K_AM_PCI_INDEX_8_BIT_DISP) {
386
2.01k
    SStream_concat(O, "$%" PRIx32 "(pc,%s", pc + 2 + op->mem.disp,
387
2.01k
             s_spacing);
388
11.5k
  } else {
389
11.5k
    SStream_concat(O, "%s$%" PRIx16 "(%s,%s",
390
11.5k
             op->mem.disp < 0 ? "-" : "", abs(op->mem.disp),
391
11.5k
             getRegName(op->mem.base_reg), s_spacing);
392
11.5k
  }
393
13.5k
  printIndexReg(O, op);
394
13.5k
  printScaleFactor(O, op->mem.scale, 1);
395
13.5k
  SStream_concat0(O, ")");
396
13.5k
}
397
398
static void printRegAddrMode(SStream *O, uint32_t pc, const cs_m68k_op *op)
399
281k
{
400
281k
  m68k_reg base_reg = op->type == M68K_OP_MEM ? op->mem.base_reg :
401
281k
                  op->reg;
402
403
281k
  switch (op->address_mode) {
404
144k
  case M68K_AM_REG_DIRECT_DATA:
405
144k
    printRegisterName(O, op);
406
144k
    break;
407
19.8k
  case M68K_AM_REG_DIRECT_ADDR:
408
19.8k
    printRegisterName(O, op);
409
19.8k
    break;
410
28.5k
  case M68K_AM_REGI_ADDR:
411
28.5k
    SStream_concat(O, "(a%" PRId32 ")", (base_reg - M68K_REG_A0));
412
28.5k
    break;
413
25.4k
  case M68K_AM_REGI_ADDR_POST_INC:
414
25.4k
    SStream_concat(O, "(a%" PRId32 ")+", (base_reg - M68K_REG_A0));
415
25.4k
    break;
416
43.4k
  case M68K_AM_REGI_ADDR_PRE_DEC:
417
43.4k
    SStream_concat(O, "-(a%" PRId32 ")", (base_reg - M68K_REG_A0));
418
43.4k
    break;
419
16.8k
  case M68K_AM_REGI_ADDR_DISP:
420
16.8k
    SStream_concat(O, "%s$%" PRIx16 "(a%" PRId32 ")",
421
16.8k
             op->mem.disp < 0 ? "-" : "", abs(op->mem.disp),
422
16.8k
             (base_reg - M68K_REG_A0));
423
16.8k
    break;
424
2.84k
  case M68K_AM_PCI_DISP:
425
2.84k
    SStream_concat(O, "$%" PRIx32 "(pc)", pc + 2 + op->mem.disp);
426
2.84k
    break;
427
0
  default:
428
0
    break;
429
281k
  }
430
281k
}
431
432
static void printBaseDisp(SStream *O, uint32_t pc, const cs_m68k_op *op)
433
3.37k
{
434
3.37k
  int is_pc = (op->address_mode == M68K_AM_PCI_INDEX_BASE_DISP);
435
436
3.37k
  if (is_pc) {
437
425
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->mem.in_disp);
438
2.94k
  } else if (op->mem.in_disp != 0) {
439
1.28k
    SStream_concat(O, "%s$%" PRIx32,
440
1.28k
             op->mem.in_disp >= 0 ? "" : "-",
441
1.28k
             abs(op->mem.in_disp));
442
1.28k
  }
443
444
3.37k
  SStream_concat0(O, "(");
445
446
3.37k
  if (is_pc) {
447
425
    SStream_concat0(O, "pc");
448
2.94k
  } else if (op->mem.base_reg != M68K_REG_INVALID) {
449
1.91k
    SStream_concat(O, "a%" PRId32, op->mem.base_reg - M68K_REG_A0);
450
1.91k
  }
451
452
3.37k
  if ((is_pc || op->mem.base_reg != M68K_REG_INVALID) &&
453
2.33k
      op->mem.index_reg != M68K_REG_INVALID)
454
1.27k
    SStream_concat(O, ",%s", s_spacing);
455
456
3.37k
  if (op->mem.index_reg != M68K_REG_INVALID) {
457
1.78k
    printIndexReg(O, op);
458
1.78k
    printScaleFactor(O, op->mem.scale, 0);
459
1.78k
  }
460
461
3.37k
  SStream_concat0(O, ")");
462
3.37k
}
463
464
static void printMemIndirect(SStream *O, uint32_t pc, const cs_m68k_op *op)
465
6.07k
{
466
6.07k
  int is_pc = (op->address_mode == M68K_AM_PC_MEMI_POST_INDEX ||
467
5.31k
         op->address_mode == M68K_AM_PC_MEMI_PRE_INDEX);
468
6.07k
  int is_post = (op->address_mode == M68K_AM_MEMI_POST_INDEX ||
469
3.98k
           op->address_mode == M68K_AM_PC_MEMI_POST_INDEX);
470
6.07k
  int is_pre = (op->address_mode == M68K_AM_MEMI_PRE_INDEX ||
471
3.64k
          op->address_mode == M68K_AM_PC_MEMI_PRE_INDEX);
472
473
6.07k
  SStream_concat0(O, "([");
474
475
6.07k
  if (is_pc) {
476
1.56k
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->mem.in_disp);
477
4.51k
  } else if (op->mem.in_disp != 0) {
478
2.32k
    SStream_concat(O, "%s$%" PRIx32,
479
2.32k
             op->mem.in_disp >= 0 ? "" : "-",
480
2.32k
             abs(op->mem.in_disp));
481
2.32k
  }
482
483
6.07k
  if (op->mem.base_reg != M68K_REG_INVALID) {
484
3.26k
    if (op->mem.in_disp != 0)
485
1.59k
      SStream_concat(O, ",%s%s", s_spacing,
486
1.59k
               getRegName(op->mem.base_reg));
487
1.67k
    else
488
1.67k
      SStream_concat(O, "%s", getRegName(op->mem.base_reg));
489
3.26k
  }
490
491
6.07k
  if (is_post)
492
2.84k
    SStream_concat0(O, "]");
493
494
6.07k
  if (op->mem.index_reg != M68K_REG_INVALID) {
495
3.72k
    SStream_concat(O, ",%s", s_spacing);
496
3.72k
    printIndexReg(O, op);
497
3.72k
  }
498
499
6.07k
  printScaleFactor(O, op->mem.scale, 0);
500
501
6.07k
  if (is_pre)
502
3.22k
    SStream_concat0(O, "]");
503
504
6.07k
  if (op->mem.out_disp != 0) {
505
2.95k
    SStream_concat(O, ",%s%s$%" PRIx32, s_spacing,
506
2.95k
             op->mem.out_disp >= 0 ? "" : "-",
507
2.95k
             abs(op->mem.out_disp));
508
2.95k
  }
509
510
6.07k
  SStream_concat0(O, ")");
511
6.07k
}
512
513
static void printAddressingMode(SStream *O, uint32_t pc, const cs_m68k *inst,
514
        const cs_m68k_op *op)
515
440k
{
516
440k
  switch (op->address_mode) {
517
40.4k
  case M68K_AM_NONE:
518
40.4k
    switch (op->type) {
519
5.68k
    case M68K_OP_REG_BITS:
520
5.68k
      registerBits(O, op);
521
5.68k
      break;
522
3.26k
    case M68K_OP_REG_PAIR:
523
3.26k
      registerPair(O, op);
524
3.26k
      break;
525
31.4k
    case M68K_OP_REG:
526
31.4k
      printRegisterName(O, op);
527
31.4k
      break;
528
0
    case M68K_OP_SHIFT:
529
0
      if (op->flags & M68K_OP_FLAG_SHIFT_LEFT)
530
0
        SStream_concat0(O, "<<");
531
0
      else if (op->flags & M68K_OP_FLAG_SHIFT_RIGHT)
532
0
        SStream_concat0(O, ">>");
533
0
      break;
534
0
    default:
535
0
      break;
536
40.4k
    }
537
40.4k
    break;
538
539
144k
  case M68K_AM_REG_DIRECT_DATA:
540
164k
  case M68K_AM_REG_DIRECT_ADDR:
541
193k
  case M68K_AM_REGI_ADDR:
542
218k
  case M68K_AM_REGI_ADDR_POST_INC:
543
262k
  case M68K_AM_REGI_ADDR_PRE_DEC:
544
279k
  case M68K_AM_REGI_ADDR_DISP:
545
281k
  case M68K_AM_PCI_DISP:
546
281k
    printRegAddrMode(O, pc, op);
547
281k
    break;
548
3.50k
  case M68K_AM_ABSOLUTE_DATA_SHORT:
549
3.50k
    SStream_concat(O, "$%" PRIx32 ".w", (uint32_t)op->mem.address);
550
3.50k
    break;
551
3.22k
  case M68K_AM_ABSOLUTE_DATA_LONG:
552
3.22k
    SStream_concat(O, "$%" PRIx64 ".l", (uint64_t)op->mem.address);
553
3.22k
    break;
554
66.4k
  case M68K_AM_IMMEDIATE:
555
66.4k
    printImmediate(O, inst, op);
556
66.4k
    break;
557
2.01k
  case M68K_AM_PCI_INDEX_8_BIT_DISP:
558
13.5k
  case M68K_AM_AREGI_INDEX_8_BIT_DISP:
559
13.5k
    printIndex8BitDisp(O, pc, op);
560
13.5k
    break;
561
425
  case M68K_AM_PCI_INDEX_BASE_DISP:
562
3.37k
  case M68K_AM_AREGI_INDEX_BASE_DISP:
563
3.37k
    printBaseDisp(O, pc, op);
564
3.37k
    break;
565
761
  case M68K_AM_PC_MEMI_POST_INDEX:
566
1.56k
  case M68K_AM_PC_MEMI_PRE_INDEX:
567
3.98k
  case M68K_AM_MEMI_PRE_INDEX:
568
6.07k
  case M68K_AM_MEMI_POST_INDEX:
569
6.07k
    printMemIndirect(O, pc, op);
570
6.07k
    break;
571
22.2k
  case M68K_AM_BRANCH_DISPLACEMENT:
572
22.2k
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->br_disp.disp);
573
22.2k
  default:
574
22.2k
    break;
575
440k
  }
576
577
440k
  printBitfield(O, op);
578
440k
  if (op->flags & M68K_OP_FLAG_MEM_UPDATE)
579
0
    SStream_concat0(O, "&");
580
440k
}
581
582
static void printCAS2(SStream *O, uint32_t pc, const cs_m68k *ext)
583
1.45k
{
584
1.45k
  printAddressingMode(O, pc, ext, &ext->operands[0]);
585
1.45k
  SStream_concat0(O, ",");
586
1.45k
  printAddressingMode(O, pc, ext, &ext->operands[1]);
587
1.45k
  SStream_concat0(O, ",");
588
589
1.45k
  SStream_concat(O, "(%s):(%s)",
590
1.45k
           s_reg_names[ext->operands[2].reg_pair.reg_0],
591
1.45k
           s_reg_names[ext->operands[2].reg_pair.reg_1]);
592
1.45k
}
593
594
static void printCacheOp(SStream *O, uint32_t pc, const cs_m68k *ext)
595
2.00k
{
596
2.00k
  static const char *const cache_names[] = { "nc", "dc", "ic", "bc" };
597
2.00k
  unsigned int sel = (unsigned int)ext->operands[0].imm;
598
2.00k
  int i;
599
600
2.00k
  if (sel < ARR_SIZE(cache_names))
601
2.00k
    SStream_concat0(O, cache_names[sel]);
602
0
  else
603
0
    SStream_concat(O, "#$%" PRIx64, ext->operands[0].imm);
604
605
3.72k
  for (i = 1; i < ext->op_count; ++i) {
606
1.72k
    SStream_concat(O, ",%s", s_spacing);
607
1.72k
    printAddressingMode(O, pc, ext, &ext->operands[i]);
608
1.72k
  }
609
2.00k
}
610
611
static void printPackedMoveDestination(SStream *O, uint32_t pc,
612
               const cs_m68k *ext)
613
520
{
614
520
  const cs_m68k_op *k_factor = &ext->operands[2];
615
616
520
  printAddressingMode(O, pc, ext, &ext->operands[0]);
617
520
  SStream_concat(O, ",%s", s_spacing);
618
520
  printAddressingMode(O, pc, ext, &ext->operands[1]);
619
520
  SStream_concat0(O, "{");
620
520
  if (k_factor->type == M68K_OP_IMM)
621
347
    SStream_concat(O, "#%" PRId64, (int64_t)k_factor->imm);
622
173
  else
623
173
    printAddressingMode(O, pc, ext, k_factor);
624
520
  SStream_concat0(O, "}");
625
520
}
626
627
#endif
628
629
static void printOpSize(SStream *O, const cs_m68k *ext)
630
245k
{
631
245k
  switch (ext->op_size.type) {
632
0
  case M68K_SIZE_TYPE_INVALID:
633
0
    break;
634
239k
  case M68K_SIZE_TYPE_CPU:
635
239k
    switch (ext->op_size.cpu_size) {
636
76.9k
    case M68K_CPU_SIZE_BYTE:
637
76.9k
      SStream_concat0(O, ".b");
638
76.9k
      break;
639
60.9k
    case M68K_CPU_SIZE_WORD:
640
60.9k
      SStream_concat0(O, ".w");
641
60.9k
      break;
642
64.7k
    case M68K_CPU_SIZE_LONG:
643
64.7k
      SStream_concat0(O, ".l");
644
64.7k
      break;
645
36.9k
    case M68K_CPU_SIZE_NONE:
646
36.9k
      break;
647
239k
    }
648
239k
    break;
649
239k
  case M68K_SIZE_TYPE_FPU:
650
6.25k
    switch (ext->op_size.fpu_size) {
651
865
    case M68K_FPU_SIZE_SINGLE:
652
865
      SStream_concat0(O, ".s");
653
865
      break;
654
441
    case M68K_FPU_SIZE_DOUBLE:
655
441
      SStream_concat0(O, ".d");
656
441
      break;
657
3.18k
    case M68K_FPU_SIZE_EXTENDED:
658
3.18k
      SStream_concat0(O, ".x");
659
3.18k
      break;
660
1.76k
    case M68K_FPU_SIZE_PACKED:
661
1.76k
      SStream_concat0(O, ".p");
662
1.76k
      break;
663
0
    case M68K_FPU_SIZE_NONE:
664
0
      break;
665
6.25k
    }
666
6.25k
    break;
667
245k
  }
668
245k
}
669
670
void M68K_printInst(MCInst *MI, SStream *O, void *PrinterInfo)
671
309k
{
672
309k
#ifndef CAPSTONE_DIET
673
309k
  m68k_info *info = (m68k_info *)PrinterInfo;
674
309k
  cs_m68k *ext = &info->extension;
675
309k
  cs_detail *detail = NULL;
676
309k
  int i = 0;
677
678
309k
  if (detail_is_set(MI)) {
679
309k
    detail = get_detail(MI);
680
309k
    int regs_read_count = MIN((int)ARR_SIZE(detail->regs_read),
681
309k
            info->regs_read_count);
682
309k
    int regs_write_count = MIN((int)ARR_SIZE(detail->regs_write),
683
309k
             info->regs_write_count);
684
309k
    int groups_count =
685
309k
      MIN((int)ARR_SIZE(detail->groups), info->groups_count);
686
687
309k
    memcpy(&detail->m68k, ext, sizeof(cs_m68k));
688
309k
    memcpy(&detail->regs_read, &info->regs_read,
689
309k
           regs_read_count * sizeof(info->regs_read[0]));
690
309k
    detail->regs_read_count = regs_read_count;
691
692
309k
    memcpy(&detail->regs_write, &info->regs_write,
693
309k
           regs_write_count * sizeof(info->regs_write[0]));
694
309k
    detail->regs_write_count = regs_write_count;
695
696
309k
    memcpy(&detail->groups, &info->groups, groups_count);
697
309k
    detail->groups_count = groups_count;
698
309k
  }
699
700
309k
  if (MI->Opcode == M68K_INS_INVALID) {
701
63.2k
    if (ext->op_count)
702
63.2k
      SStream_concat(O, "dc.w $%" PRIx32,
703
63.2k
               (uint32_t)ext->operands[0].imm);
704
0
    else
705
0
      SStream_concat(O, "dc.w $<unknown>");
706
63.2k
    return;
707
63.2k
  }
708
709
245k
  SStream_concat0(O, (char *)s_instruction_names[MI->Opcode]);
710
245k
  printOpSize(O, ext);
711
245k
  SStream_concat0(O, " ");
712
713
245k
  if (MI->Opcode == M68K_INS_CAS2) {
714
1.45k
    printCAS2(O, info->pc, ext);
715
1.45k
    return;
716
1.45k
  }
717
718
244k
  if (MI->Opcode >= M68K_INS_CINVL && MI->Opcode <= M68K_INS_CPUSHA) {
719
2.00k
    printCacheOp(O, info->pc, ext);
720
2.00k
    return;
721
2.00k
  }
722
723
242k
  if (MI->Opcode == M68K_INS_FMOVE &&
724
5.49k
      ext->op_size.type == M68K_SIZE_TYPE_FPU &&
725
4.26k
      ext->op_size.fpu_size == M68K_FPU_SIZE_PACKED &&
726
1.76k
      ext->op_count == 3) {
727
520
    printPackedMoveDestination(O, info->pc, ext);
728
520
    return;
729
520
  }
730
731
676k
  for (i = 0; i < ext->op_count; ++i) {
732
435k
    printAddressingMode(O, info->pc, ext, &ext->operands[i]);
733
435k
    if ((i + 1) != ext->op_count)
734
196k
      SStream_concat(O, ",%s", s_spacing);
735
435k
  }
736
241k
#endif
737
241k
}
738
739
const char *M68K_reg_name(csh handle, unsigned int reg)
740
381k
{
741
#ifdef CAPSTONE_DIET
742
  return NULL;
743
#else
744
381k
  if (reg >= ARR_SIZE(s_reg_names)) {
745
0
    return NULL;
746
0
  }
747
381k
  return s_reg_names[(int)reg];
748
381k
#endif
749
381k
}
750
751
void M68K_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
752
309k
{
753
309k
  insn->id = id; // These id's matches for 68k
754
309k
}
755
756
const char *M68K_insn_name(csh handle, unsigned int id)
757
309k
{
758
#ifdef CAPSTONE_DIET
759
  return NULL;
760
#else
761
309k
  if (id >= ARR_SIZE(s_instruction_names)) {
762
0
    return NULL;
763
0
  }
764
309k
  return s_instruction_names[id];
765
309k
#endif
766
309k
}
767
768
#ifndef CAPSTONE_DIET
769
static const name_map group_name_maps[] = {
770
  { M68K_GRP_INVALID, NULL },
771
  { M68K_GRP_JUMP, "jump" },
772
  { M68K_GRP_RET, "ret" },
773
  { M68K_GRP_IRET, "iret" },
774
  { M68K_GRP_BRANCH_RELATIVE, "branch_relative" },
775
};
776
#endif
777
778
const char *M68K_group_name(csh handle, unsigned int id)
779
48.9k
{
780
48.9k
#ifndef CAPSTONE_DIET
781
48.9k
  return id2name(group_name_maps, ARR_SIZE(group_name_maps), id);
782
#else
783
  return NULL;
784
#endif
785
48.9k
}
786
787
#ifndef CAPSTONE_DIET
788
void M68K_reg_access(const cs_insn *insn, cs_regs regs_read,
789
         uint8_t *regs_read_count, cs_regs regs_write,
790
         uint8_t *regs_write_count)
791
0
{
792
0
  uint8_t read_count, write_count;
793
794
0
  read_count = insn->detail->regs_read_count;
795
0
  write_count = insn->detail->regs_write_count;
796
797
  // implicit registers
798
0
  memcpy(regs_read, insn->detail->regs_read,
799
0
         read_count * sizeof(insn->detail->regs_read[0]));
800
0
  memcpy(regs_write, insn->detail->regs_write,
801
0
         write_count * sizeof(insn->detail->regs_write[0]));
802
803
0
  *regs_read_count = read_count;
804
0
  *regs_write_count = write_count;
805
0
}
806
#endif