Coverage Report

Created: 2025-08-28 06:43

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