Coverage Report

Created: 2025-07-20 06:54

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