Coverage Report

Created: 2024-09-08 06:22

/src/capstonenext/arch/PowerPC/PPCMapping.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
#include "capstone/ppc.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
#define GET_REGINFO_MC_DESC
20
#include "PPCGenRegisterInfo.inc"
21
22
void PPC_init_mri(MCRegisterInfo *MRI)
23
2.16k
{
24
2.16k
  MCRegisterInfo_InitMCRegisterInfo(MRI, PPCRegDesc, PPC_REG_ENDING, 0, 0,
25
2.16k
            PPCMCRegisterClasses,
26
2.16k
            ARR_SIZE(PPCMCRegisterClasses), 0, 0,
27
2.16k
            PPCRegDiffLists, 0, PPCSubRegIdxLists,
28
2.16k
            ARR_SIZE(PPCSubRegIdxLists),
29
2.16k
            PPCRegEncodingTable);
30
2.16k
}
31
32
const char *PPC_reg_name(csh handle, unsigned int reg)
33
48.6k
{
34
48.6k
  if (reg > PPC_REG_INVALID && reg < PPC_REG_ENDING)
35
48.6k
    return PPC_LLVM_getRegisterName(reg);
36
0
  return NULL;
37
48.6k
}
38
39
// given internal insn id, return public instruction info
40
void PPC_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
41
69.3k
{
42
  // We do this after Instruction disassembly.
43
69.3k
}
44
45
#ifndef CAPSTONE_DIET
46
47
static const char *const insn_name_maps[] = {
48
#include "PPCGenCSMappingInsnName.inc"
49
};
50
51
static const name_map insn_alias_mnem_map[] = {
52
#include "PPCGenCSAliasMnemMap.inc"
53
  { PPC_INS_ALIAS_SLWI, "slwi" },
54
  { PPC_INS_ALIAS_SRWI, "srwi" },
55
  { PPC_INS_ALIAS_SLDI, "sldi" },
56
  { PPC_INS_ALIAS_END, NULL },
57
};
58
59
#endif
60
61
const char *PPC_insn_name(csh handle, unsigned int id)
62
69.3k
{
63
69.3k
#ifndef CAPSTONE_DIET
64
69.3k
  if (id < PPC_INS_ALIAS_END && id > PPC_INS_ALIAS_BEGIN) {
65
0
    if (id - PPC_INS_ALIAS_BEGIN >= ARR_SIZE(insn_alias_mnem_map))
66
0
      return NULL;
67
68
0
    return insn_alias_mnem_map[id - PPC_INS_ALIAS_BEGIN - 1].name;
69
0
  }
70
69.3k
  if (id >= PPC_INS_ENDING)
71
0
    return NULL;
72
73
69.3k
  return insn_name_maps[id];
74
#else
75
  return NULL;
76
#endif
77
69.3k
}
78
79
#ifndef CAPSTONE_DIET
80
static const name_map group_name_maps[] = {
81
  // generic groups
82
  { PPC_GRP_INVALID, NULL },
83
  { PPC_GRP_JUMP, "jump" },
84
  { PPC_GRP_CALL, "call" },
85
  { PPC_GRP_INT, "int" },
86
  { PPC_GRP_PRIVILEGE, "privilege" },
87
  { PPC_GRP_BRANCH_RELATIVE, "branch_relative" },
88
89
// architecture-specific groups
90
#include "PPCGenCSFeatureName.inc"
91
};
92
#endif
93
94
const char *PPC_group_name(csh handle, unsigned int id)
95
54.5k
{
96
54.5k
#ifndef CAPSTONE_DIET
97
54.5k
  return id2name(group_name_maps, ARR_SIZE(group_name_maps), id);
98
#else
99
  return NULL;
100
#endif
101
54.5k
}
102
103
const insn_map ppc_insns[] = {
104
#include "PPCGenCSMappingInsn.inc"
105
};
106
107
void PPC_check_updates_cr0(MCInst *MI)
108
70.7k
{
109
70.7k
#ifndef CAPSTONE_DIET
110
70.7k
  if (!detail_is_set(MI))
111
0
    return;
112
70.7k
  cs_detail *detail = get_detail(MI);
113
89.5k
  for (int i = 0; i < detail->regs_write_count; ++i) {
114
24.7k
    if (detail->regs_write[i] == 0)
115
0
      return;
116
24.7k
    if (detail->regs_write[i] == PPC_REG_CR0) {
117
5.96k
      PPC_get_detail(MI)->update_cr0 = true;
118
5.96k
      return;
119
5.96k
    }
120
24.7k
  }
121
70.7k
#endif // CAPSTONE_DIET
122
70.7k
}
123
124
/// Parses and adds the branch predicate information and the BH field.
125
static void PPC_add_branch_predicates(MCInst *MI, const uint8_t *Bytes,
126
              size_t BytesLen)
127
70.7k
{
128
70.7k
  if (!detail_is_set(MI))
129
0
    return;
130
70.7k
#ifndef CAPSTONE_DIET
131
70.7k
  assert(MI && Bytes);
132
70.7k
  if (BytesLen < 4)
133
778
    return;
134
135
69.9k
  ppc_insn_form form = ppc_insns[MI->Opcode].suppl_info.ppc.form;
136
69.9k
  bool b_form = ppc_is_b_form(form);
137
69.9k
  if (!(b_form || form == PPC_INSN_FORM_XLFORM_2))
138
61.3k
    return;
139
140
8.55k
  uint32_t Inst = readBytes32(MI, Bytes);
141
142
8.55k
  uint8_t bi = 0;
143
8.55k
  if (b_form)
144
8.31k
    bi = (Inst & PPC_INSN_FORM_B_BI_MASK) >> 16;
145
236
  else
146
236
    bi = (Inst & PPC_INSN_FORM_XL_BI_MASK) >> 16;
147
148
8.55k
  uint8_t bo = 0;
149
8.55k
  if (b_form)
150
8.31k
    bo = (Inst & PPC_INSN_FORM_B_BO_MASK) >> 21;
151
236
  else
152
236
    bo = (Inst & PPC_INSN_FORM_XL_BO_MASK) >> 21;
153
154
8.55k
  PPC_get_detail(MI)->bc.bo = bo;
155
8.55k
  PPC_get_detail(MI)->bc.bi = bi;
156
8.55k
  PPC_get_detail(MI)->bc.crX_bit = bi % 4;
157
8.55k
  PPC_get_detail(MI)->bc.crX = PPC_REG_CR0 + (bi / 4);
158
8.55k
  PPC_get_detail(MI)->bc.hint = PPC_get_hint(bo);
159
8.55k
  PPC_get_detail(MI)->bc.pred_cr = PPC_get_branch_pred(bi, bo, true);
160
8.55k
  PPC_get_detail(MI)->bc.pred_ctr = PPC_get_branch_pred(bi, bo, false);
161
162
8.55k
  if (ppc_is_b_form(form))
163
8.31k
    return;
164
165
236
  uint8_t bh = (Inst & PPC_INSN_FORM_XL_BH_MASK) >> 11;
166
236
  uint16_t xo = (Inst & PPC_INSN_FORM_XL_XO_MASK) >> 1;
167
  // Pre-defined values for XO fields (PowerISA v3.1B)
168
236
  uint16_t bcctr_xo_field = 528;
169
236
  uint16_t bctar_xo_field = 560;
170
236
  bool cond = (xo == bcctr_xo_field || xo == bctar_xo_field);
171
236
  switch (bh) {
172
0
  default:
173
0
    assert(0 && "Invalid BH value.");
174
118
  case 0:
175
118
    PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_NO_SUBROUTINE_RET :
176
118
               PPC_BH_SUBROUTINE_RET;
177
118
    break;
178
31
  case 1:
179
31
    PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_RESERVED :
180
31
               PPC_BH_NO_SUBROUTINE_RET;
181
31
    break;
182
68
  case 2:
183
68
    PPC_get_detail(MI)->bc.bh = PPC_BH_RESERVED;
184
68
    break;
185
19
  case 3:
186
19
    PPC_get_detail(MI)->bc.bh = PPC_BH_NOT_PREDICTABLE;
187
19
    break;
188
236
  }
189
236
#endif // CAPSTONE_DIET
190
236
}
191
192
void PPC_set_instr_map_data(MCInst *MI, const uint8_t *Bytes, size_t BytesLen)
193
70.7k
{
194
70.7k
  map_cs_id(MI, ppc_insns, ARR_SIZE(ppc_insns));
195
70.7k
  map_implicit_reads(MI, ppc_insns);
196
70.7k
  map_implicit_writes(MI, ppc_insns);
197
70.7k
  map_groups(MI, ppc_insns);
198
70.7k
  PPC_add_branch_predicates(MI, Bytes, BytesLen);
199
70.7k
  PPC_check_updates_cr0(MI);
200
70.7k
  const ppc_suppl_info *suppl_info = map_get_suppl_info(MI, ppc_insns);
201
70.7k
  if (suppl_info) {
202
70.7k
    PPC_get_detail(MI)->format = suppl_info->form;
203
70.7k
  }
204
70.7k
}
205
206
/// Initialize PPCs detail.
207
void PPC_init_cs_detail(MCInst *MI)
208
70.7k
{
209
70.7k
  if (!detail_is_set(MI))
210
0
    return;
211
70.7k
  memset(get_detail(MI), 0, offsetof(cs_detail, ppc) + sizeof(cs_ppc));
212
70.7k
  PPC_get_detail(MI)->bc.bi = UINT8_MAX;
213
70.7k
  PPC_get_detail(MI)->bc.bo = UINT8_MAX;
214
70.7k
  PPC_get_detail(MI)->bc.crX = PPC_REG_INVALID;
215
70.7k
  PPC_get_detail(MI)->bc.crX_bit = PPC_BI_INVALID;
216
70.7k
  PPC_get_detail(MI)->bc.pred_cr = PPC_PRED_INVALID;
217
70.7k
  PPC_get_detail(MI)->bc.pred_ctr = PPC_PRED_INVALID;
218
70.7k
  PPC_get_detail(MI)->bc.hint = PPC_BR_NOT_GIVEN;
219
70.7k
  PPC_get_detail(MI)->bc.bh = PPC_BH_INVALID;
220
70.7k
}
221
222
void PPC_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info)
223
69.3k
{
224
69.3k
  MI->MRI = (MCRegisterInfo *)info;
225
69.3k
  MI->fillDetailOps = detail_is_set(MI);
226
69.3k
  MI->flat_insn->usesAliasDetails = map_use_alias_details(MI);
227
69.3k
  PPC_LLVM_printInst(MI, MI->address, "", O);
228
69.3k
#ifndef CAPSTONE_DIET
229
69.3k
  map_set_alias_id(MI, O, insn_alias_mnem_map,
230
69.3k
       ARR_SIZE(insn_alias_mnem_map));
231
69.3k
#endif
232
69.3k
}
233
234
bool PPC_getInstruction(csh handle, const uint8_t *bytes, size_t bytes_len,
235
      MCInst *instr, uint16_t *size, uint64_t address,
236
      void *info)
237
70.7k
{
238
70.7k
  PPC_init_cs_detail(instr);
239
70.7k
  DecodeStatus result = PPC_LLVM_getInstruction(
240
70.7k
    handle, bytes, bytes_len, instr, size, address, info);
241
70.7k
  PPC_set_instr_map_data(instr, bytes, bytes_len);
242
70.7k
  return result != MCDisassembler_Fail;
243
70.7k
}
244
245
bool PPC_getFeatureBits(unsigned int mode, unsigned int feature)
246
309k
{
247
309k
  if ((feature == PPC_FeatureQPX) && (mode & CS_MODE_QPX) == 0) {
248
36.5k
    return false;
249
273k
  } else if ((feature == PPC_FeatureSPE) && (mode & CS_MODE_SPE) == 0) {
250
36.5k
    return false;
251
236k
  } else if ((feature == PPC_FeatureBookE) &&
252
236k
       (mode & CS_MODE_BOOKE) == 0) {
253
138
    return false;
254
236k
  } else if ((feature == PPC_FeaturePS) && (mode & CS_MODE_PS) == 0) {
255
18.7k
    return false;
256
18.7k
  }
257
258
  // No AIX support for now.
259
217k
  if (feature == PPC_FeatureModernAIXAs || feature == PPC_AIXOS)
260
72.2k
    return false;
261
  // TODO Make it optional
262
145k
  if (feature == PPC_FeatureMSYNC)
263
49
    return false;
264
265
  // By default support everything
266
145k
  return true;
267
145k
}
268
269
#ifndef CAPSTONE_DIET
270
static const map_insn_ops insn_operands[] = {
271
#include "PPCGenCSMappingInsnOp.inc"
272
};
273
#endif
274
275
/// @brief Handles memory operands.
276
/// @param MI The MCInst.
277
/// @param OpNum The operand index.
278
static void handle_memory_operand(MCInst *MI, unsigned OpNum)
279
23.4k
{
280
23.4k
  cs_op_type op_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM;
281
282
  // If this is called from printOperand() we do not know if a
283
  // register is a base or an offset reg (imm is always disponent).
284
  // So we assume the base register is always added before the offset register
285
  // and set the flag appropriately.
286
23.4k
  bool is_off_reg =
287
23.4k
    ((op_type == CS_OP_REG) &&
288
23.4k
     PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID);
289
23.4k
  PPC_set_detail_op_mem(MI, OpNum, MCInst_getOpVal(MI, OpNum),
290
23.4k
            is_off_reg);
291
23.4k
}
292
293
static void add_cs_detail_general(MCInst *MI, ppc_op_group op_group,
294
          unsigned OpNum)
295
225k
{
296
225k
  if (!detail_is_set(MI))
297
0
    return;
298
299
225k
  switch (op_group) {
300
0
  default:
301
0
    printf("General operand group %d not handled!\n", op_group);
302
0
    return;
303
142k
  case PPC_OP_GROUP_Operand: {
304
142k
    cs_op_type op_type = map_get_op_type(MI, OpNum);
305
306
    // Check for memory operands emitted via printOperand()
307
142k
    if (doing_mem(MI) && !(op_type & CS_OP_MEM)) {
308
      // Close previous memory operand
309
412
      set_mem_access(MI, false);
310
141k
    } else if (doing_mem(MI) || (op_type & CS_OP_MEM)) {
311
      // The memory operands use printOperand() to
312
      // emit their register and immediates.
313
23.4k
      if (!doing_mem(MI))
314
902
        set_mem_access(MI, true);
315
23.4k
      handle_memory_operand(MI, OpNum);
316
23.4k
      return;
317
23.4k
    }
318
319
118k
    assert((op_type & CS_OP_MEM) ==
320
118k
           0); // doing_mem should have been true.
321
322
118k
    if (op_type == CS_OP_REG)
323
117k
      PPC_set_detail_op_reg(MI, OpNum,
324
117k
                MCInst_getOpVal(MI, OpNum));
325
823
    else if (op_type == CS_OP_IMM)
326
823
      PPC_set_detail_op_imm(MI, OpNum,
327
823
                MCInst_getOpVal(MI, OpNum));
328
0
    else
329
0
      assert(0 && "Operand type not handled.");
330
118k
    break;
331
118k
  }
332
118k
  case PPC_OP_GROUP_ImmZeroOperand:
333
3.34k
  case PPC_OP_GROUP_U1ImmOperand:
334
3.99k
  case PPC_OP_GROUP_U2ImmOperand:
335
5.15k
  case PPC_OP_GROUP_U3ImmOperand:
336
7.04k
  case PPC_OP_GROUP_U4ImmOperand:
337
20.3k
  case PPC_OP_GROUP_U5ImmOperand:
338
22.0k
  case PPC_OP_GROUP_U6ImmOperand:
339
22.1k
  case PPC_OP_GROUP_U7ImmOperand:
340
22.1k
  case PPC_OP_GROUP_U8ImmOperand:
341
22.2k
  case PPC_OP_GROUP_U10ImmOperand:
342
22.4k
  case PPC_OP_GROUP_U12ImmOperand:
343
22.4k
    PPC_set_detail_op_imm(MI, OpNum,
344
22.4k
              (uint32_t)MCInst_getOpVal(MI, OpNum));
345
22.4k
    break;
346
5.17k
  case PPC_OP_GROUP_U16ImmOperand:
347
5.17k
    if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum)))
348
      // Handled in printOperand()
349
0
      return;
350
5.17k
    PPC_set_detail_op_imm(MI, OpNum,
351
5.17k
              (uint32_t)MCInst_getOpVal(MI, OpNum));
352
5.17k
    break;
353
28
  case PPC_OP_GROUP_S5ImmOperand: {
354
28
    int Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
355
28
    Imm = SignExtend32((Imm), 5);
356
28
    PPC_set_detail_op_imm(MI, OpNum, Imm);
357
28
    break;
358
5.17k
  }
359
698
  case PPC_OP_GROUP_S12ImmOperand: {
360
698
    int64_t Imm = SignExtend64(
361
698
      MCOperand_getImm(MCInst_getOperand(MI, (OpNum))), 12);
362
698
    if (doing_mem(MI)) {
363
698
      PPC_set_detail_op_mem(MI, OpNum, Imm, true);
364
698
      break;
365
698
    }
366
0
    PPC_set_detail_op_imm(MI, OpNum, Imm);
367
0
    break;
368
698
  }
369
25.6k
  case PPC_OP_GROUP_S16ImmOperand: {
370
25.6k
    if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum)))
371
      // Handled in printOperand()
372
0
      return;
373
25.6k
    int16_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
374
25.6k
    if (doing_mem(MI)) {
375
16.3k
      PPC_set_detail_op_mem(MI, OpNum, Imm, true);
376
16.3k
      break;
377
16.3k
    }
378
9.27k
    PPC_set_detail_op_imm(MI, OpNum, Imm);
379
9.27k
    break;
380
25.6k
  }
381
648
  case PPC_OP_GROUP_S34ImmOperand: {
382
648
    if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum)))
383
      // Handled in printOperand()
384
0
      return;
385
648
    int64_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum)));
386
648
    if (doing_mem(MI)) {
387
437
      PPC_set_detail_op_mem(MI, OpNum, Imm, true);
388
437
      break;
389
437
    }
390
211
    PPC_set_detail_op_imm(MI, OpNum, Imm);
391
211
    break;
392
648
  }
393
0
  case PPC_OP_GROUP_ATBitsAsHint: {
394
0
    PPC_get_detail(MI)->bc.hint =
395
0
      (ppc_br_hint)MCInst_getOpVal(MI, OpNum);
396
0
    break;
397
648
  }
398
3.16k
  case PPC_OP_GROUP_AbsBranchOperand: {
399
3.16k
    if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum)))
400
      // Handled in printOperand()
401
0
      return;
402
3.16k
    unsigned Val = MCInst_getOpVal(MI, OpNum) << 2;
403
3.16k
    int32_t Imm = SignExtend32(Val, 32);
404
3.16k
    PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM;
405
3.16k
    PPC_get_detail_op(MI, 0)->imm = Imm;
406
3.16k
    PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
407
3.16k
    PPC_inc_op_count(MI);
408
3.16k
    break;
409
3.16k
  }
410
0
  case PPC_OP_GROUP_TLSCall:
411
    // Handled in PPCInstPrinter and printOperand.
412
0
    return;
413
65
  case PPC_OP_GROUP_crbitm: {
414
65
    unsigned CCReg = MCInst_getOpVal(MI, OpNum);
415
65
    PPC_set_detail_op_reg(MI, OpNum, CCReg);
416
65
    break;
417
3.16k
  }
418
6.38k
  case PPC_OP_GROUP_BranchOperand: {
419
6.38k
    if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNum))))
420
      // Handled in printOperand()
421
0
      return;
422
6.38k
    int32_t Imm = SignExtend32(
423
6.38k
      ((unsigned)MCInst_getOpVal(MI, (OpNum)) << 2), 32);
424
6.38k
    uint64_t Address = MI->address + Imm;
425
6.38k
    if (IS_32BIT(MI->csh->mode))
426
1.88k
      Address &= 0xffffffff;
427
6.38k
    PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM;
428
6.38k
    PPC_get_detail_op(MI, 0)->imm = Address;
429
6.38k
    PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
430
6.38k
    PPC_inc_op_count(MI);
431
6.38k
    break;
432
6.38k
  }
433
  // Memory operands have their `set_mem_access()` calls
434
  // in PPCInstPrinter.
435
16.3k
  case PPC_OP_GROUP_MemRegImm:
436
18.6k
  case PPC_OP_GROUP_MemRegReg: {
437
    // These cases print 0 if the base register is R0.
438
    // So no printOperand() function is called.
439
    // We must handle the zero case here.
440
18.6k
    unsigned OpNumReg = 0;
441
18.6k
    if (op_group == PPC_OP_GROUP_MemRegImm)
442
16.3k
      OpNumReg = OpNum + 1;
443
2.31k
    else
444
2.31k
      OpNumReg = OpNum;
445
446
18.6k
    MCOperand *Op = MCInst_getOperand(MI, OpNumReg);
447
18.6k
    if (MCOperand_isReg(Op) && MCOperand_getReg(Op) == PPC_R0) {
448
0
      PPC_get_detail_op(MI, 0)->mem.base = PPC_REG_ZERO;
449
0
      PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM;
450
0
      PPC_get_detail_op(MI, 0)->access =
451
0
        map_get_op_access(MI, OpNum);
452
0
    }
453
18.6k
    break;
454
16.3k
  }
455
21
  case PPC_OP_GROUP_MemRegImmHash:
456
212
  case PPC_OP_GROUP_MemRegImm34:
457
458
  case PPC_OP_GROUP_MemRegImm34PCRel:
458
    // Handled in other printOperand functions.
459
458
    break;
460
225k
  }
461
225k
}
462
463
/// Fills cs_detail with the data of the operand.
464
/// Calls to this function should not be added by hand! Please checkout the
465
/// patch `AddCSDetail` of the CppTranslator.
466
void PPC_add_cs_detail(MCInst *MI, ppc_op_group op_group, va_list args)
467
225k
{
468
225k
  if (!detail_is_set(MI) || !map_fill_detail_ops(MI))
469
0
    return;
470
471
225k
  switch (op_group) {
472
0
  default:
473
0
    printf("Operand group %d not handled!\n", op_group);
474
0
    return;
475
0
  case PPC_OP_GROUP_PredicateOperand: {
476
0
    unsigned OpNum = va_arg(args, unsigned);
477
0
    const char *Modifier = va_arg(args, const char *);
478
0
    if ((strcmp(Modifier, "cc") == 0) ||
479
0
        (strcmp(Modifier, "pm") == 0)) {
480
0
      unsigned Val = MCInst_getOpVal(MI, OpNum);
481
0
      unsigned bo = Val & 0x1f;
482
0
      unsigned bi = (Val & 0x1e0) >> 5;
483
0
      PPC_get_detail(MI)->bc.bo = bo;
484
0
      PPC_get_detail(MI)->bc.bi = bi;
485
0
      PPC_get_detail(MI)->bc.crX_bit = bi % 4;
486
0
      PPC_get_detail(MI)->bc.crX = PPC_REG_CR0 + (bi / 4);
487
0
      PPC_get_detail(MI)->bc.pred_cr =
488
0
        PPC_get_branch_pred(bi, bo, true);
489
0
      PPC_get_detail(MI)->bc.pred_ctr =
490
0
        PPC_get_branch_pred(bi, bo, false);
491
0
      PPC_get_detail(MI)->bc.hint = PPC_get_hint(bo);
492
0
    }
493
0
    return;
494
0
  }
495
698
  case PPC_OP_GROUP_S12ImmOperand:
496
142k
  case PPC_OP_GROUP_Operand:
497
145k
  case PPC_OP_GROUP_MemRegReg:
498
146k
  case PPC_OP_GROUP_U6ImmOperand:
499
160k
  case PPC_OP_GROUP_U5ImmOperand:
500
176k
  case PPC_OP_GROUP_MemRegImm:
501
202k
  case PPC_OP_GROUP_S16ImmOperand:
502
202k
  case PPC_OP_GROUP_U2ImmOperand:
503
207k
  case PPC_OP_GROUP_U16ImmOperand:
504
214k
  case PPC_OP_GROUP_BranchOperand:
505
217k
  case PPC_OP_GROUP_AbsBranchOperand:
506
220k
  case PPC_OP_GROUP_U1ImmOperand:
507
220k
  case PPC_OP_GROUP_TLSCall:
508
221k
  case PPC_OP_GROUP_U3ImmOperand:
509
221k
  case PPC_OP_GROUP_S5ImmOperand:
510
221k
  case PPC_OP_GROUP_MemRegImmHash:
511
223k
  case PPC_OP_GROUP_U4ImmOperand:
512
223k
  case PPC_OP_GROUP_U10ImmOperand:
513
223k
  case PPC_OP_GROUP_crbitm:
514
224k
  case PPC_OP_GROUP_S34ImmOperand:
515
224k
  case PPC_OP_GROUP_ImmZeroOperand:
516
224k
  case PPC_OP_GROUP_MemRegImm34:
517
225k
  case PPC_OP_GROUP_MemRegImm34PCRel:
518
225k
  case PPC_OP_GROUP_U8ImmOperand:
519
225k
  case PPC_OP_GROUP_U12ImmOperand:
520
225k
  case PPC_OP_GROUP_U7ImmOperand:
521
225k
  case PPC_OP_GROUP_ATBitsAsHint: {
522
225k
    unsigned OpNum = va_arg(args, unsigned);
523
225k
    add_cs_detail_general(MI, op_group, OpNum);
524
225k
    return;
525
225k
  }
526
225k
  }
527
225k
}
528
529
void PPC_set_detail_op_mem(MCInst *MI, unsigned OpNum, uint64_t Val,
530
         bool is_off_reg)
531
40.9k
{
532
40.9k
  if (!detail_is_set(MI))
533
0
    return;
534
535
40.9k
  assert(map_get_op_type(MI, OpNum) & CS_OP_MEM);
536
40.9k
  cs_op_type secondary_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM;
537
538
40.9k
  switch (secondary_type) {
539
0
  default:
540
0
    assert(0 && "Secondary type not supported yet.");
541
23.4k
  case CS_OP_REG:
542
23.4k
    if (is_off_reg) {
543
2.88k
      PPC_get_detail_op(MI, 0)->mem.offset = Val;
544
2.88k
      if (PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID)
545
2.88k
        set_mem_access(MI, false);
546
20.6k
    }  else {
547
20.6k
      PPC_get_detail_op(MI, 0)->mem.base = Val;
548
20.6k
      if (MCInst_opIsTying(MI, OpNum))
549
0
        map_add_implicit_write(MI, MCInst_getOpVal(MI, OpNum));
550
20.6k
    }
551
23.4k
    break;
552
17.4k
  case CS_OP_IMM:
553
17.4k
    PPC_get_detail_op(MI, 0)->mem.disp = Val;
554
17.4k
    if (PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID)
555
0
      set_mem_access(MI, false);
556
17.4k
    break;
557
40.9k
  }
558
559
40.9k
  PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM;
560
40.9k
  PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
561
40.9k
}
562
563
/// Adds a register PPC operand at position OpNum and increases the op_count by
564
/// one.
565
void PPC_set_detail_op_reg(MCInst *MI, unsigned OpNum, ppc_reg Reg)
566
117k
{
567
117k
  if (!detail_is_set(MI))
568
0
    return;
569
117k
  assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM));
570
117k
  assert(map_get_op_type(MI, OpNum) == CS_OP_REG);
571
572
117k
  PPC_get_detail_op(MI, 0)->type = PPC_OP_REG;
573
117k
  PPC_get_detail_op(MI, 0)->reg = Reg;
574
117k
  PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
575
117k
  PPC_inc_op_count(MI);
576
117k
}
577
578
/// Adds an immediate PPC operand at position OpNum and increases the op_count
579
/// by one.
580
void PPC_set_detail_op_imm(MCInst *MI, unsigned OpNum, int64_t Imm)
581
38.0k
{
582
38.0k
  if (!detail_is_set(MI))
583
0
    return;
584
38.0k
  assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM));
585
38.0k
  assert(map_get_op_type(MI, OpNum) == CS_OP_IMM);
586
587
38.0k
  PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM;
588
38.0k
  PPC_get_detail_op(MI, 0)->imm = Imm;
589
38.0k
  PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
590
38.0k
  PPC_inc_op_count(MI);
591
38.0k
}
592
593
void PPC_set_mem_access(MCInst *MI, bool status)
594
44.0k
{
595
44.0k
  if (!detail_is_set(MI))
596
0
    return;
597
44.0k
  if ((!status && !doing_mem(MI)) || (status && doing_mem(MI)))
598
2.46k
    return; // Nothing to do
599
600
41.6k
  set_doing_mem(MI, status);
601
41.6k
  if (status) {
602
20.8k
    PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM;
603
20.8k
    PPC_get_detail_op(MI, 0)->mem.base = PPC_REG_INVALID;
604
20.8k
    PPC_get_detail_op(MI, 0)->mem.offset = PPC_REG_INVALID;
605
20.8k
    PPC_get_detail_op(MI, 0)->mem.disp = 0;
606
607
20.8k
#ifndef CAPSTONE_DIET
608
20.8k
    uint8_t access =
609
20.8k
      map_get_op_access(MI, PPC_get_detail(MI)->op_count);
610
20.8k
    PPC_get_detail_op(MI, 0)->access = access;
611
20.8k
#endif
612
20.8k
  } else {
613
    // done, select the next operand slot
614
20.8k
    PPC_inc_op_count(MI);
615
20.8k
  }
616
41.6k
}
617
618
void PPC_setup_op(cs_ppc_op *op)
619
682
{
620
682
  memset(op, 0, sizeof(cs_ppc_op));
621
682
  op->type = PPC_OP_INVALID;
622
682
}
623
624
/// Inserts a immediate to the detail operands at @index.
625
/// Already present operands are moved.
626
void PPC_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Val,
627
         cs_ac_type access)
628
682
{
629
682
  if (!detail_is_set(MI) || !map_fill_detail_ops(MI))
630
0
    return;
631
632
682
  assert(PPC_get_detail(MI)->op_count < PPC_NUM_OPS);
633
634
682
  cs_ppc_op op;
635
682
  PPC_setup_op(&op);
636
682
  op.type = PPC_OP_IMM;
637
682
  op.imm = Val;
638
682
  op.access = access;
639
640
682
  cs_ppc_op *ops = PPC_get_detail(MI)->operands;
641
682
  int i = PPC_get_detail(MI)->op_count - 1;
642
682
  for (; i >= index; --i) {
643
176
    ops[i + 1] = ops[i];
644
176
    if (i == index)
645
176
      break;
646
176
  }
647
682
  ops[index] = op;
648
682
  PPC_inc_op_count(MI);
649
682
}
650
651
#endif