// SPDX-FileCopyrightText: 2020 Florian Märkl // SPDX-License-Identifier: LGPL-3.0-only #include #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)