Coverage Report

Created: 2025-10-10 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/capstonenext/arch/PowerPC/PPCMapping.c
Line
Count
Source
1
/* Capstone Disassembly Engine */
2
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2015 */
3
4
#include "capstone/capstone.h"
5
#ifdef CAPSTONE_HAS_POWERPC
6
7
#include <stdio.h> // debug
8
#include <string.h>
9
10
#include "../../cs_simple_types.h"
11
#include "../../Mapping.h"
12
#include "../../MCDisassembler.h"
13
#include "../../utils.h"
14
15
#include "PPCLinkage.h"
16
#include "PPCMapping.h"
17
#include "PPCMCTargetDesc.h"
18
19
static int P7InheritableFeatures[] = {
20
  PPC_DirectivePwr7,     PPC_FeatureAltivec,
21
  PPC_FeatureVSX,        PPC_FeatureMFOCRF,
22
  PPC_FeatureFCPSGN,     PPC_FeatureFSqrt,
23
  PPC_FeatureFRE,        PPC_FeatureFRES,
24
  PPC_FeatureFRSQRTE,    PPC_FeatureFRSQRTES,
25
  PPC_FeatureRecipPrec,  PPC_FeatureSTFIWX,
26
  PPC_FeatureLFIWAX,     PPC_FeatureFPRND,
27
  PPC_FeatureFPCVT,      PPC_FeatureISEL,
28
  PPC_FeaturePOPCNTD,    PPC_FeatureCMPB,
29
  PPC_FeatureLDBRX,      PPC_Feature64Bit,
30
  PPC_FeatureBPERMD,     PPC_FeatureExtDiv,
31
  PPC_FeatureMFTB,       PPC_DeprecatedDST,
32
  PPC_FeatureTwoConstNR, PPC_FeatureUnalignedFloats,
33
  PPC_FeatureISA2_06,    INT_MAX
34
};
35
36
static int *P7Features[] = { P7InheritableFeatures };
37
38
// Power8
39
static int P8AdditionalFeatures[] = { PPC_DirectivePwr8,
40
              PPC_FeatureP8Altivec,
41
              PPC_FeatureP8Vector,
42
              PPC_FeatureP8Crypto,
43
              PPC_FeatureHTM,
44
              PPC_FeatureDirectMove,
45
              PPC_FeatureICBT,
46
              PPC_FeaturePartwordAtomic,
47
              PPC_FeatureQuadwordAtomic,
48
              PPC_FeaturePredictableSelectIsExpensive,
49
              PPC_FeatureISA2_07,
50
              PPC_FeatureCRBits,
51
              INT_MAX };
52
53
static int P8SpecificFeatures[] = { PPC_FeatureAddiLoadFusion,
54
            PPC_FeatureAddisLoadFusion, INT_MAX };
55
56
static int *P8Features[] = { P7InheritableFeatures, P8AdditionalFeatures,
57
           P8SpecificFeatures };
58
59
static int P9AdditionalFeatures[] = { PPC_DirectivePwr9,
60
              PPC_FeatureP9Altivec,
61
              PPC_FeatureP9Vector,
62
              PPC_FeaturePPCPreRASched,
63
              PPC_FeaturePPCPostRASched,
64
              PPC_FeatureISA3_0,
65
              PPC_FeaturePredictableSelectIsExpensive,
66
              INT_MAX };
67
68
static int P9SpecificFeatures[] = { PPC_FeatureVectorsUseTwoUnits, INT_MAX };
69
70
static int *P9Features[] = { P7InheritableFeatures, P8AdditionalFeatures,
71
           P9AdditionalFeatures, P9SpecificFeatures };
72
73
static int P10AdditionalFeatures[] = { PPC_FeatureStoreFusion,
74
               PPC_FeatureAddLogicalFusion,
75
               PPC_FeatureLogicalAddFusion,
76
               PPC_FeatureLogicalFusion,
77
               PPC_FeatureArithAddFusion,
78
               PPC_FeatureSha3Fusion,
79
               PPC_DirectivePwr10,
80
               PPC_FeatureISA3_1,
81
               PPC_FeaturePrefixInstrs,
82
               PPC_FeaturePCRelativeMemops,
83
               PPC_FeatureP10Vector,
84
               PPC_FeatureMMA,
85
               PPC_FeaturePairedVectorMemops,
86
               PPC_FeatureFastMFLR,
87
               INT_MAX };
88
89
static int *P10Features[] = { P7InheritableFeatures, P8AdditionalFeatures,
90
            P9AdditionalFeatures, P10AdditionalFeatures };
91
92
static int FutureAdditionalFeatures[] = { PPC_FeatureISAFuture, INT_MAX };
93
94
static int *FutureFeatures[] = { P7InheritableFeatures, P8AdditionalFeatures,
95
         P9AdditionalFeatures, P10AdditionalFeatures,
96
         FutureAdditionalFeatures };
97
98
static inline bool is_feature_of(int feature, int **feature_set, int set_size)
99
0
{
100
0
  for (size_t i = 0; i < set_size; ++i) {
101
0
    size_t j = 0;
102
0
    while (feature_set[i][j] != INT_MAX) {
103
0
      if (feature == feature_set[i][j]) {
104
0
        return true;
105
0
      }
106
0
      ++j;
107
0
    }
108
0
  }
109
0
  return false;
110
0
}
111
112
#define GET_REGINFO_MC_DESC
113
#include "PPCGenRegisterInfo.inc"
114
115
void PPC_init_mri(MCRegisterInfo *MRI)
116
1.09k
{
117
1.09k
  MCRegisterInfo_InitMCRegisterInfo(MRI, PPCRegDesc, PPC_REG_ENDING, 0, 0,
118
1.09k
            PPCMCRegisterClasses,
119
1.09k
            ARR_SIZE(PPCMCRegisterClasses), 0, 0,
120
1.09k
            PPCRegDiffLists, 0, PPCSubRegIdxLists,
121
1.09k
            ARR_SIZE(PPCSubRegIdxLists),
122
1.09k
            PPCRegEncodingTable);
123
1.09k
}
124
125
const char *PPC_reg_name(csh handle, unsigned int reg)
126
20.2k
{
127
20.2k
  if (reg > PPC_REG_INVALID && reg < PPC_REG_ENDING)
128
20.2k
    return PPC_LLVM_getRegisterName(reg);
129
0
  return NULL;
130
20.2k
}
131
132
// given internal insn id, return public instruction info
133
void PPC_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
134
23.7k
{
135
  // We do this after Instruction disassembly.
136
23.7k
}
137
138
#ifndef CAPSTONE_DIET
139
140
static const char *const insn_name_maps[] = {
141
#include "PPCGenCSMappingInsnName.inc"
142
};
143
144
static const name_map insn_alias_mnem_map[] = {
145
#include "PPCGenCSAliasMnemMap.inc"
146
  { PPC_INS_ALIAS_SLWI, "slwi" },
147
  { PPC_INS_ALIAS_SRWI, "srwi" },
148
  { PPC_INS_ALIAS_SLDI, "sldi" },
149
  { PPC_INS_ALIAS_END, NULL },
150
};
151
152
#endif
153
154
const char *PPC_insn_name(csh handle, unsigned int id)
155
23.7k
{
156
23.7k
#ifndef CAPSTONE_DIET
157
23.7k
  if (id < PPC_INS_ALIAS_END && id > PPC_INS_ALIAS_BEGIN) {
158
0
    if (id - PPC_INS_ALIAS_BEGIN >= ARR_SIZE(insn_alias_mnem_map))
159
0
      return NULL;
160
161
0
    return insn_alias_mnem_map[id - PPC_INS_ALIAS_BEGIN - 1].name;
162
0
  }
163
23.7k
  if (id >= PPC_INS_ENDING)
164
0
    return NULL;
165
166
23.7k
  return insn_name_maps[id];
167
#else
168
  return NULL;
169
#endif
170
23.7k
}
171
172
#ifndef CAPSTONE_DIET
173
static const name_map group_name_maps[] = {
174
  // generic groups
175
  { PPC_GRP_INVALID, NULL },
176
  { PPC_GRP_JUMP, "jump" },
177
  { PPC_GRP_CALL, "call" },
178
  { PPC_GRP_RET, "ret" },
179
  { PPC_GRP_INT, "int" },
180
  { PPC_GRP_IRET, "iret" },
181
  { PPC_GRP_PRIVILEGE, "privilege" },
182
  { PPC_GRP_BRANCH_RELATIVE, "branch_relative" },
183
184
// architecture-specific groups
185
#include "PPCGenCSFeatureName.inc"
186
};
187
#endif
188
189
const char *PPC_group_name(csh handle, unsigned int id)
190
23.2k
{
191
23.2k
#ifndef CAPSTONE_DIET
192
23.2k
  return id2name(group_name_maps, ARR_SIZE(group_name_maps), id);
193
#else
194
  return NULL;
195
#endif
196
23.2k
}
197
198
const insn_map ppc_insns[] = {
199
#include "PPCGenCSMappingInsn.inc"
200
};
201
202
void PPC_check_updates_cr0(MCInst *MI)
203
24.2k
{
204
24.2k
#ifndef CAPSTONE_DIET
205
24.2k
  if (!detail_is_set(MI))
206
0
    return;
207
24.2k
  cs_detail *detail = get_detail(MI);
208
31.9k
  for (int i = 0; i < detail->regs_write_count; ++i) {
209
8.72k
    if (detail->regs_write[i] == 0)
210
0
      return;
211
8.72k
    if (detail->regs_write[i] == PPC_REG_CR0) {
212
1.08k
      PPC_get_detail(MI)->update_cr0 = true;
213
1.08k
      return;
214
1.08k
    }
215
8.72k
  }
216
24.2k
#endif // CAPSTONE_DIET
217
24.2k
}
218
219
/// Parses and adds the branch predicate information and the BH field.
220
static void PPC_add_branch_predicates(MCInst *MI, const uint8_t *Bytes,
221
              size_t BytesLen)
222
24.2k
{
223
24.2k
  if (!detail_is_set(MI))
224
0
    return;
225
24.2k
#ifndef CAPSTONE_DIET
226
24.2k
  CS_ASSERT_RET(MI && Bytes);
227
24.2k
  if (BytesLen < 4)
228
327
    return;
229
230
23.9k
  ppc_insn_form form = ppc_insns[MI->Opcode].suppl_info.ppc.form;
231
23.9k
  bool b_form = ppc_is_b_form(form);
232
23.9k
  if (!(b_form || form == PPC_INSN_FORM_XLFORM_2))
233
19.4k
    return;
234
235
4.49k
  uint32_t Inst = readBytes32(MI, Bytes);
236
237
4.49k
  uint8_t bi = 0;
238
4.49k
  if (b_form)
239
4.11k
    bi = (Inst & PPC_INSN_FORM_B_BI_MASK) >> 16;
240
383
  else
241
383
    bi = (Inst & PPC_INSN_FORM_XL_BI_MASK) >> 16;
242
243
4.49k
  uint8_t bo = 0;
244
4.49k
  if (b_form)
245
4.11k
    bo = (Inst & PPC_INSN_FORM_B_BO_MASK) >> 21;
246
383
  else
247
383
    bo = (Inst & PPC_INSN_FORM_XL_BO_MASK) >> 21;
248
249
4.49k
  PPC_get_detail(MI)->bc.bo = bo;
250
4.49k
  PPC_get_detail(MI)->bc.bi = bi;
251
4.49k
  PPC_get_detail(MI)->bc.crX_bit = bi % 4;
252
4.49k
  PPC_get_detail(MI)->bc.crX = PPC_REG_CR0 + (bi / 4);
253
4.49k
  PPC_get_detail(MI)->bc.hint = PPC_get_hint(bo);
254
4.49k
  PPC_get_detail(MI)->bc.pred_cr = PPC_get_branch_pred(bi, bo, true);
255
4.49k
  PPC_get_detail(MI)->bc.pred_ctr = PPC_get_branch_pred(bi, bo, false);
256
257
4.49k
  if (ppc_is_b_form(form))
258
4.11k
    return;
259
260
383
  uint8_t bh = (Inst & PPC_INSN_FORM_XL_BH_MASK) >> 11;
261
383
  uint16_t xo = (Inst & PPC_INSN_FORM_XL_XO_MASK) >> 1;
262
  // Pre-defined values for XO fields (PowerISA v3.1B)
263
383
  uint16_t bcctr_xo_field = 528;
264
383
  uint16_t bctar_xo_field = 560;
265
383
  bool cond = (xo == bcctr_xo_field || xo == bctar_xo_field);
266
383
  switch (bh) {
267
0
  default:
268
0
    CS_ASSERT_RET(0 && "Invalid BH value.");
269
214
  case 0:
270
214
    PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_NO_SUBROUTINE_RET :
271
214
               PPC_BH_SUBROUTINE_RET;
272
214
    break;
273
45
  case 1:
274
45
    PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_RESERVED :
275
45
               PPC_BH_NO_SUBROUTINE_RET;
276
45
    break;
277
15
  case 2:
278
15
    PPC_get_detail(MI)->bc.bh = PPC_BH_RESERVED;
279
15
    break;
280
109
  case 3:
281
109
    PPC_get_detail(MI)->bc.bh = PPC_BH_NOT_PREDICTABLE;
282
109
    break;
283
383
  }
284
383
#endif // CAPSTONE_DIET
285
383
}
286
287
void PPC_set_instr_map_data(MCInst *MI, const uint8_t *Bytes, size_t BytesLen)
288
24.2k
{
289
24.2k
  map_cs_id(MI, ppc_insns, ARR_SIZE(ppc_insns));
290
24.2k
  map_implicit_reads(MI, ppc_insns);
291
24.2k
  map_implicit_writes(MI, ppc_insns);
292
24.2k
  map_groups(MI, ppc_insns);
293
24.2k
  PPC_add_branch_predicates(MI, Bytes, BytesLen);
294
24.2k
  PPC_check_updates_cr0(MI);
295
24.2k
  const ppc_suppl_info *suppl_info = map_get_suppl_info(MI, ppc_insns);
296
24.2k
  if (suppl_info) {
297
24.2k
    PPC_get_detail(MI)->format = suppl_info->form;
298
24.2k
  }
299
24.2k
}
300
301
/// Initialize PPCs detail.
302
void PPC_init_cs_detail(MCInst *MI)
303
24.2k
{
304
24.2k
  if (!detail_is_set(MI))
305
0
    return;
306
24.2k
  memset(get_detail(MI), 0, offsetof(cs_detail, ppc) + sizeof(cs_ppc));
307
24.2k
  PPC_get_detail(MI)->bc.bi = UINT8_MAX;
308
24.2k
  PPC_get_detail(MI)->bc.bo = UINT8_MAX;
309
24.2k
  PPC_get_detail(MI)->bc.crX = PPC_REG_INVALID;
310
24.2k
  PPC_get_detail(MI)->bc.crX_bit = PPC_BI_INVALID;
311
24.2k
  PPC_get_detail(MI)->bc.pred_cr = PPC_PRED_INVALID;
312
24.2k
  PPC_get_detail(MI)->bc.pred_ctr = PPC_PRED_INVALID;
313
24.2k
  PPC_get_detail(MI)->bc.hint = PPC_BR_NOT_GIVEN;
314
24.2k
  PPC_get_detail(MI)->bc.bh = PPC_BH_INVALID;
315
24.2k
}
316
317
void PPC_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info)
318
23.7k
{
319
23.7k
  MI->MRI = (MCRegisterInfo *)info;
320
23.7k
  MI->fillDetailOps = detail_is_set(MI);
321
23.7k
  MI->flat_insn->usesAliasDetails = map_use_alias_details(MI);
322
23.7k
  PPC_LLVM_printInst(MI, MI->address, "", O);
323
23.7k
#ifndef CAPSTONE_DIET
324
23.7k
  map_set_alias_id(MI, O, insn_alias_mnem_map,
325
23.7k
       ARR_SIZE(insn_alias_mnem_map));
326
23.7k
#endif
327
23.7k
}
328
329
bool PPC_getInstruction(csh handle, const uint8_t *bytes, size_t bytes_len,
330
      MCInst *instr, uint16_t *size, uint64_t address,
331
      void *info)
332
24.2k
{
333
24.2k
  PPC_init_cs_detail(instr);
334
24.2k
  DecodeStatus result = PPC_LLVM_getInstruction(
335
24.2k
    handle, bytes, bytes_len, instr, size, address, info);
336
24.2k
  PPC_set_instr_map_data(instr, bytes, bytes_len);
337
24.2k
  return result != MCDisassembler_Fail;
338
24.2k
}
339
340
bool PPC_getFeatureBits(unsigned int mode, unsigned int feature)
341
107k
{
342
107k
  if (feature == PPC_FeatureQPX) {
343
25.9k
    return (mode & CS_MODE_QPX) != 0;
344
81.7k
  } else if (feature == PPC_FeatureSPE) {
345
14.1k
    return (mode & CS_MODE_SPE) != 0;
346
67.5k
  } else if (feature == PPC_FeatureBookE) {
347
210
    return (mode & CS_MODE_BOOKE) != 0;
348
67.3k
  } else if (feature == PPC_FeaturePS) {
349
14.5k
    return (mode & CS_MODE_PS) != 0;
350
52.7k
  } else if (feature == PPC_FeatureModernAIXAs) {
351
24.0k
    return (mode & CS_MODE_MODERN_AIX_AS) != 0;
352
28.7k
  } else if (feature == PPC_AIXOS) {
353
145
    return (mode & CS_MODE_AIX_OS) != 0 ||
354
145
           (mode & CS_MODE_MODERN_AIX_AS) != 0;
355
28.6k
  } else if (feature == PPC_FeatureMSYNC) {
356
57
    return (mode & CS_MODE_MSYNC) != 0;
357
57
  }
358
28.5k
  if ((mode & (CS_MODE_PWR7 | CS_MODE_PWR8 | CS_MODE_PWR9 |
359
28.5k
         CS_MODE_PWR10 | CS_MODE_PPC_ISA_FUTURE)) == 0) {
360
    // By default support everything
361
28.5k
    return true;
362
28.5k
  }
363
364
0
  if (is_feature_of(feature, P7Features, ARR_SIZE(P7Features))) {
365
0
    return (mode & (CS_MODE_PWR7 | CS_MODE_PWR8 | CS_MODE_PWR9 |
366
0
        CS_MODE_PWR10 | CS_MODE_PPC_ISA_FUTURE));
367
0
  }
368
0
  if (is_feature_of(feature, P8Features, ARR_SIZE(P8Features))) {
369
0
    return (mode & (CS_MODE_PWR8 | CS_MODE_PWR9 | CS_MODE_PWR10 |
370
0
        CS_MODE_PPC_ISA_FUTURE));
371
0
  }
372
0
  if (is_feature_of(feature, P9Features, ARR_SIZE(P9Features))) {
373
0
    return (mode & (CS_MODE_PWR9 | CS_MODE_PWR10 |
374
0
        CS_MODE_PPC_ISA_FUTURE));
375
0
  }
376
0
  if (is_feature_of(feature, P10Features, ARR_SIZE(P10Features))) {
377
0
    return (mode & (CS_MODE_PWR10 | CS_MODE_PPC_ISA_FUTURE));
378
0
  }
379
0
  if (is_feature_of(feature, FutureFeatures, ARR_SIZE(FutureFeatures))) {
380
0
    return (mode & CS_MODE_PPC_ISA_FUTURE);
381
0
  }
382
383
  // By default support everything
384
0
  return true;
385
0
}
386
387
#ifndef CAPSTONE_DIET
388
static const map_insn_ops insn_operands[] = {
389
#include "PPCGenCSMappingInsnOp.inc"
390
};
391
#endif
392
393
/// @brief Handles memory operands.
394
/// @param MI The MCInst.
395
/// @param OpNum The operand index.
396
static void handle_memory_operand(MCInst *MI, unsigned OpNum)
397
7.07k
{
398
7.07k
  cs_op_type op_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM;
399
400
  // If this is called from printOperand() we do not know if a
401
  // register is a base or an offset reg (imm is always disponent).
402
  // So we assume the base register is always added before the offset register
403
  // and set the flag appropriately.
404
7.07k
  bool is_off_reg =
405
7.07k
    ((op_type == CS_OP_REG) &&
406
7.07k
     PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID);
407
7.07k
  PPC_set_detail_op_mem(MI, OpNum, MCInst_getOpVal(MI, OpNum),
408
7.07k
            is_off_reg);
409
7.07k
}
410
411
static void add_cs_detail_general(MCInst *MI, ppc_op_group op_group,
412
          unsigned OpNum)
413
71.3k
{
414
71.3k
  if (!detail_is_set(MI))
415
0
    return;
416
417
71.3k
  switch (op_group) {
418
0
  default:
419
0
    printf("General operand group %d not handled!\n", op_group);
420
0
    return;
421
45.7k
  case PPC_OP_GROUP_Operand: {
422
45.7k
    cs_op_type op_type = map_get_op_type(MI, OpNum);
423
424
    // Check for memory operands emitted via printOperand()
425
45.7k
    if (doing_mem(MI) && !(op_type & CS_OP_MEM)) {
426
      // Close previous memory operand
427
55
      set_mem_access(MI, false);
428
45.7k
    } else if (doing_mem(MI) || (op_type & CS_OP_MEM)) {
429
      // The memory operands use printOperand() to
430
      // emit their register and immediates.
431
7.07k
      if (!doing_mem(MI))
432
257
        set_mem_access(MI, true);
433
7.07k
      handle_memory_operand(MI, OpNum);
434
7.07k
      return;
435
7.07k
    }
436
437
38.7k
    CS_ASSERT_RET((op_type & CS_OP_MEM) ==
438
38.7k
            0); // doing_mem should have been true.
439
440
38.7k
    if (op_type == CS_OP_REG)
441
38.0k
      PPC_set_detail_op_reg(MI, OpNum,
442
38.0k
                MCInst_getOpVal(MI, OpNum));
443
674
    else if (op_type == CS_OP_IMM)
444
674
      PPC_set_detail_op_imm(MI, OpNum,
445
674
                MCInst_getOpVal(MI, OpNum));
446
0
    else
447
0
      CS_ASSERT_RET(0 && "Operand type not handled.");
448
38.7k
    break;
449
45.7k
  }
450
153
  case PPC_OP_GROUP_ImmZeroOperand:
451
1.22k
  case PPC_OP_GROUP_U1ImmOperand:
452
1.86k
  case PPC_OP_GROUP_U2ImmOperand:
453
2.59k
  case PPC_OP_GROUP_U3ImmOperand:
454
3.13k
  case PPC_OP_GROUP_U4ImmOperand:
455
6.47k
  case PPC_OP_GROUP_U5ImmOperand:
456
7.39k
  case PPC_OP_GROUP_U6ImmOperand:
457
7.53k
  case PPC_OP_GROUP_U7ImmOperand:
458
7.53k
  case PPC_OP_GROUP_U8ImmOperand:
459
7.54k
  case PPC_OP_GROUP_U10ImmOperand:
460
7.61k
  case PPC_OP_GROUP_U12ImmOperand:
461
7.61k
    PPC_set_detail_op_imm(MI, OpNum,
462
7.61k
              (uint32_t)MCInst_getOpVal(MI, OpNum));
463
7.61k
    break;
464
1.11k
  case PPC_OP_GROUP_U16ImmOperand:
465
1.11k
    if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum)))
466
      // Handled in printOperand()
467
0
      return;
468
1.11k
    PPC_set_detail_op_imm(MI, OpNum,
469
1.11k
              (uint32_t)MCInst_getOpVal(MI, OpNum));
470
1.11k
    break;
471
95
  case PPC_OP_GROUP_S5ImmOperand: {
472
95
    int Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
473
95
    Imm = SignExtend32((Imm), 5);
474
95
    PPC_set_detail_op_imm(MI, OpNum, Imm);
475
95
    break;
476
1.11k
  }
477
159
  case PPC_OP_GROUP_S12ImmOperand: {
478
159
    int64_t Imm = SignExtend64(
479
159
      MCOperand_getImm(MCInst_getOperand(MI, (OpNum))), 12);
480
159
    if (doing_mem(MI)) {
481
159
      PPC_set_detail_op_mem(MI, OpNum, Imm, true);
482
159
      break;
483
159
    }
484
0
    PPC_set_detail_op_imm(MI, OpNum, Imm);
485
0
    break;
486
159
  }
487
5.98k
  case PPC_OP_GROUP_S16ImmOperand: {
488
5.98k
    if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum)))
489
      // Handled in printOperand()
490
0
      return;
491
5.98k
    int16_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
492
5.98k
    if (doing_mem(MI)) {
493
4.57k
      PPC_set_detail_op_mem(MI, OpNum, Imm, true);
494
4.57k
      break;
495
4.57k
    }
496
1.41k
    PPC_set_detail_op_imm(MI, OpNum, Imm);
497
1.41k
    break;
498
5.98k
  }
499
305
  case PPC_OP_GROUP_S34ImmOperand: {
500
305
    if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum)))
501
      // Handled in printOperand()
502
0
      return;
503
305
    int64_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
504
305
    if (doing_mem(MI)) {
505
224
      PPC_set_detail_op_mem(MI, OpNum, Imm, true);
506
224
      break;
507
224
    }
508
81
    PPC_set_detail_op_imm(MI, OpNum, Imm);
509
81
    break;
510
305
  }
511
0
  case PPC_OP_GROUP_ATBitsAsHint: {
512
0
    PPC_get_detail(MI)->bc.hint =
513
0
      (ppc_br_hint)MCInst_getOpVal(MI, OpNum);
514
0
    break;
515
305
  }
516
1.93k
  case PPC_OP_GROUP_AbsBranchOperand: {
517
1.93k
    if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum)))
518
      // Handled in printOperand()
519
0
      return;
520
1.93k
    unsigned Val = MCInst_getOpVal(MI, OpNum) << 2;
521
1.93k
    PPC_check_safe_inc(MI);
522
1.93k
    PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM;
523
1.93k
    PPC_get_detail_op(MI, 0)->imm = Val;
524
1.93k
    PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
525
1.93k
    PPC_inc_op_count(MI);
526
1.93k
    break;
527
1.93k
  }
528
0
  case PPC_OP_GROUP_TLSCall:
529
    // Handled in PPCInstPrinter and printOperand.
530
0
    return;
531
390
  case PPC_OP_GROUP_crbitm: {
532
390
    unsigned CCReg = MCInst_getOpVal(MI, OpNum);
533
390
    PPC_set_detail_op_reg(MI, OpNum, CCReg);
534
390
    break;
535
1.93k
  }
536
2.36k
  case PPC_OP_GROUP_BranchOperand: {
537
2.36k
    if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNum))))
538
      // Handled in printOperand()
539
0
      return;
540
2.36k
    int32_t Imm = SignExtend32(
541
2.36k
      ((unsigned)MCInst_getOpVal(MI, (OpNum)) << 2), 32);
542
2.36k
    uint64_t Address = MI->address + Imm;
543
2.36k
    if (IS_32BIT(MI->csh->mode))
544
577
      Address &= 0xffffffff;
545
2.36k
    PPC_check_safe_inc(MI);
546
2.36k
    PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM;
547
2.36k
    PPC_get_detail_op(MI, 0)->imm = Address;
548
2.36k
    PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
549
2.36k
    PPC_inc_op_count(MI);
550
2.36k
    break;
551
2.36k
  }
552
  // Memory operands have their `set_mem_access()` calls
553
  // in PPCInstPrinter.
554
4.57k
  case PPC_OP_GROUP_MemRegImm:
555
5.40k
  case PPC_OP_GROUP_MemRegReg: {
556
    // These cases print 0 if the base register is R0.
557
    // So no printOperand() function is called.
558
    // We must handle the zero case here.
559
5.40k
    unsigned OpNumReg = 0;
560
5.40k
    if (op_group == PPC_OP_GROUP_MemRegImm)
561
4.57k
      OpNumReg = OpNum + 1;
562
828
    else
563
828
      OpNumReg = OpNum;
564
565
5.40k
    MCOperand *Op = MCInst_getOperand(MI, OpNumReg);
566
5.40k
    if (MCOperand_isReg(Op) && MCOperand_getReg(Op) == PPC_R0) {
567
0
      PPC_get_detail_op(MI, 0)->mem.base = PPC_REG_ZERO;
568
0
      PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM;
569
0
      PPC_get_detail_op(MI, 0)->access =
570
0
        map_get_op_access(MI, OpNum);
571
0
    }
572
5.40k
    break;
573
4.57k
  }
574
13
  case PPC_OP_GROUP_MemRegImmHash:
575
93
  case PPC_OP_GROUP_MemRegImm34:
576
237
  case PPC_OP_GROUP_MemRegImm34PCRel:
577
    // Handled in other printOperand functions.
578
237
    break;
579
71.3k
  }
580
71.3k
}
581
582
void PPC_add_cs_detail_1(MCInst *MI, ppc_op_group op_group, unsigned OpNum,
583
       const char *Modifier)
584
0
{
585
0
  if (!detail_is_set(MI) || !map_fill_detail_ops(MI))
586
0
    return;
587
588
0
  switch (op_group) {
589
0
  default:
590
0
    printf("Operand group %d not handled!\n", op_group);
591
0
    return;
592
0
  case PPC_OP_GROUP_PredicateOperand: {
593
0
    if ((strcmp(Modifier, "cc") == 0) ||
594
0
        (strcmp(Modifier, "pm") == 0)) {
595
0
      unsigned Val = MCInst_getOpVal(MI, OpNum);
596
0
      unsigned bo = Val & 0x1f;
597
0
      unsigned bi = (Val & 0x1e0) >> 5;
598
0
      PPC_get_detail(MI)->bc.bo = bo;
599
0
      PPC_get_detail(MI)->bc.bi = bi;
600
0
      PPC_get_detail(MI)->bc.crX_bit = bi % 4;
601
0
      PPC_get_detail(MI)->bc.crX = PPC_REG_CR0 + (bi / 4);
602
0
      PPC_get_detail(MI)->bc.pred_cr =
603
0
        PPC_get_branch_pred(bi, bo, true);
604
0
      PPC_get_detail(MI)->bc.pred_ctr =
605
0
        PPC_get_branch_pred(bi, bo, false);
606
0
      PPC_get_detail(MI)->bc.hint = PPC_get_hint(bo);
607
0
    }
608
0
    return;
609
0
  }
610
0
  }
611
0
}
612
613
/// Fills cs_detail with the data of the operand.
614
/// Calls to this function should not be added by hand! Please checkout the
615
/// patch `AddCSDetail` of the CppTranslator.
616
void PPC_add_cs_detail_0(MCInst *MI, ppc_op_group op_group, unsigned OpNo)
617
71.3k
{
618
71.3k
  if (!detail_is_set(MI) || !map_fill_detail_ops(MI))
619
0
    return;
620
621
71.3k
  switch (op_group) {
622
0
  default:
623
0
    printf("Operand group %d not handled!\n", op_group);
624
0
    return;
625
159
  case PPC_OP_GROUP_S12ImmOperand:
626
45.9k
  case PPC_OP_GROUP_Operand:
627
46.7k
  case PPC_OP_GROUP_MemRegReg:
628
47.6k
  case PPC_OP_GROUP_U6ImmOperand:
629
51.0k
  case PPC_OP_GROUP_U5ImmOperand:
630
55.6k
  case PPC_OP_GROUP_MemRegImm:
631
61.6k
  case PPC_OP_GROUP_S16ImmOperand:
632
62.2k
  case PPC_OP_GROUP_U2ImmOperand:
633
63.3k
  case PPC_OP_GROUP_U16ImmOperand:
634
65.7k
  case PPC_OP_GROUP_BranchOperand:
635
67.6k
  case PPC_OP_GROUP_AbsBranchOperand:
636
68.7k
  case PPC_OP_GROUP_U1ImmOperand:
637
68.7k
  case PPC_OP_GROUP_TLSCall:
638
69.4k
  case PPC_OP_GROUP_U3ImmOperand:
639
69.5k
  case PPC_OP_GROUP_S5ImmOperand:
640
69.5k
  case PPC_OP_GROUP_MemRegImmHash:
641
70.1k
  case PPC_OP_GROUP_U4ImmOperand:
642
70.1k
  case PPC_OP_GROUP_U10ImmOperand:
643
70.5k
  case PPC_OP_GROUP_crbitm:
644
70.8k
  case PPC_OP_GROUP_S34ImmOperand:
645
70.9k
  case PPC_OP_GROUP_ImmZeroOperand:
646
71.0k
  case PPC_OP_GROUP_MemRegImm34:
647
71.1k
  case PPC_OP_GROUP_MemRegImm34PCRel:
648
71.1k
  case PPC_OP_GROUP_U8ImmOperand:
649
71.2k
  case PPC_OP_GROUP_U12ImmOperand:
650
71.3k
  case PPC_OP_GROUP_U7ImmOperand:
651
71.3k
  case PPC_OP_GROUP_ATBitsAsHint: {
652
71.3k
    add_cs_detail_general(MI, op_group, OpNo);
653
71.3k
    return;
654
71.3k
  }
655
71.3k
  }
656
71.3k
}
657
658
void PPC_set_detail_op_mem(MCInst *MI, unsigned OpNum, uint64_t Val,
659
         bool is_off_reg)
660
12.0k
{
661
12.0k
  if (!detail_is_set(MI))
662
0
    return;
663
664
12.0k
  CS_ASSERT_RET(map_get_op_type(MI, OpNum) & CS_OP_MEM);
665
12.0k
  cs_op_type secondary_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM;
666
667
12.0k
  switch (secondary_type) {
668
0
  default:
669
0
    CS_ASSERT_RET(0 && "Secondary type not supported yet.");
670
7.07k
  case CS_OP_REG:
671
7.07k
    if (is_off_reg) {
672
1.09k
      PPC_get_detail_op(MI, 0)->mem.offset = Val;
673
1.09k
      if (PPC_get_detail_op(MI, 0)->mem.base !=
674
1.09k
          PPC_REG_INVALID)
675
1.09k
        set_mem_access(MI, false);
676
5.97k
    } else {
677
5.97k
      PPC_get_detail_op(MI, 0)->mem.base = Val;
678
5.97k
      if (MCInst_opIsTying(MI, OpNum))
679
0
        map_add_implicit_write(
680
0
          MI, MCInst_getOpVal(MI, OpNum));
681
5.97k
    }
682
7.07k
    break;
683
4.95k
  case CS_OP_IMM:
684
4.95k
    PPC_get_detail_op(MI, 0)->mem.disp = Val;
685
4.95k
    if (PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID)
686
0
      set_mem_access(MI, false);
687
4.95k
    break;
688
12.0k
  }
689
690
12.0k
  PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM;
691
12.0k
  PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
692
12.0k
}
693
694
/// Adds a register PPC operand at position OpNum and increases the op_count by
695
/// one.
696
void PPC_set_detail_op_reg(MCInst *MI, unsigned OpNum, ppc_reg Reg)
697
38.4k
{
698
38.4k
  if (!detail_is_set(MI))
699
0
    return;
700
38.4k
  PPC_check_safe_inc(MI);
701
38.4k
  CS_ASSERT_RET(!(map_get_op_type(MI, OpNum) & CS_OP_MEM));
702
38.4k
  CS_ASSERT_RET(map_get_op_type(MI, OpNum) == CS_OP_REG);
703
704
38.4k
  PPC_get_detail_op(MI, 0)->type = PPC_OP_REG;
705
38.4k
  PPC_get_detail_op(MI, 0)->reg = Reg;
706
38.4k
  PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
707
38.4k
  PPC_inc_op_count(MI);
708
38.4k
}
709
710
/// Adds an immediate PPC operand at position OpNum and increases the op_count
711
/// by one.
712
void PPC_set_detail_op_imm(MCInst *MI, unsigned OpNum, int64_t Imm)
713
11.0k
{
714
11.0k
  if (!detail_is_set(MI))
715
0
    return;
716
11.0k
  PPC_check_safe_inc(MI);
717
11.0k
  CS_ASSERT_RET(!(map_get_op_type(MI, OpNum) & CS_OP_MEM));
718
11.0k
  CS_ASSERT_RET(map_get_op_type(MI, OpNum) == CS_OP_IMM);
719
720
11.0k
  PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM;
721
11.0k
  PPC_get_detail_op(MI, 0)->imm = Imm;
722
11.0k
  PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
723
11.0k
  PPC_inc_op_count(MI);
724
11.0k
}
725
726
void PPC_set_mem_access(MCInst *MI, bool status)
727
13.1k
{
728
13.1k
  if (!detail_is_set(MI))
729
0
    return;
730
13.1k
  PPC_check_safe_inc(MI);
731
13.1k
  if ((!status && !doing_mem(MI)) || (status && doing_mem(MI)))
732
894
    return; // Nothing to do
733
734
12.2k
  set_doing_mem(MI, status);
735
12.2k
  if (status) {
736
6.12k
    PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM;
737
6.12k
    PPC_get_detail_op(MI, 0)->mem.base = PPC_REG_INVALID;
738
6.12k
    PPC_get_detail_op(MI, 0)->mem.offset = PPC_REG_INVALID;
739
6.12k
    PPC_get_detail_op(MI, 0)->mem.disp = 0;
740
741
6.12k
#ifndef CAPSTONE_DIET
742
6.12k
    uint8_t access =
743
6.12k
      map_get_op_access(MI, PPC_get_detail(MI)->op_count);
744
6.12k
    PPC_get_detail_op(MI, 0)->access = access;
745
6.12k
#endif
746
6.12k
  } else {
747
    // done, select the next operand slot
748
6.12k
    PPC_inc_op_count(MI);
749
6.12k
  }
750
12.2k
}
751
752
void PPC_setup_op(cs_ppc_op *op)
753
54
{
754
54
  memset(op, 0, sizeof(cs_ppc_op));
755
54
  op->type = PPC_OP_INVALID;
756
54
}
757
758
/// Inserts a immediate to the detail operands at @index.
759
/// Already present operands are moved.
760
void PPC_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Val,
761
         cs_ac_type access)
762
54
{
763
54
  if (!detail_is_set(MI) || !map_fill_detail_ops(MI))
764
0
    return;
765
766
54
  PPC_check_safe_inc(MI);
767
768
54
  cs_ppc_op op;
769
54
  PPC_setup_op(&op);
770
54
  op.type = PPC_OP_IMM;
771
54
  op.imm = Val;
772
54
  op.access = access;
773
774
54
  cs_ppc_op *ops = PPC_get_detail(MI)->operands;
775
54
  int i = PPC_get_detail(MI)->op_count - 1;
776
54
  for (; i >= index; --i) {
777
0
    ops[i + 1] = ops[i];
778
0
    if (i == index)
779
0
      break;
780
0
  }
781
54
  ops[index] = op;
782
54
  PPC_inc_op_count(MI);
783
54
}
784
785
#endif