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