Coverage Report

Created: 2026-11-12 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/capstonev5/arch/Sparc/SparcInstPrinter.c
Line
Count
Source
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
1.18k
{
45
1.18k
  if (MI->csh->detail) {
46
1.18k
    MI->flat_insn->detail->sparc.hint = hint;
47
1.18k
  }
48
1.18k
}
49
50
static void Sparc_add_reg(MCInst *MI, unsigned int reg)
51
5.29k
{
52
5.29k
  if (MI->csh->detail) {
53
5.29k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
54
5.29k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
55
5.29k
    MI->flat_insn->detail->sparc.op_count++;
56
5.29k
  }
57
5.29k
}
58
59
static void set_mem_access(MCInst *MI, bool status)
60
14.4k
{
61
14.4k
  if (MI->csh->detail != CS_OPT_ON)
62
0
    return;
63
64
14.4k
  MI->csh->doing_mem = status;
65
66
14.4k
  if (status) {
67
7.23k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_MEM;
68
7.23k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = SPARC_REG_INVALID;
69
7.23k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = 0;
70
7.23k
  } else {
71
    // done, create the next operand slot
72
7.23k
    MI->flat_insn->detail->sparc.op_count++;
73
7.23k
  }
74
14.4k
}
75
76
void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
77
87.8k
{
78
87.8k
  if (((cs_struct *)ud)->detail != CS_OPT_ON)
79
0
    return;
80
81
  // fix up some instructions
82
87.8k
  if (insn->id == SPARC_INS_CASX) {
83
    // first op is actually a memop, not regop
84
66
    insn->detail->sparc.operands[0].type = SPARC_OP_MEM;
85
66
    insn->detail->sparc.operands[0].mem.base = (uint8_t)insn->detail->sparc.operands[0].reg;
86
66
    insn->detail->sparc.operands[0].mem.disp = 0;
87
66
  }
88
87.8k
}
89
90
static void printRegName(SStream *OS, unsigned RegNo)
91
83.8k
{
92
83.8k
  SStream_concat0(OS, "%");
93
83.8k
  SStream_concat0(OS, getRegisterName(RegNo));
94
83.8k
}
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
45.0k
{
104
45.0k
  switch (MCInst_getOpcode(MI)) {
105
41.8k
    default: return false;
106
195
    case SP_LDDri:
107
261
    case SP_LDDrr:
108
261
         SStream_concat0(O, "ldd\t[");
109
261
         printMemOperand(MI, 1, O, NULL);
110
261
         SStream_concat0(O, "], ");
111
261
         printOperand(MI, 0, O);
112
261
         return true;
113
67
    case SP_LDSTUBri:
114
105
    case SP_LDSTUBrr:
115
105
         SStream_concat0(O, "ldstub\t[");
116
105
         printMemOperand(MI, 1, O, NULL);
117
105
         SStream_concat0(O, "], ");
118
105
         printOperand(MI, 0, O);
119
105
         return true;
120
195
    case SP_STDri:
121
261
    case SP_STDrr:
122
261
         SStream_concat0(O, "std\t");
123
261
         printOperand(MI, 2, O);
124
261
         SStream_concat0(O, ", [");
125
261
         printMemOperand(MI, 0, O, NULL);
126
261
         SStream_concat0(O, "]");
127
261
         return true;
128
360
    case SP_JMPLrr:
129
1.65k
    case SP_JMPLri:
130
1.65k
         if (MCInst_getNumOperands(MI) != 3)
131
0
           return false;
132
1.65k
         if (!MCOperand_isReg(MCInst_getOperand(MI, 0)))
133
0
           return false;
134
135
1.65k
         switch (MCOperand_getReg(MCInst_getOperand(MI, 0))) {
136
212
           default: return false;
137
1.07k
           case SP_G0: // jmp $addr | ret | retl
138
1.07k
                if (MCOperand_isImm(MCInst_getOperand(MI, 2)) &&
139
1.00k
                  MCOperand_getImm(MCInst_getOperand(MI, 2)) == 8) {
140
668
                  switch(MCOperand_getReg(MCInst_getOperand(MI, 1))) {
141
204
                    default: break;
142
249
                    case SP_I7: SStream_concat0(O, "ret"); MCInst_setOpcodePub(MI, SPARC_INS_RET); return true;
143
215
                    case SP_O7: SStream_concat0(O, "retl"); MCInst_setOpcodePub(MI, SPARC_INS_RETL); return true;
144
668
                  }
145
668
                }
146
147
606
                SStream_concat0(O, "jmp\t");
148
606
                MCInst_setOpcodePub(MI, SPARC_INS_JMP);
149
606
                printMemOperand(MI, 1, O, NULL);
150
606
                return true;
151
373
           case SP_O7: // call $addr
152
373
                SStream_concat0(O, "call ");
153
373
                MCInst_setOpcodePub(MI, SPARC_INS_CALL);
154
373
                printMemOperand(MI, 1, O, NULL);
155
373
                return true;
156
1.65k
         }
157
202
    case SP_V9FCMPS:
158
270
    case SP_V9FCMPD:
159
476
    case SP_V9FCMPQ:
160
550
    case SP_V9FCMPES:
161
760
    case SP_V9FCMPED:
162
984
    case SP_V9FCMPEQ:
163
984
         if (MI->csh->mode & CS_MODE_V9 || (MCInst_getNumOperands(MI) != 3) ||
164
430
             (!MCOperand_isReg(MCInst_getOperand(MI, 0))) ||
165
430
             (MCOperand_getReg(MCInst_getOperand(MI, 0)) != SP_FCC0))
166
984
             return false;
167
         // if V8, skip printing %fcc0.
168
0
         switch(MCInst_getOpcode(MI)) {
169
0
           default:
170
0
           case SP_V9FCMPS:  SStream_concat0(O, "fcmps\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPS); break;
171
0
           case SP_V9FCMPD:  SStream_concat0(O, "fcmpd\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPD); break;
172
0
           case SP_V9FCMPQ:  SStream_concat0(O, "fcmpq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPQ); break;
173
0
           case SP_V9FCMPES: SStream_concat0(O, "fcmpes\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPES); break;
174
0
           case SP_V9FCMPED: SStream_concat0(O, "fcmped\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPED); break;
175
0
           case SP_V9FCMPEQ: SStream_concat0(O, "fcmpeq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPEQ); break;
176
0
         }
177
0
         printOperand(MI, 1, O);
178
0
         SStream_concat0(O, ", ");
179
0
         printOperand(MI, 2, O);
180
0
         return true;
181
45.0k
  }
182
45.0k
}
183
184
static void printOperand(MCInst *MI, int opNum, SStream *O)
185
149k
{
186
149k
  int64_t Imm;
187
149k
  unsigned reg;
188
149k
  MCOperand *MO = MCInst_getOperand(MI, opNum);
189
190
149k
  if (MCOperand_isReg(MO)) {
191
83.8k
    reg = MCOperand_getReg(MO);
192
83.8k
    printRegName(O, reg);
193
83.8k
    reg = Sparc_map_register(reg);
194
195
83.8k
    if (MI->csh->detail) {
196
83.8k
      if (MI->csh->doing_mem) {
197
8.70k
        if (MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base)
198
1.46k
          MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.index = (uint8_t)reg;
199
7.23k
        else
200
7.23k
          MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = (uint8_t)reg;
201
75.1k
      } else {
202
75.1k
        MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
203
75.1k
        MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
204
75.1k
        MI->flat_insn->detail->sparc.op_count++;
205
75.1k
      }
206
83.8k
    }
207
208
83.8k
    return;
209
83.8k
  }
210
211
65.5k
  if (MCOperand_isImm(MO)) {
212
65.3k
    Imm = (int)MCOperand_getImm(MO);
213
214
    // Conditional branches displacements needs to be signextended to be
215
    // able to jump backwards.
216
    //
217
    // Displacements are measured as the number of instructions forward or
218
    // backward, so they need to be multiplied by 4
219
65.3k
    switch (MI->Opcode) {
220
7.13k
      case SP_CALL:
221
        // Imm = SignExtend32(Imm, 30);
222
7.13k
        Imm += MI->address;
223
7.13k
        break;
224
225
      // Branch on integer condition with prediction (BPcc)
226
      // Branch on floating point condition with prediction (FBPfcc)
227
268
      case SP_BPICC:
228
487
      case SP_BPICCA:
229
4.21k
      case SP_BPICCANT:
230
7.82k
      case SP_BPICCNT:
231
8.34k
      case SP_BPXCC:
232
8.57k
      case SP_BPXCCA:
233
11.8k
      case SP_BPXCCANT:
234
16.1k
      case SP_BPXCCNT:
235
16.4k
      case SP_BPFCC:
236
16.6k
      case SP_BPFCCA:
237
20.2k
      case SP_BPFCCANT:
238
23.8k
      case SP_BPFCCNT:
239
23.8k
        Imm = SignExtend32(Imm, 19);
240
23.8k
        Imm = MI->address + Imm * 4;
241
23.8k
        break;
242
243
      // Branch on integer condition (Bicc)
244
      // Branch on floating point condition (FBfcc)
245
415
      case SP_BA:
246
4.48k
      case SP_BCOND:
247
8.33k
      case SP_BCONDA:
248
8.87k
      case SP_FBCOND:
249
9.36k
      case SP_FBCONDA:
250
9.36k
        Imm = SignExtend32(Imm, 22);
251
9.36k
        Imm = MI->address + Imm * 4;
252
9.36k
        break;
253
254
      // Branch on integer register with prediction (BPr)
255
147
      case SP_BPGEZapn:
256
346
      case SP_BPGEZapt:
257
544
      case SP_BPGEZnapn:
258
746
      case SP_BPGEZnapt:
259
953
      case SP_BPGZapn:
260
1.15k
      case SP_BPGZapt:
261
1.49k
      case SP_BPGZnapn:
262
1.69k
      case SP_BPGZnapt:
263
1.76k
      case SP_BPLEZapn:
264
1.96k
      case SP_BPLEZapt:
265
2.19k
      case SP_BPLEZnapn:
266
2.67k
      case SP_BPLEZnapt:
267
3.09k
      case SP_BPLZapn:
268
3.29k
      case SP_BPLZapt:
269
3.57k
      case SP_BPLZnapn:
270
3.77k
      case SP_BPLZnapt:
271
4.33k
      case SP_BPNZapn:
272
4.53k
      case SP_BPNZapt:
273
4.75k
      case SP_BPNZnapn:
274
4.83k
      case SP_BPNZnapt:
275
5.11k
      case SP_BPZapn:
276
5.31k
      case SP_BPZapt:
277
5.74k
      case SP_BPZnapn:
278
5.81k
      case SP_BPZnapt:
279
5.81k
        Imm = SignExtend32(Imm, 16);
280
5.81k
        Imm = MI->address + Imm * 4;
281
5.81k
        break;
282
65.3k
    }
283
    
284
65.3k
    printInt64(O, Imm);
285
286
65.3k
    if (MI->csh->detail) {
287
65.3k
      if (MI->csh->doing_mem) {
288
4.12k
        MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = Imm;
289
61.2k
      } else {
290
61.2k
        MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_IMM;
291
61.2k
        MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].imm = Imm;
292
61.2k
        MI->flat_insn->detail->sparc.op_count++;
293
61.2k
      }
294
65.3k
    }
295
65.3k
  }
296
297
65.5k
  return;
298
65.5k
}
299
300
static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier)
301
7.23k
{
302
7.23k
  MCOperand *MO;
303
304
7.23k
  set_mem_access(MI, true);
305
7.23k
  printOperand(MI, opNum, O);
306
307
  // If this is an ADD operand, emit it like normal operands.
308
7.23k
  if (Modifier && !strcmp(Modifier, "arith")) {
309
0
    SStream_concat0(O, ", ");
310
0
    printOperand(MI, opNum + 1, O);
311
0
    set_mem_access(MI, false);
312
0
    return;
313
0
  }
314
315
7.23k
  MO = MCInst_getOperand(MI, opNum + 1);
316
317
7.23k
  if (MCOperand_isReg(MO) && (MCOperand_getReg(MO) == SP_G0)) {
318
1.33k
    set_mem_access(MI, false);
319
1.33k
    return;   // don't print "+%g0"
320
1.33k
  }
321
322
5.90k
  if (MCOperand_isImm(MO) && (MCOperand_getImm(MO) == 0)) {
323
316
    set_mem_access(MI, false);
324
316
    return;   // don't print "+0"
325
316
  }
326
327
5.59k
  SStream_concat0(O, "+");  // qq
328
329
5.59k
  printOperand(MI, opNum + 1, O);
330
5.59k
  set_mem_access(MI, false);
331
5.59k
}
332
333
static void printCCOperand(MCInst *MI, int opNum, SStream *O)
334
8.00k
{
335
8.00k
  int CC = (int)MCOperand_getImm(MCInst_getOperand(MI, opNum)) + 256;
336
337
8.00k
  switch (MCInst_getOpcode(MI)) {
338
4.11k
    default: break;
339
4.11k
    case SP_FBCOND:
340
1.02k
    case SP_FBCONDA:
341
1.32k
    case SP_BPFCC:
342
1.57k
    case SP_BPFCCA:
343
1.57k
    case SP_BPFCCNT:
344
1.57k
    case SP_BPFCCANT:
345
2.17k
    case SP_MOVFCCrr:  case SP_V9MOVFCCrr:
346
2.68k
    case SP_MOVFCCri:  case SP_V9MOVFCCri:
347
3.02k
    case SP_FMOVS_FCC: case SP_V9FMOVS_FCC:
348
3.63k
    case SP_FMOVD_FCC: case SP_V9FMOVD_FCC:
349
3.89k
    case SP_FMOVQ_FCC: case SP_V9FMOVQ_FCC:
350
         // Make sure CC is a fp conditional flag.
351
3.89k
         CC = (CC < 16+256) ? (CC + 16) : CC;
352
3.89k
         break;
353
8.00k
  }
354
355
8.00k
  SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC));
356
357
8.00k
  if (MI->csh->detail)
358
8.00k
    MI->flat_insn->detail->sparc.cc = (sparc_cc)CC;
359
8.00k
}
360
361
362
static bool printGetPCX(MCInst *MI, unsigned opNum, SStream *O)
363
0
{
364
0
  return true;
365
0
}
366
367
368
#define PRINT_ALIAS_INSTR
369
#include "SparcGenAsmWriter.inc"
370
371
void Sparc_printInst(MCInst *MI, SStream *O, void *Info)
372
87.8k
{
373
87.8k
  char *mnem, *p;
374
87.8k
  char instr[64]; // Sparc has no instruction this long
375
376
87.8k
  mnem = printAliasInstr(MI, O, Info);
377
87.8k
  if (mnem) {
378
    // fixup instruction id due to the change in alias instruction
379
42.7k
    unsigned cpy_len = sizeof(instr) - 1 < strlen(mnem) ? sizeof(instr) - 1 : strlen(mnem);
380
42.7k
    memcpy(instr, mnem, cpy_len);
381
42.7k
    instr[cpy_len] = '\0';
382
    // does this contains hint with a coma?
383
42.7k
    p = strchr(instr, ',');
384
42.7k
    if (p)
385
25.9k
      *p = '\0'; // now instr only has instruction mnemonic
386
42.7k
    MCInst_setOpcodePub(MI, Sparc_map_insn(instr));
387
42.7k
    switch(MCInst_getOpcode(MI)) {
388
4.06k
      case SP_BCOND:
389
7.92k
      case SP_BCONDA:
390
11.6k
      case SP_BPICCANT:
391
15.2k
      case SP_BPICCNT:
392
18.4k
      case SP_BPXCCANT:
393
22.8k
      case SP_BPXCCNT:
394
28.5k
      case SP_TXCCri:
395
32.9k
      case SP_TXCCrr:
396
32.9k
        if (MI->csh->detail) {
397
          // skip 'b', 't'
398
32.9k
          MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 1);
399
32.9k
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
400
32.9k
        }
401
32.9k
        break;
402
3.56k
      case SP_BPFCCANT:
403
7.17k
      case SP_BPFCCNT:
404
7.17k
        if (MI->csh->detail) {
405
          // skip 'fb'
406
7.17k
          MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 2);
407
7.17k
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
408
7.17k
        }
409
7.17k
        break;
410
0
      case SP_FMOVD_ICC:
411
0
      case SP_FMOVD_XCC:
412
0
      case SP_FMOVQ_ICC:
413
0
      case SP_FMOVQ_XCC:
414
0
      case SP_FMOVS_ICC:
415
0
      case SP_FMOVS_XCC:
416
0
        if (MI->csh->detail) {
417
          // skip 'fmovd', 'fmovq', 'fmovs'
418
0
          MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 5);
419
0
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
420
0
        }
421
0
        break;
422
0
      case SP_MOVICCri:
423
0
      case SP_MOVICCrr:
424
0
      case SP_MOVXCCri:
425
0
      case SP_MOVXCCrr:
426
0
        if (MI->csh->detail) {
427
          // skip 'mov'
428
0
          MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 3);
429
0
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
430
0
        }
431
0
        break;
432
0
      case SP_V9FMOVD_FCC:
433
0
      case SP_V9FMOVQ_FCC:
434
0
      case SP_V9FMOVS_FCC:
435
0
        if (MI->csh->detail) {
436
          // skip 'fmovd', 'fmovq', 'fmovs'
437
0
          MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 5);
438
0
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
439
0
        }
440
0
        break;
441
0
      case SP_V9MOVFCCri:
442
0
      case SP_V9MOVFCCrr:
443
0
        if (MI->csh->detail) {
444
          // skip 'mov'
445
0
          MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 3);
446
0
          MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
447
0
        }
448
0
        break;
449
2.64k
      default:
450
2.64k
        break;
451
42.7k
    }
452
42.7k
    cs_mem_free(mnem);
453
45.0k
  } else {
454
45.0k
    if (!printSparcAliasInstr(MI, O))
455
43.0k
      printInstruction(MI, O, NULL);
456
45.0k
  }
457
87.8k
}
458
459
void Sparc_addReg(MCInst *MI, int reg)
460
25.0k
{
461
25.0k
  if (MI->csh->detail) {
462
25.0k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
463
25.0k
    MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
464
25.0k
    MI->flat_insn->detail->sparc.op_count++;
465
25.0k
  }
466
25.0k
}
467
468
#endif