rizin/librz/arch/p/analysis/analysis_sysz.c
2024-09-15 19:12:07 +08:00

210 lines
4.7 KiB
C

// SPDX-FileCopyrightText: 2014-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/systemz.h>
// instruction set: http://www.tachyonsoft.com/inst390m.htm
#define INSOP(n) insn->detail->sysz.operands[n]
static void opex(RzStrBuf *buf, csh handle, cs_insn *insn) {
int i;
PJ *pj = pj_new();
if (!pj) {
return;
}
pj_o(pj);
pj_ka(pj, "operands");
cs_sysz *x = &insn->detail->sysz;
for (i = 0; i < x->op_count; i++) {
cs_sysz_op *op = x->operands + i;
pj_o(pj);
switch (op->type) {
case SYSZ_OP_REG:
pj_ks(pj, "type", "reg");
pj_ks(pj, "value", cs_reg_name(handle, op->reg));
break;
case SYSZ_OP_IMM:
pj_ks(pj, "type", "imm");
pj_kN(pj, "value", op->imm);
break;
case SYSZ_OP_MEM:
pj_ks(pj, "type", "mem");
if (op->mem.base != SYSZ_REG_INVALID) {
pj_ks(pj, "base", cs_reg_name(handle, op->mem.base));
}
pj_kN(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);
rz_strbuf_init(buf);
rz_strbuf_append(buf, pj_string(pj));
pj_free(pj);
}
static int analyze_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask) {
csh handle;
cs_insn *insn;
int mode = CS_MODE_BIG_ENDIAN;
int ret = cs_open(CS_ARCH_SYSZ, mode, &handle);
if (ret == CS_ERR_OK) {
cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
// capstone-next
int n = cs_disasm(handle, (const ut8 *)buf, len, addr, 1, &insn);
if (n < 1) {
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
} else {
if (mask & RZ_ANALYSIS_OP_MASK_OPEX) {
opex(&op->opex, handle, insn);
}
op->size = insn->size;
switch (insn->id) {
case SYSZ_INS_BRCL:
case SYSZ_INS_BRASL:
op->type = RZ_ANALYSIS_OP_TYPE_CALL;
break;
case SYSZ_INS_BR:
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
break;
case SYSZ_INS_BRC:
case SYSZ_INS_BER:
case SYSZ_INS_BHR:
case SYSZ_INS_BHER:
case SYSZ_INS_BLR:
case SYSZ_INS_BLER:
case SYSZ_INS_BLHR:
case SYSZ_INS_BNER:
case SYSZ_INS_BNHR:
case SYSZ_INS_BNHER:
case SYSZ_INS_BNLR:
case SYSZ_INS_BNLER:
case SYSZ_INS_BNLHR:
case SYSZ_INS_BNOR:
case SYSZ_INS_BOR:
case SYSZ_INS_BASR:
case SYSZ_INS_BRAS:
case SYSZ_INS_BRCT:
case SYSZ_INS_BRCTG:
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
break;
case SYSZ_INS_JE:
case SYSZ_INS_JGE:
case SYSZ_INS_JHE:
case SYSZ_INS_JGHE:
case SYSZ_INS_JH:
case SYSZ_INS_JGH:
case SYSZ_INS_JLE:
case SYSZ_INS_JGLE:
case SYSZ_INS_JLH:
case SYSZ_INS_JGLH:
case SYSZ_INS_JL:
case SYSZ_INS_JGL:
case SYSZ_INS_JNE:
case SYSZ_INS_JGNE:
case SYSZ_INS_JNHE:
case SYSZ_INS_JGNHE:
case SYSZ_INS_JNH:
case SYSZ_INS_JGNH:
case SYSZ_INS_JNLE:
case SYSZ_INS_JGNLE:
case SYSZ_INS_JNLH:
case SYSZ_INS_JGNLH:
case SYSZ_INS_JNL:
case SYSZ_INS_JGNL:
case SYSZ_INS_JNO:
case SYSZ_INS_JGNO:
case SYSZ_INS_JO:
case SYSZ_INS_JGO:
case SYSZ_INS_JG:
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
op->jump = INSOP(0).imm;
op->fail = addr + op->size;
break;
case SYSZ_INS_J:
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
op->jump = INSOP(0).imm;
op->fail = UT64_MAX;
break;
}
}
cs_free(insn, n);
cs_close(&handle);
}
return op->size;
}
static char *get_reg_profile(RzAnalysis *analysis) {
const char *p =
"=PC r15\n"
"=LR r14\n"
"=SP r13\n"
"=BP r12\n"
"=A0 r0\n"
"=A1 r1\n"
"=A2 r2\n"
"=A3 r3\n"
"=SN r0\n"
"gpr sb .32 36 0\n" // r9
"gpr sl .32 40 0\n" // rl0
"gpr fp .32 44 0\n" // r11
"gpr ip .32 48 0\n" // r12
"gpr sp .32 52 0\n" // r13
"gpr lr .32 56 0\n" // r14
"gpr pc .32 60 0\n" // r15
"gpr r0 .32 0 0\n"
"gpr r1 .32 4 0\n"
"gpr r2 .32 8 0\n"
"gpr r3 .32 12 0\n"
"gpr r4 .32 16 0\n"
"gpr r5 .32 20 0\n"
"gpr r6 .32 24 0\n"
"gpr r7 .32 28 0\n"
"gpr r8 .32 32 0\n"
"gpr r9 .32 36 0\n"
"gpr r10 .32 40 0\n"
"gpr r11 .32 44 0\n"
"gpr r12 .32 48 0\n"
"gpr r13 .32 52 0\n"
"gpr r14 .32 56 0\n"
"gpr r15 .32 60 0\n";
return rz_str_dup(p);
}
static int archinfo(RzAnalysis *a, RzAnalysisInfoType query) {
switch (query) {
case RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE:
return 2;
case RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE:
return 4;
case RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN:
/* fall-thru */
case RZ_ANALYSIS_ARCHINFO_DATA_ALIGN:
return 2;
case RZ_ANALYSIS_ARCHINFO_CAN_USE_POINTERS:
return true;
default:
return -1;
}
}
RzAnalysisPlugin rz_analysis_plugin_sysz = {
.name = "sysz",
.desc = "Capstone SystemZ microanalysis",
.esil = false,
.license = "BSD",
.arch = "sysz",
.bits = 32 | 64,
.op = &analyze_op,
.archinfo = archinfo,
.get_reg_profile = &get_reg_profile,
};