Coverage Report

Created: 2025-07-01 07:03

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