Coverage Report

Created: 2026-11-12 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
#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
205k
{
127
205k
  return s_reg_names[(int)reg];
128
205k
}
129
130
static void printRegbits(SStream *O, bool *need_sep, uint32_t data,
131
       const char *prefix)
132
15.5k
{
133
15.5k
  unsigned int first;
134
15.5k
  int i;
135
136
122k
  for (i = 0; i < 8; ++i) {
137
107k
    if (!(data & (1 << i)))
138
92.6k
      continue;
139
140
14.6k
    first = i;
141
31.8k
    while (i < 7 && (data & (1 << (i + 1))))
142
17.2k
      i++;
143
144
14.6k
    if (*need_sep)
145
9.41k
      SStream_concat1(O, '/');
146
14.6k
    *need_sep = true;
147
148
14.6k
    SStream_concat(O, "%s%" PRIu32, prefix, first);
149
150
14.6k
    if ((unsigned int)i > first)
151
6.37k
      SStream_concat(O, "-%s%" PRIu32, prefix,
152
6.37k
               (unsigned int)i);
153
14.6k
  }
154
15.5k
}
155
156
static void registerBits(SStream *O, const cs_m68k_op *op)
157
5.60k
{
158
5.60k
  unsigned int data = op->register_bits;
159
5.60k
  bool need_sep = false;
160
161
5.60k
  if (!data) {
162
413
    SStream_concat(O, "%s", "#$0");
163
413
    return;
164
413
  }
165
166
5.18k
  printRegbits(O, &need_sep, data & 0xff, "d");
167
5.18k
  printRegbits(O, &need_sep, (data >> 8) & 0xff, "a");
168
5.18k
  printRegbits(O, &need_sep, (data >> 16) & 0xff, "fp");
169
5.18k
}
170
171
static void registerPair(SStream *O, const cs_m68k_op *op)
172
2.00k
{
173
2.00k
  SStream_concat(O, "%s:%s", s_reg_names[op->reg_pair.reg_0],
174
2.00k
           s_reg_names[op->reg_pair.reg_1]);
175
2.00k
}
176
177
static void printRegisterName(SStream *O, const cs_m68k_op *op)
178
177k
{
179
177k
  SStream_concat(O, "%s", getRegName(op->reg));
180
177k
  if (op->flags & M68K_OP_FLAG_REG_LOWER)
181
0
    SStream_concat0(O, "l");
182
177k
  else if (op->flags & M68K_OP_FLAG_REG_UPPER)
183
0
    SStream_concat0(O, "u");
184
177k
}
185
186
static void printScaleFactor(SStream *O, uint8_t scale, int threshold)
187
17.9k
{
188
17.9k
  if (scale > threshold)
189
10.0k
    SStream_concat(O, "%s*%s%" PRId8, s_spacing, s_spacing, scale);
190
17.9k
}
191
192
static void printIndexReg(SStream *O, const cs_m68k_op *op)
193
15.0k
{
194
15.0k
  SStream_concat(O, "%s.%c", getRegName(op->mem.index_reg),
195
15.0k
           op->mem.index_size ? 'l' : 'w');
196
15.0k
}
197
198
static void printBitfield(SStream *O, const cs_m68k_op *op)
199
391k
{
200
391k
  if (!op->mem.bitfield)
201
389k
    return;
202
2.20k
  SStream_concat0(O, "{");
203
2.20k
  if (M68K_BF_IS_REG(op->mem.offset))
204
1.55k
    SStream_concat(O, "d%" PRId8, M68K_BF_REG_NUM(op->mem.offset));
205
647
  else
206
647
    SStream_concat(O, "%" PRId8, op->mem.offset);
207
2.20k
  SStream_concat0(O, ":");
208
2.20k
  if (M68K_BF_IS_REG(op->mem.width))
209
766
    SStream_concat(O, "d%" PRId8, M68K_BF_REG_NUM(op->mem.width));
210
1.43k
  else
211
1.43k
    SStream_concat(O, "%" PRId8, op->mem.width);
212
2.20k
  SStream_concat0(O, "}");
213
2.20k
}
214
215
static bool packed_bcd_to_string(uint64_t packed, char digits[17])
216
488
{
217
488
  unsigned int i;
218
219
3.20k
  for (i = 0; i < 16; ++i) {
220
3.11k
    unsigned int digit =
221
3.11k
      (unsigned int)((packed >> ((15 - i) * 4)) & 0xf);
222
3.11k
    if (digit > 9)
223
402
      return false;
224
2.71k
    digits[i] = (char)('0' + digit);
225
2.71k
  }
226
86
  digits[16] = '\0';
227
86
  return true;
228
488
}
229
230
static bool packed_exponent_to_string(uint16_t packed, char digits[4])
231
761
{
232
761
  unsigned int i;
233
234
2.46k
  for (i = 0; i < 3; ++i) {
235
1.97k
    unsigned int digit =
236
1.97k
      (unsigned int)((packed >> ((2 - i) * 4)) & 0xf);
237
1.97k
    if (digit > 9)
238
273
      return false;
239
1.70k
    digits[i] = (char)('0' + digit);
240
1.70k
  }
241
488
  digits[3] = '\0';
242
488
  return true;
243
761
}
244
245
static void printPackedImmediate(SStream *O, const m68k_op_fp_packed *value)
246
1.00k
{
247
1.00k
  const uint32_t header = value->header;
248
1.00k
  const bool negative = (header & 0x80000000U) != 0;
249
1.00k
  const bool negative_exponent = (header & 0x40000000U) != 0;
250
1.00k
  const uint16_t exponent = (uint16_t)((header >> 16) & 0x0fff);
251
1.00k
  const unsigned int integer_digit = header & 0xf;
252
1.00k
  char exponent_digits[4];
253
1.00k
  char fraction_digits[17];
254
255
  /* SE=1, y=3, and exponent=FFF encode infinity or NaN. */
256
1.00k
  if (((header >> 16) & 0x7fff) == 0x7fff) {
257
97
    SStream_concat(O, "#0e%s%s", negative ? "-" : "",
258
97
             value->fraction == 0 ? "inf" : "nan");
259
97
    return;
260
97
  }
261
262
909
  if (integer_digit == 0 && value->fraction == 0) {
263
67
    SStream_concat(O, "#0e%s0", negative ? "-" : "");
264
67
    return;
265
67
  }
266
267
842
  if (integer_digit > 9 ||
268
761
      !packed_exponent_to_string(exponent, exponent_digits) ||
269
756
      !packed_bcd_to_string(value->fraction, fraction_digits)) {
270
756
    SStream_concat0(O, "#<invalid-packed>");
271
756
    return;
272
756
  }
273
274
86
  SStream_concat(O, "#0e%s%u.%se%c%s", negative ? "-" : "", integer_digit,
275
86
           fraction_digits, negative_exponent ? '-' : '+',
276
86
           exponent_digits);
277
86
}
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.47k
{
285
1.47k
  if (shift < 64) {
286
1.15k
    uint64_t quotient = value >> shift;
287
1.15k
    uint64_t remainder = value & ((1ULL << shift) - 1);
288
1.15k
    uint64_t halfway = 1ULL << (shift - 1);
289
1.15k
    if (remainder > halfway ||
290
822
        (remainder == halfway && (quotient & 1)))
291
596
      return quotient + 1;
292
558
    return quotient;
293
1.15k
  }
294
318
  if (value > 0x8000000000000000ULL)
295
252
    return 1;
296
66
  return 0;
297
318
}
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.38k
{
303
2.38k
  const uint16_t sign_exp = value->sign_exp;
304
2.38k
  const uint64_t significand = value->significand;
305
2.38k
  const uint64_t sign = ((uint64_t)(sign_exp & 0x8000)) << 48;
306
2.38k
  const unsigned int E = sign_exp & 0x7fff;
307
308
2.38k
  if (E == 0x7fff) {
309
179
    uint64_t fraction = significand & 0x7fffffffffffffffULL;
310
179
    if (fraction == 0)
311
67
      return BitsToDouble(sign | 0x7ff0000000000000ULL);
312
112
    return BitsToDouble(sign | 0x7ff0000000000000ULL |
313
112
            ((fraction >> 11) | 0x0008000000000000ULL));
314
179
  }
315
316
2.20k
  if (E == 0 || significand == 0)
317
136
    return BitsToDouble(sign);
318
319
2.06k
  {
320
2.06k
    unsigned int leading = CountLeadingZeros_64(significand);
321
2.06k
    uint64_t normalized = significand << leading;
322
2.06k
    int64_t e = (int64_t)E - 16383 - (int64_t)leading;
323
324
2.06k
    if (e > 1023)
325
239
      return BitsToDouble(sign | 0x7ff0000000000000ULL);
326
327
1.82k
    if (e >= -1022) {
328
604
      uint64_t rounded = round_right_to_even(normalized, 11);
329
604
      if (rounded == (1ULL << 53)) {
330
180
        rounded >>= 1;
331
180
        ++e;
332
180
        if (e > 1023)
333
66
          return BitsToDouble(
334
66
            sign | 0x7ff0000000000000ULL);
335
180
      }
336
538
      return BitsToDouble(sign |
337
538
              ((uint64_t)(e + 1023) << 52) |
338
538
              (rounded & 0x000fffffffffffffULL));
339
604
    }
340
341
1.22k
    {
342
1.22k
      uint64_t shift = (uint64_t)(-e - 1011);
343
1.22k
      uint64_t fraction =
344
1.22k
        shift > 64 ? 0 :
345
1.22k
               round_right_to_even(
346
868
                 normalized,
347
868
                 (unsigned int)shift);
348
1.22k
      return BitsToDouble(sign | fraction);
349
1.82k
    }
350
1.82k
  }
351
1.82k
}
352
#endif
353
354
static void printImmediate(SStream *O, const cs_m68k *inst,
355
         const cs_m68k_op *op)
356
56.4k
{
357
56.4k
  if (inst->op_size.type == M68K_SIZE_TYPE_FPU) {
358
3.77k
    if (op->type == M68K_OP_FP_PACKED) {
359
1.00k
      printPackedImmediate(O, &op->fp_packed);
360
1.00k
      return;
361
1.00k
    }
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.76k
    if (op->type == M68K_OP_FP_SINGLE)
369
88
      SStream_concat(O, "#%f", op->simm);
370
2.67k
    else if (op->type == M68K_OP_FP_DOUBLE)
371
73
      SStream_concat(O, "#%f", op->dimm);
372
2.60k
    else if (op->type == M68K_OP_FP_EXTENDED)
373
2.38k
      SStream_concat(O, "#0e%g",
374
2.38k
               extended_to_double(&op->fp_extended));
375
225
    else
376
225
      SStream_concat(O, "#<unsupported>");
377
2.76k
    return;
378
3.77k
#endif
379
3.77k
  }
380
52.6k
  SStream_concat(O, "#$%" PRIx64, op->imm);
381
52.6k
}
382
383
static void printIndex8BitDisp(SStream *O, uint32_t pc, const cs_m68k_op *op)
384
10.6k
{
385
10.6k
  if (op->address_mode == M68K_AM_PCI_INDEX_8_BIT_DISP) {
386
1.45k
    SStream_concat(O, "$%" PRIx32 "(pc,%s", pc + 2 + op->mem.disp,
387
1.45k
             s_spacing);
388
9.17k
  } else {
389
9.17k
    SStream_concat(O, "%s$%" PRIx16 "(%s,%s",
390
9.17k
             op->mem.disp < 0 ? "-" : "", abs(op->mem.disp),
391
9.17k
             getRegName(op->mem.base_reg), s_spacing);
392
9.17k
  }
393
10.6k
  printIndexReg(O, op);
394
10.6k
  printScaleFactor(O, op->mem.scale, 1);
395
10.6k
  SStream_concat0(O, ")");
396
10.6k
}
397
398
static void printRegAddrMode(SStream *O, uint32_t pc, const cs_m68k_op *op)
399
254k
{
400
254k
  m68k_reg base_reg = op->type == M68K_OP_MEM ? op->mem.base_reg :
401
254k
                  op->reg;
402
403
254k
  switch (op->address_mode) {
404
128k
  case M68K_AM_REG_DIRECT_DATA:
405
128k
    printRegisterName(O, op);
406
128k
    break;
407
19.2k
  case M68K_AM_REG_DIRECT_ADDR:
408
19.2k
    printRegisterName(O, op);
409
19.2k
    break;
410
24.8k
  case M68K_AM_REGI_ADDR:
411
24.8k
    SStream_concat(O, "(a%" PRId32 ")", (base_reg - M68K_REG_A0));
412
24.8k
    break;
413
22.6k
  case M68K_AM_REGI_ADDR_POST_INC:
414
22.6k
    SStream_concat(O, "(a%" PRId32 ")+", (base_reg - M68K_REG_A0));
415
22.6k
    break;
416
40.0k
  case M68K_AM_REGI_ADDR_PRE_DEC:
417
40.0k
    SStream_concat(O, "-(a%" PRId32 ")", (base_reg - M68K_REG_A0));
418
40.0k
    break;
419
16.1k
  case M68K_AM_REGI_ADDR_DISP:
420
16.1k
    SStream_concat(O, "%s$%" PRIx16 "(a%" PRId32 ")",
421
16.1k
             op->mem.disp < 0 ? "-" : "", abs(op->mem.disp),
422
16.1k
             (base_reg - M68K_REG_A0));
423
16.1k
    break;
424
2.94k
  case M68K_AM_PCI_DISP:
425
2.94k
    SStream_concat(O, "$%" PRIx32 "(pc)", pc + 2 + op->mem.disp);
426
2.94k
    break;
427
0
  default:
428
0
    break;
429
254k
  }
430
254k
}
431
432
static void printBaseDisp(SStream *O, uint32_t pc, const cs_m68k_op *op)
433
2.92k
{
434
2.92k
  int is_pc = (op->address_mode == M68K_AM_PCI_INDEX_BASE_DISP);
435
436
2.92k
  if (is_pc) {
437
283
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->mem.in_disp);
438
2.63k
  } else if (op->mem.in_disp != 0) {
439
1.14k
    SStream_concat(O, "%s$%" PRIx32,
440
1.14k
             op->mem.in_disp >= 0 ? "" : "-",
441
1.14k
             abs(op->mem.in_disp));
442
1.14k
  }
443
444
2.92k
  SStream_concat0(O, "(");
445
446
2.92k
  if (is_pc) {
447
283
    SStream_concat0(O, "pc");
448
2.63k
  } else if (op->mem.base_reg != M68K_REG_INVALID) {
449
2.08k
    SStream_concat(O, "a%" PRId32, op->mem.base_reg - M68K_REG_A0);
450
2.08k
  }
451
452
2.92k
  if ((is_pc || op->mem.base_reg != M68K_REG_INVALID) &&
453
2.37k
      op->mem.index_reg != M68K_REG_INVALID)
454
1.57k
    SStream_concat(O, ",%s", s_spacing);
455
456
2.92k
  if (op->mem.index_reg != M68K_REG_INVALID) {
457
1.92k
    printIndexReg(O, op);
458
1.92k
    printScaleFactor(O, op->mem.scale, 0);
459
1.92k
  }
460
461
2.92k
  SStream_concat0(O, ")");
462
2.92k
}
463
464
static void printMemIndirect(SStream *O, uint32_t pc, const cs_m68k_op *op)
465
5.35k
{
466
5.35k
  int is_pc = (op->address_mode == M68K_AM_PC_MEMI_POST_INDEX ||
467
4.76k
         op->address_mode == M68K_AM_PC_MEMI_PRE_INDEX);
468
5.35k
  int is_post = (op->address_mode == M68K_AM_MEMI_POST_INDEX ||
469
3.59k
           op->address_mode == M68K_AM_PC_MEMI_POST_INDEX);
470
5.35k
  int is_pre = (op->address_mode == M68K_AM_MEMI_PRE_INDEX ||
471
3.01k
          op->address_mode == M68K_AM_PC_MEMI_PRE_INDEX);
472
473
5.35k
  SStream_concat0(O, "([");
474
475
5.35k
  if (is_pc) {
476
1.26k
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->mem.in_disp);
477
4.08k
  } else if (op->mem.in_disp != 0) {
478
1.99k
    SStream_concat(O, "%s$%" PRIx32,
479
1.99k
             op->mem.in_disp >= 0 ? "" : "-",
480
1.99k
             abs(op->mem.in_disp));
481
1.99k
  }
482
483
5.35k
  if (op->mem.base_reg != M68K_REG_INVALID) {
484
3.02k
    if (op->mem.in_disp != 0)
485
1.43k
      SStream_concat(O, ",%s%s", s_spacing,
486
1.43k
               getRegName(op->mem.base_reg));
487
1.58k
    else
488
1.58k
      SStream_concat(O, "%s", getRegName(op->mem.base_reg));
489
3.02k
  }
490
491
5.35k
  if (is_post)
492
2.33k
    SStream_concat0(O, "]");
493
494
5.35k
  if (op->mem.index_reg != M68K_REG_INVALID) {
495
2.52k
    SStream_concat(O, ",%s", s_spacing);
496
2.52k
    printIndexReg(O, op);
497
2.52k
  }
498
499
5.35k
  printScaleFactor(O, op->mem.scale, 0);
500
501
5.35k
  if (is_pre)
502
3.01k
    SStream_concat0(O, "]");
503
504
5.35k
  if (op->mem.out_disp != 0) {
505
2.45k
    SStream_concat(O, ",%s%s$%" PRIx32, s_spacing,
506
2.45k
             op->mem.out_disp >= 0 ? "" : "-",
507
2.45k
             abs(op->mem.out_disp));
508
2.45k
  }
509
510
5.35k
  SStream_concat0(O, ")");
511
5.35k
}
512
513
static void printAddressingMode(SStream *O, uint32_t pc, const cs_m68k *inst,
514
        const cs_m68k_op *op)
515
391k
{
516
391k
  switch (op->address_mode) {
517
37.5k
  case M68K_AM_NONE:
518
37.5k
    switch (op->type) {
519
5.60k
    case M68K_OP_REG_BITS:
520
5.60k
      registerBits(O, op);
521
5.60k
      break;
522
2.00k
    case M68K_OP_REG_PAIR:
523
2.00k
      registerPair(O, op);
524
2.00k
      break;
525
29.9k
    case M68K_OP_REG:
526
29.9k
      printRegisterName(O, op);
527
29.9k
      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
37.5k
    }
537
37.5k
    break;
538
539
128k
  case M68K_AM_REG_DIRECT_DATA:
540
147k
  case M68K_AM_REG_DIRECT_ADDR:
541
172k
  case M68K_AM_REGI_ADDR:
542
195k
  case M68K_AM_REGI_ADDR_POST_INC:
543
235k
  case M68K_AM_REGI_ADDR_PRE_DEC:
544
251k
  case M68K_AM_REGI_ADDR_DISP:
545
254k
  case M68K_AM_PCI_DISP:
546
254k
    printRegAddrMode(O, pc, op);
547
254k
    break;
548
2.48k
  case M68K_AM_ABSOLUTE_DATA_SHORT:
549
2.48k
    SStream_concat(O, "$%" PRIx32 ".w", (uint32_t)op->mem.address);
550
2.48k
    break;
551
2.31k
  case M68K_AM_ABSOLUTE_DATA_LONG:
552
2.31k
    SStream_concat(O, "$%" PRIx64 ".l", (uint64_t)op->mem.address);
553
2.31k
    break;
554
56.4k
  case M68K_AM_IMMEDIATE:
555
56.4k
    printImmediate(O, inst, op);
556
56.4k
    break;
557
1.45k
  case M68K_AM_PCI_INDEX_8_BIT_DISP:
558
10.6k
  case M68K_AM_AREGI_INDEX_8_BIT_DISP:
559
10.6k
    printIndex8BitDisp(O, pc, op);
560
10.6k
    break;
561
283
  case M68K_AM_PCI_INDEX_BASE_DISP:
562
2.92k
  case M68K_AM_AREGI_INDEX_BASE_DISP:
563
2.92k
    printBaseDisp(O, pc, op);
564
2.92k
    break;
565
583
  case M68K_AM_PC_MEMI_POST_INDEX:
566
1.26k
  case M68K_AM_PC_MEMI_PRE_INDEX:
567
3.59k
  case M68K_AM_MEMI_PRE_INDEX:
568
5.35k
  case M68K_AM_MEMI_POST_INDEX:
569
5.35k
    printMemIndirect(O, pc, op);
570
5.35k
    break;
571
19.4k
  case M68K_AM_BRANCH_DISPLACEMENT:
572
19.4k
    SStream_concat(O, "$%" PRIx32, pc + 2 + op->br_disp.disp);
573
19.4k
  default:
574
19.4k
    break;
575
391k
  }
576
577
391k
  printBitfield(O, op);
578
391k
  if (op->flags & M68K_OP_FLAG_MEM_UPDATE)
579
0
    SStream_concat0(O, "&");
580
391k
}
581
582
static void printCAS2(SStream *O, uint32_t pc, const cs_m68k *ext)
583
668
{
584
668
  printAddressingMode(O, pc, ext, &ext->operands[0]);
585
668
  SStream_concat0(O, ",");
586
668
  printAddressingMode(O, pc, ext, &ext->operands[1]);
587
668
  SStream_concat0(O, ",");
588
589
668
  SStream_concat(O, "(%s):(%s)",
590
668
           s_reg_names[ext->operands[2].reg_pair.reg_0],
591
668
           s_reg_names[ext->operands[2].reg_pair.reg_1]);
592
668
}
593
594
static void printCacheOp(SStream *O, uint32_t pc, const cs_m68k *ext)
595
1.28k
{
596
1.28k
  static const char *const cache_names[] = { "nc", "dc", "ic", "bc" };
597
1.28k
  unsigned int sel = (unsigned int)ext->operands[0].imm;
598
1.28k
  int i;
599
600
1.28k
  if (sel < ARR_SIZE(cache_names))
601
1.28k
    SStream_concat0(O, cache_names[sel]);
602
0
  else
603
0
    SStream_concat(O, "#$%" PRIx64, ext->operands[0].imm);
604
605
2.32k
  for (i = 1; i < ext->op_count; ++i) {
606
1.04k
    SStream_concat(O, ",%s", s_spacing);
607
1.04k
    printAddressingMode(O, pc, ext, &ext->operands[i]);
608
1.04k
  }
609
1.28k
}
610
611
static void printPackedMoveDestination(SStream *O, uint32_t pc,
612
               const cs_m68k *ext)
613
884
{
614
884
  const cs_m68k_op *k_factor = &ext->operands[2];
615
616
884
  printAddressingMode(O, pc, ext, &ext->operands[0]);
617
884
  SStream_concat(O, ",%s", s_spacing);
618
884
  printAddressingMode(O, pc, ext, &ext->operands[1]);
619
884
  SStream_concat0(O, "{");
620
884
  if (k_factor->type == M68K_OP_IMM)
621
573
    SStream_concat(O, "#%" PRId64, (int64_t)k_factor->imm);
622
311
  else
623
311
    printAddressingMode(O, pc, ext, k_factor);
624
884
  SStream_concat0(O, "}");
625
884
}
626
627
#endif
628
629
static void printOpSize(SStream *O, const cs_m68k *ext)
630
218k
{
631
218k
  switch (ext->op_size.type) {
632
0
  case M68K_SIZE_TYPE_INVALID:
633
0
    break;
634
211k
  case M68K_SIZE_TYPE_CPU:
635
211k
    switch (ext->op_size.cpu_size) {
636
61.9k
    case M68K_CPU_SIZE_BYTE:
637
61.9k
      SStream_concat0(O, ".b");
638
61.9k
      break;
639
57.9k
    case M68K_CPU_SIZE_WORD:
640
57.9k
      SStream_concat0(O, ".w");
641
57.9k
      break;
642
58.6k
    case M68K_CPU_SIZE_LONG:
643
58.6k
      SStream_concat0(O, ".l");
644
58.6k
      break;
645
33.4k
    case M68K_CPU_SIZE_NONE:
646
33.4k
      break;
647
211k
    }
648
211k
    break;
649
211k
  case M68K_SIZE_TYPE_FPU:
650
6.32k
    switch (ext->op_size.fpu_size) {
651
297
    case M68K_FPU_SIZE_SINGLE:
652
297
      SStream_concat0(O, ".s");
653
297
      break;
654
378
    case M68K_FPU_SIZE_DOUBLE:
655
378
      SStream_concat0(O, ".d");
656
378
      break;
657
3.54k
    case M68K_FPU_SIZE_EXTENDED:
658
3.54k
      SStream_concat0(O, ".x");
659
3.54k
      break;
660
2.10k
    case M68K_FPU_SIZE_PACKED:
661
2.10k
      SStream_concat0(O, ".p");
662
2.10k
      break;
663
0
    case M68K_FPU_SIZE_NONE:
664
0
      break;
665
6.32k
    }
666
6.32k
    break;
667
218k
  }
668
218k
}
669
670
void M68K_printInst(MCInst *MI, SStream *O, void *PrinterInfo)
671
270k
{
672
270k
#ifndef CAPSTONE_DIET
673
270k
  m68k_info *info = (m68k_info *)PrinterInfo;
674
270k
  cs_m68k *ext = &info->extension;
675
270k
  cs_detail *detail = NULL;
676
270k
  int i = 0;
677
678
270k
  if (detail_is_set(MI)) {
679
270k
    detail = get_detail(MI);
680
270k
    int regs_read_count = MIN((int)ARR_SIZE(detail->regs_read),
681
270k
            info->regs_read_count);
682
270k
    int regs_write_count = MIN((int)ARR_SIZE(detail->regs_write),
683
270k
             info->regs_write_count);
684
270k
    int groups_count =
685
270k
      MIN((int)ARR_SIZE(detail->groups), info->groups_count);
686
687
270k
    memcpy(&detail->m68k, ext, sizeof(cs_m68k));
688
270k
    memcpy(&detail->regs_read, &info->regs_read,
689
270k
           regs_read_count * sizeof(info->regs_read[0]));
690
270k
    detail->regs_read_count = regs_read_count;
691
692
270k
    memcpy(&detail->regs_write, &info->regs_write,
693
270k
           regs_write_count * sizeof(info->regs_write[0]));
694
270k
    detail->regs_write_count = regs_write_count;
695
696
270k
    memcpy(&detail->groups, &info->groups, groups_count);
697
270k
    detail->groups_count = groups_count;
698
270k
  }
699
700
270k
  if (MI->Opcode == M68K_INS_INVALID) {
701
52.1k
    if (ext->op_count)
702
52.1k
      SStream_concat(O, "dc.w $%" PRIx32,
703
52.1k
               (uint32_t)ext->operands[0].imm);
704
0
    else
705
0
      SStream_concat(O, "dc.w $<unknown>");
706
52.1k
    return;
707
52.1k
  }
708
709
218k
  SStream_concat0(O, (char *)s_instruction_names[MI->Opcode]);
710
218k
  printOpSize(O, ext);
711
218k
  SStream_concat0(O, " ");
712
713
218k
  if (MI->Opcode == M68K_INS_CAS2) {
714
668
    printCAS2(O, info->pc, ext);
715
668
    return;
716
668
  }
717
718
217k
  if (MI->Opcode >= M68K_INS_CINVL && MI->Opcode <= M68K_INS_CPUSHA) {
719
1.28k
    printCacheOp(O, info->pc, ext);
720
1.28k
    return;
721
1.28k
  }
722
723
216k
  if (MI->Opcode == M68K_INS_FMOVE &&
724
6.11k
      ext->op_size.type == M68K_SIZE_TYPE_FPU &&
725
4.82k
      ext->op_size.fpu_size == M68K_FPU_SIZE_PACKED &&
726
2.10k
      ext->op_count == 3) {
727
884
    printPackedMoveDestination(O, info->pc, ext);
728
884
    return;
729
884
  }
730
731
602k
  for (i = 0; i < ext->op_count; ++i) {
732
387k
    printAddressingMode(O, info->pc, ext, &ext->operands[i]);
733
387k
    if ((i + 1) != ext->op_count)
734
174k
      SStream_concat(O, ",%s", s_spacing);
735
387k
  }
736
215k
#endif
737
215k
}
738
739
const char *M68K_reg_name(csh handle, unsigned int reg)
740
343k
{
741
#ifdef CAPSTONE_DIET
742
  return NULL;
743
#else
744
343k
  if (reg >= ARR_SIZE(s_reg_names)) {
745
0
    return NULL;
746
0
  }
747
343k
  return s_reg_names[(int)reg];
748
343k
#endif
749
343k
}
750
751
void M68K_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
752
270k
{
753
270k
  insn->id = id; // These id's matches for 68k
754
270k
}
755
756
const char *M68K_insn_name(csh handle, unsigned int id)
757
270k
{
758
#ifdef CAPSTONE_DIET
759
  return NULL;
760
#else
761
270k
  if (id >= ARR_SIZE(s_instruction_names)) {
762
0
    return NULL;
763
0
  }
764
270k
  return s_instruction_names[id];
765
270k
#endif
766
270k
}
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
43.0k
{
780
43.0k
#ifndef CAPSTONE_DIET
781
43.0k
  return id2name(group_name_maps, ARR_SIZE(group_name_maps), id);
782
#else
783
  return NULL;
784
#endif
785
43.0k
}
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