Coverage Report

Created: 2026-09-28 06:34

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