Coverage Report

Created: 2024-08-21 06:24

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