Coverage Report

Created: 2025-07-01 07:03

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