1818 lines
52 KiB
C
1818 lines
52 KiB
C
// SPDX-FileCopyrightText: 2013-2019 pancake <pancake@nopcode.org>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_analysis.h>
|
|
#include <rz_lib.h>
|
|
#include <capstone/capstone.h>
|
|
#include <capstone/ppc.h>
|
|
#include "ppc/libvle/vle.h"
|
|
#include "ppc/ppc_analysis.h"
|
|
#include "ppc/ppc_il.h"
|
|
#include "rz_util/rz_strbuf.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;
|
|
};
|
|
|
|
#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;
|
|
}
|
|
|
|
typedef struct {
|
|
char cmask1[32];
|
|
char cmask2[32];
|
|
char words[8][64];
|
|
char cspr[16];
|
|
csh handle;
|
|
int omode;
|
|
int obits;
|
|
RzRegItem base_regs[4];
|
|
} PPCContext;
|
|
|
|
static bool ppc_init(void **user) {
|
|
PPCContext *ctx = RZ_NEW0(PPCContext);
|
|
if (!ctx) {
|
|
return false;
|
|
}
|
|
ctx->handle = 0;
|
|
ctx->omode = -1;
|
|
ctx->obits = -1;
|
|
*user = ctx;
|
|
return true;
|
|
}
|
|
|
|
static const char *cmask64(RzAnalysis *a, const char *mb_c, const char *me_c) {
|
|
PPCContext *ctx = (PPCContext *)a->plugin_data;
|
|
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(ctx->cmask1, sizeof(ctx->cmask1), "0x%" PFMT64x, mask64(mb, me));
|
|
return ctx->cmask1;
|
|
}
|
|
|
|
static const char *cmask32(RzAnalysis *a, const char *mb_c, const char *me_c) {
|
|
PPCContext *ctx = (PPCContext *)a->plugin_data;
|
|
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(ctx->cmask2, sizeof(ctx->cmask2), "0x%" PFMT32x "", mask32(mb, me));
|
|
return ctx->cmask2;
|
|
}
|
|
|
|
static char *getarg2(RzAnalysis *a, struct Getarg *gop, int n, const char *setstr) {
|
|
PPCContext *ctx = (PPCContext *)a->plugin_data;
|
|
cs_insn *insn = gop->insn;
|
|
csh handle = gop->handle;
|
|
cs_ppc_op op;
|
|
|
|
if (n < 0 || n >= 8) {
|
|
return NULL;
|
|
}
|
|
op = INSOP(n);
|
|
switch (op.type) {
|
|
case PPC_OP_INVALID:
|
|
ctx->words[n][0] = '\0';
|
|
// strcpy (words[n], "invalid");
|
|
break;
|
|
case PPC_OP_REG:
|
|
snprintf(ctx->words[n], sizeof(ctx->words[n]),
|
|
"%s%s", cs_reg_name(handle, op.reg), setstr);
|
|
break;
|
|
case PPC_OP_IMM:
|
|
snprintf(ctx->words[n], sizeof(ctx->words[n]),
|
|
"0x%" PFMT64x "%s", (ut64)op.imm, setstr);
|
|
break;
|
|
case PPC_OP_MEM:
|
|
snprintf(ctx->words[n], sizeof(ctx->words[n]),
|
|
"%" PFMT64d ",%s,+,%s",
|
|
(ut64)op.mem.disp,
|
|
cs_reg_name(handle, op.mem.base), setstr);
|
|
break;
|
|
#if CS_NEXT_VERSION < 6
|
|
case PPC_OP_CRX: // Condition Register field
|
|
snprintf(ctx->words[n], sizeof(ctx->words[n]),
|
|
"%" PFMT64d "%s", (ut64)op.imm, setstr);
|
|
break;
|
|
#endif
|
|
}
|
|
return ctx->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;
|
|
#if CS_NEXT_VERSION < 6
|
|
case PPC_OP_CRX: // Condition Register field
|
|
value = (ut64)op.imm;
|
|
break;
|
|
#endif
|
|
}
|
|
return value;
|
|
}
|
|
|
|
static const char *getspr(RzAnalysis *a, struct Getarg *gop, int n) {
|
|
PPCContext *ctx = (PPCContext *)a->plugin_data;
|
|
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(ctx->cspr, sizeof(ctx->cspr), "spr_%u", spr);
|
|
break;
|
|
}
|
|
return ctx->cspr;
|
|
}
|
|
|
|
static RzStructuredData *ppc_opex(csh handle, cs_insn *insn) {
|
|
if (!insn->detail) {
|
|
return NULL;
|
|
}
|
|
|
|
RzStructuredData *root = rz_structured_data_new_map();
|
|
if (!root) {
|
|
return NULL;
|
|
}
|
|
|
|
RzStructuredData *opex = rz_structured_data_map_add_map(root, "opex");
|
|
if (!opex) {
|
|
rz_structured_data_free(root);
|
|
return NULL;
|
|
}
|
|
|
|
RzStructuredData *operands = rz_structured_data_map_add_array(opex, "operands");
|
|
cs_ppc *x = &insn->detail->ppc;
|
|
for (st32 i = 0; i < x->op_count; i++) {
|
|
cs_ppc_op *op = x->operands + i;
|
|
RzStructuredData *operand = rz_structured_data_array_add_map(operands);
|
|
switch (op->type) {
|
|
case PPC_OP_REG:
|
|
rz_structured_data_map_add_string(operand, "type", "reg");
|
|
rz_structured_data_map_add_string(operand, "value", cs_reg_name(handle, op->reg));
|
|
break;
|
|
case PPC_OP_IMM:
|
|
rz_structured_data_map_add_string(operand, "type", "imm");
|
|
rz_structured_data_map_add_signed(operand, "value", op->imm);
|
|
break;
|
|
case PPC_OP_MEM:
|
|
rz_structured_data_map_add_string(operand, "type", "mem");
|
|
if (op->mem.base != PPC_REG_INVALID) {
|
|
rz_structured_data_map_add_string(operand, "base", cs_reg_name(handle, op->mem.base));
|
|
}
|
|
rz_structured_data_map_add_signed(operand, "disp", op->mem.disp);
|
|
break;
|
|
default:
|
|
rz_structured_data_map_add_string(operand, "type", "invalid");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return root;
|
|
}
|
|
|
|
#define PPCSPR(n) getspr(a, &gop, n)
|
|
#define ARG(n) getarg2(a, &gop, n, "")
|
|
#define ARG2(n, m) getarg2(a, &gop, n, m)
|
|
|
|
static char *ppc_get_reg_profile(RzAnalysis *analysis) {
|
|
const char *p = NULL;
|
|
if (analysis->bits == 64) {
|
|
p =
|
|
"=PC pc\n"
|
|
"=SP r1\n"
|
|
"=BP r31\n"
|
|
"=SN r3\n" // also for 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"
|
|
"=OF ov\n"
|
|
"=CF ca\n"
|
|
|
|
"gpr r0 .64 0 0 \n"
|
|
"gpr r1 .64 8 0 \n"
|
|
"gpr r2 .64 16 0 \n"
|
|
"gpr r3 .64 24 0 \n"
|
|
"gpr r4 .64 32 0 \n"
|
|
"gpr r5 .64 40 0 \n"
|
|
"gpr r6 .64 48 0 \n"
|
|
"gpr r7 .64 56 0 \n"
|
|
"gpr r8 .64 64 0 \n"
|
|
"gpr r9 .64 72 0 \n"
|
|
"gpr r10 .64 80 0 \n"
|
|
"gpr r11 .64 88 0 \n"
|
|
"gpr r12 .64 96 0 \n"
|
|
"gpr r13 .64 104 0 \n"
|
|
"gpr r14 .64 112 0 \n"
|
|
"gpr r15 .64 120 0 \n"
|
|
"gpr r16 .64 128 0 \n"
|
|
"gpr r17 .64 136 0 \n"
|
|
"gpr r18 .64 144 0 \n"
|
|
"gpr r19 .64 152 0 \n"
|
|
"gpr r20 .64 160 0 \n"
|
|
"gpr r21 .64 168 0 \n"
|
|
"gpr r22 .64 176 0 \n"
|
|
"gpr r23 .64 184 0 \n"
|
|
"gpr r24 .64 192 0 \n"
|
|
"gpr r25 .64 200 0 \n"
|
|
"gpr r26 .64 208 0 \n"
|
|
"gpr r27 .64 216 0 \n"
|
|
"gpr r28 .64 224 0 \n"
|
|
"gpr r29 .64 232 0 \n"
|
|
"gpr r30 .64 240 0 \n"
|
|
"gpr r31 .64 248 0 \n"
|
|
"vc vs0 .128 256 0 \n"
|
|
"vc vs1 .128 272 0 \n"
|
|
"vc vs2 .128 288 0 \n"
|
|
"vc vs3 .128 304 0 \n"
|
|
"vc vs4 .128 320 0 \n"
|
|
"vc vs5 .128 336 0 \n"
|
|
"vc vs6 .128 352 0 \n"
|
|
"vc vs7 .128 368 0 \n"
|
|
"vc vs8 .128 384 0 \n"
|
|
"vc vs9 .128 400 0 \n"
|
|
"vc vs10 .128 416 0 \n"
|
|
"vc vs11 .128 432 0 \n"
|
|
"vc vs12 .128 448 0 \n"
|
|
"vc vs13 .128 464 0 \n"
|
|
"vc vs14 .128 480 0 \n"
|
|
"vc vs15 .128 496 0 \n"
|
|
"vc vs16 .128 512 0 \n"
|
|
"vc vs17 .128 528 0 \n"
|
|
"vc vs18 .128 544 0 \n"
|
|
"vc vs19 .128 560 0 \n"
|
|
"vc vs20 .128 576 0 \n"
|
|
"vc vs21 .128 592 0 \n"
|
|
"vc vs22 .128 608 0 \n"
|
|
"vc vs23 .128 624 0 \n"
|
|
"vc vs24 .128 640 0 \n"
|
|
"vc vs25 .128 656 0 \n"
|
|
"vc vs26 .128 672 0 \n"
|
|
"vc vs27 .128 688 0 \n"
|
|
"vc vs28 .128 704 0 \n"
|
|
"vc vs29 .128 720 0 \n"
|
|
"vc vs30 .128 736 0 \n"
|
|
"vc vs31 .128 752 0 \n"
|
|
"vc vs32 .128 768 0 \n"
|
|
"vc vs33 .128 784 0 \n"
|
|
"vc vs34 .128 800 0 \n"
|
|
"vc vs35 .128 816 0 \n"
|
|
"vc vs36 .128 832 0 \n"
|
|
"vc vs37 .128 848 0 \n"
|
|
"vc vs38 .128 864 0 \n"
|
|
"vc vs39 .128 880 0 \n"
|
|
"vc vs40 .128 896 0 \n"
|
|
"vc vs41 .128 912 0 \n"
|
|
"vc vs42 .128 928 0 \n"
|
|
"vc vs43 .128 944 0 \n"
|
|
"vc vs44 .128 960 0 \n"
|
|
"vc vs45 .128 976 0 \n"
|
|
"vc vs46 .128 992 0 \n"
|
|
"vc vs47 .128 1008 0 \n"
|
|
"vc vs48 .128 1024 0 \n"
|
|
"vc vs49 .128 1040 0 \n"
|
|
"vc vs50 .128 1056 0 \n"
|
|
"vc vs51 .128 1072 0 \n"
|
|
"vc vs52 .128 1088 0 \n"
|
|
"vc vs53 .128 1104 0 \n"
|
|
"vc vs54 .128 1120 0 \n"
|
|
"vc vs55 .128 1136 0 \n"
|
|
"vc vs56 .128 1152 0 \n"
|
|
"vc vs57 .128 1168 0 \n"
|
|
"vc vs58 .128 1184 0 \n"
|
|
"vc vs59 .128 1200 0 \n"
|
|
"vc vs60 .128 1216 0 \n"
|
|
"vc vs61 .128 1232 0 \n"
|
|
"vc vs62 .128 1248 0 \n"
|
|
"vc vs63 .128 1264 0 \n"
|
|
"fpu f0 .64 1280 0 \n"
|
|
"fpu f1 .64 1288 0 \n"
|
|
"fpu f2 .64 1296 0 \n"
|
|
"fpu f3 .64 1304 0 \n"
|
|
"fpu f4 .64 1312 0 \n"
|
|
"fpu f5 .64 1320 0 \n"
|
|
"fpu f6 .64 1328 0 \n"
|
|
"fpu f7 .64 1336 0 \n"
|
|
"fpu f8 .64 1344 0 \n"
|
|
"fpu f9 .64 1352 0 \n"
|
|
"fpu f10 .64 1360 0 \n"
|
|
"fpu f11 .64 1368 0 \n"
|
|
"fpu f12 .64 1376 0 \n"
|
|
"fpu f13 .64 1384 0 \n"
|
|
"fpu f14 .64 1392 0 \n"
|
|
"fpu f15 .64 1400 0 \n"
|
|
"fpu f16 .64 1408 0 \n"
|
|
"fpu f17 .64 1416 0 \n"
|
|
"fpu f18 .64 1424 0 \n"
|
|
"fpu f19 .64 1432 0 \n"
|
|
"fpu f20 .64 1440 0 \n"
|
|
"fpu f21 .64 1448 0 \n"
|
|
"fpu f22 .64 1456 0 \n"
|
|
"fpu f23 .64 1464 0 \n"
|
|
"fpu f24 .64 1472 0 \n"
|
|
"fpu f25 .64 1480 0 \n"
|
|
"fpu f26 .64 1488 0 \n"
|
|
"fpu f27 .64 1496 0 \n"
|
|
"fpu f28 .64 1504 0 \n"
|
|
"fpu f29 .64 1512 0 \n"
|
|
"fpu f30 .64 1520 0 \n"
|
|
"fpu f31 .64 1528 0 \n"
|
|
"vc v0 .128 1536 0 \n"
|
|
"vc v1 .128 1552 0 \n"
|
|
"vc v2 .128 1568 0 \n"
|
|
"vc v3 .128 1584 0 \n"
|
|
"vc v4 .128 1600 0 \n"
|
|
"vc v5 .128 1616 0 \n"
|
|
"vc v6 .128 1632 0 \n"
|
|
"vc v7 .128 1648 0 \n"
|
|
"vc v8 .128 1664 0 \n"
|
|
"vc v9 .128 1680 0 \n"
|
|
"vc v10 .128 1696 0 \n"
|
|
"vc v11 .128 1712 0 \n"
|
|
"vc v12 .128 1728 0 \n"
|
|
"vc v13 .128 1744 0 \n"
|
|
"vc v14 .128 1760 0 \n"
|
|
"vc v15 .128 1776 0 \n"
|
|
"vc v16 .128 1792 0 \n"
|
|
"vc v17 .128 1808 0 \n"
|
|
"vc v18 .128 1824 0 \n"
|
|
"vc v19 .128 1840 0 \n"
|
|
"vc v20 .128 1856 0 \n"
|
|
"vc v21 .128 1872 0 \n"
|
|
"vc v22 .128 1888 0 \n"
|
|
"vc v23 .128 1904 0 \n"
|
|
"vc v24 .128 1920 0 \n"
|
|
"vc v25 .128 1936 0 \n"
|
|
"vc v26 .128 1952 0 \n"
|
|
"vc v27 .128 1968 0 \n"
|
|
"vc v28 .128 1984 0 \n"
|
|
"vc v29 .128 2000 0 \n"
|
|
"vc v30 .128 2016 0 \n"
|
|
"vc v31 .128 2032 0 \n"
|
|
"ctr xer .64 2048 0 # Fixed-Point Exception Register\n"
|
|
"vcc vrsave .32 2056 0 # VR Save Register\n"
|
|
"ctr fpscr .64 2060 0 # Floating-Point Status and Control Register\n"
|
|
"vcc vscr .32 2068 0 # Vector Status and Control Register\n"
|
|
"ctr cr .32 2072 0 # Condition Register\n"
|
|
"ctr lr .64 2076 0 # Link Register\n"
|
|
"ctr ctr .64 2084 0 # Count Register\n"
|
|
"ctr tar .64 2092 0 # Target Address Register\n"
|
|
"ctr ppr .64 2100 0 # Process Priority Register\n"
|
|
"ctr dscr .64 2108 0 # Data Stream Control Register\n"
|
|
"ctr bescr .64 2116 0 # Branch Event Status and Control Register\n"
|
|
"ctr ebbhr .64 2124 0 # Event-Based Branch Handler Register\n"
|
|
"ctr ebbrr .64 2132 0 # Event-Based Branch Return Register\n"
|
|
"ctr lpcr .64 2140 0 # Logical Partitioning Control Register\n"
|
|
"ctr hrmor .64 2148 0 # Hypervisor Real Mode Offset Register\n"
|
|
"ctr lpidr .32 2156 0 # Logical Partition Identification Regiser\n"
|
|
"ctr pcr .64 2160 0 # Processor Compatibility Register\n"
|
|
"ctr tir .64 2168 0 # Thread Identification Register\n"
|
|
"ctr urmor .64 2176 0 # Ultravisor Real Mode Offset Register\n"
|
|
"ctr smfctrl .64 2184 0 # Secure Memory Facility Control Register\n"
|
|
"ctr msr .64 2192 0 # Machine State Register\n"
|
|
"ctr pvr .32 2200 0 # Processor Version Register\n"
|
|
"ctr pir .32 2204 0 # Processor Version Register\n"
|
|
"ctr pidr .32 2208 0 # Processor Identification Register\n"
|
|
"ctr ctrl .32 2212 0 # Control Register\n"
|
|
"ctr pspb .32 2216 0 # Problem State Priority Boost Register\n"
|
|
"ctr rpr .64 2220 0 # Relative Priority Register\n"
|
|
"ctr hashkey .64 2228 0 # Hash Key Register\n"
|
|
"ctr hashpkey .64 2236 0 # Hash Privileged Key Register\n"
|
|
"ctr sprg0 .64 2244 0 # Software-use SPR 0\n"
|
|
"ctr sprg1 .64 2252 0 # Software-use SPR 1\n"
|
|
"ctr sprg2 .64 2260 0 # Software-use SPR 2\n"
|
|
"ctr sprg3 .64 2268 0 # Software-use SPR 3\n"
|
|
"ctr hsprg0 .64 2276 0 # Hypervisor Software-use SPR 0\n"
|
|
"ctr hsprg1 .64 2284 0 # Hypervisor Software-use SPR 1\n"
|
|
"ctr usprg0 .64 2292 0 # Ultravisor Software-use SPR 0\n"
|
|
"ctr usprg1 .64 2300 0 # Ultravisor Software-use SPR 1\n"
|
|
"ctr srr0 .64 2308 0 # Machine Status Save/Restore Register 0\n"
|
|
"ctr srr1 .64 2316 0 # Machine Status Save/Restore Register 1\n"
|
|
"ctr hsrr0 .64 2324 0 # Hypervisor Machine Status Save/Restore Register 0\n"
|
|
"ctr hsrr1 .64 2332 0 # Hypervisor Machine Status Save/Restore Register 1\n"
|
|
"ctr usrr0 .64 2340 0 # Hypervisor Machine Status Save/Restore Register 0\n"
|
|
"ctr usrr1 .64 2348 0 # Ultravisor Machine Status Save/Restore Register 1\n"
|
|
"ctr asdr .64 2356 0 # Access Segment Descriptor Register\n"
|
|
"ctr dar .64 2364 0 # Data Address Register\n"
|
|
"ctr hdar .64 2372 0 # Hypervisor Data Address Register\n"
|
|
"ctr dsisr .32 2380 0 # Data Storage Interrupt Status Register\n"
|
|
"ctr hdsisr .32 2384 0 # Hypervisor Data Storage Interrupt Status Register\n"
|
|
"ctr heir .64 2388 0 # Hypervisor Emulation Instruction Register\n"
|
|
"ctr hmer .64 2396 0 # Hypervisor Maintenance Exception Register\n"
|
|
"ctr hmeer .64 2404 0 # Hypervisor Maintenance Exception Enable Register\n"
|
|
"ctr fscr .64 2412 0 # Facility Status and Control Register\n"
|
|
"ctr hfscr .64 2420 0 # Hypervisor Facility Status and Control Register\n"
|
|
"ctr purr .64 2428 0 # Process Utilization of Resources Register\n"
|
|
"ctr spurr .64 2436 0 # Scaled Process Utilization of Resources Register\n"
|
|
"ctr dexcr .64 2444 0 # Dynamic Execution Control Register\n"
|
|
"ctr hdexcr .64 2452 0 # Hypervisor Dynamic Execution Control Register\n"
|
|
"ctr udexcr .64 2460 0 # Ultravisor Dynamic Execution Control Register\n"
|
|
"ctr cfar .64 2468 0 # Come-From Address Register\n"
|
|
"ctr mmcr0 .64 2476 0 # Monitor Mode Control Register 0\n"
|
|
"ctr mmcr1 .64 2484 0 # Monitor Mode Control Register 1\n"
|
|
"ctr mmcr2 .64 2492 0 # Monitor Mode Control Register 2\n"
|
|
"ctr mmcra .64 2500 0 # Monitor Mode Control Register A\n"
|
|
"ctr siar .64 2508 0 # Sampled Instruction Address Register\n"
|
|
"ctr sdar .64 2516 0 # Sampled Data Address Register\n"
|
|
"ctr sier .64 2524 0 # Sampled Instruction Event Register\n"
|
|
"ctr sier2 .64 2532 0 # Sampled Instruction Event Register 2\n"
|
|
"ctr sier3 .64 2540 0 # Sampled Instruction Event Register 3\n"
|
|
"ctr mmcr3 .64 2548 0 # Monitor Mode Control Register 2\n"
|
|
"ctr dpdes .64 2556 0 # Directed Privileged Doorbell Exception State Register\n"
|
|
"ctr pc .64 2564 0 # Programm Counter\n"
|
|
"ctr cr0 .4 2572 0 # Condition Register Field 0\n"
|
|
"ctr cr1 .4 2573 0 # Condition Register Field 1\n"
|
|
"ctr cr2 .4 2574 0 # Condition Register Field 2\n"
|
|
"ctr cr3 .4 2575 0 # Condition Register Field 3\n"
|
|
"ctr cr4 .4 2576 0 # Condition Register Field 4\n"
|
|
"ctr cr5 .4 2577 0 # Condition Register Field 5\n"
|
|
"ctr cr6 .4 2578 0 # Condition Register Field 6\n"
|
|
"ctr cr7 .4 2579 0 # Condition Register Field 7\n"
|
|
"ctr ppr32 .32 2580 0 # Process Priority Register 32-bit\n"
|
|
"flg so .1 2584 0 # Summary Overflow\n"
|
|
"flg ov .1 2585 0 # Overflow\n"
|
|
"flg ca .1 2586 0 # Carry\n"
|
|
"gpr 0 .64 2587 0 # The zero register.\n";
|
|
return rz_str_dup(p);
|
|
} else {
|
|
p =
|
|
"=PC pc\n"
|
|
"=SP r1\n"
|
|
"=BP r31\n"
|
|
"=SN r3\n" // also for 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"
|
|
"=OF ov\n"
|
|
"=CF ca\n"
|
|
|
|
"gpr r0 .32 0 0 \n"
|
|
"gpr r1 .32 8 0 \n"
|
|
"gpr r2 .32 16 0 \n"
|
|
"gpr r3 .32 24 0 \n"
|
|
"gpr r4 .32 32 0 \n"
|
|
"gpr r5 .32 40 0 \n"
|
|
"gpr r6 .32 48 0 \n"
|
|
"gpr r7 .32 56 0 \n"
|
|
"gpr r8 .32 64 0 \n"
|
|
"gpr r9 .32 72 0 \n"
|
|
"gpr r10 .32 80 0 \n"
|
|
"gpr r11 .32 88 0 \n"
|
|
"gpr r12 .32 96 0 \n"
|
|
"gpr r13 .32 104 0 \n"
|
|
"gpr r14 .32 112 0 \n"
|
|
"gpr r15 .32 120 0 \n"
|
|
"gpr r16 .32 128 0 \n"
|
|
"gpr r17 .32 136 0 \n"
|
|
"gpr r18 .32 144 0 \n"
|
|
"gpr r19 .32 152 0 \n"
|
|
"gpr r20 .32 160 0 \n"
|
|
"gpr r21 .32 168 0 \n"
|
|
"gpr r22 .32 176 0 \n"
|
|
"gpr r23 .32 184 0 \n"
|
|
"gpr r24 .32 192 0 \n"
|
|
"gpr r25 .32 200 0 \n"
|
|
"gpr r26 .32 208 0 \n"
|
|
"gpr r27 .32 216 0 \n"
|
|
"gpr r28 .32 224 0 \n"
|
|
"gpr r29 .32 232 0 \n"
|
|
"gpr r30 .32 240 0 \n"
|
|
"gpr r31 .32 248 0 \n"
|
|
"vc vs0 .128 256 0 \n"
|
|
"vc vs1 .128 272 0 \n"
|
|
"vc vs2 .128 288 0 \n"
|
|
"vc vs3 .128 304 0 \n"
|
|
"vc vs4 .128 320 0 \n"
|
|
"vc vs5 .128 336 0 \n"
|
|
"vc vs6 .128 352 0 \n"
|
|
"vc vs7 .128 368 0 \n"
|
|
"vc vs8 .128 384 0 \n"
|
|
"vc vs9 .128 400 0 \n"
|
|
"vc vs10 .128 416 0 \n"
|
|
"vc vs11 .128 432 0 \n"
|
|
"vc vs12 .128 448 0 \n"
|
|
"vc vs13 .128 464 0 \n"
|
|
"vc vs14 .128 480 0 \n"
|
|
"vc vs15 .128 496 0 \n"
|
|
"vc vs16 .128 512 0 \n"
|
|
"vc vs17 .128 528 0 \n"
|
|
"vc vs18 .128 544 0 \n"
|
|
"vc vs19 .128 560 0 \n"
|
|
"vc vs20 .128 576 0 \n"
|
|
"vc vs21 .128 592 0 \n"
|
|
"vc vs22 .128 608 0 \n"
|
|
"vc vs23 .128 624 0 \n"
|
|
"vc vs24 .128 640 0 \n"
|
|
"vc vs25 .128 656 0 \n"
|
|
"vc vs26 .128 672 0 \n"
|
|
"vc vs27 .128 688 0 \n"
|
|
"vc vs28 .128 704 0 \n"
|
|
"vc vs29 .128 720 0 \n"
|
|
"vc vs30 .128 736 0 \n"
|
|
"vc vs31 .128 752 0 \n"
|
|
"vc vs32 .128 768 0 \n"
|
|
"vc vs33 .128 784 0 \n"
|
|
"vc vs34 .128 800 0 \n"
|
|
"vc vs35 .128 816 0 \n"
|
|
"vc vs36 .128 832 0 \n"
|
|
"vc vs37 .128 848 0 \n"
|
|
"vc vs38 .128 864 0 \n"
|
|
"vc vs39 .128 880 0 \n"
|
|
"vc vs40 .128 896 0 \n"
|
|
"vc vs41 .128 912 0 \n"
|
|
"vc vs42 .128 928 0 \n"
|
|
"vc vs43 .128 944 0 \n"
|
|
"vc vs44 .128 960 0 \n"
|
|
"vc vs45 .128 976 0 \n"
|
|
"vc vs46 .128 992 0 \n"
|
|
"vc vs47 .128 1008 0 \n"
|
|
"vc vs48 .128 1024 0 \n"
|
|
"vc vs49 .128 1040 0 \n"
|
|
"vc vs50 .128 1056 0 \n"
|
|
"vc vs51 .128 1072 0 \n"
|
|
"vc vs52 .128 1088 0 \n"
|
|
"vc vs53 .128 1104 0 \n"
|
|
"vc vs54 .128 1120 0 \n"
|
|
"vc vs55 .128 1136 0 \n"
|
|
"vc vs56 .128 1152 0 \n"
|
|
"vc vs57 .128 1168 0 \n"
|
|
"vc vs58 .128 1184 0 \n"
|
|
"vc vs59 .128 1200 0 \n"
|
|
"vc vs60 .128 1216 0 \n"
|
|
"vc vs61 .128 1232 0 \n"
|
|
"vc vs62 .128 1248 0 \n"
|
|
"vc vs63 .128 1264 0 \n"
|
|
"fpu f0 .64 1280 0 \n"
|
|
"fpu f1 .64 1288 0 \n"
|
|
"fpu f2 .64 1296 0 \n"
|
|
"fpu f3 .64 1304 0 \n"
|
|
"fpu f4 .64 1312 0 \n"
|
|
"fpu f5 .64 1320 0 \n"
|
|
"fpu f6 .64 1328 0 \n"
|
|
"fpu f7 .64 1336 0 \n"
|
|
"fpu f8 .64 1344 0 \n"
|
|
"fpu f9 .64 1352 0 \n"
|
|
"fpu f10 .64 1360 0 \n"
|
|
"fpu f11 .64 1368 0 \n"
|
|
"fpu f12 .64 1376 0 \n"
|
|
"fpu f13 .64 1384 0 \n"
|
|
"fpu f14 .64 1392 0 \n"
|
|
"fpu f15 .64 1400 0 \n"
|
|
"fpu f16 .64 1408 0 \n"
|
|
"fpu f17 .64 1416 0 \n"
|
|
"fpu f18 .64 1424 0 \n"
|
|
"fpu f19 .64 1432 0 \n"
|
|
"fpu f20 .64 1440 0 \n"
|
|
"fpu f21 .64 1448 0 \n"
|
|
"fpu f22 .64 1456 0 \n"
|
|
"fpu f23 .64 1464 0 \n"
|
|
"fpu f24 .64 1472 0 \n"
|
|
"fpu f25 .64 1480 0 \n"
|
|
"fpu f26 .64 1488 0 \n"
|
|
"fpu f27 .64 1496 0 \n"
|
|
"fpu f28 .64 1504 0 \n"
|
|
"fpu f29 .64 1512 0 \n"
|
|
"fpu f30 .64 1520 0 \n"
|
|
"fpu f31 .64 1528 0 \n"
|
|
"vc v0 .128 1536 0 \n"
|
|
"vc v1 .128 1552 0 \n"
|
|
"vc v2 .128 1568 0 \n"
|
|
"vc v3 .128 1584 0 \n"
|
|
"vc v4 .128 1600 0 \n"
|
|
"vc v5 .128 1616 0 \n"
|
|
"vc v6 .128 1632 0 \n"
|
|
"vc v7 .128 1648 0 \n"
|
|
"vc v8 .128 1664 0 \n"
|
|
"vc v9 .128 1680 0 \n"
|
|
"vc v10 .128 1696 0 \n"
|
|
"vc v11 .128 1712 0 \n"
|
|
"vc v12 .128 1728 0 \n"
|
|
"vc v13 .128 1744 0 \n"
|
|
"vc v14 .128 1760 0 \n"
|
|
"vc v15 .128 1776 0 \n"
|
|
"vc v16 .128 1792 0 \n"
|
|
"vc v17 .128 1808 0 \n"
|
|
"vc v18 .128 1824 0 \n"
|
|
"vc v19 .128 1840 0 \n"
|
|
"vc v20 .128 1856 0 \n"
|
|
"vc v21 .128 1872 0 \n"
|
|
"vc v22 .128 1888 0 \n"
|
|
"vc v23 .128 1904 0 \n"
|
|
"vc v24 .128 1920 0 \n"
|
|
"vc v25 .128 1936 0 \n"
|
|
"vc v26 .128 1952 0 \n"
|
|
"vc v27 .128 1968 0 \n"
|
|
"vc v28 .128 1984 0 \n"
|
|
"vc v29 .128 2000 0 \n"
|
|
"vc v30 .128 2016 0 \n"
|
|
"vc v31 .128 2032 0 \n"
|
|
"ctr xer .64 2048 0 # Fixed-Point Exception Register\n"
|
|
"vcc vrsave .32 2056 0 # VR Save Register\n"
|
|
"ctr fpscr .64 2060 0 # Floating-Point Status and Control Register\n"
|
|
"vcc vscr .32 2068 0 # Vector Status and Control Register\n"
|
|
"ctr cr .32 2072 0 # Condition Register\n"
|
|
"ctr lr .32 2076 0 # Link Register\n"
|
|
"ctr ctr .32 2084 0 # Count Register\n"
|
|
"ctr tar .32 2092 0 # Target Address Register\n"
|
|
"ctr ppr .64 2100 0 # Process Priority Register\n"
|
|
"ctr dscr .64 2108 0 # Data Stream Control Register\n"
|
|
"ctr bescr .64 2116 0 # Branch Event Status and Control Register\n"
|
|
"ctr ebbhr .64 2124 0 # Event-Based Branch Handler Register\n"
|
|
"ctr ebbrr .64 2132 0 # Event-Based Branch Return Register\n"
|
|
"ctr lpcr .64 2140 0 # Logical Partitioning Control Register\n"
|
|
"ctr hrmor .64 2148 0 # Hypervisor Real Mode Offset Register\n"
|
|
"ctr lpidr .32 2156 0 # Logical Partition Identification Regiser\n"
|
|
"ctr pcr .64 2160 0 # Processor Compatibility Register\n"
|
|
"ctr tir .64 2168 0 # Thread Identification Register\n"
|
|
"ctr urmor .64 2176 0 # Ultravisor Real Mode Offset Register\n"
|
|
"ctr smfctrl .64 2184 0 # Secure Memory Facility Control Register\n"
|
|
"ctr msr .64 2192 0 # Machine State Register\n"
|
|
"ctr pvr .32 2200 0 # Processor Version Register\n"
|
|
"ctr pir .32 2204 0 # Processor Version Register\n"
|
|
"ctr pidr .32 2208 0 # Processor Identification Register\n"
|
|
"ctr ctrl .32 2212 0 # Control Register\n"
|
|
"ctr pspb .32 2216 0 # Problem State Priority Boost Register\n"
|
|
"ctr rpr .64 2220 0 # Relative Priority Register\n"
|
|
"ctr hashkey .64 2228 0 # Hash Key Register\n"
|
|
"ctr hashpkey .64 2236 0 # Hash Privileged Key Register\n"
|
|
"ctr sprg0 .64 2244 0 # Software-use SPR 0\n"
|
|
"ctr sprg1 .64 2252 0 # Software-use SPR 1\n"
|
|
"ctr sprg2 .64 2260 0 # Software-use SPR 2\n"
|
|
"ctr sprg3 .64 2268 0 # Software-use SPR 3\n"
|
|
"ctr hsprg0 .64 2276 0 # Hypervisor Software-use SPR 0\n"
|
|
"ctr hsprg1 .64 2284 0 # Hypervisor Software-use SPR 1\n"
|
|
"ctr usprg0 .64 2292 0 # Ultravisor Software-use SPR 0\n"
|
|
"ctr usprg1 .64 2300 0 # Ultravisor Software-use SPR 1\n"
|
|
"ctr srr0 .64 2308 0 # Machine Status Save/Restore Register 0\n"
|
|
"ctr srr1 .64 2316 0 # Machine Status Save/Restore Register 1\n"
|
|
"ctr hsrr0 .64 2324 0 # Hypervisor Machine Status Save/Restore Register 0\n"
|
|
"ctr hsrr1 .64 2332 0 # Hypervisor Machine Status Save/Restore Register 1\n"
|
|
"ctr usrr0 .64 2340 0 # Hypervisor Machine Status Save/Restore Register 0\n"
|
|
"ctr usrr1 .64 2348 0 # Ultravisor Machine Status Save/Restore Register 1\n"
|
|
"ctr asdr .64 2356 0 # Access Segment Descriptor Register\n"
|
|
"ctr dar .64 2364 0 # Data Address Register\n"
|
|
"ctr hdar .64 2372 0 # Hypervisor Data Address Register\n"
|
|
"ctr dsisr .32 2380 0 # Data Storage Interrupt Status Register\n"
|
|
"ctr hdsisr .32 2384 0 # Hypervisor Data Storage Interrupt Status Register\n"
|
|
"ctr heir .64 2388 0 # Hypervisor Emulation Instruction Register\n"
|
|
"ctr hmer .64 2396 0 # Hypervisor Maintenance Exception Register\n"
|
|
"ctr hmeer .64 2404 0 # Hypervisor Maintenance Exception Enable Register\n"
|
|
"ctr fscr .64 2412 0 # Facility Status and Control Register\n"
|
|
"ctr hfscr .64 2420 0 # Hypervisor Facility Status and Control Register\n"
|
|
"ctr purr .64 2428 0 # Process Utilization of Resources Register\n"
|
|
"ctr spurr .64 2436 0 # Scaled Process Utilization of Resources Register\n"
|
|
"ctr dexcr .64 2444 0 # Dynamic Execution Control Register\n"
|
|
"ctr hdexcr .64 2452 0 # Hypervisor Dynamic Execution Control Register\n"
|
|
"ctr udexcr .64 2460 0 # Ultravisor Dynamic Execution Control Register\n"
|
|
"ctr cfar .64 2468 0 # Come-From Address Register\n"
|
|
"ctr mmcr0 .64 2476 0 # Monitor Mode Control Register 0\n"
|
|
"ctr mmcr1 .64 2484 0 # Monitor Mode Control Register 1\n"
|
|
"ctr mmcr2 .64 2492 0 # Monitor Mode Control Register 2\n"
|
|
"ctr mmcra .64 2500 0 # Monitor Mode Control Register A\n"
|
|
"ctr siar .64 2508 0 # Sampled Instruction Address Register\n"
|
|
"ctr sdar .64 2516 0 # Sampled Data Address Register\n"
|
|
"ctr sier .64 2524 0 # Sampled Instruction Event Register\n"
|
|
"ctr sier2 .64 2532 0 # Sampled Instruction Event Register 2\n"
|
|
"ctr sier3 .64 2540 0 # Sampled Instruction Event Register 3\n"
|
|
"ctr mmcr3 .64 2548 0 # Monitor Mode Control Register 2\n"
|
|
"ctr dpdes .64 2556 0 # Directed Privileged Doorbell Exception State Register\n"
|
|
"ctr pc .64 2564 0 # Programm Counter\n"
|
|
"ctr cr0 .4 2572 0 # Condition Register Field 0\n"
|
|
"ctr cr1 .4 2573 0 # Condition Register Field 1\n"
|
|
"ctr cr2 .4 2574 0 # Condition Register Field 2\n"
|
|
"ctr cr3 .4 2575 0 # Condition Register Field 3\n"
|
|
"ctr cr4 .4 2576 0 # Condition Register Field 4\n"
|
|
"ctr cr5 .4 2577 0 # Condition Register Field 5\n"
|
|
"ctr cr6 .4 2578 0 # Condition Register Field 6\n"
|
|
"ctr cr7 .4 2579 0 # Condition Register Field 7\n"
|
|
"ctr ppr32 .32 2580 0 # Process Priority Register 32-bit\n"
|
|
"flg so .1 2584 0 # Summary Overflow\n"
|
|
"flg ov .1 2585 0 # Overflow\n"
|
|
"flg ca .1 2586 0 # Carry\n"
|
|
"gpr 0 .32 2587 0 # The zero register.\n";
|
|
return rz_str_dup(p);
|
|
}
|
|
}
|
|
|
|
static int analyze_op_vle(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask) {
|
|
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->analysis_op;
|
|
// op->id = instr->type;
|
|
|
|
if (mask & RZ_ANALYSIS_OP_MASK_DISASM) {
|
|
op->mnemonic = rz_str_dup(instr->name);
|
|
}
|
|
switch (op->type) {
|
|
case RZ_ANALYSIS_OP_TYPE_ILL:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_ADD:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_AND:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_CALL:
|
|
op->jump = addr + instr->fields[instr->n - 1].value;
|
|
op->fail = addr + op->size;
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_CCALL:
|
|
op->eob = true;
|
|
op->jump = addr + instr->fields[instr->n - 1].value;
|
|
op->fail = addr + op->size;
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_CJMP:
|
|
op->cond = instr->cond; // RZ_TYPE_COND_NE;
|
|
op->eob = true;
|
|
op->jump = addr + instr->fields[instr->n - 1].value;
|
|
op->fail = addr + op->size;
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_CMP:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_JMP:
|
|
op->jump = addr + instr->fields[instr->n - 1].value;
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_LOAD:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_MOV:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_MUL:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_NOT:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_OR:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_ROR:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_ROL:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_RCALL:
|
|
op->eob = true;
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_RET:
|
|
op->eob = true;
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_RJMP:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_SHL:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_SHR:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_STORE:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_SUB:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_SWI:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_SYNC:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_TRAP:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_XOR:
|
|
break;
|
|
default:
|
|
// RZ_LOG_ERROR("Missing an RZ_ANALYSIS_OP_TYPE (%"PFMT64u")\n", op->type);
|
|
break;
|
|
}
|
|
vle_free(instr);
|
|
return op->size;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int parse_reg_name(RzRegItem *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 void create_src_dst(RzAnalysisOp *op, PPCContext *ctx) {
|
|
op->src[0] = rz_analysis_value_new();
|
|
op->src[1] = rz_analysis_value_new();
|
|
op->src[2] = rz_analysis_value_new();
|
|
op->dst = rz_analysis_value_new();
|
|
ZERO_FILL(ctx->base_regs[0]);
|
|
ZERO_FILL(ctx->base_regs[1]);
|
|
ZERO_FILL(ctx->base_regs[2]);
|
|
ZERO_FILL(ctx->base_regs[3]);
|
|
}
|
|
|
|
static void set_src_dst(RzAnalysisValue *val, csh *handle, cs_insn *insn, int x, PPCContext *ctx) {
|
|
cs_ppc_op ppcop = INSOP(x);
|
|
parse_reg_name(&ctx->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 = &ctx->base_regs[x];
|
|
}
|
|
|
|
static void op_fillval(RzAnalysisOp *op, csh handle, cs_insn *insn, PPCContext *ctx) {
|
|
create_src_dst(op, ctx);
|
|
switch (op->type & RZ_ANALYSIS_OP_TYPE_MASK) {
|
|
case RZ_ANALYSIS_OP_TYPE_MOV:
|
|
case RZ_ANALYSIS_OP_TYPE_CMP:
|
|
case RZ_ANALYSIS_OP_TYPE_ADD:
|
|
case RZ_ANALYSIS_OP_TYPE_SUB:
|
|
case RZ_ANALYSIS_OP_TYPE_MUL:
|
|
case RZ_ANALYSIS_OP_TYPE_DIV:
|
|
case RZ_ANALYSIS_OP_TYPE_SHR:
|
|
case RZ_ANALYSIS_OP_TYPE_SHL:
|
|
case RZ_ANALYSIS_OP_TYPE_SAL:
|
|
case RZ_ANALYSIS_OP_TYPE_SAR:
|
|
case RZ_ANALYSIS_OP_TYPE_OR:
|
|
case RZ_ANALYSIS_OP_TYPE_AND:
|
|
case RZ_ANALYSIS_OP_TYPE_XOR:
|
|
case RZ_ANALYSIS_OP_TYPE_NOR:
|
|
case RZ_ANALYSIS_OP_TYPE_NOT:
|
|
case RZ_ANALYSIS_OP_TYPE_LOAD:
|
|
case RZ_ANALYSIS_OP_TYPE_LEA:
|
|
case RZ_ANALYSIS_OP_TYPE_ROR:
|
|
case RZ_ANALYSIS_OP_TYPE_ROL:
|
|
case RZ_ANALYSIS_OP_TYPE_CAST:
|
|
set_src_dst(op->src[2], &handle, insn, 3, ctx);
|
|
set_src_dst(op->src[1], &handle, insn, 2, ctx);
|
|
set_src_dst(op->src[0], &handle, insn, 1, ctx);
|
|
set_src_dst(op->dst, &handle, insn, 0, ctx);
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_STORE:
|
|
set_src_dst(op->dst, &handle, insn, 1, ctx);
|
|
set_src_dst(op->src[0], &handle, insn, 0, ctx);
|
|
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;
|
|
}
|
|
|
|
static int ppc_analyze_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask) {
|
|
PPCContext *ctx = (PPCContext *)a->plugin_data;
|
|
int n, ret;
|
|
cs_insn *insn;
|
|
char *op1;
|
|
int mode = (a->bits == 64) ? CS_MODE_64 : (a->bits == 32) ? CS_MODE_32
|
|
: 0;
|
|
mode |= a->big_endian ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN;
|
|
|
|
if (a->cpu && strncmp(a->cpu, "vle", 3) == 0) {
|
|
// vle is big-endian only
|
|
if (!a->big_endian) {
|
|
return -1;
|
|
}
|
|
ret = analyze_op_vle(a, op, addr, buf, len, mask);
|
|
if (ret >= 0) {
|
|
return op->size;
|
|
}
|
|
} else if (a->cpu && RZ_STR_EQ(a->cpu, "qpx")) {
|
|
mode |= CS_MODE_QPX;
|
|
}
|
|
|
|
if (mode != ctx->omode || a->bits != ctx->obits) {
|
|
cs_close(&ctx->handle);
|
|
ctx->handle = 0;
|
|
ctx->omode = mode;
|
|
ctx->obits = a->bits;
|
|
}
|
|
if (ctx->handle == 0) {
|
|
ret = cs_open(CS_ARCH_PPC, mode, &ctx->handle);
|
|
if (ret != CS_ERR_OK) {
|
|
return -1;
|
|
}
|
|
cs_option(ctx->handle, CS_OPT_DETAIL, CS_OPT_ON);
|
|
#if CS_NEXT_VERSION >= 6
|
|
cs_option(ctx->handle, CS_OPT_DETAIL, CS_OPT_DETAIL_REAL);
|
|
#endif
|
|
}
|
|
op->size = 4;
|
|
|
|
// capstone-next
|
|
n = cs_disasm(ctx->handle, (const ut8 *)buf, len, addr, 1, &insn);
|
|
if (n < 1) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
|
|
op->il_op = rz_il_op_new_empty();
|
|
} else {
|
|
op->il_op = rz_ppc_cs_get_il_op(ctx->handle, insn, mode);
|
|
if (mask & RZ_ANALYSIS_OP_MASK_DISASM) {
|
|
op->mnemonic = rz_str_dup(insn->mnemonic);
|
|
}
|
|
if (mask & RZ_ANALYSIS_OP_MASK_OPEX) {
|
|
op->opex = ppc_opex(ctx->handle, insn);
|
|
}
|
|
struct Getarg gop = {
|
|
.handle = ctx->handle,
|
|
.insn = insn,
|
|
.bits = a->bits
|
|
};
|
|
op->size = insn->size;
|
|
op->id = insn->id;
|
|
switch (insn->id) {
|
|
case PPC_INS_CMPB:
|
|
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 == 5 && CS_NEXT_VERSION < 6
|
|
case PPC_INS_CMP:
|
|
case PPC_INS_CMPI:
|
|
#endif
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CMP;
|
|
op->sign = true;
|
|
/* 0b01 == equal
|
|
* 0b10 == less than */
|
|
if (ARG(2)[0] == '\0') {
|
|
esilprintf(op, ",%s,%s,-,!,cr0,=,%s,%s,<,?{2,cr0,|=,}", ARG(1), ARG(0), ARG(1), ARG(0));
|
|
} else {
|
|
esilprintf(op, ",%s,%s,-,!,%s,=,%s,%s,<,?{2,%s,|=,}", ARG(2), ARG(1), ARG(0), ARG(2), ARG(1), ARG(0));
|
|
}
|
|
break;
|
|
case PPC_INS_MFLR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "lr,%s,=", ARG(0));
|
|
break;
|
|
case PPC_INS_MTLR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "%s,lr,=", ARG(0));
|
|
break;
|
|
#if CS_NEXT_VERSION < 6
|
|
case PPC_INS_CLRLWI:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_AND;
|
|
esilprintf(op, "%s,%s,&,%s,=", ARG(1), cmask32(a, ARG(2), "0x1F"), ARG(0));
|
|
break;
|
|
case PPC_INS_MR:
|
|
#endif
|
|
case PPC_INS_LI:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
op->val = IMM(1);
|
|
esilprintf(op, "%s,%s,=", ARG(1), ARG(0));
|
|
break;
|
|
case PPC_INS_LIS:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
op->val = IMM(1);
|
|
op->val <<= 16;
|
|
esilprintf(op, "%s0000,%s,=", ARG(1), ARG(0));
|
|
break;
|
|
case PPC_INS_RLWINM:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ROL;
|
|
esilprintf(op, "%s,%s,<<<,%s,&,%s,=", ARG(2), ARG(1), cmask32(a, ARG(3), ARG(4)), ARG(0));
|
|
break;
|
|
case PPC_INS_SC:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SWI;
|
|
esilprintf(op, "0,$");
|
|
break;
|
|
case PPC_INS_EXTSB:
|
|
op->sign = true;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
if (a->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->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:
|
|
#if CS_NEXT_VERSION < 6
|
|
case PPC_INS_LWSYNC:
|
|
case PPC_INS_MSYNC:
|
|
case PPC_INS_PTESYNC:
|
|
#endif
|
|
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 = RZ_ANALYSIS_OP_TYPE_NOP;
|
|
esilprintf(op, ",");
|
|
break;
|
|
case PPC_INS_STW:
|
|
case PPC_INS_STWUX:
|
|
case PPC_INS_STWX:
|
|
case PPC_INS_STWCX:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
esilprintf(op, "%s,%s", ARG(0), ARG2(1, "=[4]"));
|
|
break;
|
|
case PPC_INS_STWU:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_STACK_INC;
|
|
op->stackptr = -atoi(op1);
|
|
}
|
|
break;
|
|
case PPC_INS_STWBRX:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
break;
|
|
case PPC_INS_STB:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
esilprintf(op, "%s,%s", ARG(0), ARG2(1, "=[1]"));
|
|
break;
|
|
case PPC_INS_STBU:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
esilprintf(op, "%s,%s", ARG(0), ARG2(1, "=[2]"));
|
|
break;
|
|
case PPC_INS_STHU:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
esilprintf(op, "%s,%s", ARG(0), ARG2(1, "=[8]"));
|
|
break;
|
|
case PPC_INS_STDU:
|
|
op->type = RZ_ANALYSIS_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:
|
|
case PPC_INS_LBZCIX:
|
|
case PPC_INS_LBZU:
|
|
case PPC_INS_LBZUX:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
esilprintf(op, "%s,%s,=", ARG2(1, "[1]"), ARG(0));
|
|
break;
|
|
case PPC_INS_LD:
|
|
case PPC_INS_LDARX:
|
|
case PPC_INS_LDCIX:
|
|
case PPC_INS_LDU:
|
|
case PPC_INS_LDUX:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
esilprintf(op, "%s,%s,=", ARG2(1, "[8]"), ARG(0));
|
|
break;
|
|
case PPC_INS_LDBRX:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_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 = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
break;
|
|
case PPC_INS_LWA:
|
|
case PPC_INS_LWARX:
|
|
case PPC_INS_LWAUX:
|
|
case PPC_INS_LWAX:
|
|
case PPC_INS_LWZ:
|
|
case PPC_INS_LWZCIX:
|
|
case PPC_INS_LWZX:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
esilprintf(op, "%s,%s,=", ARG2(1, "[4]"), ARG(0));
|
|
break;
|
|
case PPC_INS_LWZU:
|
|
case PPC_INS_LWZUX:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
break;
|
|
case PPC_INS_SLW:
|
|
case PPC_INS_SLWI:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_SHR;
|
|
esilprintf(op, "%s,%s,>>,%s,=", ARG(2), ARG(1), ARG(0));
|
|
break;
|
|
case PPC_INS_MULLI:
|
|
op->sign = true;
|
|
// fallthrough
|
|
case PPC_INS_MULLW:
|
|
case PPC_INS_MULLD:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MUL;
|
|
esilprintf(op, "%s,%s,*,%s,=", ARG(2), ARG(1), ARG(0));
|
|
break;
|
|
#if CS_NEXT_VERSION < 6
|
|
case PPC_INS_SUB:
|
|
case PPC_INS_SUBC:
|
|
#endif
|
|
case PPC_INS_SUBF:
|
|
case PPC_INS_SUBFIC:
|
|
case PPC_INS_SUBFZE:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
esilprintf(op, "%s,%s,-,%s,=", ARG(1), ARG(2), ARG(0));
|
|
break;
|
|
case PPC_INS_ADDI:
|
|
op->val = ((st16)IMM(2));
|
|
op->sign = true;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
esilprintf(op, "%" PFMT64d ",%s,+,%s,=", (st64)op->val, ARG(1), ARG(0));
|
|
break;
|
|
case PPC_INS_ADD:
|
|
op->sign = true;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
esilprintf(op, "%s,%s,+,%s,=", ARG(2), ARG(1), ARG(0));
|
|
break;
|
|
#if CS_NEXT_VERSION < 6
|
|
case PPC_INS_CRCLR:
|
|
case PPC_INS_CRSET:
|
|
case PPC_INS_CRMOVE:
|
|
case PPC_INS_CRNOT:
|
|
#endif
|
|
case PPC_INS_CRXOR:
|
|
case PPC_INS_CRNOR:
|
|
// reset conditional bits
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
break;
|
|
case PPC_INS_ADDC:
|
|
case PPC_INS_ADDIC:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
esilprintf(op, "%s,%s,+,%s,=", ARG(2), ARG(1), ARG(0));
|
|
break;
|
|
case PPC_INS_ADDE:
|
|
case PPC_INS_ADDIS:
|
|
case PPC_INS_ADDME:
|
|
case PPC_INS_ADDZE:
|
|
#if CS_NEXT_VERSION >= 6
|
|
switch (insn->alias_id) {
|
|
default:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
esilprintf(op, "%s,%s,+,%s,=", ARG(2), ARG(1), ARG(0));
|
|
break;
|
|
case PPC_INS_ALIAS_LIS:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
op->val = IMM(2);
|
|
op->val <<= 16;
|
|
esilprintf(op, "0x%" PFMT64x "0000,%s,=", IMM(2), ARG(0));
|
|
break;
|
|
}
|
|
#else
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
esilprintf(op, "%s,%s,+,%s,=", ARG(2), ARG(1), ARG(0));
|
|
#endif
|
|
break;
|
|
case PPC_INS_MTSPR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "%s,%s,=", ARG(1), PPCSPR(0));
|
|
break;
|
|
case PPC_INS_BCTR: // switch table here
|
|
op->type = RZ_ANALYSIS_OP_TYPE_UJMP;
|
|
esilprintf(op, "ctr,pc,=");
|
|
break;
|
|
case PPC_INS_BCTRL: // switch table here
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CALL;
|
|
esilprintf(op, "pc,lr,=,ctr,pc,=");
|
|
break;
|
|
#if CS_API_MAJOR == 5 && CS_NEXT_VERSION < 6
|
|
case PPC_INS_BEQ:
|
|
case PPC_INS_BEQA:
|
|
case PPC_INS_BFA:
|
|
case PPC_INS_BGE:
|
|
case PPC_INS_BGEA:
|
|
case PPC_INS_BGT:
|
|
case PPC_INS_BGTA:
|
|
case PPC_INS_BLE:
|
|
case PPC_INS_BLEA:
|
|
case PPC_INS_BLT:
|
|
case PPC_INS_BLTA:
|
|
case PPC_INS_BNE:
|
|
case PPC_INS_BNEA:
|
|
case PPC_INS_BNG:
|
|
case PPC_INS_BNGA:
|
|
case PPC_INS_BNL:
|
|
case PPC_INS_BNLA:
|
|
case PPC_INS_BNS:
|
|
case PPC_INS_BNSA:
|
|
case PPC_INS_BNU:
|
|
case PPC_INS_BNUA:
|
|
case PPC_INS_BSO:
|
|
case PPC_INS_BSOA:
|
|
case PPC_INS_BUN:
|
|
case PPC_INS_BUNA:
|
|
#endif
|
|
#if CS_NEXT_VERSION < 6
|
|
case PPC_INS_BT:
|
|
case PPC_INS_BF:
|
|
switch (insn->detail->ppc.operands[0].type) {
|
|
case PPC_OP_CRX:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->fail = addr + op->size;
|
|
break;
|
|
case PPC_OP_REG:
|
|
if (op->type == RZ_ANALYSIS_OP_TYPE_CJMP) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_UCJMP;
|
|
} else {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
}
|
|
op->jump = IMM(1);
|
|
op->fail = addr + op->size;
|
|
// op->type = RZ_ANALYSIS_OP_TYPE_UJMP;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case PPC_INS_BDNZ:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = IMM(0);
|
|
op->fail = addr + op->size;
|
|
break;
|
|
case PPC_INS_BDNZL:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = IMM(0);
|
|
op->fail = addr + op->size;
|
|
break;
|
|
case PPC_INS_BDNZLA:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = IMM(0);
|
|
op->fail = addr + op->size;
|
|
break;
|
|
case PPC_INS_BDNZLR:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
break;
|
|
case PPC_INS_BDZ:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = IMM(0);
|
|
op->fail = addr + op->size;
|
|
break;
|
|
case PPC_INS_BDZL:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = IMM(0);
|
|
op->fail = addr + op->size;
|
|
break;
|
|
case PPC_INS_BDZLA:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = IMM(0);
|
|
op->fail = addr + op->size;
|
|
break;
|
|
case PPC_INS_BDZLR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->fail = addr + op->size;
|
|
esilprintf(op, "1,ctr,-=,$z,?{,lr,pc,=,}");
|
|
break;
|
|
case PPC_INS_BDZLRL:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->fail = addr + op->size;
|
|
break;
|
|
#endif
|
|
case PPC_INS_B:
|
|
case PPC_INS_BC:
|
|
case PPC_INS_BA:
|
|
case PPC_INS_BCL:
|
|
case PPC_INS_BLR:
|
|
case PPC_INS_BLRL:
|
|
case PPC_INS_BCLR:
|
|
case PPC_INS_BCLRL:
|
|
case PPC_INS_BCCTR:
|
|
case PPC_INS_BCCTRL: {
|
|
if (insn->id == PPC_INS_BC || insn->id == PPC_INS_BCCTR) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
} else if (insn->id == PPC_INS_B || insn->id == PPC_INS_BA) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
|
|
} else if (insn->id == PPC_INS_BCLR || insn->id == PPC_INS_BCLRL) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CRET;
|
|
} else if (insn->id == PPC_INS_BLR || insn->id == PPC_INS_BLRL) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RET;
|
|
} else if (insn->id == PPC_INS_BCCTRL) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CCALL;
|
|
}
|
|
bool cr_cond_set = true;
|
|
bool ctr_cond_set = true;
|
|
#if CS_NEXT_VERSION >= 6
|
|
switch (insn->detail->ppc.bc.pred_cr) {
|
|
case PPC_PRED_LT:
|
|
esilprintf(op, "2,%s,&,", cs_reg_name(ctx->handle, insn->detail->ppc.bc.crX));
|
|
#else
|
|
switch (insn->detail->ppc.bc) {
|
|
case PPC_BC_LT:
|
|
if (ARG(1)[0] == '\0') {
|
|
esilprintf(op, "2,cr0,&,");
|
|
} else {
|
|
esilprintf(op, "2,%s,&,", ARG(0));
|
|
}
|
|
#endif
|
|
break;
|
|
#if CS_NEXT_VERSION >= 6
|
|
case PPC_PRED_LE:
|
|
esilprintf(op, "3,%s,&,", cs_reg_name(ctx->handle, insn->detail->ppc.bc.crX));
|
|
#else
|
|
case PPC_BC_LE:
|
|
/* 0b01 == equal
|
|
* 0b10 == less than */
|
|
if (ARG(1)[0] == '\0') {
|
|
esilprintf(op, "3,cr0,&,?{,%s,pc,=,},", ARG(0));
|
|
} else {
|
|
esilprintf(op, "3,%s,&,?{,%s,pc,=,},", ARG(0), ARG(1));
|
|
}
|
|
#endif
|
|
break;
|
|
#if CS_NEXT_VERSION >= 6
|
|
case PPC_PRED_EQ:
|
|
esilprintf(op, "1,%s,&,", cs_reg_name(ctx->handle, insn->detail->ppc.bc.crX));
|
|
#else
|
|
case PPC_BC_EQ:
|
|
if (ARG(1)[0] == '\0') {
|
|
esilprintf(op, "1,cr0,&,");
|
|
} else {
|
|
esilprintf(op, "1,%s,&,", ARG(0));
|
|
}
|
|
#endif
|
|
break;
|
|
#if CS_NEXT_VERSION >= 6
|
|
case PPC_PRED_GE:
|
|
esilprintf(op, "2,%s,^,3,&,", cs_reg_name(ctx->handle, insn->detail->ppc.bc.crX));
|
|
#else
|
|
case PPC_BC_GE:
|
|
if (ARG(1)[0] == '\0') {
|
|
esilprintf(op, "2,cr0,^,3,&,");
|
|
} else {
|
|
esilprintf(op, "2,%s,^,3,&,", ARG(0));
|
|
}
|
|
#endif
|
|
break;
|
|
#if CS_NEXT_VERSION >= 6
|
|
case PPC_PRED_GT:
|
|
esilprintf(op, "2,%s,&,!,", cs_reg_name(ctx->handle, insn->detail->ppc.bc.crX));
|
|
#else
|
|
case PPC_BC_GT:
|
|
if (ARG(1)[0] == '\0') {
|
|
esilprintf(op, "2,cr0,&,!,");
|
|
} else {
|
|
esilprintf(op, "2,%s,&,!,", ARG(0));
|
|
}
|
|
#endif
|
|
break;
|
|
#if CS_NEXT_VERSION >= 6
|
|
case PPC_PRED_NE:
|
|
esilprintf(op, "%s,1,&,!,", cs_reg_name(ctx->handle, insn->detail->ppc.bc.crX));
|
|
#else
|
|
case PPC_BC_NE:
|
|
if (ARG(1)[0] == '\0') {
|
|
esilprintf(op, "cr0,1,&,!,");
|
|
} else {
|
|
esilprintf(op, "%s,1,&,!,", ARG(0));
|
|
}
|
|
#endif
|
|
break;
|
|
#if CS_NEXT_VERSION >= 6
|
|
case PPC_PRED_INVALID:
|
|
case PPC_PRED_UN: // unordered + PPC_PRED_SO - summary overflow
|
|
case PPC_PRED_NU: // not unordered + PPC_PRED_NS - not summary overflow
|
|
#else
|
|
case PPC_BC_INVALID:
|
|
case PPC_BC_UN: // unordered
|
|
case PPC_BC_NU: // not unordered
|
|
case PPC_BC_SO: // summary overflow
|
|
case PPC_BC_NS: // not summary overflow
|
|
#endif
|
|
default:
|
|
cr_cond_set = false;
|
|
break;
|
|
}
|
|
#if CS_NEXT_VERSION >= 6
|
|
switch (insn->detail->ppc.bc.pred_ctr) {
|
|
default:
|
|
ctr_cond_set = false;
|
|
break;
|
|
case PPC_PRED_Z:
|
|
rz_strbuf_appendf(&op->esil, "1,ctr,-=,$z,%s", cr_cond_set ? "&&,?" : "?");
|
|
break;
|
|
case PPC_PRED_NZ:
|
|
rz_strbuf_appendf(&op->esil, "1,ctr,-=,$z,!,%s", cr_cond_set ? "&&,?" : "?");
|
|
break;
|
|
}
|
|
#endif
|
|
bool is_cond = cr_cond_set || ctr_cond_set;
|
|
if (is_cond) {
|
|
rz_strbuf_appendf(&op->esil, "{,");
|
|
op->fail = addr + op->size;
|
|
}
|
|
|
|
if (insn->id == PPC_INS_B || insn->id == PPC_INS_BC || insn->id == PPC_INS_BA || insn->id == PPC_INS_BCL) {
|
|
#if CS_NEXT_VERSION >= 6
|
|
op->jump = (insn->id == PPC_INS_BC || insn->id == PPC_INS_BCL) ? IMM(2) : IMM(0);
|
|
#else
|
|
op->jump = ARG(1)[0] == '\0' ? IMM(0) : IMM(1);
|
|
#endif
|
|
}
|
|
|
|
if (insn->id == PPC_INS_BLRL ||
|
|
insn->id == PPC_INS_BCLRL ||
|
|
insn->id == PPC_INS_BCCTRL ||
|
|
insn->id == PPC_INS_BCL) {
|
|
op->fail = addr + op->size;
|
|
rz_strbuf_appendf(&op->esil, "0x%" PFMT64x ",lr,=,", op->fail);
|
|
}
|
|
|
|
// Set target source
|
|
if (insn->id == PPC_INS_BCCTR || insn->id == PPC_INS_BCCTRL) {
|
|
rz_strbuf_appendf(&op->esil, "ctr,pc,=,");
|
|
} else if (op->type == RZ_ANALYSIS_OP_TYPE_CRET || op->type == RZ_ANALYSIS_OP_TYPE_RET) {
|
|
rz_strbuf_appendf(&op->esil, "lr,pc,=,");
|
|
} else {
|
|
rz_strbuf_appendf(&op->esil, "0x%" PFMT64x ",pc,=,", op->jump);
|
|
}
|
|
if (is_cond) {
|
|
rz_strbuf_appendf(&op->esil, "},");
|
|
}
|
|
break;
|
|
}
|
|
case PPC_INS_NOR:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_XOR;
|
|
esilprintf(op, "%s,%s,^,%s,=", ARG(2), ARG(1), ARG(0));
|
|
break;
|
|
case PPC_INS_XORIS:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_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 = RZ_ANALYSIS_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 = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_TRAP;
|
|
break;
|
|
case PPC_INS_AND:
|
|
case PPC_INS_NAND:
|
|
case PPC_INS_ANDI:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_AND;
|
|
esilprintf(op, "%s,%s,&,%s,=", ARG(2), ARG(1), ARG(0));
|
|
break;
|
|
case PPC_INS_ANDIS:
|
|
op->type = RZ_ANALYSIS_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 = RZ_ANALYSIS_OP_TYPE_OR;
|
|
esilprintf(op, "%s,%s,|,%s,=", ARG(2), ARG(1), ARG(0));
|
|
break;
|
|
case PPC_INS_ORIS:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_OR;
|
|
esilprintf(op, "16,%s,<<,%s,|,%s,=", ARG(2), ARG(1), ARG(0));
|
|
break;
|
|
#if CS_NEXT_VERSION < 6
|
|
case PPC_INS_MFPVR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "pvr,%s,=", ARG(0));
|
|
break;
|
|
#endif
|
|
case PPC_INS_MFSPR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "%s,%s,=", PPCSPR(1), ARG(0));
|
|
break;
|
|
case PPC_INS_MFCTR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "ctr,%s,=", ARG(0));
|
|
break;
|
|
#if CS_NEXT_VERSION < 6
|
|
case PPC_INS_MFDCCR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "dccr,%s,=", ARG(0));
|
|
break;
|
|
case PPC_INS_MFICCR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "iccr,%s,=", ARG(0));
|
|
break;
|
|
case PPC_INS_MFDEAR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "dear,%s,=", ARG(0));
|
|
break;
|
|
#endif
|
|
case PPC_INS_MFMSR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "msr,%s,=", ARG(0));
|
|
break;
|
|
case PPC_INS_MTCTR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "%s,ctr,=", ARG(0));
|
|
break;
|
|
#if CS_NEXT_VERSION < 6
|
|
case PPC_INS_MTDCCR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "%s,dccr,=", ARG(0));
|
|
break;
|
|
case PPC_INS_MTICCR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "%s,iccr,=", ARG(0));
|
|
break;
|
|
case PPC_INS_MTDEAR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "%s,dear,=", ARG(0));
|
|
break;
|
|
#endif
|
|
case PPC_INS_MTMSR:
|
|
case PPC_INS_MTMSRD:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
esilprintf(op, "%s,msr,=", ARG(0));
|
|
break;
|
|
// Data Cache Block Zero
|
|
case PPC_INS_DCBZ:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
esilprintf(op, "%s,%s", ARG(0), ARG2(1, ",=[128]"));
|
|
break;
|
|
#if CS_NEXT_VERSION < 6
|
|
case PPC_INS_CLRLDI:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_AND;
|
|
esilprintf(op, "%s,%s,&,%s,=", ARG(1), cmask64(a, ARG(2), "0x3F"), ARG(0));
|
|
break;
|
|
case PPC_INS_ROTLDI:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ROL;
|
|
esilprintf(op, "%s,%s,<<<,%s,=", ARG(2), ARG(1), ARG(0));
|
|
break;
|
|
#endif
|
|
case PPC_INS_RLDCL:
|
|
case PPC_INS_RLDICL:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ROL;
|
|
esilprintf(op, "%s,%s,<<<,%s,&,%s,=", ARG(2), ARG(1), cmask64(a, ARG(3), "0x3F"), ARG(0));
|
|
break;
|
|
case PPC_INS_RLDCR:
|
|
case PPC_INS_RLDICR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ROL;
|
|
esilprintf(op, "%s,%s,<<<,%s,&,%s,=", ARG(2), ARG(1), cmask64(a, 0, ARG(3)), ARG(0));
|
|
break;
|
|
}
|
|
if (mask & RZ_ANALYSIS_OP_MASK_VAL) {
|
|
op_fillval(op, ctx->handle, insn, ctx);
|
|
}
|
|
if (!(mask & RZ_ANALYSIS_OP_MASK_ESIL)) {
|
|
rz_strbuf_fini(&op->esil);
|
|
}
|
|
cs_free(insn, n);
|
|
}
|
|
return op->size;
|
|
}
|
|
|
|
static int ppc_archinfo(RzAnalysis *a, RzAnalysisInfoType query) {
|
|
bool is_vle = a && a->cpu && !strncmp(a->cpu, "vle", 3);
|
|
|
|
switch (query) {
|
|
case RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE:
|
|
return is_vle ? 2 : 4;
|
|
case RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE:
|
|
return 4;
|
|
case RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN:
|
|
return is_vle ? 2 : 4;
|
|
case RZ_ANALYSIS_ARCHINFO_DATA_ALIGN:
|
|
return 1;
|
|
case RZ_ANALYSIS_ARCHINFO_CAN_USE_POINTERS:
|
|
return true;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static RzList /*<RzSearchKeyword *>*/ *ppc_analysis_preludes(RzAnalysis *analysis) {
|
|
#define KW(d, ds, m, ms) rz_list_append(l, rz_search_keyword_new((const ut8 *)d, ds, (const ut8 *)m, ms, NULL))
|
|
RzList *l = rz_list_newf((RzListFree)rz_search_keyword_free);
|
|
KW("\x7c\x08\x02\xa6", 4, NULL, 0);
|
|
return l;
|
|
}
|
|
|
|
static RzAnalysisILConfig *ppc_il_config(RzAnalysis *analysis) {
|
|
if (analysis->bits == 64) {
|
|
return rz_ppc_cs_64_il_config(analysis->big_endian);
|
|
}
|
|
return rz_ppc_cs_32_il_config(analysis->big_endian);
|
|
}
|
|
|
|
static bool ppc_fini(void *user) {
|
|
PPCContext *ctx = (PPCContext *)user;
|
|
cs_close(&ctx->handle);
|
|
if (ctx) {
|
|
RZ_FREE(ctx);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
RzAnalysisPlugin rz_analysis_plugin_ppc_cs = {
|
|
.name = "ppc",
|
|
.desc = "Capstone PowerPC analysis",
|
|
.license = "BSD",
|
|
.esil = true,
|
|
.arch = "ppc",
|
|
.bits = 32 | 64,
|
|
.archinfo = ppc_archinfo,
|
|
.preludes = ppc_analysis_preludes,
|
|
.op = &ppc_analyze_op,
|
|
.init = ppc_init,
|
|
.fini = ppc_fini,
|
|
.get_reg_profile = &ppc_get_reg_profile,
|
|
.il_config = ppc_il_config,
|
|
};
|
|
|
|
#ifndef RZ_PLUGIN_INCORE
|
|
RZ_API RzLibStruct rizin_plugin = {
|
|
.type = RZ_LIB_TYPE_ANALYSIS,
|
|
.data = &rz_analysis_plugin_ppc_cs,
|
|
.version = RZ_VERSION
|
|
};
|
|
#endif
|