Coverage Report

Created: 2026-05-30 06:22

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
74.2k
{
97
74.2k
#ifndef CAPSTONE_DIET
98
74.2k
  SStream_concat0(OS, handle->reg_name((csh)handle, reg));
99
74.2k
#endif
100
74.2k
}
101
102
static void printInstructionName(cs_struct *handle, SStream *OS,
103
         unsigned int insn)
104
191k
{
105
191k
#ifndef CAPSTONE_DIET
106
191k
  SStream_concat0(OS, handle->insn_name((csh)handle, insn));
107
191k
#endif
108
191k
}
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
102k
{
128
102k
  static const char s_inc_dec[][3] = { "--", "-", "", "+", "++" };
129
130
102k
  if (!op->idx.inc_dec)
131
80.3k
    return;
132
133
22.6k
  if ((!isPost && !(op->idx.flags & M680X_IDX_POST_INC_DEC)) ||
134
16.4k
      (isPost && (op->idx.flags & M680X_IDX_POST_INC_DEC))) {
135
11.3k
    const char *prePostfix = "";
136
137
11.3k
    if (info->cpu_type == M680X_CPU_TYPE_CPU12)
138
3.83k
      prePostfix = (op->idx.inc_dec < 0) ? "-" : "+";
139
7.48k
    else if (op->idx.inc_dec >= -2 && (op->idx.inc_dec <= 2)) {
140
5.32k
      prePostfix = (char *)s_inc_dec[op->idx.inc_dec + 2];
141
5.32k
    }
142
143
11.3k
    SStream_concat0(O, prePostfix);
144
11.3k
  }
145
22.6k
}
146
147
static void printOperand(MCInst *MI, SStream *O, m680x_info *info,
148
       cs_m680x_op *op)
149
177k
{
150
177k
  switch (op->type) {
151
18.5k
  case M680X_OP_REGISTER:
152
18.5k
    printRegName(MI->csh, O, op->reg);
153
18.5k
    break;
154
155
5.39k
  case M680X_OP_CONSTANT:
156
5.39k
    SStream_concat(O, "%u", op->const_val);
157
5.39k
    break;
158
159
18.7k
  case M680X_OP_IMMEDIATE:
160
18.7k
    if (MI->csh->imm_unsigned)
161
0
      SStream_concat(O, "#%u",
162
0
               get_unsigned(op->imm, op->size));
163
18.7k
    else
164
18.7k
      SStream_concat(O, "#%d", op->imm);
165
166
18.7k
    break;
167
168
51.4k
  case M680X_OP_INDEXED:
169
51.4k
    if (op->idx.flags & M680X_IDX_INDIRECT)
170
5.46k
      SStream_concat0(O, "[");
171
172
51.4k
    if (op->idx.offset_reg != M680X_REG_INVALID)
173
4.15k
      printRegName(MI->csh, O, op->idx.offset_reg);
174
47.3k
    else if (op->idx.offset_bits > 0) {
175
30.8k
      if (op->idx.base_reg == M680X_REG_PC)
176
3.12k
        SStream_concat(O, "$%04x", op->idx.offset_addr);
177
27.7k
      else
178
27.7k
        SStream_concat(O, "%d", op->idx.offset);
179
30.8k
    } else if (op->idx.inc_dec != 0 &&
180
10.8k
         info->cpu_type == M680X_CPU_TYPE_CPU12)
181
3.83k
      SStream_concat(O, "%d", abs(op->idx.inc_dec));
182
183
51.4k
    if (!(op->idx.flags & M680X_IDX_NO_COMMA))
184
49.9k
      SStream_concat(O, ", ");
185
186
51.4k
    printIncDec(false, O, info, op);
187
188
51.4k
    printRegName(MI->csh, O, op->idx.base_reg);
189
190
51.4k
    if (op->idx.base_reg == M680X_REG_PC &&
191
3.53k
        (op->idx.offset_bits > 0))
192
3.12k
      SStream_concat(O, "r");
193
194
51.4k
    printIncDec(true, O, info, op);
195
196
51.4k
    if (op->idx.flags & M680X_IDX_INDIRECT)
197
5.46k
      SStream_concat(O, "]");
198
199
51.4k
    break;
200
201
18.8k
  case M680X_OP_RELATIVE:
202
18.8k
    SStream_concat(O, "$%04x", op->rel.address);
203
18.8k
    break;
204
205
39.3k
  case M680X_OP_DIRECT:
206
39.3k
    SStream_concat(O, "$%02x", op->direct_addr);
207
39.3k
    break;
208
209
25.3k
  case M680X_OP_EXTENDED:
210
25.3k
    if (op->ext.indirect)
211
233
      SStream_concat(O, "[$%04x]", op->ext.address);
212
25.1k
    else {
213
25.1k
      if (op->ext.address < 256) {
214
1.26k
        SStream_concat(O, ">$%04x", op->ext.address);
215
23.8k
      } else {
216
23.8k
        SStream_concat(O, "$%04x", op->ext.address);
217
23.8k
      }
218
25.1k
    }
219
220
25.3k
    break;
221
222
0
  default:
223
0
    SStream_concat0(O, "<invalid_operand>");
224
0
    break;
225
177k
  }
226
177k
}
227
228
static const char *getDelimiter(m680x_info *info, cs_m680x *m680x)
229
214k
{
230
214k
  bool indexed = false;
231
214k
  int count = 0;
232
214k
  int i;
233
234
214k
  if (info->insn == M680X_INS_TFM)
235
417
    return ", ";
236
237
214k
  if (m680x->op_count > 1) {
238
303k
    for (i = 0; i < m680x->op_count; ++i) {
239
207k
      if (m680x->operands[i].type == M680X_OP_INDEXED)
240
34.6k
        indexed = true;
241
242
207k
      if (m680x->operands[i].type != M680X_OP_REGISTER)
243
107k
        count++;
244
207k
    }
245
95.9k
  }
246
247
214k
  return (indexed && (count >= 1)) ? "; " : ", ";
248
214k
};
249
250
void M680X_printInst(MCInst *MI, SStream *O, void *PrinterInfo)
251
214k
{
252
214k
  m680x_info *info = (m680x_info *)PrinterInfo;
253
214k
  cs_m680x *m680x = &info->m680x;
254
214k
  cs_detail *detail = MI->flat_insn->detail;
255
214k
  int suppress_operands = 0;
256
214k
  const char *delimiter = getDelimiter(info, m680x);
257
214k
  int i;
258
259
214k
  if (detail != NULL)
260
214k
    memcpy(&detail->m680x, m680x, sizeof(cs_m680x));
261
262
214k
  if (info->insn == M680X_INS_INVLD || info->insn == M680X_INS_ILLGL) {
263
23.0k
    if (m680x->op_count)
264
23.0k
      SStream_concat(O, "fcb $%02x", m680x->operands[0].imm);
265
0
    else
266
0
      SStream_concat0(O, "fcb $<unknown>");
267
268
23.0k
    return;
269
23.0k
  }
270
271
191k
  printInstructionName(MI->csh, O, info->insn);
272
191k
  SStream_concat0(O, " ");
273
274
191k
  if ((m680x->flags & M680X_FIRST_OP_IN_MNEM) != 0)
275
101k
    suppress_operands++;
276
277
191k
  if ((m680x->flags & M680X_SECOND_OP_IN_MNEM) != 0)
278
2.46k
    suppress_operands++;
279
280
472k
  for (i = 0; i < m680x->op_count; ++i) {
281
281k
    if (i >= suppress_operands) {
282
177k
      printOperand(MI, O, info, &m680x->operands[i]);
283
284
177k
      if ((i + 1) != m680x->op_count)
285
32.5k
        SStream_concat0(O, delimiter);
286
177k
    }
287
281k
  }
288
191k
}
289
290
const char *M680X_reg_name(csh handle, unsigned int reg)
291
667k
{
292
667k
#ifndef CAPSTONE_DIET
293
294
667k
  if (reg >= ARR_SIZE(s_reg_names))
295
0
    return NULL;
296
297
667k
  return s_reg_names[(int)reg];
298
#else
299
  return NULL;
300
#endif
301
667k
}
302
303
const char *M680X_insn_name(csh handle, unsigned int id)
304
406k
{
305
406k
#ifndef CAPSTONE_DIET
306
307
406k
  if (id >= ARR_SIZE(s_instruction_names))
308
0
    return NULL;
309
406k
  else
310
406k
    return s_instruction_names[(int)id];
311
312
#else
313
  return NULL;
314
#endif
315
406k
}
316
317
const char *M680X_group_name(csh handle, unsigned int id)
318
50.9k
{
319
50.9k
#ifndef CAPSTONE_DIET
320
50.9k
  return id2name(s_group_names, ARR_SIZE(s_group_names), id);
321
#else
322
  return NULL;
323
#endif
324
50.9k
}
325
326
cs_err M680X_instprinter_init(cs_struct *ud)
327
1.30k
{
328
1.30k
#ifndef CAPSTONE_DIET
329
330
1.30k
  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
1.30k
  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
1.30k
  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
1.30k
#endif
346
347
1.30k
  return CS_ERR_OK;
348
1.30k
}
349
350
#endif