blob: 34a8836a8f0d153712c9ae308c1d7aae55bd9d9c [file] [log] [blame]
Wolfgang Schwotzer22b4d0e2017-10-21 15:44:36 +02001/* 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
19static 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
24static 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
89static 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
101static 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
108static 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
116static 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
131static 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 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
153static 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
236static 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
258void 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
298const char *M680X_reg_name(csh handle, unsigned int reg)
299{
300#ifndef CAPSTONE_DIET
301
302 if (reg >= M680X_REG_ENDING)
303 return NULL;
304
305 return s_reg_names[(int)reg];
306#else
307 return NULL;
308#endif
309}
310
311const 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
325const 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
334cs_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