Skip to content

Commit

Permalink
hppa: use capstone disassembler
Browse files Browse the repository at this point in the history
  • Loading branch information
XVilka committed May 4, 2024
1 parent b06557b commit d1c404b
Show file tree
Hide file tree
Showing 6 changed files with 422 additions and 0 deletions.
18 changes: 18 additions & 0 deletions librz/arch/isa/hppa/hppa.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2024 Anton Kochkov <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

#include <rz_types.h>
#include <capstone.h>

#ifndef RZ_HPPA_H
#define RZ_HPPA_H

typedef struct {
csh h;
cs_mode mode;
cs_insn *insn;
ut32 count;
ut32 word;
} RzAsmHPPAContext;

#endif // RZ_HPPA_H
82 changes: 82 additions & 0 deletions librz/arch/isa/hppa/hppa.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-FileCopyrightText: 2023 billow <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

#include <capstone/capstone.h>
#include <capstone/hppa.h>
#include "hppa.h"

static inline cs_mode hppa_cpu_to_cs_mode(const char *cpu_type) {
if (RZ_STR_ISNOTEMPTY(cpu_type)) {
if (!strcmp(cpu_type, "hppa1.1")) {
return CS_MODE_HPPA_11;
}
if (!strcmp(cpu_type, "hppa2.0")) {
return CS_MODE_HPPA_20;
}
if (!strcmp(cpu_type, "hppa2.0w")) {
return CS_MODE_HPPA_20W;
}
}
return CS_MODE_HPPA_11;
}

static inline bool hppa_setup_cs_handle(RzAsmHPPAContext *ctx, const char *cpu, const char *features) {
const cs_mode mode = hppa_cpu_to_cs_mode(cpu) | CS_MODE_BIG_ENDIAN;
if (mode != ctx->mode) {
cs_close(&ctx->h);
ctx->h = 0;
ctx->mode = mode;
}

if (ctx->h != 0) {
return true;
}
cs_err err = cs_open(CS_ARCH_HPPA, mode, &ctx->h);
if (err) {
RZ_LOG_ERROR("Failed on cs_open() with error returned: %u\n", err);
return false;
}
err = cs_option(ctx->h, CS_OPT_DETAIL,
RZ_STR_ISNOTEMPTY(features) || features == NULL ? CS_OPT_ON : CS_OPT_OFF);
if (err) {
RZ_LOG_ERROR("Failed on cs_open() with error returned: %u\n", err);
return false;
}
return true;
}

static inline ut8 hppa_op_count(cs_insn *insn) {
return insn->detail->hppa.op_count;
}

static inline cs_hppa_op *hppa_op_get(cs_insn *insn, int idx) {
if (idx >= hppa_op_count(insn)) {
RZ_LOG_WARN("Failed to get operand%d [%d]: \"%s %s\"\n",
idx, hppa_op_count(insn), insn->mnemonic, insn->op_str);
rz_warn_if_reached();
return NULL;
}
return &insn->detail->hppa.operands[idx];
}

static inline const char *hppa_op_as_reg(RzAsmHPPAContext *ctx, int idx) {
const cs_hppa_op *op = hppa_op_get(ctx->insn, idx);
if (op->type != HPPA_OP_REG) {
RZ_LOG_WARN("Failed to get operand%d [%d]: \"%s %s\" [reg]\n",
idx, hppa_op_count(ctx->insn), ctx->insn->mnemonic, ctx->insn->op_str);
rz_warn_if_reached();
return NULL;
}
return cs_reg_name(ctx->h, op->reg);
}

static inline st64 hppa_op_as_imm(RzAsmHPPAContext *ctx, int idx) {
const cs_hppa_op *op = hppa_op_get(ctx->insn, idx);
if (op->type != HPPA_OP_IMM) {
RZ_LOG_WARN("Failed to get operand%d [%d]: \"%s %s\" [imm]\n",
idx, hppa_op_count(ctx->insn), ctx->insn->mnemonic, ctx->insn->op_str);
rz_warn_if_reached();
return 0;
}
return op->imm;
}
2 changes: 2 additions & 0 deletions librz/arch/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ arch_plugins_list = [
'gb',
'h8300',
'hexagon',
'hppa_cs',
'i4004',
'i8080',
'java',
Expand Down Expand Up @@ -76,6 +77,7 @@ arch_plugin_sources = [
'p/arch_ebc.c',
'p/arch_gb.c',
'p/arch_h8300.c',
'p/arch_hppa_cs.c',
'p/arch_hexagon.c',
'p/arch_i4004.c',
'p/arch_i8080.c',
Expand Down
227 changes: 227 additions & 0 deletions librz/arch/p/analysis/analysis_hppa_cs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
// SPDX-FileCopyrightText: 2024 Anton Kochkov <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

#include <rz_types.h>
#include <rz_lib.h>
#include <rz_asm.h>
#include <capstone/capstone.h>

#include <hppa/hppa.inc>

static char *hppa_reg_profile(RzAnalysis *_) {
const char *p =
"=PC pc\n"
"=SP gr30\n"
"=A0 gr26\n"
"=A1 gr25\n"
"=A2 gr24\n"
"=A3 gr23\n"
"gpr gr0 .32 0 0\n"
"gpr gr1 .32 4 0\n"
"gpr gr2 .32 8 0\n"
"gpr gr3 .32 12 0\n"
"gpr gr4 .32 16 0\n"
"gpr gr5 .32 20 0\n"
"gpr gr6 .32 24 0\n"
"gpr gr7 .32 28 0\n"
"gpr gr8 .32 32 0\n"
"gpr gr9 .32 36 0\n"
"gpr gr10 .32 40 0\n"
"gpr gr11 .32 44 0\n"
"gpr gr12 .32 48 0\n"
"gpr gr13 .32 52 0\n"
"gpr gr14 .32 56 0\n"
"gpr gr15 .32 60 0\n"
"gpr gr16 .32 64 0\n"
"gpr gr17 .32 68 0\n"
"gpr gr18 .32 72 0\n"
"gpr gr19 .32 76 0\n"
"gpr gr20 .32 80 0\n"
"gpr gr21 .32 84 0\n"
"gpr gr22 .32 88 0\n"
"gpr gr23 .32 92 0\n"
"gpr gr24 .32 96 0\n"
"gpr gr25 .32 100 0\n"
"gpr gr26 .32 104 0\n"
"gpr gr27 .32 108 0\n"
"gpr gr28 .32 112 0\n"
"gpr gr29 .32 116 0\n"
"gpr gr30 .32 120 0\n"
"gpr gr31 .32 124 0\n"
"ctr sr0 .32 128 0\n"
"ctr sr1 .32 132 0\n"
"ctr sr2 .32 136 0\n"
"ctr sr3 .32 140 0\n"
"ctr sr4 .32 144 0\n"
"ctr sr5 .32 148 0\n"
"ctr sr6 .32 152 0\n"
"ctr sr7 .32 156 0\n"
"flg psw .32 160 0\n";
return strdup(p);
}

static void hppa_opex(RzAsmHPPAContext *ctx, RzStrBuf *sb) {
PJ *pj = pj_new();
if (!pj) {
return;
}
pj_o(pj);
pj_ka(pj, "operands");
cs_hppa *hpc = &ctx->insn->detail->hppa;
for (st32 i = 0; i < hpc->op_count; i++) {
cs_hppa_op *op = hpc->operands + i;
pj_o(pj);
switch (op->type) {
case HPPA_OP_INVALID: {
pj_ks(pj, "type", "invalid");
break;
}
case HPPA_OP_REG: {
pj_ks(pj, "type", "reg");
pj_ks(pj, "value", cs_reg_name(ctx->h, op->reg));
break;
}
case HPPA_OP_IMM: {
pj_ks(pj, "type", "imm");
pj_ki(pj, "value", op->imm);
break;
}
case HPPA_OP_MEM: {
pj_ks(pj, "type", "mem");
pj_ks(pj, "base", cs_reg_name(ctx->h, op->mem.base));
pj_ks(pj, "space", cs_reg_name(ctx->h, op->mem.space));
break;
}
// FIXME: Handle other types as well
default:
break;
}
pj_end(pj);
}
pj_end(pj);
pj_end(pj);

rz_strbuf_init(sb);
rz_strbuf_append(sb, pj_string(pj));
pj_free(pj);
}

static void hppa_op_set_type(RzAsmHPPAContext *ctx, RzAnalysisOp *op) {
switch (ctx->insn->id) {
default: {
op->type = RZ_ANALYSIS_OP_TYPE_UNK;
break;
}
case HPPA_INS_BL: {
op->type = RZ_ANALYSIS_OP_TYPE_IRCALL;
op->jump = hppa_op_as_imm(ctx, 0);
break;
}
case HPPA_INS_BLR: {
op->type = RZ_ANALYSIS_OP_TYPE_IRJMP;
op->reg = hppa_op_as_reg(ctx, 0);
break;
}
}
}

static int
hppa_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask) {
if (!(a && op && data && len > 0)) {
return 0;
}
if (!a->big_endian) {
return -1;
}

RzAsmHPPAContext *ctx = a->plugin_data;
if (!hppa_setup_cs_handle(ctx, a->cpu, NULL)) {
return -1;
}

op->size = 2;

ctx->insn = NULL;
ctx->count = cs_disasm(ctx->h, (const ut8 *)data, len, addr, 1, &ctx->insn);
if (ctx->count <= 0 || !ctx->insn) {
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
if (mask & RZ_ANALYSIS_OP_MASK_DISASM) {
op->mnemonic = strdup("invalid");
}
goto beach;
}

if (mask & RZ_ANALYSIS_OP_MASK_DISASM) {
op->mnemonic = rz_str_newf("%s%s%s",
ctx->insn->mnemonic, ctx->insn->op_str[0] ? " " : "", ctx->insn->op_str);
}
op->size = ctx->insn->size;
op->id = (int)ctx->insn->id;
op->addr = ctx->insn->address;
hppa_op_set_type(ctx, op);
if (mask & RZ_ANALYSIS_OP_MASK_OPEX) {
hppa_opex(ctx, &op->opex);
}

beach:
cs_free(ctx->insn, ctx->count);
return op->size;
}

static int hppa_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:
case RZ_ANALYSIS_ARCHINFO_DATA_ALIGN:
case RZ_ANALYSIS_ARCHINFO_CAN_USE_POINTERS:
default:
return -1;
}
}

static bool hppa_init(void **u) {
if (!u) {
return false;
}
RzAsmHPPAContext *ctx = RZ_NEW0(RzAsmHPPAContext);
if (!ctx) {
return false;
}
*u = ctx;
return true;
}

static bool hppa_fini(void *u) {
if (!u) {
return true;
}
RzAsmHPPAContext *ctx = u;
cs_close(&ctx->h);
free(u);
return true;
}

RzAnalysisPlugin rz_analysis_plugin_hppa_cs = {
.name = "hppa",
.desc = "Capstone HP PA-RISC analysis plugin",
.author = "xvilka",
.license = "LGPL3",
.arch = "hppa",
.bits = 32 | 64,
.get_reg_profile = hppa_reg_profile,
.archinfo = hppa_archinfo,
.op = hppa_op,
.init = hppa_init,
.fini = hppa_fini,
};

#ifndef RZ_PLUGIN_INCORE
RZ_API RzLibStruct rizin_plugin = {
.type = RZ_LIB_TYPE_ANALYSIS,
.data = &rz_analysis_plugin_hppa_cs,
.version = RZ_VERSION
};
#endif
9 changes: 9 additions & 0 deletions librz/arch/p/arch_hppa_cs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-FileCopyrightText: 2024 RizinOrg <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

#include <deprecated_arch_helper.h>

#include "analysis/analysis_hppa_cs.c"
#include "asm/asm_hppa_cs.c"

RZ_ARCH_PLUGIN_DEFINE_DEPRECATED(hppa_cs);
Loading

0 comments on commit d1c404b

Please sign in to comment.