Coverage Report

Created: 2023-09-25 06:24

/src/capstonenext/arch/Sparc/SparcInstPrinter.c
Line
Count
Source (jump to first uncovered line)
1
//===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax --------===//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
//
10
// This class prints an Sparc MCInst to a .s file.
11
//
12
//===----------------------------------------------------------------------===//
13
14
/* Capstone Disassembly Engine */
15
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2015 */
16
17
#ifdef CAPSTONE_HAS_SPARC
18
19
#ifdef _MSC_VER
20
#define _CRT_SECURE_NO_WARNINGS
21
#endif
22
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <limits.h>
27
28
#include "SparcInstPrinter.h"
29
#include "../../MCInst.h"
30
#include "../../utils.h"
31
#include "../../SStream.h"
32
#include "../../MCRegisterInfo.h"
33
#include "../../MathExtras.h"
34
#include "SparcMapping.h"
35
36
#include "Sparc.h"
37
38
static const char *getRegisterName(unsigned RegNo);
39
static void printInstruction(MCInst *MI, SStream *O, const MCRegisterInfo *MRI);
40
static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier);
41
static void printOperand(MCInst *MI, int opNum, SStream *O);
42
43
static void Sparc_add_hint(MCInst *MI, unsigned int hint)
44
2.07k
{
45
2.07k
  if (MI->csh->detail_opt) {
46
2.07k
    MI->flat_insn->detail->sparc.hint = hint;
47
2.07k
  }
48
2.07k
}
49
50
static void Sparc_add_reg(MCInst *MI, unsigned int reg)
51
2.77k
{
52
2.77k
  if (MI->csh->detail_opt) {
53
2.77k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
54
2.77k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
55
2.77k
    MI->flat_insn->detail->sparc.op_count++;
56
2.77k
  }
57
2.77k
}
58
59
static void set_mem_access(MCInst *MI, bool status)
60
9.81k
{
61
9.81k
  if (MI->csh->detail_opt != CS_OPT_ON)
62
0
    return;
63
64
9.81k
  MI->csh->doing_mem = status;
65
66
9.81k
  if (status) {
67
4.90k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_MEM;
68
4.90k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = SPARC_REG_INVALID;
69
4.90k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = 0;
70
4.90k
  } else {
71
    // done, create the next operand slot
72
4.90k
    MI->flat_insn->detail->sparc.op_count++;
73
4.90k
  }
74
9.81k
}
75
76
void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
77
77.6k
{
78
77.6k
  if (((cs_struct *)ud)->detail_opt != CS_OPT_ON)
79
0
    return;
80
81
  // fix up some instructions
82
77.6k
  if (insn->id == SPARC_INS_CASX) {
83
    // first op is actually a memop, not regop
84
18
    insn->detail->sparc.operands[0].type = SPARC_OP_MEM;
85
18
    insn->detail->sparc.operands[0].mem.base = (uint8_t)insn->detail->sparc.operands[0].reg;
86
18
    insn->detail->sparc.operands[0].mem.disp = 0;
87
18
  }
88
77.6k
}
89
90
static void printRegName(SStream *OS, unsigned RegNo)
91
59.7k
{
92
59.7k
  SStream_concat0(OS, "%");
93
59.7k
  SStream_concat0(OS, getRegisterName(RegNo));
94
59.7k
}
95
96
#define GET_INSTRINFO_ENUM
97
#include "SparcGenInstrInfo.inc"
98
99
#define GET_REGINFO_ENUM
100
#include "SparcGenRegisterInfo.inc"
101
102
static bool printSparcAliasInstr(MCInst *MI, SStream *O)
103
47.2k
{
104
47.2k
  switch (MCInst_getOpcode(MI)) {
105
42.8k
    default: return false;
106
1.94k
    case SP_JMPLrr:
107
2.44k
    case SP_JMPLri:
108
2.44k
         if (MCInst_getNumOperands(MI) != 3)
109
0
           return false;
110
2.44k
         if (!MCOperand_isReg(MCInst_getOperand(MI, 0)))
111
0
           return false;
112
113
2.44k
         switch (MCOperand_getReg(MCInst_getOperand(MI, 0))) {
114
410
           default: return false;
115
2.00k
           case SP_G0: // jmp $addr | ret | retl
116
2.00k
                if (MCOperand_isImm(MCInst_getOperand(MI, 2)) &&
117
2.00k
                  MCOperand_getImm(MCInst_getOperand(MI, 2)) == 8) {
118
154
                  switch(MCOperand_getReg(MCInst_getOperand(MI, 1))) {
119
66
                    default: break;
120
66
                    case SP_I7: SStream_concat0(O, "ret"); MCInst_setOpcodePub(MI, SPARC_INS_RET); return true;
121
28
                    case SP_O7: SStream_concat0(O, "retl"); MCInst_setOpcodePub(MI, SPARC_INS_RETL); return true;
122
154
                  }
123
154
                }
124
125
1.91k
                SStream_concat0(O, "jmp\t");
126
1.91k
                MCInst_setOpcodePub(MI, SPARC_INS_JMP);
127
1.91k
                printMemOperand(MI, 1, O, NULL);
128
1.91k
                return true;
129
39
           case SP_O7: // call $addr
130
39
                SStream_concat0(O, "call ");
131
39
                MCInst_setOpcodePub(MI, SPARC_INS_CALL);
132
39
                printMemOperand(MI, 1, O, NULL);
133
39
                return true;
134
2.44k
         }
135
207
    case SP_V9FCMPS:
136
419
    case SP_V9FCMPD:
137
1.06k
    case SP_V9FCMPQ:
138
1.60k
    case SP_V9FCMPES:
139
1.86k
    case SP_V9FCMPED:
140
1.93k
    case SP_V9FCMPEQ:
141
1.93k
         if (MI->csh->mode & CS_MODE_V9 || (MCInst_getNumOperands(MI) != 3) ||
142
1.93k
             (!MCOperand_isReg(MCInst_getOperand(MI, 0))) ||
143
1.93k
             (MCOperand_getReg(MCInst_getOperand(MI, 0)) != SP_FCC0))
144
1.93k
             return false;
145
         // if V8, skip printing %fcc0.
146
0
         switch(MCInst_getOpcode(MI)) {
147
0
           default:
148
0
           case SP_V9FCMPS:  SStream_concat0(O, "fcmps\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPS); break;
149
0
           case SP_V9FCMPD:  SStream_concat0(O, "fcmpd\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPD); break;
150
0
           case SP_V9FCMPQ:  SStream_concat0(O, "fcmpq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPQ); break;
151
0
           case SP_V9FCMPES: SStream_concat0(O, "fcmpes\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPES); break;
152
0
           case SP_V9FCMPED: SStream_concat0(O, "fcmped\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPED); break;
153
0
           case SP_V9FCMPEQ: SStream_concat0(O, "fcmpeq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPEQ); break;
154
0
         }
155
0
         printOperand(MI, 1, O);
156
0
         SStream_concat0(O, ", ");
157
0
         printOperand(MI, 2, O);
158
0
         return true;
159
47.2k
  }
160
47.2k
}
161
162
static void printOperand(MCInst *MI, int opNum, SStream *O)
163
124k
{
164
124k
  int64_t Imm;
165
124k
  unsigned reg;
166
124k
  MCOperand *MO = MCInst_getOperand(MI, opNum);
167
168
124k
  if (MCOperand_isReg(MO)) {
169
59.7k
    reg = MCOperand_getReg(MO);
170
59.7k
    printRegName(O, reg);
171
59.7k
    reg = Sparc_map_register(reg);
172
173
59.7k
    if (MI->csh->detail_opt) {
174
59.7k
      if (MI->csh->doing_mem) {
175
6.35k
        if (MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base)
176
1.45k
          MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.index = (uint8_t)reg;
177
4.90k
        else
178
4.90k
          MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = (uint8_t)reg;
179
53.4k
      } else {
180
53.4k
        MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
181
53.4k
        MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
182
53.4k
        MI->flat_insn->detail->sparc.op_count++;
183
53.4k
      }
184
59.7k
    }
185
186
59.7k
    return;
187
59.7k
  }
188
189
64.5k
  if (MCOperand_isImm(MO)) {
190
64.5k
    Imm = (int)MCOperand_getImm(MO);
191
192
    // Conditional branches displacements needs to be signextended to be
193
    // able to jump backwards.
194
    //
195
    // Displacements are measured as the number of instructions forward or
196
    // backward, so they need to be multiplied by 4
197
64.5k
    switch (MI->Opcode) {
198
13.5k
      case SP_CALL:
199
        // Imm = SignExtend32(Imm, 30);
200
13.5k
        Imm += MI->address;
201
13.5k
        break;
202
203
      // Branch on integer condition with prediction (BPcc)
204
      // Branch on floating point condition with prediction (FBPfcc)
205
493
      case SP_BPICC:
206
733
      case SP_BPICCA:
207
3.17k
      case SP_BPICCANT:
208
7.39k
      case SP_BPICCNT:
209
7.85k
      case SP_BPXCC:
210
8.07k
      case SP_BPXCCA:
211
9.76k
      case SP_BPXCCANT:
212
11.5k
      case SP_BPXCCNT:
213
11.9k
      case SP_BPFCC:
214
12.5k
      case SP_BPFCCA:
215
16.6k
      case SP_BPFCCANT:
216
20.9k
      case SP_BPFCCNT:
217
20.9k
        Imm = SignExtend32(Imm, 19);
218
20.9k
        Imm = MI->address + Imm * 4;
219
20.9k
        break;
220
221
      // Branch on integer condition (Bicc)
222
      // Branch on floating point condition (FBfcc)
223
292
      case SP_BA:
224
2.66k
      case SP_BCOND:
225
4.86k
      case SP_BCONDA:
226
6.20k
      case SP_FBCOND:
227
7.25k
      case SP_FBCONDA:
228
7.25k
        Imm = SignExtend32(Imm, 22);
229
7.25k
        Imm = MI->address + Imm * 4;
230
7.25k
        break;
231
232
      // Branch on integer register with prediction (BPr)
233
414
      case SP_BPGEZapn:
234
688
      case SP_BPGEZapt:
235
767
      case SP_BPGEZnapn:
236
835
      case SP_BPGEZnapt:
237
1.04k
      case SP_BPGZapn:
238
1.15k
      case SP_BPGZapt:
239
1.21k
      case SP_BPGZnapn:
240
1.28k
      case SP_BPGZnapt:
241
1.54k
      case SP_BPLEZapn:
242
1.66k
      case SP_BPLEZapt:
243
1.79k
      case SP_BPLEZnapn:
244
1.87k
      case SP_BPLEZnapt:
245
2.12k
      case SP_BPLZapn:
246
2.28k
      case SP_BPLZapt:
247
2.48k
      case SP_BPLZnapn:
248
2.58k
      case SP_BPLZnapt:
249
2.65k
      case SP_BPNZapn:
250
2.71k
      case SP_BPNZapt:
251
2.80k
      case SP_BPNZnapn:
252
3.00k
      case SP_BPNZnapt:
253
3.55k
      case SP_BPZapn:
254
3.65k
      case SP_BPZapt:
255
3.93k
      case SP_BPZnapn:
256
4.01k
      case SP_BPZnapt:
257
4.01k
        Imm = SignExtend32(Imm, 16);
258
4.01k
        Imm = MI->address + Imm * 4;
259
4.01k
        break;
260
64.5k
    }
261
    
262
64.5k
    printInt64(O, Imm);
263
264
64.5k
    if (MI->csh->detail_opt) {
265
64.5k
      if (MI->csh->doing_mem) {
266
2.11k
        MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = Imm;
267
62.4k
      } else {
268
62.4k
        MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_IMM;
269
62.4k
        MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].imm = Imm;
270
62.4k
        MI->flat_insn->detail->sparc.op_count++;
271
62.4k
      }
272
64.5k
    }
273
64.5k
  }
274
275
64.5k
  return;
276
64.5k
}
277
278
static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier)
279
4.90k
{
280
4.90k
  MCOperand *MO;
281
282
4.90k
  set_mem_access(MI, true);
283
4.90k
  printOperand(MI, opNum, O);
284
285
  // If this is an ADD operand, emit it like normal operands.
286
4.90k
  if (Modifier && !strcmp(Modifier, "arith")) {
287
0
    SStream_concat0(O, ", ");
288
0
    printOperand(MI, opNum + 1, O);
289
0
    set_mem_access(MI, false);
290
0
    return;
291
0
  }
292
293
4.90k
  MO = MCInst_getOperand(MI, opNum + 1);
294
295
4.90k
  if (MCOperand_isReg(MO) && (MCOperand_getReg(MO) == SP_G0)) {
296
1.24k
    set_mem_access(MI, false);
297
1.24k
    return;   // don't print "+%g0"
298
1.24k
  }
299
300
3.65k
  if (MCOperand_isImm(MO) && (MCOperand_getImm(MO) == 0)) {
301
91
    set_mem_access(MI, false);
302
91
    return;   // don't print "+0"
303
91
  }
304
305
3.56k
  SStream_concat0(O, "+");  // qq
306
307
3.56k
  printOperand(MI, opNum + 1, O);
308
3.56k
  set_mem_access(MI, false);
309
3.56k
}
310
311
static void printCCOperand(MCInst *MI, int opNum, SStream *O)
312
6.91k
{
313
6.91k
  int CC = (int)MCOperand_getImm(MCInst_getOperand(MI, opNum)) + 256;
314
315
6.91k
  switch (MCInst_getOpcode(MI)) {
316
2.15k
    default: break;
317
2.15k
    case SP_FBCOND:
318
2.38k
    case SP_FBCONDA:
319
2.85k
    case SP_BPFCC:
320
3.41k
    case SP_BPFCCA:
321
3.41k
    case SP_BPFCCNT:
322
3.41k
    case SP_BPFCCANT:
323
3.75k
    case SP_MOVFCCrr:  case SP_V9MOVFCCrr:
324
4.16k
    case SP_MOVFCCri:  case SP_V9MOVFCCri:
325
4.57k
    case SP_FMOVS_FCC: case SP_V9FMOVS_FCC:
326
4.63k
    case SP_FMOVD_FCC: case SP_V9FMOVD_FCC:
327
4.76k
    case SP_FMOVQ_FCC: case SP_V9FMOVQ_FCC:
328
         // Make sure CC is a fp conditional flag.
329
4.76k
         CC = (CC < 16+256) ? (CC + 16) : CC;
330
4.76k
         break;
331
6.91k
  }
332
333
6.91k
  SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC));
334
335
6.91k
  if (MI->csh->detail_opt)
336
6.91k
    MI->flat_insn->detail->sparc.cc = (sparc_cc)CC;
337
6.91k
}
338
339
340
static bool printGetPCX(MCInst *MI, unsigned opNum, SStream *O)
341
0
{
342
0
  return true;
343
0
}
344
345
346
#define PRINT_ALIAS_INSTR
347
#include "SparcGenAsmWriter.inc"
348
349
void Sparc_printInst(MCInst *MI, SStream *O, void *Info)
350
77.6k
{
351
77.6k
  char *mnem, *p;
352
77.6k
  char instr[64]; // Sparc has no instruction this long
353
354
77.6k
  mnem = printAliasInstr(MI, O, Info);
355
77.6k
  if (mnem) {
356
    // fixup instruction id due to the change in alias instruction
357
30.4k
    unsigned cpy_len = sizeof(instr) < strlen(mnem) ? sizeof(instr) : strlen(mnem);
358
30.4k
    memcpy(instr, mnem, cpy_len);
359
30.4k
    instr[cpy_len - 1] = '\0';
360
    // does this contains hint with a coma?
361
30.4k
    p = strchr(instr, ',');
362
30.4k
    if (p)
363
20.7k
      *p = '\0'; // now instr only has instruction mnemonic
364
30.4k
    MCInst_setOpcodePub(MI, Sparc_map_insn(instr));
365
30.4k
    switch(MCInst_getOpcode(MI)) {
366
2.37k
      case SP_BCOND:
367
4.57k
      case SP_BCONDA:
368
7.01k
      case SP_BPICCANT:
369
11.2k
      case SP_BPICCNT:
370
12.9k
      case SP_BPXCCANT:
371
14.6k
      case SP_BPXCCNT:
372
18.2k
      case SP_TXCCri:
373
21.1k
      case SP_TXCCrr:
374
21.1k
        if (MI->csh->detail_opt) {
375
          // skip 'b', 't'
376
21.1k
          MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 1);
377
21.1k
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
378
21.1k
        }
379
21.1k
        break;
380
4.05k
      case SP_BPFCCANT:
381
8.43k
      case SP_BPFCCNT:
382
8.43k
        if (MI->csh->detail_opt) {
383
          // skip 'fb'
384
8.43k
          MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 2);
385
8.43k
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
386
8.43k
        }
387
8.43k
        break;
388
0
      case SP_FMOVD_ICC:
389
0
      case SP_FMOVD_XCC:
390
0
      case SP_FMOVQ_ICC:
391
0
      case SP_FMOVQ_XCC:
392
0
      case SP_FMOVS_ICC:
393
0
      case SP_FMOVS_XCC:
394
0
        if (MI->csh->detail_opt) {
395
          // skip 'fmovd', 'fmovq', 'fmovs'
396
0
          MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 5);
397
0
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
398
0
        }
399
0
        break;
400
0
      case SP_MOVICCri:
401
0
      case SP_MOVICCrr:
402
0
      case SP_MOVXCCri:
403
0
      case SP_MOVXCCrr:
404
0
        if (MI->csh->detail_opt) {
405
          // skip 'mov'
406
0
          MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 3);
407
0
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
408
0
        }
409
0
        break;
410
0
      case SP_V9FMOVD_FCC:
411
0
      case SP_V9FMOVQ_FCC:
412
0
      case SP_V9FMOVS_FCC:
413
0
        if (MI->csh->detail_opt) {
414
          // skip 'fmovd', 'fmovq', 'fmovs'
415
0
          MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 5);
416
0
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
417
0
        }
418
0
        break;
419
0
      case SP_V9MOVFCCri:
420
0
      case SP_V9MOVFCCrr:
421
0
        if (MI->csh->detail_opt) {
422
          // skip 'mov'
423
0
          MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 3);
424
0
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
425
0
        }
426
0
        break;
427
833
      default:
428
833
        break;
429
30.4k
    }
430
30.4k
    cs_mem_free(mnem);
431
47.2k
  } else {
432
47.2k
    if (!printSparcAliasInstr(MI, O))
433
45.1k
      printInstruction(MI, O, NULL);
434
47.2k
  }
435
77.6k
}
436
437
void Sparc_addReg(MCInst *MI, int reg)
438
16.6k
{
439
16.6k
  if (MI->csh->detail_opt) {
440
16.6k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
441
16.6k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
442
16.6k
    MI->flat_insn->detail->sparc.op_count++;
443
16.6k
  }
444
16.6k
}
445
446
#endif