356 lines
11 KiB
C
356 lines
11 KiB
C
// SPDX-FileCopyrightText: 2020 Florian Märkl <info@florianmaerkl.de>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_analysis.h>
|
|
|
|
#include "minunit.h"
|
|
|
|
const RzAnalysisHint empty_hint = {
|
|
.addr = UT64_MAX,
|
|
.ptr = 0,
|
|
.val = UT64_MAX,
|
|
.jump = UT64_MAX,
|
|
.fail = UT64_MAX,
|
|
.ret = UT64_MAX,
|
|
.arch = 0,
|
|
.opcode = NULL,
|
|
.syntax = NULL,
|
|
.esil = NULL,
|
|
.offset = NULL,
|
|
.type = 0,
|
|
.size = 0,
|
|
.bits = 0,
|
|
.new_bits = 0,
|
|
.immbase = 0,
|
|
.high = 0,
|
|
.nword = 0,
|
|
.stackframe = UT64_MAX,
|
|
.enum_name = NULL,
|
|
};
|
|
|
|
bool hint_equals(const RzAnalysisHint *a, const RzAnalysisHint *b) {
|
|
#define CHECK_EQ(member) mu_assert_eq(a->member, b->member, "hint member " #member)
|
|
CHECK_EQ(ptr);
|
|
CHECK_EQ(val);
|
|
CHECK_EQ(jump);
|
|
CHECK_EQ(fail);
|
|
CHECK_EQ(ret);
|
|
CHECK_EQ(type);
|
|
CHECK_EQ(size);
|
|
CHECK_EQ(bits);
|
|
CHECK_EQ(new_bits);
|
|
CHECK_EQ(immbase);
|
|
CHECK_EQ(high);
|
|
CHECK_EQ(nword);
|
|
CHECK_EQ(stackframe);
|
|
#undef CHECK_EQ
|
|
#define CHECK_STREQ(member) mu_assert_nullable_streq(a->member, b->member, "hint member " #member)
|
|
CHECK_STREQ(arch);
|
|
CHECK_STREQ(opcode);
|
|
CHECK_STREQ(syntax);
|
|
CHECK_STREQ(esil);
|
|
CHECK_STREQ(offset);
|
|
CHECK_STREQ(enum_name);
|
|
#undef CHECK_STREQ
|
|
return true;
|
|
}
|
|
|
|
#define assert_hint_eq(actual, expected) \
|
|
do { \
|
|
if (actual == NULL) \
|
|
mu_assert("hint", expected == &empty_hint); /* TODO: remove this part, only else should be used! */ \
|
|
else \
|
|
mu_assert("hint", hint_equals(actual, expected)); \
|
|
} while (0)
|
|
|
|
bool test_rz_analysis_addr_hints() {
|
|
RzAnalysis *analysis = rz_analysis_new(NULL);
|
|
RzAnalysisHint *hint = rz_analysis_hint_get(analysis, 0x1337);
|
|
assert_hint_eq(hint, &empty_hint);
|
|
rz_analysis_hint_free(hint);
|
|
|
|
RzAnalysisHint cur = empty_hint;
|
|
#define CHECK \
|
|
hint = rz_analysis_hint_get(analysis, 0x1337); \
|
|
assert_hint_eq(hint, &cur); \
|
|
rz_analysis_hint_free(hint);
|
|
hint = rz_analysis_hint_get(analysis, 0x1338);
|
|
assert_hint_eq(hint, &empty_hint);
|
|
rz_analysis_hint_free(hint);
|
|
hint = rz_analysis_hint_get(analysis, 0x1336);
|
|
assert_hint_eq(hint, &empty_hint);
|
|
rz_analysis_hint_free(hint);
|
|
|
|
// set --------
|
|
|
|
rz_analysis_hint_set_syntax(analysis, 0x1337, "mysyntax");
|
|
cur.syntax = "mysyntax";
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_type(analysis, 0x1337, RZ_ANALYSIS_OP_TYPE_RET);
|
|
cur.type = RZ_ANALYSIS_OP_TYPE_RET;
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_jump(analysis, 0x1337, 0xdeadbeef);
|
|
cur.jump = 0xdeadbeef;
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_fail(analysis, 0x1337, 0xc0ffee);
|
|
cur.fail = 0xc0ffee;
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_nword(analysis, 0x1337, 42);
|
|
cur.nword = 42;
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_offset(analysis, 0x1337, "mytypeoff");
|
|
cur.offset = "mytypeoff";
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_immbase(analysis, 0x1337, 7);
|
|
cur.immbase = 7;
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_enum(analysis, 0x1337, "BLA");
|
|
cur.enum_name = "BLA";
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_size(analysis, 0x1337, 0x123);
|
|
cur.size = 0x123;
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_opcode(analysis, 0x1337, "myopcode");
|
|
cur.opcode = "myopcode";
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_esil(analysis, 0x1337, "/,-rf,rm");
|
|
cur.esil = "/,-rf,rm";
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_pointer(analysis, 0x1337, 0x4242);
|
|
cur.ptr = 0x4242;
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_ret(analysis, 0x1337, 0xf00d);
|
|
cur.ret = 0xf00d;
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_high(analysis, 0x1337);
|
|
cur.high = true;
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_stackframe(analysis, 0x1337, 0x4321);
|
|
cur.stackframe = 0x4321;
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_val(analysis, 0x1337, 0x112358d);
|
|
cur.val = 0x112358d;
|
|
CHECK
|
|
|
|
rz_analysis_hint_set_newbits(analysis, 0x1337, 16);
|
|
cur.new_bits = 16;
|
|
CHECK
|
|
|
|
// unset --------
|
|
|
|
rz_analysis_hint_unset_syntax(analysis, 0x1337);
|
|
cur.syntax = NULL;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_type(analysis, 0x1337);
|
|
cur.type = 0;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_jump(analysis, 0x1337);
|
|
cur.jump = UT64_MAX;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_fail(analysis, 0x1337);
|
|
cur.fail = UT64_MAX;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_nword(analysis, 0x1337);
|
|
cur.nword = 0;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_offset(analysis, 0x1337);
|
|
cur.offset = NULL;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_immbase(analysis, 0x1337);
|
|
cur.immbase = 0;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_enum(analysis, 0x1337);
|
|
cur.enum_name = NULL;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_size(analysis, 0x1337);
|
|
cur.size = 0;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_opcode(analysis, 0x1337);
|
|
cur.opcode = NULL;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_esil(analysis, 0x1337);
|
|
cur.esil = NULL;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_pointer(analysis, 0x1337);
|
|
cur.ptr = 0;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_ret(analysis, 0x1337);
|
|
cur.ret = UT64_MAX;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_high(analysis, 0x1337);
|
|
cur.high = false;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_stackframe(analysis, 0x1337);
|
|
cur.stackframe = UT64_MAX;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_val(analysis, 0x1337);
|
|
cur.val = UT64_MAX;
|
|
CHECK
|
|
|
|
rz_analysis_hint_unset_newbits(analysis, 0x1337);
|
|
cur.new_bits = 0;
|
|
// CHECK
|
|
hint = rz_analysis_hint_get(analysis, 0x1337);
|
|
assert_hint_eq(hint, &empty_hint);
|
|
rz_analysis_hint_free(hint);
|
|
|
|
rz_analysis_free(analysis);
|
|
mu_end;
|
|
#undef CHECK
|
|
}
|
|
|
|
#define RANGED_TEST(name, val, resetval, assert_val) \
|
|
bool test_rz_analysis_hints_##name() { \
|
|
RzAnalysis *analysis = rz_analysis_new(NULL); \
|
|
\
|
|
ut64 hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0x1337, &hint_addr), resetval, "no " #name ""); \
|
|
mu_assert_eq(hint_addr, UT64_MAX, "hint addr"); \
|
|
\
|
|
rz_analysis_hint_##name##_at(analysis, 0x1337, NULL); /* make sure this does not null-deref */ \
|
|
\
|
|
/* -- */ \
|
|
rz_analysis_hint_set_##name(analysis, 0x1337, val); \
|
|
\
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0x1337, &hint_addr), val, #name " at addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0x1338, &hint_addr), val, #name " after addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, UT64_MAX, &hint_addr), val, #name " after addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0x1336, &hint_addr), resetval, "no " #name " before addr"); \
|
|
mu_assert_eq(hint_addr, UT64_MAX, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0, &hint_addr), resetval, "no " #name " before addr"); \
|
|
mu_assert_eq(hint_addr, UT64_MAX, "hint addr"); \
|
|
\
|
|
rz_analysis_hint_##name##_at(analysis, 0x1337, NULL); /* make sure this does not null-deref */ \
|
|
\
|
|
RzAnalysisHint cur = empty_hint; \
|
|
cur.name = val; \
|
|
RzAnalysisHint *hint = rz_analysis_hint_get(analysis, 0x1337); \
|
|
assert_hint_eq(hint, &cur); \
|
|
rz_analysis_hint_free(hint); \
|
|
hint = rz_analysis_hint_get(analysis, 0x1338); \
|
|
assert_hint_eq(hint, &cur); \
|
|
rz_analysis_hint_free(hint); \
|
|
hint = rz_analysis_hint_get(analysis, 0x1336); \
|
|
assert_hint_eq(hint, &empty_hint); \
|
|
rz_analysis_hint_free(hint); \
|
|
\
|
|
/* -- */ \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0xdeadbeef, &hint_addr), val, "before reset " #name " at addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
rz_analysis_hint_set_##name(analysis, 0xdeadbeef, resetval); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0xdeadbeef, &hint_addr), resetval, "reset " #name " at addr"); \
|
|
mu_assert_eq(hint_addr, 0xdeadbeef, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0xdeadbeef + 1, &hint_addr), resetval, "reset " #name " after addr"); \
|
|
mu_assert_eq(hint_addr, 0xdeadbeef, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, UT64_MAX, &hint_addr), resetval, "reset " #name " after addr"); \
|
|
mu_assert_eq(hint_addr, 0xdeadbeef, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0xdeadbeef - 1, &hint_addr), val, "" #name " before addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
\
|
|
/* -- */ \
|
|
rz_analysis_hint_unset_##name(analysis, 0xdeadbeef); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0x1337, &hint_addr), val, #name " at addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0x1338, &hint_addr), val, #name " after addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, UT64_MAX, &hint_addr), val, #name " after addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0x1336, &hint_addr), resetval, "no " #name " before addr"); \
|
|
mu_assert_eq(hint_addr, UT64_MAX, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0, &hint_addr), resetval, "no " #name " before addr"); \
|
|
mu_assert_eq(hint_addr, UT64_MAX, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0xdeadbeef, &hint_addr), val, "unset reset " #name " at addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0xdeadbeef + 1, &hint_addr), val, "unset reset " #name " after addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, UT64_MAX, &hint_addr), val, "unset reset " #name " after addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0xdeadbeef - 1, &hint_addr), val, #name " before addr"); \
|
|
mu_assert_eq(hint_addr, 0x1337, "hint addr"); \
|
|
\
|
|
/* -- */ \
|
|
rz_analysis_hint_unset_##name(analysis, 0x1337); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0x1336, &hint_addr), resetval, "unset " #name ""); \
|
|
mu_assert_eq(hint_addr, UT64_MAX, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0, &hint_addr), resetval, "unset " #name ""); \
|
|
mu_assert_eq(hint_addr, UT64_MAX, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0x1337, &hint_addr), resetval, "unset " #name ""); \
|
|
mu_assert_eq(hint_addr, UT64_MAX, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, 0x1338, &hint_addr), resetval, "unset " #name ""); \
|
|
mu_assert_eq(hint_addr, UT64_MAX, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
assert_val(rz_analysis_hint_##name##_at(analysis, UT64_MAX, &hint_addr), resetval, "unset " #name ""); \
|
|
mu_assert_eq(hint_addr, UT64_MAX, "hint addr"); \
|
|
hint_addr = 0xdead; \
|
|
\
|
|
rz_analysis_free(analysis); \
|
|
mu_end; \
|
|
}
|
|
|
|
RANGED_TEST(arch, "6502", NULL, mu_assert_nullable_streq)
|
|
RANGED_TEST(bits, 16, 0, mu_assert_eq)
|
|
|
|
bool all_tests() {
|
|
mu_run_test(test_rz_analysis_addr_hints);
|
|
mu_run_test(test_rz_analysis_hints_arch);
|
|
mu_run_test(test_rz_analysis_hints_bits);
|
|
return tests_passed != tests_run;
|
|
}
|
|
|
|
mu_main(all_tests)
|