Coverage Report

Created: 2026-03-03 06:15

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