* Fill `op->reg` for ARM64 `br`/`blr` analysis * This fixes software single-stepping on `br`/`blr` instructions on ARM64 * Fill `op->reg` for ARM `bx`/`blx` analysis * This fixes software single-stepping on `bx`/`blx` instructions on ARM * Set `bx` as `RZ_ANALYSIS_OP_TYPE_RJMP` * Fill `RzAnalysisValue->type` * Use only `RzAnalysisValue` in `rz_core_link_stroff()` * Fill `op->ireg/disp/scale` for ARM `ldr` analysis * This fixes software single-stepping for `ldr pc` on ARM * Fix riscv inverted src/dst values for store instructions * Fix riscv analysis with buffer of size 2 * Add unit tests for `RzAnalysisOp` and `RzAnalysisValue` Co-authored-by: Giovanni <561184+wargio@users.noreply.github.com>
102 lines
4.9 KiB
C
102 lines
4.9 KiB
C
// SPDX-FileCopyrightText: 2021 GustavoLCR <gugulcr@gmail.com>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_analysis.h>
|
|
#include "minunit.h"
|
|
|
|
#define SWITCH_TO_ARCH_BITS(arch, bits) \
|
|
rz_analysis_use(analysis, arch); \
|
|
rz_analysis_set_bits(analysis, bits);
|
|
|
|
bool test_rz_analysis_op_val() {
|
|
RzAnalysis *analysis = rz_analysis_new();
|
|
RzAnalysisOp op;
|
|
SWITCH_TO_ARCH_BITS("x86", 64);
|
|
// mov rax, [rbx+rcx+4]
|
|
int len = rz_analysis_op(analysis, &op, 0, (const ut8 *)"\x48\x8b\x44\x0b\x04", 5, RZ_ANALYSIS_OP_MASK_VAL);
|
|
mu_assert_eq(len, 5, "Op is of size 5");
|
|
mu_assert_eq(op.dst->type, RZ_ANALYSIS_VAL_REG, "Destination should be reg");
|
|
mu_assert_streq(op.dst->reg->name, "rax", "Dst reg should be rax");
|
|
mu_assert_eq(op.src[0]->type, RZ_ANALYSIS_VAL_MEM, "Source should be mem");
|
|
mu_assert_streq(op.src[0]->reg->name, "rbx", "Source reg base should be rbx");
|
|
mu_assert_streq(op.src[0]->regdelta->name, "rcx", "Source reg delta should be rcx");
|
|
mu_assert_eq(op.src[0]->delta, 4, "Source delta should be 4");
|
|
rz_analysis_op_fini(&op);
|
|
len = rz_analysis_op(analysis, &op, 0, (const ut8 *)"\x48\xc7\xc0\x04\x00\x00\x00", 7, RZ_ANALYSIS_OP_MASK_VAL);
|
|
mu_assert_eq(len, 7, "Op is of size 7");
|
|
mu_assert_eq(op.dst->type, RZ_ANALYSIS_VAL_REG, "Destination should be reg");
|
|
mu_assert_eq(op.src[0]->type, RZ_ANALYSIS_VAL_IMM, "Source should be imm");
|
|
mu_assert_eq(op.src[0]->imm, 4, "Source imm should be 4");
|
|
rz_analysis_op_fini(&op);
|
|
|
|
SWITCH_TO_ARCH_BITS("arm", 64);
|
|
// ldr x1, [x2, x3]
|
|
len = rz_analysis_op(analysis, &op, 0, (const ut8 *)"\x41\x68\x63\xf8", 4, RZ_ANALYSIS_OP_MASK_VAL);
|
|
mu_assert_eq(len, 4, "Op is of size 4");
|
|
mu_assert_eq(op.dst->type, RZ_ANALYSIS_VAL_REG, "Destination should be reg");
|
|
mu_assert_streq(op.dst->reg->name, "x1", "Dst reg should be x1");
|
|
mu_assert_eq(op.src[0]->type, RZ_ANALYSIS_VAL_MEM, "Source should be mem");
|
|
mu_assert_streq(op.src[0]->reg->name, "x2", "Source reg base should be x2");
|
|
mu_assert_streq(op.src[0]->regdelta->name, "x3", "Source reg base should be x3");
|
|
rz_analysis_op_fini(&op);
|
|
// mov x1, 400
|
|
len = rz_analysis_op(analysis, &op, 0, (const ut8 *)"\x01\x32\x80\xd2", 4, RZ_ANALYSIS_OP_MASK_VAL);
|
|
mu_assert_eq(len, 4, "Op is of size 4");
|
|
mu_assert_eq(op.dst->type, RZ_ANALYSIS_VAL_REG, "Destination should be reg");
|
|
mu_assert_streq(op.dst->reg->name, "x1", "Dst reg should be x1");
|
|
mu_assert_eq(op.src[0]->type, RZ_ANALYSIS_VAL_IMM, "Source should be imm");
|
|
mu_assert_eq(op.src[0]->imm, 400, "Source imm should be 400");
|
|
rz_analysis_op_fini(&op);
|
|
|
|
SWITCH_TO_ARCH_BITS("arm", 32);
|
|
// ldr r1, [ r2, r3 ]
|
|
len = rz_analysis_op(analysis, &op, 0, (const ut8 *)"\x03\x10\x92\xe7", 4, RZ_ANALYSIS_OP_MASK_VAL);
|
|
mu_assert_eq(len, 4, "Op is of size 4");
|
|
mu_assert_eq(op.dst->type, RZ_ANALYSIS_VAL_REG, "Destination should be reg");
|
|
mu_assert_streq(op.dst->reg->name, "r1", "Dst reg should be r1");
|
|
mu_assert_eq(op.src[0]->type, RZ_ANALYSIS_VAL_MEM, "Source should be mem");
|
|
mu_assert_streq(op.src[0]->reg->name, "r2", "Source reg base should be r2");
|
|
mu_assert_streq(op.src[0]->regdelta->name, "r3", "Source reg base should be r3");
|
|
rz_analysis_op_fini(&op);
|
|
|
|
SWITCH_TO_ARCH_BITS("arm", 16);
|
|
// ldr r1, [ r2, r3 ]
|
|
len = rz_analysis_op(analysis, &op, 0, (const ut8 *)"\xd1\x58", 2, RZ_ANALYSIS_OP_MASK_VAL);
|
|
mu_assert_eq(len, 2, "Op is of size 2");
|
|
mu_assert_eq(op.dst->type, RZ_ANALYSIS_VAL_REG, "Destination should be reg");
|
|
mu_assert_streq(op.dst->reg->name, "r1", "Dst reg should be r1");
|
|
mu_assert_eq(op.src[0]->type, RZ_ANALYSIS_VAL_MEM, "Source should be mem");
|
|
mu_assert_streq(op.src[0]->reg->name, "r2", "Source reg base should be r2");
|
|
mu_assert_streq(op.src[0]->regdelta->name, "r3", "Source reg base should be r3");
|
|
rz_analysis_op_fini(&op);
|
|
|
|
SWITCH_TO_ARCH_BITS("riscv", 32);
|
|
// lw s10, 64(sp)
|
|
len = rz_analysis_op(analysis, &op, 0, (const ut8 *)"\x06\x4d", 2, RZ_ANALYSIS_OP_MASK_VAL);
|
|
mu_assert_eq(len, 2, "Op is of size 2");
|
|
mu_assert_eq(op.dst->type, RZ_ANALYSIS_VAL_REG, "Destination should be reg");
|
|
mu_assert_streq(op.dst->reg->name, "s10", "Dst reg should be s10");
|
|
mu_assert_eq(op.src[0]->type, RZ_ANALYSIS_VAL_MEM, "Source should be mem");
|
|
mu_assert_streq(op.src[0]->reg->name, "sp", "Source reg base should be sp");
|
|
mu_assert_eq(op.src[0]->delta, 64, "Source delta should be 64");
|
|
rz_analysis_op_fini(&op);
|
|
// sw s0, 136(sp)
|
|
len = rz_analysis_op(analysis, &op, 0, (const ut8 *)"\x22\xc5", 2, RZ_ANALYSIS_OP_MASK_VAL);
|
|
mu_assert_eq(len, 2, "Op is of size 2");
|
|
mu_assert_eq(op.dst->type, RZ_ANALYSIS_VAL_MEM, "Destination should be reg");
|
|
mu_assert_streq(op.dst->reg->name, "sp", "Dst reg should be s10");
|
|
mu_assert_eq(op.dst->delta, 136, "Source delta should be 64");
|
|
mu_assert_eq(op.src[0]->type, RZ_ANALYSIS_VAL_REG, "Source should be reg");
|
|
mu_assert_streq(op.src[0]->reg->name, "s0", "Source reg base should be s0");
|
|
rz_analysis_op_fini(&op);
|
|
|
|
rz_analysis_free(analysis);
|
|
mu_end;
|
|
}
|
|
|
|
int all_tests() {
|
|
mu_run_test(test_rz_analysis_op_val);
|
|
return tests_passed != tests_run;
|
|
}
|
|
|
|
mu_main(all_tests)
|