/src/capstonev5/arch/SH/SHInstPrinter.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Capstone Disassembly Engine */ |
2 | | /* By Yoshinori Sato, 2022 */ |
3 | | |
4 | | #include <string.h> |
5 | | #include "SHInstPrinter.h" |
6 | | |
7 | | |
8 | | #ifndef CAPSTONE_DIET |
9 | | static const char* const s_reg_names[] = { |
10 | | "invalid", |
11 | | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", |
12 | | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", |
13 | | "r0_bank", "r1_bank", "r2_bank", "r3_bank", |
14 | | "r4_bank", "r5_bank", "r6_bank", "r7_bank", |
15 | | "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", |
16 | | "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15", |
17 | | "dr0", "dr2", "dr4", "dr6", "dr8", "dr10", "dr12", "dr14", |
18 | | "xd0", "xd2", "xd4", "xd6", "xd8", "xd10", "xd12", "xd14", |
19 | | "xf0", "xf1", "xf2", "xf3", "xf4", "xf5", "xf6", "xf7", |
20 | | "xf8", "xf9", "xf10", "xf11", "xf12", "xf13", "xf14", "xf15", |
21 | | "fv0", "fv4", "fv8", "fv12", |
22 | | "xmtrx", |
23 | | "pc", "pr", "mach", "macl", |
24 | | "sr", "gbr", "ssr", "spc", "sgr", "dbr", "vbr", "tbr", |
25 | | "rs", "re", "mod", |
26 | | "fpul", "fpscr", |
27 | | "x0", "x1", "y0", "y1", "a0", "a1", "a0g", "a1g", "m0", "m1", |
28 | | "dsr", |
29 | | "0x0", "0x1", "0x2", "0x3", "0x4", "0x5", "0x6", "0x7", |
30 | | "0x8", "0x9", "0xa", "0xb", "0xc", "0xd", "0xe", "0xf", |
31 | | }; |
32 | | #endif |
33 | | |
34 | | const char* SH_reg_name(csh handle, unsigned int reg) |
35 | 0 | { |
36 | | #ifdef CAPSTONE_DIET |
37 | | return NULL; |
38 | | #else |
39 | 0 | if (reg >= ARR_SIZE(s_reg_names)) { |
40 | 0 | return NULL; |
41 | 0 | } |
42 | 0 | return s_reg_names[(int)reg]; |
43 | 0 | #endif |
44 | 0 | } |
45 | | |
46 | | |
47 | | void SH_get_insn_id(cs_struct* h, cs_insn* insn, unsigned int id) |
48 | 0 | { |
49 | 0 | insn->id = id; // These id's matches for sh |
50 | 0 | } |
51 | | |
52 | | #ifndef CAPSTONE_DIET |
53 | | static const char* const s_insn_names[] = { |
54 | | "unknwon", |
55 | | "add", "add", "addc", "addv", "and", |
56 | | "band", "bandnot", "bclr", |
57 | | "bf", "bf/s", "bld", "bldnot", "bor", "bornot", "bra", "braf", |
58 | | "bset", "bsr", "bsrf", "bst", "bt", "bt/s", "bxor", |
59 | | "clips", "clipu", |
60 | | "clrdmxy", |
61 | | "clrmac", "clrs", "clrt", |
62 | | "cmp/eq", "cmp/ge", "cmp/gt", "cmp/hi", "cmp/hs", "cmp/pl", |
63 | | "cmp/pz", "cmp/str", |
64 | | "div0s", "div0u", "div1", |
65 | | "divs", "divu", |
66 | | "dmuls.l", "dmulu.l", |
67 | | "dt", |
68 | | "exts", "exts", "extu", "extu", |
69 | | "fabs", "fadd", "fcmp/eq", "fcmp/gt", |
70 | | "fcnvds", "fcnvsd", "fdiv", |
71 | | "fipr", "fldi0", "fldi1", "flds", "float", |
72 | | "fmac", "fmov", "fmul", "fneg", "fpchg", |
73 | | "frchg", "fsca", "fschg", "fsqrt", "fsrra", |
74 | | "fsts", "fsub", "ftrc", "ftrv", |
75 | | "icbi", |
76 | | "jmp", "jsr", "jsr/n", |
77 | | "ldbank", |
78 | | "ldc", "ldrc", "ldre", "ldrs", "lds", |
79 | | "ldtlb", |
80 | | "mac.l", "mac.w", |
81 | | "mov", "mova", "movca", "movco", "movi20", "movi20s", |
82 | | "movli", "movml", "movmu", "movrt", "movt", "movu", "movua", |
83 | | "mul.l", "mulr", "muls", "mulu", |
84 | | "neg", "negc", |
85 | | "nop", |
86 | | "not", "nott", |
87 | | "ocbi", "ocbp", "ocbwb", |
88 | | "or", |
89 | | "pref", "prefi", |
90 | | "resbank", |
91 | | "rotcl", "rotcr", "rotl", "rotr", |
92 | | "rte", "rts", "rts/n", "rtv/n", |
93 | | "setdmx", "setdmy", "setrc", |
94 | | "sets", "sett", |
95 | | "shad", "shal", "shar", "shld", "shll", |
96 | | "shll16", "shll2", "shll8", |
97 | | "shlr", "shlr16", "shlr2", "shlr8", |
98 | | "sleep", |
99 | | "stbank", |
100 | | "stc", "sts", |
101 | | "sub", "subc", "subv", |
102 | | "swap", "swap", |
103 | | "synco", |
104 | | "tas", |
105 | | "trapa", |
106 | | "tst", |
107 | | "xor", |
108 | | "xtrct", |
109 | | }; |
110 | | #endif |
111 | | |
112 | | const char* SH_insn_name(csh handle, unsigned int id) |
113 | 0 | { |
114 | | #ifdef CAPSTONE_DIET |
115 | | return NULL; |
116 | | #else |
117 | 0 | if (id >= ARR_SIZE(s_insn_names)) { |
118 | 0 | return NULL; |
119 | 0 | } |
120 | 0 | return s_insn_names[id]; |
121 | 0 | #endif |
122 | 0 | } |
123 | | |
124 | | #ifndef CAPSTONE_DIET |
125 | | #endif |
126 | | |
127 | | #ifndef CAPSTONE_DIET |
128 | | static void print_dsp_double(SStream *O, sh_info *info, int xy) |
129 | 0 | { |
130 | 0 | char suffix_xy = 'x' + xy; |
131 | 0 | int i; |
132 | 0 | if (info->op.operands[xy].dsp.insn == SH_INS_DSP_NOP) { |
133 | 0 | if ((info->op.operands[0].dsp.insn == SH_INS_DSP_NOP) && |
134 | 0 | (info->op.operands[1].dsp.insn == SH_INS_DSP_NOP)) { |
135 | 0 | SStream_concat(O, "nop%c", suffix_xy); |
136 | 0 | } |
137 | 0 | } else { |
138 | 0 | SStream_concat(O, "mov%c", suffix_xy); |
139 | 0 | switch(info->op.operands[xy].dsp.size) { |
140 | 0 | case 16: |
141 | 0 | SStream_concat0(O, ".w "); |
142 | 0 | break; |
143 | 0 | case 32: |
144 | 0 | SStream_concat0(O, ".l "); |
145 | 0 | break; |
146 | 0 | } |
147 | | |
148 | 0 | for (i = 0; i < 2; i++) { |
149 | 0 | switch(info->op.operands[xy].dsp.operand[i]) { |
150 | 0 | default: |
151 | 0 | break; |
152 | 0 | case SH_OP_DSP_REG_IND: |
153 | 0 | SStream_concat(O, "@%s", s_reg_names[info->op.operands[xy].dsp.r[i]]); |
154 | 0 | break; |
155 | 0 | case SH_OP_DSP_REG_POST: |
156 | 0 | SStream_concat(O, "@%s+", s_reg_names[info->op.operands[xy].dsp.r[i]]); |
157 | 0 | break; |
158 | 0 | case SH_OP_DSP_REG_INDEX: |
159 | 0 | SStream_concat(O, "@%s+%s", s_reg_names[info->op.operands[xy].dsp.r[i]], s_reg_names[SH_REG_R8 + xy]); |
160 | 0 | break; |
161 | 0 | case SH_OP_DSP_REG: |
162 | 0 | SStream_concat(O, "%s", s_reg_names[info->op.operands[xy].dsp.r[i]]); |
163 | 0 | break; |
164 | 0 | } |
165 | 0 | if (i == 0) |
166 | 0 | SStream_concat0(O, ","); |
167 | 0 | } |
168 | 0 | } |
169 | 0 | if (xy == 0) |
170 | 0 | SStream_concat0(O, " "); |
171 | 0 | } |
172 | | |
173 | | static const char *s_dsp_insns[] = { |
174 | | "invalid", |
175 | | "nop", |
176 | | "mov", |
177 | | "pshl", |
178 | | "psha", |
179 | | "pmuls", |
180 | | "pclr_pmuls", |
181 | | "psub_pmuls", |
182 | | "padd_pmuls", |
183 | | "psubc", |
184 | | "paddc", |
185 | | "pcmp", |
186 | | "pabs", |
187 | | "prnd", |
188 | | "psub", |
189 | | "psub", |
190 | | "padd", |
191 | | "pand", |
192 | | "pxor", |
193 | | "por", |
194 | | "pdec", |
195 | | "pinc", |
196 | | "pclr", |
197 | | "pdmsb", |
198 | | "pneg", |
199 | | "pcopy", |
200 | | "psts", |
201 | | "plds", |
202 | | "pswap", |
203 | | "pwad", |
204 | | "pwsb", |
205 | | }; |
206 | | |
207 | | static void print_dsp(SStream *O, sh_info *info) |
208 | 0 | { |
209 | 0 | int i; |
210 | 0 | switch(info->op.op_count) { |
211 | 0 | case 1: |
212 | | // single transfer |
213 | 0 | SStream_concat0(O, "movs"); |
214 | 0 | switch(info->op.operands[0].dsp.size) { |
215 | 0 | case 16: |
216 | 0 | SStream_concat0(O, ".w "); |
217 | 0 | break; |
218 | 0 | case 32: |
219 | 0 | SStream_concat0(O, ".l "); |
220 | 0 | break; |
221 | 0 | } |
222 | 0 | for (i = 0; i < 2; i++) { |
223 | 0 | switch(info->op.operands[0].dsp.operand[i]) { |
224 | 0 | default: |
225 | 0 | break; |
226 | 0 | case SH_OP_DSP_REG_PRE: |
227 | 0 | SStream_concat(O, "@-%s", s_reg_names[info->op.operands[0].dsp.r[i]]); |
228 | 0 | break; |
229 | 0 | case SH_OP_DSP_REG_IND: |
230 | 0 | SStream_concat(O, "@%s", s_reg_names[info->op.operands[0].dsp.r[i]]); |
231 | 0 | break; |
232 | 0 | case SH_OP_DSP_REG_POST: |
233 | 0 | SStream_concat(O, "@%s+", s_reg_names[info->op.operands[0].dsp.r[i]]); |
234 | 0 | break; |
235 | 0 | case SH_OP_DSP_REG_INDEX: |
236 | 0 | SStream_concat(O, "@%s+%s", s_reg_names[info->op.operands[0].dsp.r[i]],s_reg_names[SH_REG_R8]); |
237 | 0 | break; |
238 | 0 | case SH_OP_DSP_REG: |
239 | 0 | SStream_concat(O, "%s", s_reg_names[info->op.operands[0].dsp.r[i]]); |
240 | 0 | } |
241 | 0 | if (i == 0) |
242 | 0 | SStream_concat0(O, ","); |
243 | 0 | } |
244 | 0 | break; |
245 | 0 | case 2: // Double transfer |
246 | 0 | print_dsp_double(O, info, 0); |
247 | 0 | print_dsp_double(O, info, 1); |
248 | 0 | break; |
249 | 0 | case 3: // Parallel |
250 | 0 | switch(info->op.operands[2].dsp.cc) { |
251 | 0 | default: |
252 | 0 | break; |
253 | 0 | case SH_DSP_CC_DCT: |
254 | 0 | SStream_concat0(O,"dct "); |
255 | 0 | break; |
256 | 0 | case SH_DSP_CC_DCF: |
257 | 0 | SStream_concat0(O,"dcf "); |
258 | 0 | break; |
259 | 0 | } |
260 | 0 | switch(info->op.operands[2].dsp.insn) { |
261 | 0 | case SH_INS_DSP_PSUB_PMULS: |
262 | 0 | case SH_INS_DSP_PADD_PMULS: |
263 | 0 | switch(info->op.operands[2].dsp.insn) { |
264 | 0 | default: |
265 | 0 | break; |
266 | 0 | case SH_INS_DSP_PSUB_PMULS: |
267 | 0 | SStream_concat0(O, "psub "); |
268 | 0 | break; |
269 | 0 | case SH_INS_DSP_PADD_PMULS: |
270 | 0 | SStream_concat0(O, "padd "); |
271 | 0 | break; |
272 | 0 | } |
273 | 0 | for (i = 0; i < 6; i++) { |
274 | 0 | SStream_concat(O, "%s", s_reg_names[info->op.operands[2].dsp.r[i]]); |
275 | 0 | if ((i % 3) < 2) |
276 | 0 | SStream_concat0(O, ","); |
277 | 0 | if (i == 2) |
278 | 0 | SStream_concat(O, " %s ", s_dsp_insns[SH_INS_DSP_PMULS]); |
279 | 0 | } |
280 | 0 | break; |
281 | 0 | case SH_INS_DSP_PCLR_PMULS: |
282 | 0 | SStream_concat0(O, s_dsp_insns[SH_INS_DSP_PCLR]); |
283 | 0 | SStream_concat(O, " %s ", s_reg_names[info->op.operands[2].dsp.r[3]]); |
284 | 0 | SStream_concat(O, "%s ", s_dsp_insns[SH_INS_DSP_PMULS]); |
285 | 0 | for (i = 0; i < 3; i++) { |
286 | 0 | SStream_concat(O, "%s", s_reg_names[info->op.operands[2].dsp.r[i]]); |
287 | 0 | if (i < 2) |
288 | 0 | SStream_concat0(O, ","); |
289 | 0 | } |
290 | 0 | break; |
291 | | |
292 | 0 | default: |
293 | 0 | SStream_concat0(O, s_dsp_insns[info->op.operands[2].dsp.insn]); |
294 | 0 | SStream_concat0(O, " "); |
295 | 0 | for (i = 0; i < 3; i++) { |
296 | 0 | if (info->op.operands[2].dsp.r[i] == SH_REG_INVALID) { |
297 | 0 | if (i == 0) { |
298 | 0 | SStream_concat(O, "#%d", info->op.operands[2].dsp.imm); |
299 | 0 | } |
300 | 0 | } else |
301 | 0 | SStream_concat(O, "%s", s_reg_names[info->op.operands[2].dsp.r[i]]); |
302 | 0 | if (i < 2 && info->op.operands[2].dsp.r[i + 1] != SH_REG_INVALID) |
303 | 0 | SStream_concat0(O, ","); |
304 | 0 | } |
305 | 0 | } |
306 | | |
307 | 0 | if (info->op.operands[0].dsp.insn != SH_INS_DSP_NOP) { |
308 | 0 | SStream_concat0(O, " "); |
309 | 0 | print_dsp_double(O, info, 0); |
310 | 0 | } |
311 | 0 | if (info->op.operands[1].dsp.insn != SH_INS_DSP_NOP) { |
312 | 0 | SStream_concat0(O, " "); |
313 | 0 | print_dsp_double(O, info, 1); |
314 | 0 | } |
315 | 0 | break; |
316 | 0 | } |
317 | 0 | } |
318 | | |
319 | 0 | static void PrintMemop(SStream *O, sh_op_mem *op) { |
320 | 0 | switch(op->address) { |
321 | 0 | case SH_OP_MEM_INVALID: |
322 | 0 | break; |
323 | 0 | case SH_OP_MEM_REG_IND: |
324 | 0 | SStream_concat(O, "@%s", s_reg_names[op->reg]); |
325 | 0 | break; |
326 | 0 | case SH_OP_MEM_REG_POST: |
327 | 0 | SStream_concat(O, "@%s+", s_reg_names[op->reg]); |
328 | 0 | break; |
329 | 0 | case SH_OP_MEM_REG_PRE: |
330 | 0 | SStream_concat(O, "@-%s", s_reg_names[op->reg]); |
331 | 0 | break; |
332 | 0 | case SH_OP_MEM_REG_DISP: |
333 | 0 | SStream_concat(O, "@(%d,%s)", op->disp, s_reg_names[op->reg]); |
334 | 0 | break; |
335 | 0 | case SH_OP_MEM_REG_R0: /// <= R0 indexed |
336 | 0 | SStream_concat(O, "@(%s,%s)", |
337 | 0 | s_reg_names[SH_REG_R0], s_reg_names[op->reg]); |
338 | 0 | break; |
339 | 0 | case SH_OP_MEM_GBR_DISP: /// <= GBR based displaysment |
340 | 0 | SStream_concat(O, "@(%d,%s)", |
341 | 0 | op->disp, s_reg_names[SH_REG_GBR]); |
342 | 0 | break; |
343 | 0 | case SH_OP_MEM_GBR_R0: /// <= GBR based R0 indexed |
344 | 0 | SStream_concat(O, "@(%s,%s)", |
345 | 0 | s_reg_names[SH_REG_R0], s_reg_names[SH_REG_GBR]); |
346 | 0 | break; |
347 | 0 | case SH_OP_MEM_PCR: /// <= PC relative |
348 | 0 | SStream_concat(O, "0x%x", op->disp); |
349 | 0 | break; |
350 | 0 | case SH_OP_MEM_TBR_DISP: /// <= GBR based displaysment |
351 | 0 | SStream_concat(O, "@@(%d,%s)", |
352 | 0 | op->disp, s_reg_names[SH_REG_TBR]); |
353 | 0 | break; |
354 | 0 | } |
355 | 0 | } |
356 | | #endif |
357 | | |
358 | | void SH_printInst(MCInst* MI, SStream* O, void* PrinterInfo) |
359 | 0 | { |
360 | 0 | #ifndef CAPSTONE_DIET |
361 | 0 | sh_info *info = (sh_info *)PrinterInfo; |
362 | 0 | int i; |
363 | 0 | int imm; |
364 | |
|
365 | 0 | if (MI->Opcode == SH_INS_DSP) { |
366 | 0 | print_dsp(O, info); |
367 | 0 | return; |
368 | 0 | } |
369 | | |
370 | 0 | SStream_concat0(O, (char*)s_insn_names[MI->Opcode]); |
371 | 0 | switch(info->op.size) { |
372 | 0 | case 8: |
373 | 0 | SStream_concat0(O, ".b"); |
374 | 0 | break; |
375 | 0 | case 16: |
376 | 0 | SStream_concat0(O, ".w"); |
377 | 0 | break; |
378 | 0 | case 32: |
379 | 0 | SStream_concat0(O, ".l"); |
380 | 0 | break; |
381 | 0 | case 64: |
382 | 0 | SStream_concat0(O, ".d"); |
383 | 0 | break; |
384 | 0 | } |
385 | 0 | SStream_concat0(O, " "); |
386 | 0 | for (i = 0; i < info->op.op_count; i++) { |
387 | 0 | switch(info->op.operands[i].type) { |
388 | 0 | case SH_OP_INVALID: |
389 | 0 | break; |
390 | 0 | case SH_OP_REG: |
391 | 0 | SStream_concat0(O, s_reg_names[info->op.operands[i].reg]); |
392 | 0 | break; |
393 | 0 | case SH_OP_IMM: |
394 | 0 | imm = info->op.operands[i].imm; |
395 | 0 | SStream_concat(O, "#%d", imm); |
396 | 0 | break; |
397 | 0 | case SH_OP_MEM: |
398 | 0 | PrintMemop(O, &info->op.operands[i].mem); |
399 | 0 | break; |
400 | 0 | } |
401 | 0 | if (i < (info->op.op_count - 1)) { |
402 | 0 | SStream_concat0(O, ","); |
403 | 0 | } |
404 | 0 | } |
405 | 0 | #endif |
406 | 0 | } |
407 | | |
408 | | #ifndef CAPSTONE_DIET |
409 | | static const name_map group_name_maps[] = { |
410 | | { SH_GRP_INVALID , NULL }, |
411 | | { SH_GRP_JUMP, "jump" }, |
412 | | { SH_GRP_CALL, "call" }, |
413 | | { SH_GRP_INT, "int" }, |
414 | | { SH_GRP_RET , "ret" }, |
415 | | { SH_GRP_IRET, "iret" }, |
416 | | { SH_GRP_PRIVILEGE, "privilege" }, |
417 | | { SH_GRP_BRANCH_RELATIVE, "branch_relative" }, |
418 | | { SH_GRP_SH2, "SH2" }, |
419 | | { SH_GRP_SH2E, "SH2E" }, |
420 | | { SH_GRP_SH2DSP, "SH2-DSP" }, |
421 | | { SH_GRP_SH2A, "SH2A" }, |
422 | | { SH_GRP_SH2AFPU, "SH2A-FPU" }, |
423 | | { SH_GRP_SH3, "SH3" }, |
424 | | { SH_GRP_SH3DSP, "SH3-DSP" }, |
425 | | { SH_GRP_SH4, "SH4" }, |
426 | | { SH_GRP_SH4A, "SH4A" }, |
427 | | }; |
428 | | #endif |
429 | | |
430 | | const char *SH_group_name(csh handle, unsigned int id) |
431 | 0 | { |
432 | 0 | #ifndef CAPSTONE_DIET |
433 | 0 | return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); |
434 | | #else |
435 | | return NULL; |
436 | | #endif |
437 | 0 | } |
438 | | |