Coverage Report

Created: 2026-09-03 07:09

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