Coverage Report

Created: 2025-08-28 06:43

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