Coverage Report

Created: 2026-06-15 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/capstonenext/arch/M680X/M680XInstPrinter.c
Line
Count
Source
1
/* Capstone Disassembly Engine */
2
/* M680X Backend by Wolfgang Schwotzer <wolfgang.schwotzer@gmx.net> 2017 */
3
4
#ifdef CAPSTONE_HAS_M680X
5
#include <stdio.h>
6
#include <stdlib.h>
7
#include <string.h>
8
#include <capstone/platform.h>
9
10
#include "../../cs_priv.h"
11
#include "../../MCInst.h"
12
#include "../../SStream.h"
13
#include "../../MCRegisterInfo.h"
14
#include "../../Mapping.h"
15
#include "../../MCInstPrinter.h"
16
#include "../../utils.h"
17
#include "M680XInstPrinter.h"
18
#include "M680XDisassembler.h"
19
#include "M680XDisassemblerInternals.h"
20
21
#ifndef CAPSTONE_DIET
22
static const char s_reg_names[][10] = {
23
  "<invalid>", "a",  "b",  "e",  "f",   "0",    "d",    "w",
24
  "cc",      "dp", "md", "hx", "h",   "x",    "y",    "s",
25
  "u",       "v",  "q",  "pc", "spc", "tmp2", "tmp3",
26
};
27
28
static const char s_instruction_names[][6] = {
29
  "invld", "aba",   "abx",   "aby",   "adc",   "adca",  "adcb",  "adcd",
30
  "adcr",  "add",   "adda",  "addb",  "addd",  "adde",  "addf",  "addr",
31
  "addw",  "addx",  "addy",  "aded",  "adex",  "adey",  "aim",   "ais",
32
  "aix",   "and",   "anda",  "andb",  "andx",  "andy",  "andcc", "andd",
33
  "andr",  "asl",   "asla",  "aslb",  "asld",  "aslw",  "aslx",  "asly",
34
  "asr",   "asra",  "asrb",  "asrd",  "asrw",  "asrx",  "asry",  "band",
35
  "bcc",   "bclr",  "bcs",   "beor",  "beq",   "bge",   "bgnd",  "bgt",
36
  "bhcc",  "bhcs",  "bhi",   "biand", "bieor", "bih",   "bil",   "bior",
37
  "bit",   "bita",  "bitb",  "bitx",  "bity",  "bitd",  "bitmd", "ble",
38
  "bls",   "blt",   "bmc",   "bmi",   "bms",   "bne",   "bor",   "bpl",
39
  "brclr", "brset", "bra",   "brn",   "bset",  "bsr",   "btas",  "bvc",
40
  "bvs",   "call",  "cba",   "cbeq",  "cbeqa", "cbeqx", "clc",   "cli",
41
  "clr",   "clra",  "clrb",  "clrd",  "clre",  "clrf",  "clrh",  "clrw",
42
  "clrx",  "clry",  "clv",   "cmp",   "cmpa",  "cmpb",  "cmpd",  "cmpe",
43
  "cmpf",  "cmpr",  "cmps",  "cmpu",  "cmpw",  "cmpx",  "cmpy",  "com",
44
  "coma",  "comb",  "comd",  "come",  "comf",  "comw",  "comx",  "comy",
45
  "cpd",   "cped",  "cpes",  "cpex",  "cpey",  "cphx",  "cps",   "cpx",
46
  "cpy",   "cwai",  "daa",   "dbeq",  "dbne",  "dbnz",  "dbnza", "dbnzx",
47
  "dec",   "deca",  "decb",  "decd",  "dece",  "decf",  "decw",  "decx",
48
  "decy",  "des",   "dex",   "dey",   "div",   "divd",  "divq",  "ediv",
49
  "edivs", "eim",   "emacs", "emaxd", "emaxm", "emind", "eminm", "emul",
50
  "emuls", "eor",   "eora",  "eorb",  "eord",  "eorr",  "eorx",  "eory",
51
  "etbl",  "exg",   "fdiv",  "gldaa", "gldab", "gldd",  "glds",  "gldx",
52
  "gldy",  "gstaa", "gstab", "gstd",  "gsts",  "gstx",  "gsty",  "ibeq",
53
  "ibne",  "idiv",  "idivs", "illgl", "inc",   "inca",  "incb",  "incd",
54
  "ince",  "incf",  "incw",  "incx",  "incy",  "ins",   "inx",   "iny",
55
  "jmp",   "jsr",   "lbcc",  "lbcs",  "lbeq",  "lbge",  "lbgt",  "lbhi",
56
  "lble",  "lbls",  "lblt",  "lbmi",  "lbne",  "lbpl",  "lbra",  "lbrn",
57
  "lbsr",  "lbvc",  "lbvs",  "lda",   "ldaa",  "ldab",  "ldb",   "ldbt",
58
  "ldd",   "lde",   "ldf",   "ldhx",  "ldmd",  "ldq",   "lds",   "ldu",
59
  "ldw",   "ldx",   "ldy",   "leas",  "leau",  "leax",  "leay",  "lsl",
60
  "lsla",  "lslb",  "lsld",  "lslx",  "lsr",   "lsra",  "lsrb",  "lsrd",
61
  "lsrw",  "lsrx",  "lsry",  "maxa",  "maxm",  "mem",   "mina",  "minm",
62
  "mov",   "movb",  "movw",  "mul",   "muld",  "neg",   "nega",  "negb",
63
  "negd",  "negw",  "negx",  "negy",  "nop",   "nsa",   "oim",   "ora",
64
  "oraa",  "orab",  "orb",   "orcc",  "ord",   "orr",   "orx",   "ory",
65
  "psha",  "pshb",  "pshc",  "pshcw", "pshd",  "pshh",  "pshs",  "pshsw",
66
  "pshu",  "pshuw", "pshx",  "pshy",  "pula",  "pulb",  "pulc",  "pulcw",
67
  "puld",  "pulh",  "puls",  "pulsw", "pulu",  "puluw", "pulx",  "puly",
68
  "rev",   "revw",  "rol",   "rola",  "rolb",  "rold",  "rolw",  "rolx",
69
  "roly",  "ror",   "rora",  "rorb",  "rord",  "rorw",  "rorx",  "rory",
70
  "rsp",   "rtc",   "rti",   "rts",   "sba",   "sbc",   "sbca",  "sbcb",
71
  "sbcd",  "sbcr",  "sbed",  "sbex",  "sbey",  "sec",   "sei",   "sev",
72
  "sex",   "sexw",  "sha",   "sla",   "slp",   "sta",   "staa",  "stab",
73
  "stb",   "stbt",  "std",   "ste",   "stf",   "stop",  "sthx",  "stq",
74
  "sts",   "stu",   "stw",   "stx",   "sty",   "sub",   "suba",  "subb",
75
  "subd",  "sube",  "subf",  "subr",  "subw",  "subx",  "suby",  "swi",
76
  "swi2",  "swi3",  "sync",  "sys",   "tab",   "tap",   "tax",   "tba",
77
  "tbeq",  "tbl",   "tbne",  "test",  "tfm",   "tfr",   "tim",   "tpa",
78
  "trap",  "tst",   "tsta",  "tstb",  "tstd",  "tste",  "tstf",  "tstw",
79
  "tstx",  "tsty",  "tsx",   "tsy",   "txa",   "txs",   "tys",   "wai",
80
  "wait",  "wav",   "wavr",  "xgdx",  "xgdy",
81
};
82
83
static const name_map s_group_names[] = {
84
  { M680X_GRP_INVALID, "<invalid>" },
85
  { M680X_GRP_JUMP, "jump" },
86
  { M680X_GRP_CALL, "call" },
87
  { M680X_GRP_RET, "return" },
88
  { M680X_GRP_INT, "interrupt" },
89
  { M680X_GRP_IRET, "interrupt_return" },
90
  { M680X_GRP_PRIV, "privileged" },
91
  { M680X_GRP_BRAREL, "branch_relative" },
92
};
93
#endif
94
95
static void printRegName(cs_struct *handle, SStream *OS, unsigned int reg)
96
137k
{
97
137k
#ifndef CAPSTONE_DIET
98
137k
  SStream_concat0(OS, handle->reg_name((csh)handle, reg));
99
137k
#endif
100
137k
}
101
102
static void printInstructionName(cs_struct *handle, SStream *OS,
103
         unsigned int insn)
104
349k
{
105
349k
#ifndef CAPSTONE_DIET
106
349k
  SStream_concat0(OS, handle->insn_name((csh)handle, insn));
107
349k
#endif
108
349k
}
109
110
static uint32_t get_unsigned(int32_t value, int byte_size)
111
0
{
112
0
  switch (byte_size) {
113
0
  case 1:
114
0
    return (uint32_t)(value & 0xff);
115
116
0
  case 2:
117
0
    return (uint32_t)(value & 0xffff);
118
119
0
  default:
120
0
  case 4:
121
0
    return (uint32_t)value;
122
0
  }
123
0
}
124
125
static void printIncDec(bool isPost, SStream *O, m680x_info *info,
126
      cs_m680x_op *op)
127
193k
{
128
193k
  static const char s_inc_dec[][3] = { "--", "-", "", "+", "++" };
129
130
193k
  if (!op->idx.inc_dec)
131
154k
    return;
132
133
39.6k
  if ((!isPost && !(op->idx.flags & M680X_IDX_POST_INC_DEC)) ||
134
29.6k
      (isPost && (op->idx.flags & M680X_IDX_POST_INC_DEC))) {
135
19.8k
    const char *prePostfix = "";
136
137
19.8k
    if (info->cpu_type == M680X_CPU_TYPE_CPU12)
138
9.57k
      prePostfix = (op->idx.inc_dec < 0) ? "-" : "+";
139
10.2k
    else if (op->idx.inc_dec >= -2 && (op->idx.inc_dec <= 2)) {
140
9.14k
      prePostfix = (char *)s_inc_dec[op->idx.inc_dec + 2];
141
9.14k
    }
142
143
19.8k
    SStream_concat0(O, prePostfix);
144
19.8k
  }
145
39.6k
}
146
147
static void printOperand(MCInst *MI, SStream *O, m680x_info *info,
148
       cs_m680x_op *op)
149
320k
{
150
320k
  switch (op->type) {
151
32.3k
  case M680X_OP_REGISTER:
152
32.3k
    printRegName(MI->csh, O, op->reg);
153
32.3k
    break;
154
155
8.01k
  case M680X_OP_CONSTANT:
156
8.01k
    SStream_concat(O, "%u", op->const_val);
157
8.01k
    break;
158
159
34.0k
  case M680X_OP_IMMEDIATE:
160
34.0k
    if (MI->csh->imm_unsigned)
161
0
      SStream_concat(O, "#%u",
162
0
               get_unsigned(op->imm, op->size));
163
34.0k
    else
164
34.0k
      SStream_concat(O, "#%d", op->imm);
165
166
34.0k
    break;
167
168
96.8k
  case M680X_OP_INDEXED:
169
96.8k
    if (op->idx.flags & M680X_IDX_INDIRECT)
170
9.58k
      SStream_concat0(O, "[");
171
172
96.8k
    if (op->idx.offset_reg != M680X_REG_INVALID)
173
8.70k
      printRegName(MI->csh, O, op->idx.offset_reg);
174
88.1k
    else if (op->idx.offset_bits > 0) {
175
59.5k
      if (op->idx.base_reg == M680X_REG_PC)
176
8.28k
        SStream_concat(O, "$%04x", op->idx.offset_addr);
177
51.2k
      else
178
51.2k
        SStream_concat(O, "%d", op->idx.offset);
179
59.5k
    } else if (op->idx.inc_dec != 0 &&
180
17.7k
         info->cpu_type == M680X_CPU_TYPE_CPU12)
181
9.57k
      SStream_concat(O, "%d", abs(op->idx.inc_dec));
182
183
96.8k
    if (!(op->idx.flags & M680X_IDX_NO_COMMA))
184
93.4k
      SStream_concat(O, ", ");
185
186
96.8k
    printIncDec(false, O, info, op);
187
188
96.8k
    printRegName(MI->csh, O, op->idx.base_reg);
189
190
96.8k
    if (op->idx.base_reg == M680X_REG_PC &&
191
10.1k
        (op->idx.offset_bits > 0))
192
8.28k
      SStream_concat(O, "r");
193
194
96.8k
    printIncDec(true, O, info, op);
195
196
96.8k
    if (op->idx.flags & M680X_IDX_INDIRECT)
197
9.58k
      SStream_concat(O, "]");
198
199
96.8k
    break;
200
201
34.9k
  case M680X_OP_RELATIVE:
202
34.9k
    SStream_concat(O, "$%04x", op->rel.address);
203
34.9k
    break;
204
205
58.4k
  case M680X_OP_DIRECT:
206
58.4k
    SStream_concat(O, "$%02x", op->direct_addr);
207
58.4k
    break;
208
209
55.5k
  case M680X_OP_EXTENDED:
210
55.5k
    if (op->ext.indirect)
211
396
      SStream_concat(O, "[$%04x]", op->ext.address);
212
55.1k
    else {
213
55.1k
      if (op->ext.address < 256) {
214
3.55k
        SStream_concat(O, ">$%04x", op->ext.address);
215
51.5k
      } else {
216
51.5k
        SStream_concat(O, "$%04x", op->ext.address);
217
51.5k
      }
218
55.1k
    }
219
220
55.5k
    break;
221
222
0
  default:
223
0
    SStream_concat0(O, "<invalid_operand>");
224
0
    break;
225
320k
  }
226
320k
}
227
228
static const char *getDelimiter(m680x_info *info, cs_m680x *m680x)
229
392k
{
230
392k
  bool indexed = false;
231
392k
  int count = 0;
232
392k
  int i;
233
234
392k
  if (info->insn == M680X_INS_TFM)
235
1.21k
    return ", ";
236
237
391k
  if (m680x->op_count > 1) {
238
564k
    for (i = 0; i < m680x->op_count; ++i) {
239
385k
      if (m680x->operands[i].type == M680X_OP_INDEXED)
240
67.4k
        indexed = true;
241
242
385k
      if (m680x->operands[i].type != M680X_OP_REGISTER)
243
198k
        count++;
244
385k
    }
245
179k
  }
246
247
391k
  return (indexed && (count >= 1)) ? "; " : ", ";
248
392k
};
249
250
void M680X_printInst(MCInst *MI, SStream *O, void *PrinterInfo)
251
392k
{
252
392k
  m680x_info *info = (m680x_info *)PrinterInfo;
253
392k
  cs_m680x *m680x = &info->m680x;
254
392k
  cs_detail *detail = MI->flat_insn->detail;
255
392k
  int suppress_operands = 0;
256
392k
  const char *delimiter = getDelimiter(info, m680x);
257
392k
  int i;
258
259
392k
  if (detail != NULL)
260
392k
    memcpy(&detail->m680x, m680x, sizeof(cs_m680x));
261
262
392k
  if (info->insn == M680X_INS_INVLD || info->insn == M680X_INS_ILLGL) {
263
42.7k
    if (m680x->op_count)
264
42.7k
      SStream_concat(O, "fcb $%02x", m680x->operands[0].imm);
265
0
    else
266
0
      SStream_concat0(O, "fcb $<unknown>");
267
268
42.7k
    return;
269
42.7k
  }
270
271
349k
  printInstructionName(MI->csh, O, info->insn);
272
349k
  SStream_concat0(O, " ");
273
274
349k
  if ((m680x->flags & M680X_FIRST_OP_IN_MNEM) != 0)
275
187k
    suppress_operands++;
276
277
349k
  if ((m680x->flags & M680X_SECOND_OP_IN_MNEM) != 0)
278
5.44k
    suppress_operands++;
279
280
862k
  for (i = 0; i < m680x->op_count; ++i) {
281
513k
    if (i >= suppress_operands) {
282
320k
      printOperand(MI, O, info, &m680x->operands[i]);
283
284
320k
      if ((i + 1) != m680x->op_count)
285
58.4k
        SStream_concat0(O, delimiter);
286
320k
    }
287
513k
  }
288
349k
}
289
290
const char *M680X_reg_name(csh handle, unsigned int reg)
291
1.21M
{
292
1.21M
#ifndef CAPSTONE_DIET
293
294
1.21M
  if (reg >= ARR_SIZE(s_reg_names))
295
0
    return NULL;
296
297
1.21M
  return s_reg_names[(int)reg];
298
#else
299
  return NULL;
300
#endif
301
1.21M
}
302
303
const char *M680X_insn_name(csh handle, unsigned int id)
304
741k
{
305
741k
#ifndef CAPSTONE_DIET
306
307
741k
  if (id >= ARR_SIZE(s_instruction_names))
308
0
    return NULL;
309
741k
  else
310
741k
    return s_instruction_names[(int)id];
311
312
#else
313
  return NULL;
314
#endif
315
741k
}
316
317
const char *M680X_group_name(csh handle, unsigned int id)
318
93.1k
{
319
93.1k
#ifndef CAPSTONE_DIET
320
93.1k
  return id2name(s_group_names, ARR_SIZE(s_group_names), id);
321
#else
322
  return NULL;
323
#endif
324
93.1k
}
325
326
cs_err M680X_instprinter_init(cs_struct *ud)
327
3.06k
{
328
3.06k
#ifndef CAPSTONE_DIET
329
330
3.06k
  if (M680X_REG_ENDING != ARR_SIZE(s_reg_names)) {
331
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(s_reg_names));
332
0
    return CS_ERR_MODE;
333
0
  }
334
335
3.06k
  if (M680X_INS_ENDING != ARR_SIZE(s_instruction_names)) {
336
0
    CS_ASSERT(M680X_INS_ENDING == ARR_SIZE(s_instruction_names));
337
0
    return CS_ERR_MODE;
338
0
  }
339
340
3.06k
  if (M680X_GRP_ENDING != ARR_SIZE(s_group_names)) {
341
0
    CS_ASSERT(M680X_GRP_ENDING == ARR_SIZE(s_group_names));
342
0
    return CS_ERR_MODE;
343
0
  }
344
345
3.06k
#endif
346
347
3.06k
  return CS_ERR_OK;
348
3.06k
}
349
350
#endif