radare2/libr/anal/p/anal_ppc_cs.c
2022-10-17 01:14:56 +02:00

1438 lines
36 KiB
C

/* radare2 - LGPL - Copyright 2013-2022 - pancake */
#include <r_anal.h>
#include <r_lib.h>
#include <capstone/capstone.h>
#include <capstone/ppc.h>
#include "../../asm/arch/ppc/libvle/vle.h"
#include "../../asm/arch/ppc/libps/libps.h"
#define SPR_HID0 0x3f0 /* Hardware Implementation Register 0 */
#define SPR_HID1 0x3f1 /* Hardware Implementation Register 1 */
#define SPR_HID2 0x3f3 /* Hardware Implementation Register 2 */
#define SPR_HID4 0x3f4 /* Hardware Implementation Register 4 */
#define SPR_HID5 0x3f6 /* Hardware Implementation Register 5 */
#define SPR_HID6 0x3f9 /* Hardware Implementation Register 6 */
struct Getarg {
csh handle;
cs_insn *insn;
int bits;
};
#define INSOPS insn->detail->ppc.op_count
#define INSOP(n) insn->detail->ppc.operands[n]
#define IMM(x) (ut64)(insn->detail->ppc.operands[x].imm)
#ifndef PFMT32x
#define PFMT32x "lx"
#endif
static ut64 mask64(ut64 mb, ut64 me) {
ut64 maskmb = UT64_MAX >> mb;
ut64 maskme = UT64_MAX << (63 - me);
return (mb <= me) ? maskmb & maskme : maskmb | maskme;
}
static ut32 mask32(ut32 mb, ut32 me) {
ut32 maskmb = UT32_MAX >> mb;
ut32 maskme = UT32_MAX << (31 - me);
return (mb <= me) ? maskmb & maskme : maskmb | maskme;
}
#define cmaskbuf_SIZEOF 32
static const char* cmask64(char *cmaskbuf, const char *mb_c, const char *me_c) {
ut64 mb = 0;
ut64 me = 0;
if (mb_c) {
mb = strtol (mb_c, NULL, 16);
}
if (me_c) {
me = strtol (me_c, NULL, 16);
}
snprintf (cmaskbuf, cmaskbuf_SIZEOF, "0x%"PFMT64x, mask64 (mb, me));
return cmaskbuf;
}
static const char* cmask32(char *cmaskbuf, const char *mb_c, const char *me_c) {
ut32 mb = 0;
ut32 me = 0;
if (mb_c) {
mb = strtol (mb_c, NULL, 16);
}
if (me_c) {
me = strtol (me_c, NULL, 16);
}
snprintf (cmaskbuf, cmaskbuf_SIZEOF, "0x%"PFMT32x, mask32 (mb, me));
return cmaskbuf;
}
static char *getarg2(struct Getarg *gop, int n, const char *setstr) {
cs_insn *insn = gop->insn;
csh handle = gop->handle;
static R_TH_LOCAL char words[8][64];
cs_ppc_op op;
if (n < 0 || n >= 8) {
return NULL;
}
op = INSOP (n);
switch (op.type) {
case PPC_OP_INVALID:
words[n][0] = '\0';
//strcpy (words[n], "invalid");
break;
case PPC_OP_REG:
snprintf (words[n], sizeof (words[n]),
"%s%s", cs_reg_name (handle, op.reg), setstr);
break;
case PPC_OP_IMM:
snprintf (words[n], sizeof (words[n]),
"0x%"PFMT64x"%s", (ut64) op.imm, setstr);
break;
case PPC_OP_MEM:
snprintf (words[n], sizeof (words[n]),
"%"PFMT64d",%s,+,%s",
(ut64) op.mem.disp,
cs_reg_name (handle, op.mem.base), setstr);
break;
case PPC_OP_CRX: // Condition Register field
snprintf (words[n], sizeof (words[n]),
"%"PFMT64d"%s", (ut64) op.imm, setstr);
break;
}
return words[n];
}
static ut64 getarg(struct Getarg *gop, int n) {
ut64 value = 0;
cs_insn *insn = gop->insn;
cs_ppc_op op;
if (n < 0 || n >= 8) {
return 0;
}
op = INSOP (n);
switch (op.type) {
case PPC_OP_INVALID:
break;
case PPC_OP_REG:
value = op.reg;
break;
case PPC_OP_IMM:
value = (ut64) op.imm;
break;
case PPC_OP_MEM:
value = op.mem.disp + op.mem.base;
break;
case PPC_OP_CRX: // Condition Register field
value = (ut64) op.imm;
break;
}
return value;
}
static const char* getspr(struct Getarg *gop, int n) {
static R_TH_LOCAL char cspr[16];
ut32 spr = 0;
if (n < 0 || n >= 8) {
return NULL;
}
spr = getarg (gop, 0);
switch (spr) {
case SPR_HID0:
return "hid0";
case SPR_HID1:
return "hid1";
case SPR_HID2:
return "hid2";
case SPR_HID4:
return "hid4";
case SPR_HID5:
return "hid5";
case SPR_HID6:
return "hid6";
default:
snprintf (cspr, sizeof (cspr), "spr_%u", spr);
break;
}
return cspr;
}
static void opex(RStrBuf *buf, csh handle, cs_insn *insn) {
int i;
PJ *pj = pj_new ();
if (!pj) {
return;
}
pj_o (pj);
pj_ka (pj, "operands");
cs_ppc *x = &insn->detail->ppc;
for (i = 0; i < x->op_count; i++) {
cs_ppc_op *op = x->operands + i;
pj_o (pj);
switch (op->type) {
case PPC_OP_REG:
pj_ks (pj, "type", "reg");
pj_ks (pj, "value", cs_reg_name (handle, op->reg));
break;
case PPC_OP_IMM:
pj_ks (pj, "type", "imm");
pj_kN (pj, "value", op->imm);
break;
case PPC_OP_MEM:
pj_ks (pj, "type", "mem");
if (op->mem.base != PPC_REG_INVALID) {
pj_ks (pj, "base", cs_reg_name (handle, op->mem.base));
}
pj_ki (pj, "disp", op->mem.disp);
break;
default:
pj_ks (pj, "type", "invalid");
break;
}
pj_end (pj); /* o operand */
}
pj_end (pj); /* a operands */
pj_end (pj);
r_strbuf_init (buf);
r_strbuf_append (buf, pj_string (pj));
pj_free (pj);
}
#define PPCSPR(n) getspr(&gop, n)
#define ARG(n) getarg2(&gop, n, "")
#define ARG2(n,m) getarg2(&gop, n, m)
static bool set_reg_profile(RAnal *anal) {
const char *p = NULL;
if (anal->config->bits == 32) {
p =
"=PC pc\n"
"=SP r1\n"
"=BP r31\n"
"=SR srr1\n" // status register ??
"=SN r3\n" // also for ret
"=R0 r3\n" // ret
"=A0 r3\n" // also for ret
"=A1 r4\n"
"=A2 r5\n"
"=A3 r6\n"
"=A4 r7\n"
"=A5 r8\n"
"=A6 r6\n"
"gpr srr0 .32 0 0\n"
"gpr srr1 .32 4 0\n"
"gpr r0 .32 8 0\n"
"gpr r1 .32 12 0\n"
"gpr r2 .32 16 0\n"
"gpr r3 .32 20 0\n"
"gpr r4 .32 24 0\n"
"gpr r5 .32 28 0\n"
"gpr r6 .32 32 0\n"
"gpr r7 .32 36 0\n"
"gpr r8 .32 40 0\n"
"gpr r9 .32 44 0\n"
"gpr r10 .32 48 0\n"
"gpr r11 .32 52 0\n"
"gpr r12 .32 56 0\n"
"gpr r13 .32 60 0\n"
"gpr r14 .32 64 0\n"
"gpr r15 .32 68 0\n"
"gpr r16 .32 72 0\n"
"gpr r17 .32 76 0\n"
"gpr r18 .32 80 0\n"
"gpr r19 .32 84 0\n"
"gpr r20 .32 88 0\n"
"gpr r21 .32 92 0\n"
"gpr r22 .32 96 0\n"
"gpr r23 .32 100 0\n"
"gpr r24 .32 104 0\n"
"gpr r25 .32 108 0\n"
"gpr r26 .32 112 0\n"
"gpr r27 .32 116 0\n"
"gpr r28 .32 120 0\n"
"gpr r29 .32 124 0\n"
"gpr r30 .32 128 0\n"
"gpr r31 .32 132 0\n"
"gpr lr .32 136 0\n"
"gpr ctr .32 140 0\n"
"gpr msr .32 144 0\n"
"gpr pc .32 148 0\n"
"gpr cr .64 152 0\n"
"gpr cr0 .8 152 0\n"
"gpr cr1 .8 153 0\n"
"gpr cr2 .8 154 0\n"
"gpr cr3 .8 155 0\n"
"gpr cr4 .8 156 0\n"
"gpr cr5 .8 157 0\n"
"gpr cr6 .8 158 0\n"
"gpr cr7 .8 159 0\n"
"gpr xer .32 160 0\n"
"gpr mq .32 164 0\n"
"gpr fpscr .32 168 0\n"
"gpr vrsave .32 172 0\n"
"gpr pvr .32 176 0\n"
"gpr dccr .32 180 0\n"
"gpr iccr .32 184 0\n"
"gpr dear .32 188 0\n"
"gpr hid0 .32 192 0\n"
"gpr hid1 .32 196 0\n"
"gpr hid2 .32 200 0\n"
"gpr hid3 .32 204 0\n"
"gpr hid4 .32 208 0\n"
"gpr hid5 .32 212 0\n"
"gpr hid6 .32 216 0\n"
"gpr ibat0 .64 220 0\n"
"gpr ibat1 .64 228 0\n"
"gpr ibat2 .64 236 0\n"
"gpr ibat3 .64 244 0\n"
"gpr ibat0l .32 220 0\n"
"gpr ibat1l .32 228 0\n"
"gpr ibat2l .32 236 0\n"
"gpr ibat3l .32 244 0\n"
"gpr ibat0u .32 224 0\n"
"gpr ibat1u .32 232 0\n"
"gpr ibat2u .32 240 0\n"
"gpr ibat3u .32 248 0\n"
"gpr dbat0 .64 256 0\n"
"gpr dbat1 .64 264 0\n"
"gpr dbat2 .64 272 0\n"
"gpr dbat3 .64 280 0\n"
"gpr dbat0l .32 256 0\n"
"gpr dbat1l .32 264 0\n"
"gpr dbat2l .32 272 0\n"
"gpr dbat3l .32 280 0\n"
"gpr dbat0u .32 260 0\n"
"gpr dbat1u .32 268 0\n"
"gpr dbat2u .32 276 0\n"
"gpr dbat3u .32 284 0\n"
"gpr mask .32 288 0\n";
} else {
p =
"=PC pc\n"
"=SP r1\n"
"=SR srr1\n" // status register ??
"=SN r0\n" // also for ret
"=R0 r3\n" // ret
"=A0 r3\n" // also for ret
"=A1 r4\n"
"=A2 r5\n"
"=A3 r6\n"
"=A4 r7\n"
"=A5 r8\n"
"=A6 r6\n"
"gpr srr0 .64 0 0\n"
"gpr srr1 .64 8 0\n"
"gpr r0 .64 16 0\n"
"gpr r1 .64 24 0\n"
"gpr r2 .64 32 0\n"
"gpr r3 .64 40 0\n"
"gpr r4 .64 48 0\n"
"gpr r5 .64 56 0\n"
"gpr r6 .64 64 0\n"
"gpr r7 .64 72 0\n"
"gpr r8 .64 80 0\n"
"gpr r9 .64 88 0\n"
"gpr r10 .64 96 0\n"
"gpr r11 .64 104 0\n"
"gpr r12 .64 112 0\n"
"gpr r13 .64 120 0\n"
"gpr r14 .64 128 0\n"
"gpr r15 .64 136 0\n"
"gpr r16 .64 144 0\n"
"gpr r17 .64 152 0\n"
"gpr r18 .64 160 0\n"
"gpr r19 .64 168 0\n"
"gpr r20 .64 176 0\n"
"gpr r21 .64 184 0\n"
"gpr r22 .64 192 0\n"
"gpr r23 .64 200 0\n"
"gpr r24 .64 208 0\n"
"gpr r25 .64 216 0\n"
"gpr r26 .64 224 0\n"
"gpr r27 .64 232 0\n"
"gpr r28 .64 240 0\n"
"gpr r29 .64 248 0\n"
"gpr r30 .64 256 0\n"
"gpr r31 .64 264 0\n"
"gpr lr .64 272 0\n"
"gpr ctr .64 280 0\n"
"gpr msr .64 288 0\n"
"gpr pc .64 296 0\n"
"gpr cr .64 304 0\n"
"gpr cr0 .8 304 0\n"
"gpr cr1 .8 305 0\n"
"gpr cr2 .8 306 0\n"
"gpr cr3 .8 307 0\n"
"gpr cr4 .8 308 0\n"
"gpr cr5 .8 309 0\n"
"gpr cr6 .8 310 0\n"
"gpr cr7 .8 311 0\n"
"gpr xer .64 312 0\n"
"gpr mq .64 320 0\n"
"gpr fpscr .64 328 0\n"
"gpr vrsave .64 336 0\n"
"gpr pvr .64 344 0\n"
"gpr dccr .32 352 0\n"
"gpr iccr .32 356 0\n"
"gpr dear .32 360 0\n"
"gpr hid0 .64 364 0\n"
"gpr hid1 .64 372 0\n"
"gpr hid2 .64 380 0\n"
"gpr hid3 .64 388 0\n"
"gpr hid4 .64 396 0\n"
"gpr hid5 .64 404 0\n"
"gpr hid6 .64 412 0\n"
"gpr ibat0 .64 420 0\n"
"gpr ibat1 .64 428 0\n"
"gpr ibat2 .64 436 0\n"
"gpr ibat3 .64 444 0\n"
"gpr ibat0l .32 420 0\n"
"gpr ibat1l .32 428 0\n"
"gpr ibat2l .32 436 0\n"
"gpr ibat3l .32 444 0\n"
"gpr ibat0u .32 424 0\n"
"gpr ibat1u .32 432 0\n"
"gpr ibat2u .32 440 0\n"
"gpr ibat3u .32 448 0\n"
"gpr dbat0 .64 456 0\n"
"gpr dbat1 .64 464 0\n"
"gpr dbat2 .64 472 0\n"
"gpr dbat3 .64 480 0\n"
"gpr dbat0l .32 456 0\n"
"gpr dbat1l .32 464 0\n"
"gpr dbat2l .32 472 0\n"
"gpr dbat3l .32 480 0\n"
"gpr dbat0u .32 460 0\n"
"gpr dbat1u .32 468 0\n"
"gpr dbat2u .32 476 0\n"
"gpr dbat3u .32 484 0\n"
"gpr mask .64 488 0\n"; //not a real register used on complex functions
}
return r_reg_set_profile_string (anal->reg, p);
}
static int analop_vle(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
vle_t* instr = NULL;
vle_handle handle = {0};
op->size = 2;
if (len > 1 && !vle_init (&handle, buf, len) && (instr = vle_next (&handle))) {
op->size = instr->size;
op->type = instr->anal_op;
//op->id = instr->type;
switch (op->type) {
case R_ANAL_OP_TYPE_ILL:
break;
case R_ANAL_OP_TYPE_ADD:
break;
case R_ANAL_OP_TYPE_AND:
break;
case R_ANAL_OP_TYPE_CALL:
op->jump = addr + instr->fields[instr->n - 1].value;
op->fail = addr + op->size;
break;
case R_ANAL_OP_TYPE_CCALL:
op->eob = true;
op->jump = addr + instr->fields[instr->n - 1].value;
op->fail = addr + op->size;
break;
case R_ANAL_OP_TYPE_CJMP:
op->cond = instr->cond; //R_ANAL_COND_NE;
op->eob = true;
op->jump = addr + instr->fields[instr->n - 1].value;
op->fail = addr + op->size;
break;
case R_ANAL_OP_TYPE_CMP:
break;
case R_ANAL_OP_TYPE_JMP:
op->jump = addr + instr->fields[instr->n - 1].value;
break;
case R_ANAL_OP_TYPE_LOAD:
break;
case R_ANAL_OP_TYPE_MOV:
break;
case R_ANAL_OP_TYPE_MUL:
break;
case R_ANAL_OP_TYPE_NOT:
break;
case R_ANAL_OP_TYPE_OR:
break;
case R_ANAL_OP_TYPE_ROR:
break;
case R_ANAL_OP_TYPE_ROL:
break;
case R_ANAL_OP_TYPE_RCALL:
op->eob = true;
break;
case R_ANAL_OP_TYPE_RET:
op->eob = true;
break;
case R_ANAL_OP_TYPE_RJMP:
break;
case R_ANAL_OP_TYPE_SHL:
break;
case R_ANAL_OP_TYPE_SHR:
break;
case R_ANAL_OP_TYPE_STORE:
break;
case R_ANAL_OP_TYPE_SUB:
break;
case R_ANAL_OP_TYPE_SWI:
break;
case R_ANAL_OP_TYPE_SYNC:
break;
case R_ANAL_OP_TYPE_TRAP:
break;
case R_ANAL_OP_TYPE_XOR:
break;
default:
//eprintf ("Missing an R_ANAL_OP_TYPE (%"PFMT64u")\n", op->type);
break;
}
vle_free (instr);
return op->size;
}
return -1;
}
static int parse_reg_name(RRegItem *reg, csh handle, cs_insn *insn, int reg_num) {
if (!reg) {
return -1;
}
switch (INSOP (reg_num).type) {
case PPC_OP_REG:
reg->name = (char *)cs_reg_name (handle, INSOP (reg_num).reg);
break;
case PPC_OP_MEM:
if (INSOP (reg_num).mem.base != PPC_REG_INVALID) {
reg->name = (char *)cs_reg_name (handle, INSOP (reg_num).mem.base);
}
break;
default :
break;
}
return 0;
}
static RRegItem base_regs[4];
static void create_src_dst(RAnalOp *op) {
r_vector_push (&op->srcs, NULL);
r_vector_push (&op->srcs, NULL);
r_vector_push (&op->srcs, NULL);
r_vector_push (&op->dsts, NULL);
ZERO_FILL (base_regs[0]);
ZERO_FILL (base_regs[1]);
ZERO_FILL (base_regs[2]);
ZERO_FILL (base_regs[3]);
}
static void set_src_dst(RAnalValue *val, csh *handle, cs_insn *insn, int x) {
cs_ppc_op ppcop = INSOP (x);
parse_reg_name (&base_regs[x], *handle, insn, x);
switch (ppcop.type) {
case PPC_OP_REG:
break;
case PPC_OP_MEM:
val->delta = ppcop.mem.disp;
break;
case PPC_OP_IMM:
val->imm = ppcop.imm;
break;
default:
break;
}
val->reg = &base_regs[x];
}
static void op_fillval(RAnalOp *op, csh handle, cs_insn *insn) {
create_src_dst (op);
RAnalValue *src0 = r_vector_index_ptr (&op->srcs, 0);
RAnalValue *src1 = r_vector_index_ptr (&op->srcs, 1);
RAnalValue *src2 = r_vector_index_ptr (&op->srcs, 2);
RAnalValue *dst = r_vector_index_ptr (&op->dsts, 0);
switch (op->type & R_ANAL_OP_TYPE_MASK) {
case R_ANAL_OP_TYPE_MOV:
case R_ANAL_OP_TYPE_CMP:
case R_ANAL_OP_TYPE_ADD:
case R_ANAL_OP_TYPE_SUB:
case R_ANAL_OP_TYPE_MUL:
case R_ANAL_OP_TYPE_DIV:
case R_ANAL_OP_TYPE_SHR:
case R_ANAL_OP_TYPE_SHL:
case R_ANAL_OP_TYPE_SAL:
case R_ANAL_OP_TYPE_SAR:
case R_ANAL_OP_TYPE_OR:
case R_ANAL_OP_TYPE_AND:
case R_ANAL_OP_TYPE_XOR:
case R_ANAL_OP_TYPE_NOR:
case R_ANAL_OP_TYPE_NOT:
case R_ANAL_OP_TYPE_LOAD:
case R_ANAL_OP_TYPE_LEA:
case R_ANAL_OP_TYPE_ROR:
case R_ANAL_OP_TYPE_ROL:
case R_ANAL_OP_TYPE_CAST:
set_src_dst (src2, &handle, insn, 3);
set_src_dst (src1, &handle, insn, 2);
set_src_dst (src0, &handle, insn, 1);
set_src_dst (dst, &handle, insn, 0);
break;
case R_ANAL_OP_TYPE_STORE:
set_src_dst (dst, &handle, insn, 1);
set_src_dst (src0, &handle, insn, 0);
break;
}
}
static char *shrink(char *op) {
if (!op) {
return NULL;
}
size_t len = strlen(op);
if (!len) {
return NULL;
}
op[len - 1] = 0;
return op;
}
#define CSINC PPC
#define CSINC_MODE \
((a->config->bits == 64) ? CS_MODE_64 : (a->config->bits == 32) ? CS_MODE_32 : 0) \
| (R_ARCH_CONFIG_IS_BIG_ENDIAN (a->config)? CS_MODE_BIG_ENDIAN: CS_MODE_LITTLE_ENDIAN)
#include "capstone.inc"
static int decompile_vle(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
vle_t* instr = 0;
vle_handle handle = {0};
if (len < 2) {
return -1;
}
if (!vle_init (&handle, buf, len) && (instr = vle_next (&handle))) {
op->size = instr->size;
char buf_asm[64];
vle_snprint (buf_asm, sizeof (buf_asm), addr, instr);
op->mnemonic = strdup (buf_asm);
vle_free (instr);
} else {
op->mnemonic = strdup ("invalid");
op->size = 2;
return -1;
}
return op->size;
}
static int decompile_ps(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
ppcps_t instr = {0};
if (len < 4) {
eprintf ("not eno\n");
return -1;
}
op->size = 4;
const ut32 data = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
if (libps_decode (data, &instr) < 1) {
return -1;
}
char buf_asm[64] = {0};
libps_snprint (buf_asm, sizeof (buf_asm), addr, &instr);
op->mnemonic = strdup (buf_asm);
// eprintf ("Mnemonic (%s)\n", buf_asm);
return op->size;
}
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, RAnalOpMask mask) {
char cmaskbuf[cmaskbuf_SIZEOF] = {0};
csh handle = init_capstone (a);
if (handle == 0) {
return -1;
}
int ret;
cs_insn *insn;
char *op1;
const char *cpu = a->config->cpu;
// capstone-next
int n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn);
if (mask & R_ARCH_OP_MASK_DISASM) {
ret = -1;
if (cpu && !strcmp (cpu, "vle")) {
if (!R_ARCH_CONFIG_IS_BIG_ENDIAN (a->config)) {
return -1;
}
// vle is big-endian only
ret = decompile_vle (a, op, addr, buf, len);
} else if (cpu && !strcmp (cpu, "ps")) {
// libps is big-endian only
if (!R_ARCH_CONFIG_IS_BIG_ENDIAN (a->config)) {
return -1;
}
ret = decompile_ps (a, op, addr, buf, len);
}
if (ret < 1) {
if (n > 0) {
op->mnemonic = r_str_newf ("%s%s%s",
insn->mnemonic,
insn->op_str[0]? " ": "",
insn->op_str);
} else {
op->mnemonic = strdup ("invalid");
}
}
}
if (cpu && !strcmp (cpu, "vle")) {
// vle is big-endian only
if (!R_ARCH_CONFIG_IS_BIG_ENDIAN (a->config)) {
return -1;
}
ret = analop_vle (a, op, addr, buf, len);
if (ret >= 0) {
return op->size;
}
}
op->size = 4;
if (n < 1) {
op->type = R_ANAL_OP_TYPE_ILL;
} else {
if (mask & R_ARCH_OP_MASK_OPEX) {
opex (&op->opex, handle, insn);
}
struct Getarg gop = {
.handle = handle,
.insn = insn,
.bits = a->config->bits
};
op->size = insn->size;
op->id = insn->id;
switch (insn->id) {
#if CS_API_MAJOR >= 4
case PPC_INS_CMPB:
#endif
case PPC_INS_CMPD:
case PPC_INS_CMPDI:
case PPC_INS_CMPLD:
case PPC_INS_CMPLDI:
case PPC_INS_CMPLW:
case PPC_INS_CMPLWI:
case PPC_INS_CMPW:
case PPC_INS_CMPWI:
#if CS_API_MAJOR > 4
case PPC_INS_CMP:
case PPC_INS_CMPI:
#endif
op->type = R_ANAL_OP_TYPE_CMP;
op->sign = true;
if (ARG (2)[0] == '\0') {
esilprintf (op, "%s,%s,-,0xff,&,cr0,=", ARG (1), ARG (0));
} else {
esilprintf (op, "%s,%s,-,0xff,&,%s,=", ARG (2), ARG (1), ARG (0));
}
break;
case PPC_INS_MFLR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "lr,%s,=", ARG (0));
break;
case PPC_INS_MTLR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "%s,lr,=", ARG (0));
break;
case PPC_INS_MR:
case PPC_INS_LI:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "%s,%s,=", ARG (1), ARG (0));
break;
case PPC_INS_LIS:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "%s0000,%s,=", ARG (1), ARG (0));
break;
case PPC_INS_CLRLWI:
op->type = R_ANAL_OP_TYPE_AND;
esilprintf (op, "%s,%s,&,%s,=", ARG (1), cmask32 (cmaskbuf, ARG (2), "0x1F"), ARG (0));
break;
case PPC_INS_RLWINM:
op->type = R_ANAL_OP_TYPE_ROL;
esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask32 (cmaskbuf, ARG (3), ARG (4)), ARG (0));
break;
case PPC_INS_SC:
op->type = R_ANAL_OP_TYPE_SWI;
esilprintf (op, "0,$");
break;
case PPC_INS_EXTSB:
op->sign = true;
op->type = R_ANAL_OP_TYPE_MOV;
if (a->config->bits == 64) {
esilprintf (op, "%s,0x80,&,?{,0xFFFFFFFFFFFFFF00,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0));
} else {
esilprintf (op, "%s,0x80,&,?{,0xFFFFFF00,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0));
}
break;
case PPC_INS_EXTSH:
op->sign = true;
if (a->config->bits == 64) {
esilprintf (op, "%s,0x8000,&,?{,0xFFFFFFFFFFFF0000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0));
} else {
esilprintf (op, "%s,0x8000,&,?{,0xFFFF0000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0));
}
break;
case PPC_INS_EXTSW:
op->sign = true;
esilprintf (op, "%s,0x80000000,&,?{,0xFFFFFFFF00000000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0));
break;
case PPC_INS_SYNC:
case PPC_INS_ISYNC:
case PPC_INS_LWSYNC:
case PPC_INS_MSYNC:
case PPC_INS_PTESYNC:
case PPC_INS_TLBSYNC:
case PPC_INS_SLBIA:
case PPC_INS_SLBIE:
case PPC_INS_SLBMFEE:
case PPC_INS_SLBMTE:
case PPC_INS_EIEIO:
case PPC_INS_NOP:
op->type = R_ANAL_OP_TYPE_NOP;
esilprintf (op, ",");
break;
case PPC_INS_STW:
case PPC_INS_STWUX:
case PPC_INS_STWX:
case PPC_INS_STWCX:
op->type = R_ANAL_OP_TYPE_STORE;
esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[4]"));
break;
case PPC_INS_STWU:
op->type = R_ANAL_OP_TYPE_STORE;
op1 = shrink(ARG(1));
if (!op1) {
break;
}
esilprintf (op, "%s,%s,=[4],%s=", ARG (0), op1, op1);
if (strstr (op1, "r1")) {
op->stackop = R_ANAL_STACK_INC;
op->stackptr = -atoi (op1);
}
break;
case PPC_INS_STWBRX:
op->type = R_ANAL_OP_TYPE_STORE;
break;
case PPC_INS_STB:
op->type = R_ANAL_OP_TYPE_STORE;
esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[1]"));
break;
case PPC_INS_STBU:
op->type = R_ANAL_OP_TYPE_STORE;
op1 = shrink(ARG(1));
if (!op1) {
break;
}
esilprintf (op, "%s,%s,=[1],%s=", ARG (0), op1, op1);
break;
case PPC_INS_STH:
op->type = R_ANAL_OP_TYPE_STORE;
esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[2]"));
break;
case PPC_INS_STHU:
op->type = R_ANAL_OP_TYPE_STORE;
op1 = shrink(ARG(1));
if (!op1) {
break;
}
esilprintf (op, "%s,%s,=[2],%s=", ARG (0), op1, op1);
break;
case PPC_INS_STD:
op->type = R_ANAL_OP_TYPE_STORE;
esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[8]"));
break;
case PPC_INS_STDU:
op->type = R_ANAL_OP_TYPE_STORE;
op1 = shrink(ARG(1));
if (!op1) {
break;
}
esilprintf (op, "%s,%s,=[8],%s=", ARG (0), op1, op1);
break;
case PPC_INS_LBZ:
#if CS_API_MAJOR >= 4
case PPC_INS_LBZCIX:
#endif
case PPC_INS_LBZU:
case PPC_INS_LBZUX:
op->type = R_ANAL_OP_TYPE_LOAD;
op1 = shrink(ARG(1));
if (!op1) {
break;
}
esilprintf (op, "%s,[1],%s,=,%s=", op1, ARG (0), op1);
break;
case PPC_INS_LBZX:
op->type = R_ANAL_OP_TYPE_LOAD;
esilprintf (op, "%s,%s,=", ARG2 (1, "[1]"), ARG (0));
break;
case PPC_INS_LD:
case PPC_INS_LDARX:
#if CS_API_MAJOR >= 4
case PPC_INS_LDCIX:
#endif
case PPC_INS_LDU:
case PPC_INS_LDUX:
op->type = R_ANAL_OP_TYPE_LOAD;
op1 = shrink(ARG(1));
if (!op1) {
break;
}
esilprintf (op, "%s,[8],%s,=,%s=", op1, ARG (0), op1);
break;
case PPC_INS_LDX:
op->type = R_ANAL_OP_TYPE_LOAD;
esilprintf (op, "%s,%s,=", ARG2 (1, "[8]"), ARG (0));
break;
case PPC_INS_LDBRX:
op->type = R_ANAL_OP_TYPE_LOAD;
break;
case PPC_INS_LFD:
case PPC_INS_LFDU:
case PPC_INS_LFDUX:
case PPC_INS_LFDX:
case PPC_INS_LFIWAX:
case PPC_INS_LFIWZX:
case PPC_INS_LFS:
case PPC_INS_LFSU:
case PPC_INS_LFSUX:
case PPC_INS_LFSX:
op->type = R_ANAL_OP_TYPE_LOAD;
esilprintf (op, "%s,%s,=", ARG2 (1, "[4]"), ARG (0));
break;
case PPC_INS_LHA:
case PPC_INS_LHAU:
case PPC_INS_LHAUX:
case PPC_INS_LHAX:
case PPC_INS_LHZ:
case PPC_INS_LHZU:
op->type = R_ANAL_OP_TYPE_LOAD;
op1 = shrink(ARG(1));
if (!op1) {
break;
}
esilprintf (op, "%s,[2],%s,=,%s=", op1, ARG (0), op1);
break;
case PPC_INS_LHBRX:
op->type = R_ANAL_OP_TYPE_LOAD;
break;
case PPC_INS_LWA:
case PPC_INS_LWARX:
case PPC_INS_LWAUX:
case PPC_INS_LWAX:
case PPC_INS_LWZ:
#if CS_API_MAJOR >= 4
case PPC_INS_LWZCIX:
#endif
case PPC_INS_LWZX:
op->type = R_ANAL_OP_TYPE_LOAD;
esilprintf (op, "%s,%s,=", ARG2 (1, "[4]"), ARG (0));
break;
case PPC_INS_LWZU:
case PPC_INS_LWZUX:
op->type = R_ANAL_OP_TYPE_LOAD;
op1 = shrink(ARG(1));
if (!op1) {
break;
}
esilprintf (op, "%s,[4],%s,=,%s=", op1, ARG (0), op1);
break;
case PPC_INS_LWBRX:
op->type = R_ANAL_OP_TYPE_LOAD;
break;
case PPC_INS_SLW:
case PPC_INS_SLWI:
op->type = R_ANAL_OP_TYPE_SHL;
esilprintf (op, "%s,%s,<<,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_SRW:
case PPC_INS_SRWI:
op->type = R_ANAL_OP_TYPE_SHR;
esilprintf (op, "%s,%s,>>,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_MULLI:
op->sign = true;
case PPC_INS_MULLW:
case PPC_INS_MULLD:
op->type = R_ANAL_OP_TYPE_MUL;
esilprintf (op, "%s,%s,*,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_SUB:
case PPC_INS_SUBC:
case PPC_INS_SUBF:
case PPC_INS_SUBFIC:
case PPC_INS_SUBFZE:
op->type = R_ANAL_OP_TYPE_SUB;
esilprintf (op, "%s,%s,-,%s,=", ARG (1), ARG (2), ARG (0));
break;
case PPC_INS_ADD:
case PPC_INS_ADDI:
op->sign = true;
op->type = R_ANAL_OP_TYPE_ADD;
esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_CRCLR:
case PPC_INS_CRSET:
case PPC_INS_CRMOVE:
case PPC_INS_CRXOR:
case PPC_INS_CRNOR:
case PPC_INS_CRNOT:
// reset conditional bits
op->type = R_ANAL_OP_TYPE_MOV;
break;
case PPC_INS_ADDC:
case PPC_INS_ADDIC:
op->type = R_ANAL_OP_TYPE_ADD;
esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_ADDIS:
op->type = R_ANAL_OP_TYPE_ADD;
esilprintf (op, "16,%s,<<,%s,+,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_ADDE:
case PPC_INS_ADDME:
case PPC_INS_ADDZE:
op->type = R_ANAL_OP_TYPE_ADD;
esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_MTSPR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "%s,%s,=", ARG (1), PPCSPR (0));
break;
case PPC_INS_BCTR: // switch table here
op->type = R_ANAL_OP_TYPE_UJMP;
esilprintf (op, "ctr,pc,=");
break;
case PPC_INS_BCTRL: // switch table here
op->type = R_ANAL_OP_TYPE_CALL;
esilprintf (op, "pc,lr,=,ctr,pc,=");
break;
#if CS_VERSION_MAJOR >= 5
case PPC_INS_BNE:
case PPC_INS_BNEA:
case PPC_INS_BNECTR:
case PPC_INS_BNECTRL:
case PPC_INS_BNEL:
case PPC_INS_BNELA:
case PPC_INS_BNELR:
case PPC_INS_BNELRL:
case PPC_INS_BNG:
case PPC_INS_BNGA:
case PPC_INS_BNGCTR:
case PPC_INS_BNGCTRL:
case PPC_INS_BNGL:
case PPC_INS_BNGLA:
case PPC_INS_BNGLR:
case PPC_INS_BNGLRL:
case PPC_INS_BNL:
case PPC_INS_BNLA:
case PPC_INS_BNLCTR:
case PPC_INS_BNLCTRL:
case PPC_INS_BNLL:
case PPC_INS_BNLLA:
case PPC_INS_BNLLR:
case PPC_INS_BNLLRL:
case PPC_INS_BNS:
case PPC_INS_BNSA:
case PPC_INS_BNSCTR:
case PPC_INS_BNSCTRL:
case PPC_INS_BNSL:
case PPC_INS_BNSLA:
case PPC_INS_BNSLR:
case PPC_INS_BNSLRL:
case PPC_INS_BNU:
case PPC_INS_BNUA:
case PPC_INS_BNUCTR:
case PPC_INS_BNUCTRL:
case PPC_INS_BNUL:
case PPC_INS_BNULA:
case PPC_INS_BNULR:
case PPC_INS_BNULRL:
#endif
case PPC_INS_B:
case PPC_INS_BC:
case PPC_INS_BA:
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = ARG (1)[0] == '\0' ? IMM (0) : IMM (1);
op->fail = addr + op->size;
switch (insn->detail->ppc.bc) {
case PPC_BC_LT:
if (ARG (1)[0] == '\0') {
esilprintf (op, "0x80,cr0,&,!,!,?{,%s,pc,=,},", ARG (0));
} else {
esilprintf (op, "0x80,%s,&,!,!,?{,%s,pc,=,},", ARG (0), ARG (1));
}
break;
case PPC_BC_LE:
if (ARG (1)[0] == '\0') {
esilprintf (op, "0x80,cr0,&,!,!,cr0,!,|,?{,%s,pc,=,},", ARG (0));
} else {
esilprintf (op, "0x80,%s,&,!,!,0,%s,!,|,?{,%s,pc,=,},", ARG (0), ARG (0), ARG (1));
}
break;
case PPC_BC_EQ:
if (ARG (1)[0] == '\0') {
esilprintf (op, "cr0,!,?{,%s,pc,=,},", ARG (0));
} else {
esilprintf (op, "%s,!,?{,%s,pc,=,},", ARG (0), ARG (1));
}
break;
case PPC_BC_GE:
if (ARG (1)[0] == '\0') {
esilprintf (op, "0x80,cr0,&,!,cr0,!,|,?{,%s,pc,=,},", ARG (0));
} else {
esilprintf (op, "0x80,%s,&,!,%s,!,|,?{,%s,pc,=,},", ARG (0), ARG (0), ARG (1));
}
break;
case PPC_BC_GT:
if (ARG (1)[0] == '\0') {
esilprintf (op, "0x80,cr0,&,!,?{,%s,pc,=,},", ARG (0));
} else {
esilprintf (op, "0x80,%s,&,!,?{,%s,pc,=,},", ARG (0), ARG (1));
}
break;
case PPC_BC_NE:
if (ARG (1)[0] == '\0') {
esilprintf (op, "cr0,!,!,?{,%s,pc,=,},", ARG (0));
} else {
esilprintf (op, "%s,!,!,?{,%s,pc,=,},", ARG (0), ARG (1));
}
break;
case PPC_BC_INVALID:
op->type = R_ANAL_OP_TYPE_JMP;
esilprintf (op, "%s,pc,=", ARG (0));
case PPC_BC_UN: // unordered
case PPC_BC_NU: // not unordered
case PPC_BC_SO: // summary overflow
case PPC_BC_NS: // not summary overflow
default:
break;
}
break;
case PPC_INS_BT:
case PPC_INS_BF:
switch (insn->detail->ppc.operands[0].type) {
case PPC_OP_CRX:
op->type = R_ANAL_OP_TYPE_CJMP;
op->fail = addr + op->size;
break;
case PPC_OP_REG:
if (op->type == R_ANAL_OP_TYPE_CJMP) {
op->type = R_ANAL_OP_TYPE_UCJMP;
} else {
op->type = R_ANAL_OP_TYPE_CJMP;
}
op->jump = IMM (1);
op->fail = addr + op->size;
//op->type = R_ANAL_OP_TYPE_UJMP;
default:
break;
}
break;
case PPC_INS_BDNZ:
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = IMM (0);
op->fail = addr + op->size;
esilprintf (op, "1,ctr,-=,$z,!,?{,%s,pc,=,}", ARG (0));
break;
case PPC_INS_BDNZA:
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = IMM (0);
op->fail = addr + op->size;
break;
case PPC_INS_BDNZL:
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = IMM (0);
op->fail = addr + op->size;
break;
case PPC_INS_BDNZLA:
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = IMM (0);
op->fail = addr + op->size;
break;
case PPC_INS_BDNZLR:
op->type = R_ANAL_OP_TYPE_CJMP;
op->fail = addr + op->size;
esilprintf (op, "1,ctr,-=,$z,!,?{,lr,pc,=,},");
break;
case PPC_INS_BDNZLRL:
op->fail = addr + op->size;
op->type = R_ANAL_OP_TYPE_CJMP;
break;
case PPC_INS_BDZ:
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = IMM (0);
op->fail = addr + op->size;
esilprintf (op, "1,ctr,-=,$z,?{,%s,pc,=,}", ARG (0));
break;
case PPC_INS_BDZA:
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = IMM (0);
op->fail = addr + op->size;
break;
case PPC_INS_BDZL:
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = IMM (0);
op->fail = addr + op->size;
break;
case PPC_INS_BDZLA:
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = IMM (0);
op->fail = addr + op->size;
break;
case PPC_INS_BDZLR:
op->type = R_ANAL_OP_TYPE_CJMP;
op->fail = addr + op->size;
esilprintf (op, "1,ctr,-=,$z,?{,lr,pc,=,}");
break;
case PPC_INS_BDZLRL:
op->type = R_ANAL_OP_TYPE_CJMP;
op->fail = addr + op->size;
break;
case PPC_INS_BLR:
case PPC_INS_BLRL:
case PPC_INS_BCLR:
case PPC_INS_BCLRL:
op->type = R_ANAL_OP_TYPE_CRET; //I'm a condret
op->fail = addr + op->size;
switch (insn->detail->ppc.bc) {
case PPC_BC_INVALID:
op->type = R_ANAL_OP_TYPE_RET;
esilprintf (op, "lr,pc,=");
break;
case PPC_BC_LT:
if (ARG (1)[0] == '\0') {
esilprintf (op, "0x80,cr0,&,!,!,?{,lr,pc,=,},");
} else {
esilprintf (op, "0x80,%s,&,!,!,?{,lr,pc,=,},", ARG (0));
}
break;
case PPC_BC_LE:
if (ARG (1)[0] == '\0') {
esilprintf (op, "0x80,cr0,&,!,!,cr0,!,|,?{,lr,pc,=,},");
} else {
esilprintf (op, "0x80,%s,&,!,!,0,%s,!,|,?{,lr,pc,=,},", ARG (0), ARG (0));
}
break;
case PPC_BC_EQ:
if (ARG (1)[0] == '\0') {
esilprintf (op, "cr0,!,?{,lr,pc,=,},");
} else {
esilprintf (op, "%s,!,?{,lr,pc,=,},", ARG (0));
}
break;
case PPC_BC_GE:
if (ARG (1)[0] == '\0') {
esilprintf (op, "0x80,cr0,&,!,cr0,!,|,?{,lr,pc,=,},");
} else {
esilprintf (op, "0x80,%s,&,!,%s,!,|,?{,lr,pc,=,},", ARG (0), ARG (0));
}
break;
case PPC_BC_GT:
if (ARG (1)[0] == '\0') {
esilprintf (op, "0x80,cr0,&,!,?{,lr,pc,=,},");
} else {
esilprintf (op, "0x80,%s,&,!,?{,lr,pc,=,},", ARG (0));
}
break;
case PPC_BC_NE:
if (ARG (1)[0] == '\0') {
esilprintf (op, "cr0,!,!,?{,lr,pc,=,},");
} else {
esilprintf (op, "%s,!,!,?{,lr,pc,=,},", ARG (0));
}
break;
case PPC_BC_UN: // unordered
case PPC_BC_NU: // not unordered
case PPC_BC_SO: // summary overflow
case PPC_BC_NS: // not summary overflow
default:
break;
}
break;
case PPC_INS_NOR:
op->type = R_ANAL_OP_TYPE_NOR;
esilprintf (op, "%s,%s,|,!,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_XOR:
case PPC_INS_XORI:
op->type = R_ANAL_OP_TYPE_XOR;
esilprintf (op, "%s,%s,^,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_XORIS:
op->type = R_ANAL_OP_TYPE_XOR;
esilprintf (op, "16,%s,<<,%s,^,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_DIVD:
case PPC_INS_DIVW:
op->sign = true;
op->type = R_ANAL_OP_TYPE_DIV;
esilprintf (op, "%s,%s,/,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_DIVDU:
case PPC_INS_DIVWU:
op->type = R_ANAL_OP_TYPE_DIV;
esilprintf (op, "%s,%s,/,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_BL:
case PPC_INS_BLA:
op->type = R_ANAL_OP_TYPE_CALL;
op->jump = IMM (0);
op->fail = addr + op->size;
esilprintf (op, "pc,lr,=,%s,pc,=", ARG (0));
break;
case PPC_INS_TRAP:
op->sign = true;
op->type = R_ANAL_OP_TYPE_TRAP;
break;
case PPC_INS_AND:
case PPC_INS_NAND:
case PPC_INS_ANDI:
op->type = R_ANAL_OP_TYPE_AND;
esilprintf (op, "%s,%s,&,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_ANDIS:
op->type = R_ANAL_OP_TYPE_AND;
esilprintf (op, "16,%s,<<,%s,&,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_OR:
case PPC_INS_ORI:
op->type = R_ANAL_OP_TYPE_OR;
esilprintf (op, "%s,%s,|,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_ORIS:
op->type = R_ANAL_OP_TYPE_OR;
esilprintf (op, "16,%s,<<,%s,|,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_MFPVR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "pvr,%s,=", ARG (0));
break;
case PPC_INS_MFSPR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "%s,%s,=", PPCSPR (1), ARG (0));
break;
case PPC_INS_MFCTR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "ctr,%s,=", ARG (0));
break;
case PPC_INS_MFDCCR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "dccr,%s,=", ARG (0));
break;
case PPC_INS_MFICCR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "iccr,%s,=", ARG (0));
break;
case PPC_INS_MFDEAR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "dear,%s,=", ARG (0));
break;
case PPC_INS_MFMSR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "msr,%s,=", ARG (0));
break;
case PPC_INS_MTCTR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "%s,ctr,=", ARG (0));
break;
case PPC_INS_MTDCCR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "%s,dccr,=", ARG (0));
break;
case PPC_INS_MTICCR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "%s,iccr,=", ARG (0));
break;
case PPC_INS_MTDEAR:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "%s,dear,=", ARG (0));
break;
case PPC_INS_MTMSR:
case PPC_INS_MTMSRD:
op->type = R_ANAL_OP_TYPE_MOV;
esilprintf (op, "%s,msr,=", ARG (0));
break;
// Data Cache Block Zero
case PPC_INS_DCBZ:
op->type = R_ANAL_OP_TYPE_STORE;
esilprintf (op, "%s,%s", ARG (0), ARG2 (1, ",=[128]"));
break;
case PPC_INS_CLRLDI:
op->type = R_ANAL_OP_TYPE_AND;
esilprintf (op, "%s,%s,&,%s,=", ARG (1), cmask64 (cmaskbuf, ARG (2), "0x3F"), ARG (0));
break;
case PPC_INS_ROTLDI:
op->type = R_ANAL_OP_TYPE_ROL;
esilprintf (op, "%s,%s,<<<,%s,=", ARG (2), ARG (1), ARG (0));
break;
case PPC_INS_RLDCL:
case PPC_INS_RLDICL:
op->type = R_ANAL_OP_TYPE_ROL;
esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask64 (cmaskbuf, ARG (3), "0x3F"), ARG (0));
break;
case PPC_INS_RLDCR:
case PPC_INS_RLDICR:
op->type = R_ANAL_OP_TYPE_ROL;
esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask64 (cmaskbuf, 0, ARG (3)), ARG (0));
break;
}
if (mask & R_ARCH_OP_MASK_VAL) {
op_fillval (op, handle, insn);
}
if (!(mask & R_ARCH_OP_MASK_ESIL)) {
r_strbuf_fini (&op->esil);
}
cs_free (insn, n);
//cs_close (&handle);
}
return op->size;
}
static int archinfo(RAnal *a, int q) {
const char *cpu = a->config->cpu;
if (cpu && !strncmp (cpu, "vle", 3)) {
return 2;
}
return 4;
}
static RList *anal_preludes(RAnal *anal) {
#define KW(d,ds,m,ms) r_list_append (l, r_search_keyword_new((const ut8*)d,ds,(const ut8*)m, ms, NULL))
RList *l = r_list_newf ((RListFree)r_search_keyword_free);
KW ("\x7c\x08\x02\xa6", 4, NULL, 0);
return l;
}
RAnalPlugin r_anal_plugin_ppc_cs = {
.name = "ppc",
.desc = "Capstone (+vle+ps) PowerPC disassembler",
.license = "BSD",
.esil = true,
.arch = "ppc",
.bits = 32 | 64,
.cpus = "ppc,vle,ps",
.endian = R_SYS_ENDIAN_LITTLE | R_SYS_ENDIAN_BIG,
.archinfo = archinfo,
.preludes = anal_preludes,
.op = &analop,
.set_reg_profile = &set_reg_profile,
.mnemonics = cs_mnemonics,
};
#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
.type = R_LIB_TYPE_ANAL,
.data = &r_anal_plugin_ppc_cs,
.version = R2_VERSION
};
#endif