Skip to content

Commit 3f8a42e

Browse files
committed
Decode branch predicates and BH fields.
1 parent a2b4184 commit 3f8a42e

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

arch/PowerPC/PPCMapping.c

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,72 @@ void PPC_check_updates_cr0(MCInst *MI)
9999
#endif // CAPSTONE_DIET
100100
}
101101

102-
void PPC_set_instr_map_data(MCInst *MI)
102+
/// Parses and adds the branch predicate information and the BH field.
103+
static void PPC_add_branch_predicates(MCInst *MI, const uint8_t *Bytes, size_t BytesLen) {
104+
#ifndef CAPSTONE_DIET
105+
assert(MI && Bytes);
106+
if (BytesLen < 4)
107+
return;
108+
109+
ppc_insn_form form = ppc_insns[MI->Opcode].suppl_info.ppc.form;
110+
bool b_form = ppc_is_b_form(form);
111+
if (!(b_form || form == PPC_INSN_FORM_XLFORM_2))
112+
return;
113+
114+
uint32_t Inst = readBytes32(MI, Bytes);
115+
printf("0x%x\n", Inst);
116+
117+
uint8_t bi = 0;
118+
if (b_form)
119+
bi = (Inst & PPC_INSN_FORM_B_BI_MASK) >> 16;
120+
else
121+
bi = (Inst & PPC_INSN_FORM_XL_BI_MASK) >> 16;
122+
123+
uint8_t bo = 0;
124+
if (b_form)
125+
bo = (Inst & PPC_INSN_FORM_B_BO_MASK) >> 21;
126+
else
127+
bo = (Inst & PPC_INSN_FORM_XL_BO_MASK) >> 21;
128+
129+
PPC_get_detail(MI)->bc.bi = bi;
130+
PPC_get_detail(MI)->bc.bo = bo;
131+
PPC_get_detail(MI)->bc.hint = PPC_get_hint(bo);
132+
PPC_get_detail(MI)->bc.pred = (bi << 5) | bo;
133+
if (ppc_is_b_form(form))
134+
return;
135+
136+
uint8_t bh = (Inst & PPC_INSN_FORM_XL_BH_MASK) >> 11;
137+
uint16_t xo = (Inst & PPC_INSN_FORM_XL_XO_MASK) >> 1;
138+
// Pre-defined values for XO fields (PowerISA v3.1B)
139+
uint16_t bcctr_xo_field = 528;
140+
uint16_t bctar_xo_field = 560;
141+
bool cond = (xo == bcctr_xo_field || xo == bctar_xo_field);
142+
switch (bh) {
143+
default:
144+
assert(0 && "Invalid BH value.");
145+
case 0b00:
146+
PPC_get_detail(MI)->bh = cond ? PPC_BH_NO_SUBROUTINE_RET : PPC_BH_SUBROUTINE_RET;
147+
break;
148+
case 0b01:
149+
PPC_get_detail(MI)->bh = cond ? PPC_BH_RESERVED : PPC_BH_NO_SUBROUTINE_RET;
150+
break;
151+
case 0b10:
152+
PPC_get_detail(MI)->bh = PPC_BH_RESERVED;
153+
break;
154+
case 0b11:
155+
PPC_get_detail(MI)->bh = PPC_BH_NOT_PREDICTABLE;
156+
break;
157+
}
158+
#endif // CAPSTONE_DIET
159+
}
160+
161+
void PPC_set_instr_map_data(MCInst *MI, const uint8_t *Bytes, size_t BytesLen)
103162
{
104163
map_cs_id(MI, ppc_insns, ARR_SIZE(ppc_insns));
105164
map_implicit_reads(MI, ppc_insns);
106165
map_implicit_writes(MI, ppc_insns);
107166
map_groups(MI, ppc_insns);
167+
PPC_add_branch_predicates(MI, Bytes, BytesLen);
108168
PPC_check_updates_cr0(MI);
109169
}
110170

@@ -128,7 +188,7 @@ bool PPC_getInstruction(csh handle, const uint8_t *bytes, size_t bytes_len,
128188
void *info) {
129189
PPC_init_cs_detail(instr);
130190
DecodeStatus result = PPC_LLVM_getInstruction(handle, bytes, bytes_len, instr, size, address, info);
131-
PPC_set_instr_map_data(instr);
191+
PPC_set_instr_map_data(instr, bytes, bytes_len);
132192
return result != MCDisassembler_Fail;
133193
}
134194

arch/PowerPC/PPCMapping.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ void PPC_set_detail_op_mem(MCInst *MI, unsigned OpNum, uint64_t Val, bool is_off
6868

6969
ppc_pred PPC_get_no_hint_pred(unsigned Code);
7070
void PPC_check_updates_cr0(MCInst *MI);
71-
void PPC_set_instr_map_data(MCInst *MI);
71+
void PPC_set_instr_map_data(MCInst *MI, const uint8_t *Bytes, size_t BytesLen);
7272

7373
#endif
7474

include/capstone/ppc.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,16 @@ static inline ppc_br_hint PPC_get_hint(uint8_t bo) {
140140
return PPC_BR_NOT_GIVEN;
141141
}
142142

143+
/// Encodes the different meanings of the BH field.
144+
/// The enum values does NOT match the BH field values!
145+
typedef enum {
146+
PPC_BH_INVALID = 0,
147+
PPC_BH_SUBROUTINE_RET,
148+
PPC_BH_NO_SUBROUTINE_RET,
149+
PPC_BH_NOT_PREDICTABLE,
150+
PPC_BH_RESERVED,
151+
} ppc_bh;
152+
143153
/// Operand type for instruction's operands
144154
typedef enum ppc_op_type {
145155
PPC_OP_INVALID = CS_OP_INVALID, ///< Uninitialized.
@@ -725,6 +735,9 @@ typedef struct cs_ppc {
725735
/// branch code for branch instructions
726736
ppc_bc bc;
727737

738+
/// The BH field hint if any is present.
739+
ppc_bh bh;
740+
728741
/// if update_cr0 = True, then this 'dot' insn updates CR0
729742
bool update_cr0;
730743

0 commit comments

Comments
 (0)