Coverage Report

Created: 2025-07-09 06:32

/src/capstonenext/arch/Sparc/SparcMapping.c
Line
Count
Source (jump to first uncovered line)
1
/* Capstone Disassembly Engine */
2
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2015 */
3
4
#ifdef CAPSTONE_HAS_SPARC
5
6
#include <stdio.h> // debug
7
#include <string.h>
8
9
#include "../../Mapping.h"
10
#include "../../utils.h"
11
#include "../../cs_simple_types.h"
12
13
#include "SparcMapping.h"
14
15
void Sparc_init_cs_detail(MCInst *MI)
16
38.0k
{
17
38.0k
  if (!detail_is_set(MI)) {
18
0
    return;
19
0
  }
20
38.0k
  memset(get_detail(MI), 0, offsetof(cs_detail, sparc) + sizeof(cs_sparc));
21
38.0k
  Sparc_get_detail(MI)->cc = SPARC_CC_UNDEF;
22
38.0k
  Sparc_get_detail(MI)->cc_field = SPARC_CC_FIELD_NONE;
23
38.0k
}
24
25
const insn_map sparc_insns[] = {
26
#include "SparcGenCSMappingInsn.inc"
27
};
28
29
void Sparc_set_instr_map_data(MCInst *MI)
30
38.0k
{
31
38.0k
  map_cs_id(MI, sparc_insns, ARR_SIZE(sparc_insns));
32
38.0k
  map_implicit_reads(MI, sparc_insns);
33
38.0k
  map_implicit_writes(MI, sparc_insns);
34
38.0k
  map_groups(MI, sparc_insns);
35
38.0k
  const sparc_suppl_info *suppl_info =
36
38.0k
    map_get_suppl_info(MI, sparc_insns);
37
38.0k
  if (suppl_info) {
38
38.0k
    Sparc_get_detail(MI)->format = suppl_info->form;
39
38.0k
  }
40
38.0k
}
41
42
/// Adds details which are not defined consistently as LLVM operands like
43
/// condition codes for alias instructions or branch hint bits.
44
static void Sparc_add_bit_details(MCInst *MI, const uint8_t *Bytes,
45
          size_t BytesLen)
46
38.0k
{
47
38.0k
  if (!Bytes || BytesLen < 4 || !detail_is_set(MI)) {
48
530
    return;
49
530
  }
50
37.5k
  uint32_t insn = readBytes32(MI, Bytes);
51
52
  // CC field
53
37.5k
  cs_sparc *detail = Sparc_get_detail(MI);
54
37.5k
  switch (detail->format) {
55
26.6k
  default:
56
26.6k
    break;
57
26.6k
  case SPARC_INSN_FORM_F2_2: {
58
    // This format is used either by B or FB instructions.
59
    // The op2 == 6 for the FB and 2 for B.
60
    // This is the only indicator we have here to determine which CC field is used
61
    // if we don't want big switch cases.
62
    //
63
    // See: Opcode Maps - Table 39 - Sparc V9 ISA
64
3.79k
    size_t op2 = get_insn_field_r(insn, 22, 24);
65
3.79k
    detail->cc_field = op2 == 6 ? SPARC_CC_FIELD_FCC0 : SPARC_CC_FIELD_ICC;
66
3.79k
    break;
67
0
  }
68
5.49k
  case SPARC_INSN_FORM_F2_3:
69
5.49k
    detail->cc_field = 0x4 | get_insn_field_r(insn, 20, 21);
70
5.49k
    break;
71
341
  case SPARC_INSN_FORM_TRAPSP:
72
341
    detail->cc_field = 0x4 | get_insn_field_r(insn, 11, 12);
73
341
    break;
74
434
  case SPARC_INSN_FORM_F4_1:
75
735
  case SPARC_INSN_FORM_F4_2:
76
735
    detail->cc_field = get_insn_field_r(insn, 11, 12);
77
735
    detail->cc_field |= get_insn_field_r(insn, 18, 18) << 2;
78
735
    break;
79
505
  case SPARC_INSN_FORM_F4_3:
80
505
    detail->cc_field = get_insn_field_r(insn, 11, 13);
81
505
    break;
82
37.5k
  }
83
84
  // Condition codes
85
37.5k
  switch (detail->format) {
86
19.4k
  default:
87
19.4k
    break;
88
19.4k
  case SPARC_INSN_FORM_F2_1:
89
9.08k
  case SPARC_INSN_FORM_F2_2:
90
14.5k
  case SPARC_INSN_FORM_F2_3:
91
14.9k
  case SPARC_INSN_FORM_TRAPSP: {
92
    // cond
93
    // Alias instructions don't define the conditions as operands.
94
    // We need to add them here to the details again.
95
14.9k
    sparc_cc cc = get_insn_field_r(insn, 25, 28);
96
14.9k
    if (MCInst_getOpcode(MI) == Sparc_CBCOND ||
97
14.9k
        MCInst_getOpcode(MI) == Sparc_CBCONDA) {
98
1.52k
      cc += SPARC_CC_CPCC_BEGIN;
99
1.52k
    }
100
14.9k
    detail->cc = cc;
101
14.9k
    break;
102
14.5k
  }
103
434
  case SPARC_INSN_FORM_F4_1:
104
735
  case SPARC_INSN_FORM_F4_2:
105
1.24k
  case SPARC_INSN_FORM_F4_3: {
106
1.24k
    sparc_cc cc = get_insn_field_r(insn, 14, 17);
107
1.24k
    detail->cc = cc;
108
1.24k
    break;
109
735
  }
110
1.72k
  case SPARC_INSN_FORM_F2_4: {
111
    // cond
112
    // Alias instructions don't define the conditions as operands.
113
    // We need to add them here to the details again.
114
1.72k
    sparc_cc rcc = get_insn_field_r(insn, 25, 27);
115
1.72k
    detail->cc = rcc + SPARC_CC_REG_BEGIN;
116
1.72k
    break;
117
735
  }
118
126
  case SPARC_INSN_FORM_F4_4R:
119
211
  case SPARC_INSN_FORM_F4_4I: {
120
211
    sparc_cc rcc = get_insn_field_r(insn, 10, 12);
121
211
    detail->cc = rcc + SPARC_CC_REG_BEGIN;
122
211
    break;
123
126
  }
124
37.5k
  }
125
37.5k
  switch (detail->cc_field) {
126
27.6k
  default:
127
33.3k
  case SPARC_CC_FIELD_ICC:
128
35.5k
  case SPARC_CC_FIELD_XCC:
129
35.5k
    break;
130
1.59k
  case SPARC_CC_FIELD_FCC0:
131
1.90k
  case SPARC_CC_FIELD_FCC1:
132
1.98k
  case SPARC_CC_FIELD_FCC2:
133
2.01k
  case SPARC_CC_FIELD_FCC3:
134
2.01k
    detail->cc += SPARC_CC_FCC_BEGIN;
135
2.01k
    break;
136
37.5k
  }
137
138
  // Hints
139
37.5k
  switch (detail->format) {
140
26.5k
  default:
141
26.5k
    break;
142
26.5k
  case SPARC_INSN_FORM_F2_2:
143
3.79k
    detail->hint = get_insn_field_r(insn, 29, 29);
144
3.79k
    break;
145
5.49k
  case SPARC_INSN_FORM_F2_3:
146
7.22k
  case SPARC_INSN_FORM_F2_4:
147
7.22k
    detail->hint = get_insn_field_r(insn, 29, 29);
148
7.22k
    detail->hint |=
149
7.22k
      get_insn_field_r(insn, 19, 19) == 0 ? SPARC_HINT_PN :
150
7.22k
                    SPARC_HINT_PT;
151
7.22k
    break;
152
37.5k
  }
153
37.5k
}
154
155
bool Sparc_getInstruction(csh handle, const uint8_t *code, size_t code_len,
156
        MCInst *instr, uint16_t *size, uint64_t address,
157
        void *info)
158
38.0k
{
159
38.0k
  Sparc_init_cs_detail(instr);
160
38.0k
  bool Result = Sparc_LLVM_getInstruction(handle, code, code_len, instr,
161
38.0k
            size, address,
162
38.0k
            info) != MCDisassembler_Fail;
163
38.0k
  Sparc_set_instr_map_data(instr);
164
165
38.0k
  Sparc_add_bit_details(instr, code, code_len);
166
38.0k
  return Result;
167
38.0k
}
168
169
void Sparc_init_mri(MCRegisterInfo *MRI)
170
1.56k
{
171
1.56k
  MCRegisterInfo_InitMCRegisterInfo(
172
1.56k
    MRI, SparcRegDesc, sizeof(SparcRegDesc), 0, 0,
173
1.56k
    SparcMCRegisterClasses, ARR_SIZE(SparcMCRegisterClasses), 0, 0,
174
1.56k
    SparcRegDiffLists, 0, SparcSubRegIdxLists,
175
1.56k
    ARR_SIZE(SparcSubRegIdxLists), 0);
176
1.56k
}
177
178
const char *Sparc_reg_name(csh handle, unsigned int reg)
179
16.5k
{
180
16.5k
  int syntax_opt = ((cs_struct *)(uintptr_t)handle)->syntax;
181
182
16.5k
  if (syntax_opt & CS_OPT_SYNTAX_NOREGNAME) {
183
0
    return Sparc_LLVM_getRegisterName(reg, Sparc_NoRegAltName);
184
0
  }
185
16.5k
  return Sparc_LLVM_getRegisterName(reg, Sparc_RegNamesStateReg);
186
16.5k
}
187
188
void Sparc_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
189
37.2k
{
190
  // Not used by Sparc. Information is set after disassembly.
191
37.2k
}
192
193
static const char *const insn_name_maps[] = {
194
#include "SparcGenCSMappingInsnName.inc"
195
};
196
197
#ifndef CAPSTONE_DIET
198
static const name_map insn_alias_mnem_map[] = {
199
#include "SparcGenCSAliasMnemMap.inc"
200
  { SPARC_INS_ALIAS_CALL, "call" },
201
  { SPARC_INS_ALIAS_END, NULL },
202
};
203
#endif
204
205
static void insert_op(MCInst *MI, unsigned index, cs_sparc_op op)
206
304
{
207
304
  if (!detail_is_set(MI)) {
208
0
    return;
209
0
  }
210
304
  Sparc_check_safe_inc(MI);
211
212
304
  cs_sparc_op *ops = Sparc_get_detail(MI)->operands;
213
304
  int i = Sparc_get_detail(MI)->op_count;
214
304
  if (index == -1) {
215
242
    ops[i] = op;
216
242
    Sparc_inc_op_count(MI);
217
242
    return;
218
242
  }
219
124
  for (; i > 0 && i > index; --i) {
220
62
    ops[i] = ops[i - 1];
221
62
  }
222
62
  ops[index] = op;
223
62
  Sparc_inc_op_count(MI);
224
62
}
225
226
/// Inserts a register to the detail operands at @index.
227
/// Already present operands are moved.
228
/// If @index is -1 the operand is appended.
229
static void Sparc_insert_detail_op_reg_at(MCInst *MI, unsigned index, sparc_reg Reg,
230
         cs_ac_type access)
231
304
{
232
304
  if (!detail_is_set(MI))
233
0
    return;
234
235
304
  cs_sparc_op op = { 0 };
236
304
  op.type = SPARC_OP_REG;
237
304
  op.reg = Reg;
238
304
  op.access = access;
239
304
  insert_op(MI, index, op);
240
304
}
241
242
static void Sparc_correct_details(MCInst *MI)
243
37.2k
{
244
37.2k
  if (!detail_is_set(MI)) {
245
0
    return;
246
0
  }
247
37.2k
  switch (MCInst_getOpcode(MI)) {
248
35.7k
  default:
249
35.7k
    return;
250
35.7k
  case Sparc_LDSTUBri:
251
363
  case Sparc_LDSTUBrr:
252
1.04k
  case Sparc_LDSTUBAri:
253
1.15k
  case Sparc_LDSTUBArr:
254
    // The memory gets written back with ones
255
    // but there is not write back memory operand defined
256
    // (if even possible).
257
1.15k
    Sparc_get_detail(MI)->operands[0].access = CS_AC_READ_WRITE;
258
1.15k
    break;
259
10
  case Sparc_RDPSR:
260
10
    Sparc_insert_detail_op_reg_at(MI, 0, SPARC_REG_PSR, CS_AC_READ);
261
10
    break;
262
19
  case Sparc_PWRPSRri:
263
37
  case Sparc_PWRPSRrr:
264
77
  case Sparc_WRPSRri:
265
91
  case Sparc_WRPSRrr:
266
91
    Sparc_insert_detail_op_reg_at(MI, -1, SPARC_REG_PSR, CS_AC_WRITE);
267
91
    break;
268
18
  case Sparc_RDWIM:
269
18
    Sparc_insert_detail_op_reg_at(MI, 0, SPARC_REG_WIM, CS_AC_READ);
270
18
    break;
271
38
  case Sparc_WRWIMri:
272
57
  case Sparc_WRWIMrr:
273
57
    Sparc_insert_detail_op_reg_at(MI, -1, SPARC_REG_WIM, CS_AC_WRITE);
274
57
    break;
275
34
  case Sparc_RDTBR:
276
34
    Sparc_insert_detail_op_reg_at(MI, 0, SPARC_REG_TBR, CS_AC_READ);
277
34
    break;
278
49
  case Sparc_WRTBRri:
279
94
  case Sparc_WRTBRrr:
280
94
    Sparc_insert_detail_op_reg_at(MI, -1, SPARC_REG_TBR, CS_AC_WRITE);
281
94
    break;
282
37.2k
  }
283
37.2k
}
284
285
void Sparc_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info)
286
37.2k
{
287
37.2k
  MCRegisterInfo *MRI = (MCRegisterInfo *)info;
288
37.2k
  MI->MRI = MRI;
289
37.2k
  MI->flat_insn->usesAliasDetails = map_use_alias_details(MI);
290
37.2k
  Sparc_LLVM_printInst(MI, MI->address, "", O);
291
292
37.2k
#ifndef CAPSTONE_DIET
293
37.2k
  map_set_alias_id(MI, O, insn_alias_mnem_map,
294
37.2k
       ARR_SIZE(insn_alias_mnem_map));
295
37.2k
  Sparc_correct_details(MI);
296
37.2k
#endif
297
37.2k
}
298
299
const char *Sparc_insn_name(csh handle, unsigned int id)
300
37.2k
{
301
37.2k
#ifndef CAPSTONE_DIET
302
37.2k
  if (id < SPARC_INS_ALIAS_END && id > SPARC_INS_ALIAS_BEGIN) {
303
0
    if (id - SPARC_INS_ALIAS_BEGIN >= ARR_SIZE(insn_alias_mnem_map))
304
0
      return NULL;
305
306
0
    return insn_alias_mnem_map[id - SPARC_INS_ALIAS_BEGIN - 1].name;
307
0
  }
308
37.2k
  if (id >= SPARC_INS_ENDING)
309
0
    return NULL;
310
311
37.2k
  if (id < ARR_SIZE(insn_name_maps))
312
37.2k
    return insn_name_maps[id];
313
  // not found
314
0
  return NULL;
315
#else
316
  return NULL;
317
#endif
318
37.2k
}
319
320
#ifndef CAPSTONE_DIET
321
static const name_map group_name_maps[] = {
322
  { SPARC_GRP_INVALID, NULL },
323
324
  { SPARC_GRP_JUMP, "jump" },
325
  { SPARC_GRP_CALL, "call" },
326
  { SPARC_GRP_RET, "return" },
327
  { SPARC_GRP_INT, "int" },
328
  { SPARC_GRP_IRET, "iret" },
329
  { SPARC_GRP_PRIVILEGE, "privilege" },
330
  { SPARC_GRP_BRANCH_RELATIVE, "branch_relative" },
331
332
// architecture-specific groups
333
#include "SparcGenCSFeatureName.inc"
334
};
335
#endif
336
337
const char *Sparc_group_name(csh handle, unsigned int id)
338
98.0k
{
339
98.0k
#ifndef CAPSTONE_DIET
340
98.0k
  return id2name(group_name_maps, ARR_SIZE(group_name_maps), id);
341
#else
342
  return NULL;
343
#endif
344
98.0k
}
345
346
static const map_insn_ops insn_operands[] = {
347
#include "SparcGenCSMappingInsnOp.inc"
348
};
349
350
void Sparc_set_detail_op_imm(MCInst *MI, unsigned OpNum, sparc_op_type ImmType,
351
           int64_t Imm)
352
24.4k
{
353
24.4k
  if (!detail_is_set(MI))
354
0
    return;
355
24.4k
  CS_ASSERT_RET((map_get_op_type(MI, OpNum) & ~CS_OP_MEM) == CS_OP_IMM);
356
24.4k
  CS_ASSERT_RET(ImmType == SPARC_OP_IMM);
357
358
24.4k
  Sparc_get_detail_op(MI, 0)->type = ImmType;
359
24.4k
  Sparc_get_detail_op(MI, 0)->imm = Imm;
360
24.4k
  Sparc_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
361
24.4k
  Sparc_inc_op_count(MI);
362
24.4k
}
363
364
void Sparc_set_detail_op_reg(MCInst *MI, unsigned OpNum, sparc_reg Reg)
365
27.7k
{
366
27.7k
  if (!detail_is_set(MI))
367
0
    return;
368
27.7k
  CS_ASSERT_RET((map_get_op_type(MI, OpNum) & ~CS_OP_MEM) == CS_OP_REG);
369
370
27.7k
  switch (Reg) {
371
24.7k
  default:
372
24.7k
    Sparc_get_detail_op(MI, 0)->type = SPARC_OP_REG;
373
24.7k
    Sparc_get_detail_op(MI, 0)->reg = Reg;
374
24.7k
    Sparc_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
375
24.7k
    Sparc_inc_op_count(MI);
376
24.7k
    return;
377
  // The LLVM definition is inconsistent with the cc fields.
378
  // Sometimes they are encoded as register, sometimes not at all.
379
  // For Capstone they are always saved in the cc_field field for now.
380
0
  case SPARC_REG_ICC:
381
0
    Sparc_get_detail(MI)->cc_field = SPARC_CC_FIELD_ICC;
382
0
    break;
383
935
  case SPARC_REG_FCC0:
384
935
    Sparc_get_detail(MI)->cc_field = SPARC_CC_FIELD_FCC0;
385
935
    break;
386
776
  case SPARC_REG_FCC1:
387
776
    Sparc_get_detail(MI)->cc_field = SPARC_CC_FIELD_FCC1;
388
776
    break;
389
782
  case SPARC_REG_FCC2:
390
782
    Sparc_get_detail(MI)->cc_field = SPARC_CC_FIELD_FCC2;
391
782
    break;
392
527
  case SPARC_REG_FCC3:
393
527
    Sparc_get_detail(MI)->cc_field = SPARC_CC_FIELD_FCC3;
394
527
    break;
395
27.7k
  }
396
27.7k
}
397
398
static inline bool is_single_reg_mem_case(MCInst *MI, unsigned OpNo)
399
15.5k
{
400
15.5k
  if (map_get_op_type(MI, OpNo) != CS_OP_MEM_REG) {
401
4.57k
    return false;
402
4.57k
  }
403
11.0k
  if (MI->size == 1) {
404
0
    return true;
405
11.0k
  } else if (MI->size > OpNo + 1 && Sparc_get_detail(MI)->operands[0].type != SPARC_OP_MEM) {
406
    // Next operand is not a memory operand (disponent or index reg).
407
3.03k
    return !(map_get_op_type(MI, OpNo + 1) & SPARC_OP_MEM);
408
3.03k
  }
409
7.97k
  return false;
410
11.0k
}
411
412
void Sparc_add_cs_detail_0(MCInst *MI, sparc_op_group op_group, unsigned OpNo)
413
86.7k
{
414
86.7k
  if (!detail_is_set(MI) || !map_fill_detail_ops(MI))
415
0
    return;
416
417
86.7k
  cs_op_type op_type = map_get_op_type(MI, OpNo);
418
419
86.7k
  switch (op_group) {
420
0
  default:
421
0
  case Sparc_OP_GROUP_GetPCX:
422
0
    printf("Operand group %d not handled!\n", op_group);
423
0
    return;
424
67.7k
  case Sparc_OP_GROUP_Operand:
425
67.7k
    if (op_type & CS_OP_MEM) {
426
15.5k
      if (is_single_reg_mem_case(MI, OpNo)) {
427
876
        Sparc_get_detail_op(MI, 0)->type = SPARC_OP_MEM;
428
876
        Sparc_get_detail_op(MI, 0)->mem.base =
429
876
          MCInst_getOpVal(MI, OpNo);
430
876
        Sparc_get_detail_op(MI, 0)->access =
431
876
          map_get_op_access(MI, OpNo);
432
876
        Sparc_inc_op_count(MI);
433
876
      }
434
15.5k
      break;
435
15.5k
    }
436
52.1k
    if (op_type == CS_OP_IMM) {
437
24.4k
      Sparc_set_detail_op_imm(MI, OpNo, SPARC_OP_IMM,
438
24.4k
            MCInst_getOpVal(MI, OpNo));
439
27.7k
    } else if (op_type == CS_OP_REG) {
440
27.7k
      Sparc_set_detail_op_reg(MI, OpNo,
441
27.7k
            MCInst_getOpVal(MI, OpNo));
442
27.7k
    } else {
443
0
      CS_ASSERT_RET(0 && "Op type not handled.");
444
0
    }
445
52.1k
    Sparc_get_detail_op(MI, 0)->access =
446
52.1k
      map_get_op_access(MI, OpNo);
447
52.1k
    break;
448
7.62k
  case Sparc_OP_GROUP_CCOperand: {
449
    // Handled in Sparc_add_bit_details().
450
7.62k
    break;
451
67.7k
  }
452
8.42k
  case Sparc_OP_GROUP_MemOperand: {
453
8.42k
    MCOperand *Op1 = MCInst_getOperand(MI, (OpNo));
454
8.42k
    MCOperand *Op2 = MCInst_getOperand(MI, (OpNo + 1));
455
8.42k
    if (!MCOperand_isReg(Op1) ||
456
8.42k
        MCOperand_getReg(Op1) == Sparc_G0) {
457
      // Ignored
458
604
      return;
459
604
    }
460
7.82k
    Sparc_get_detail_op(MI, 0)->type = SPARC_OP_MEM;
461
7.82k
    Sparc_get_detail_op(MI, 0)->access =
462
7.82k
      map_get_op_access(MI, OpNo);
463
7.82k
    Sparc_get_detail_op(MI, 0)->mem.base = MCOperand_getReg(Op1);
464
465
7.82k
    if (MCOperand_isReg(Op2) && MCOperand_getReg(Op2) != Sparc_G0) {
466
2.44k
      Sparc_get_detail_op(MI, 0)->mem.index =
467
2.44k
        MCOperand_getReg(Op2);
468
5.37k
    } else if (MCOperand_isImm(Op2) && MCOperand_getImm(Op2) != 0) {
469
4.47k
      Sparc_get_detail_op(MI, 0)->mem.disp =
470
4.47k
        MCOperand_getImm(Op2);
471
4.47k
    }
472
7.82k
    Sparc_inc_op_count(MI);
473
7.82k
    break;
474
8.42k
  }
475
2.78k
  case Sparc_OP_GROUP_ASITag:
476
2.78k
    Sparc_get_detail_op(MI, 0)->type = SPARC_OP_ASI;
477
2.78k
    Sparc_get_detail_op(MI, 0)->access =
478
2.78k
      map_get_op_access(MI, OpNo);
479
2.78k
    Sparc_get_detail_op(MI, 0)->asi =
480
2.78k
      MCOperand_getImm(MCInst_getOperand(MI, OpNo));
481
2.78k
    Sparc_inc_op_count(MI);
482
2.78k
    break;
483
121
  case Sparc_OP_GROUP_MembarTag:
484
121
    Sparc_get_detail_op(MI, 0)->type = SPARC_OP_MEMBAR_TAG;
485
121
    Sparc_get_detail_op(MI, 0)->access =
486
121
      map_get_op_access(MI, OpNo);
487
121
    Sparc_get_detail_op(MI, 0)->membar_tag =
488
121
      MCOperand_getImm(MCInst_getOperand(MI, OpNo));
489
121
    Sparc_inc_op_count(MI);
490
121
    break;
491
86.7k
  }
492
86.7k
}
493
494
#endif