Coverage Report

Created: 2026-09-01 07:20

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