Coverage Report

Created: 2023-09-25 06:24

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