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 
printRegName(cs_struct * handle,SStream * OS,unsigned int reg)102 static void printRegName(cs_struct *handle, SStream *OS, unsigned int reg)
103 {
104 #ifndef CAPSTONE_DIET
105 	SStream_concat(OS, handle->reg_name((csh)handle, reg));
106 #endif
107 }
108 
printInstructionName(cs_struct * handle,SStream * OS,unsigned int insn)109 static void printInstructionName(cs_struct *handle, SStream *OS,
110 	unsigned int insn)
111 {
112 #ifndef CAPSTONE_DIET
113 	SStream_concat(OS, handle->insn_name((csh)handle, insn));
114 #endif
115 }
116 
get_unsigned(int32_t value,int byte_size)117 static uint32_t get_unsigned(int32_t value, int byte_size)
118 {
119 	switch (byte_size) {
120 	case 1:
121 		return (uint32_t)(value & 0xff);
122 
123 	case 2:
124 		return (uint32_t)(value & 0xffff);
125 
126 	default:
127 	case 4:
128 		return (uint32_t)value;
129 	}
130 }
131 
printIncDec(bool isPost,SStream * O,m680x_info * info,cs_m680x_op * op)132 static void printIncDec(bool isPost, SStream *O, m680x_info *info,
133 	cs_m680x_op *op)
134 {
135 	static const char s_inc_dec[][3] = { "--", "-", "", "+", "++" };
136 
137 	if (!op->idx.inc_dec)
138 		return;
139 
140 	if ((!isPost && !(op->idx.flags & M680X_IDX_POST_INC_DEC)) ||
141 		(isPost && (op->idx.flags & M680X_IDX_POST_INC_DEC))) {
142 		const char *prePostfix = "";
143 
144 		if (info->cpu_type == M680X_CPU_TYPE_CPU12)
145 			prePostfix = (op->idx.inc_dec < 0) ? "-" : "+";
146 		else if (op->idx.inc_dec >= -2 && (op->idx.inc_dec <= 2)) {
147 			prePostfix = (char *)s_inc_dec[op->idx.inc_dec + 2];
148 		}
149 
150 		SStream_concat(O, prePostfix);
151 	}
152 }
153 
printOperand(MCInst * MI,SStream * O,m680x_info * info,cs_m680x_op * op)154 static void printOperand(MCInst *MI, SStream *O, m680x_info *info,
155 	cs_m680x_op *op)
156 {
157 	switch (op->type) {
158 	case M680X_OP_REGISTER:
159 		printRegName(MI->csh, O, op->reg);
160 		break;
161 
162 	case M680X_OP_CONSTANT:
163 		SStream_concat(O, "%u", op->const_val);
164 		break;
165 
166 	case M680X_OP_IMMEDIATE:
167 		if (MI->csh->imm_unsigned)
168 			SStream_concat(O, "#%u",
169 				get_unsigned(op->imm, op->size));
170 		else
171 			SStream_concat(O, "#%d", op->imm);
172 
173 		break;
174 
175 	case M680X_OP_INDEXED:
176 		if (op->idx.flags & M680X_IDX_INDIRECT)
177 			SStream_concat(O, "[");
178 
179 		if (op->idx.offset_reg != M680X_REG_INVALID)
180 			printRegName(MI->csh, O, op->idx.offset_reg);
181 		else if (op->idx.offset_bits > 0) {
182 			if (op->idx.base_reg == M680X_REG_PC)
183 				SStream_concat(O, "$%04x", op->idx.offset_addr);
184 			else
185 				SStream_concat(O, "%d", op->idx.offset);
186 		}
187 		else if (op->idx.inc_dec != 0 &&
188 			info->cpu_type == M680X_CPU_TYPE_CPU12)
189 			SStream_concat(O, "%d", abs(op->idx.inc_dec));
190 
191 		if (!(op->idx.flags & M680X_IDX_NO_COMMA))
192 			SStream_concat(O, ", ");
193 
194 		printIncDec(false, O, info, op);
195 
196 		printRegName(MI->csh, O, op->idx.base_reg);
197 
198 		if (op->idx.base_reg == M680X_REG_PC &&
199 			(op->idx.offset_bits > 0))
200 			SStream_concat(O, "r");
201 
202 		printIncDec(true, O, info, op);
203 
204 		if (op->idx.flags & M680X_IDX_INDIRECT)
205 			SStream_concat(O, "]");
206 
207 		break;
208 
209 	case M680X_OP_RELATIVE:
210 		SStream_concat(O, "$%04x", op->rel.address);
211 		break;
212 
213 	case M680X_OP_DIRECT:
214 		SStream_concat(O, "$%02x", op->direct_addr);
215 		break;
216 
217 	case M680X_OP_EXTENDED:
218 		if (op->ext.indirect)
219 			SStream_concat(O, "[$%04x]", op->ext.address);
220 		else {
221 			if (op->ext.address < 256) {
222 				SStream_concat(O, ">$%04x", op->ext.address);
223 			}
224 			else {
225 				SStream_concat(O, "$%04x", op->ext.address);
226 			}
227 		}
228 
229 		break;
230 
231 	default:
232 		SStream_concat(O, "<invalid_operand>");
233 		break;
234 	}
235 }
236 
getDelimiter(m680x_info * info,cs_m680x * m680x)237 static const char *getDelimiter(m680x_info *info, cs_m680x *m680x)
238 {
239 	bool indexed = false;
240 	int count = 0;
241 	int i;
242 
243 	if (info->insn == M680X_INS_TFM)
244 		return ", ";
245 
246 	if (m680x->op_count > 1) {
247 		for (i  = 0; i < m680x->op_count; ++i) {
248 			if (m680x->operands[i].type == M680X_OP_INDEXED)
249 				indexed = true;
250 
251 			if (m680x->operands[i].type != M680X_OP_REGISTER)
252 				count++;
253 		}
254 	}
255 
256 	return (indexed && (count >= 1)) ? "; " : ", ";
257 };
258 
M680X_printInst(MCInst * MI,SStream * O,void * PrinterInfo)259 void M680X_printInst(MCInst *MI, SStream *O, void *PrinterInfo)
260 {
261 	m680x_info *info = (m680x_info *)PrinterInfo;
262 	cs_m680x *m680x = &info->m680x;
263 	cs_detail *detail = MI->flat_insn->detail;
264 	int suppress_operands = 0;
265 	const char *delimiter = getDelimiter(info, m680x);
266 	int i;
267 
268 	if (detail != NULL)
269 		memcpy(&detail->m680x, m680x, sizeof(cs_m680x));
270 
271 	if (info->insn == M680X_INS_INVLD || info->insn == M680X_INS_ILLGL) {
272 		if (m680x->op_count)
273 			SStream_concat(O, "fcb $%02x", m680x->operands[0].imm);
274 		else
275 			SStream_concat(O, "fcb $<unknown>");
276 
277 		return;
278 	}
279 
280 	printInstructionName(MI->csh, O, info->insn);
281 	SStream_concat(O, " ");
282 
283 	if ((m680x->flags & M680X_FIRST_OP_IN_MNEM) != 0)
284 		suppress_operands++;
285 
286 	if ((m680x->flags & M680X_SECOND_OP_IN_MNEM) != 0)
287 		suppress_operands++;
288 
289 	for (i  = 0; i < m680x->op_count; ++i) {
290 		if (i >= suppress_operands) {
291 			printOperand(MI, O, info, &m680x->operands[i]);
292 
293 			if ((i + 1) != m680x->op_count)
294 				SStream_concat(O, delimiter);
295 		}
296 	}
297 }
298 
M680X_reg_name(csh handle,unsigned int reg)299 const char *M680X_reg_name(csh handle, unsigned int reg)
300 {
301 #ifndef CAPSTONE_DIET
302 
303 	if (reg >= ARR_SIZE(s_reg_names))
304 		return NULL;
305 
306 	return s_reg_names[(int)reg];
307 #else
308 	return NULL;
309 #endif
310 }
311 
M680X_insn_name(csh handle,unsigned int id)312 const char *M680X_insn_name(csh handle, unsigned int id)
313 {
314 #ifndef CAPSTONE_DIET
315 
316 	if (id >= ARR_SIZE(s_instruction_names))
317 		return NULL;
318 	else
319 		return s_instruction_names[(int)id];
320 
321 #else
322 	return NULL;
323 #endif
324 }
325 
M680X_group_name(csh handle,unsigned int id)326 const char *M680X_group_name(csh handle, unsigned int id)
327 {
328 #ifndef CAPSTONE_DIET
329 	return id2name(s_group_names, ARR_SIZE(s_group_names), id);
330 #else
331 	return NULL;
332 #endif
333 }
334 
M680X_instprinter_init(cs_struct * ud)335 cs_err M680X_instprinter_init(cs_struct *ud)
336 {
337 #ifndef CAPSTONE_DIET
338 
339 	if (M680X_REG_ENDING != ARR_SIZE(s_reg_names)) {
340 		CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(s_reg_names));
341 		return CS_ERR_MODE;
342 	}
343 
344 	if (M680X_INS_ENDING != ARR_SIZE(s_instruction_names)) {
345 		CS_ASSERT(M680X_INS_ENDING == ARR_SIZE(s_instruction_names));
346 		return CS_ERR_MODE;
347 	}
348 
349 	if (M680X_GRP_ENDING != ARR_SIZE(s_group_names)) {
350 		CS_ASSERT(M680X_GRP_ENDING == ARR_SIZE(s_group_names));
351 		return CS_ERR_MODE;
352 	}
353 
354 #endif
355 
356 	return CS_ERR_OK;
357 }
358 
359 #endif
360 
361