Coverage Report

Created: 2025-07-01 07:03

/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