/* * This file contains test code for ARM kprobes. * * The top level function run_all_tests() executes tests for all of the * supported instruction sets: ARM, 16-bit Thumb, and 32-bit Thumb. These tests * fall into two categories; run_api_tests() checks basic functionality of the * kprobes API, and run_test_cases() is a comprehensive test for kprobes * instruction decoding and simulation. * * run_test_cases() first checks the kprobes decoding table for self consistency * (using table_test()) then executes a series of test cases for each of the CPU * instruction forms. coverage_start() and coverage_end() are used to verify * that these test cases cover all of the possible combinations of instructions * described by the kprobes decoding tables. * * The individual test cases are in kprobes-test-arm.c and kprobes-test-thumb.c * which use the macros defined in kprobes-test.h. The rest of this * documentation will describe the operation of the framework used by these * test cases.
*/
/* * TESTING METHODOLOGY * ------------------- * * The methodology used to test an ARM instruction 'test_insn' is to use * inline assembler like: * * test_before: nop * test_case: test_insn * test_after: nop * * When the test case is run a kprobe is placed of each nop. The * post-handler of the test_before probe is used to modify the saved CPU * register context to that which we require for the test case. The * pre-handler of the of the test_after probe saves a copy of the CPU * register context. In this way we can execute test_insn with a specific * register context and see the results afterwards. * * To actually test the kprobes instruction emulation we perform the above * step a second time but with an additional kprobe on the test_case * instruction itself. If the emulation is accurate then the results seen * by the test_after probe will be identical to the first run which didn't * have a probe on test_case. * * Each test case is run several times with a variety of variations in the * flags value of stored in CPSR, and for Thumb code, different ITState. * * For instructions which can modify PC, a second test_after probe is used * like this: * * test_before: nop * test_case: test_insn * test_after: nop * b test_done * test_after2: nop * test_done: * * The test case is constructed such that test_insn branches to * test_after2, or, if testing a conditional instruction, it may just * continue to test_after. The probes inserted at both locations let us * determine which happened. A similar approach is used for testing * backwards branches... * * b test_before * b test_done @ helps to cope with off by 1 branches * test_after2: nop * b test_done * test_before: nop * test_case: test_insn * test_after: nop * test_done: * * The macros used to generate the assembler instructions describe above * are TEST_INSTRUCTION, TEST_BRANCH_F (branch forwards) and TEST_BRANCH_B * (branch backwards). In these, the local variables numbered 1, 50, 2 and * 99 represent: test_before, test_case, test_after2 and test_done. * * FRAMEWORK * --------- * * Each test case is wrapped between the pair of macros TESTCASE_START and * TESTCASE_END. As well as performing the inline assembler boilerplate, * these call out to the kprobes_test_case_start() and * kprobes_test_case_end() functions which drive the execution of the test * case. The specific arguments to use for each test case are stored as * inline data constructed using the various TEST_ARG_* macros. Putting * this all together, a simple test case may look like: * * TESTCASE_START("Testing mov r0, r7") * TEST_ARG_REG(7, 0x12345678) // Set r7=0x12345678 * TEST_ARG_END("") * TEST_INSTRUCTION("mov r0, r7") * TESTCASE_END * * Note, in practice the single convenience macro TEST_R would be used for this * instead. * * The above would expand to assembler looking something like: * * @ TESTCASE_START * bl __kprobes_test_case_start * .pushsection .rodata * "10: * .ascii "mov r0, r7" @ text title for test case * .byte 0 * .popsection * @ start of inline data... * .word 10b @ pointer to title in .rodata section * * @ TEST_ARG_REG * .byte ARG_TYPE_REG * .byte 7 * .short 0 * .word 0x1234567 * * @ TEST_ARG_END * .byte ARG_TYPE_END * .byte TEST_ISA @ flags, including ISA being tested * .short 50f-0f @ offset of 'test_before' * .short 2f-0f @ offset of 'test_after2' (if relevent) * .short 99f-0f @ offset of 'test_done' * @ start of test case code... * 0: * .code TEST_ISA @ switch to ISA being tested * * @ TEST_INSTRUCTION * 50: nop @ location for 'test_before' probe * 1: mov r0, r7 @ the test case instruction 'test_insn' * nop @ location for 'test_after' probe * * // TESTCASE_END * 2: * 99: bl __kprobes_test_case_end_##TEST_ISA * .code NONMAL_ISA * * When the above is execute the following happens... * * __kprobes_test_case_start() is an assembler wrapper which sets up space * for a stack buffer and calls the C function kprobes_test_case_start(). * This C function will do some initial processing of the inline data and * setup some global state. It then inserts the test_before and test_after * kprobes and returns a value which causes the assembler wrapper to jump * to the start of the test case code, (local label '0'). * * When the test case code executes, the test_before probe will be hit and * test_before_post_handler will call setup_test_context(). This fills the * stack buffer and CPU registers with a test pattern and then processes * the test case arguments. In our example there is one TEST_ARG_REG which * indicates that R7 should be loaded with the value 0x12345678. * * When the test_before probe ends, the test case continues and executes * the "mov r0, r7" instruction. It then hits the test_after probe and the * pre-handler for this (test_after_pre_handler) will save a copy of the * CPU register context. This should now have R0 holding the same value as * R7. * * Finally we get to the call to __kprobes_test_case_end_{32,16}. This is * an assembler wrapper which switches back to the ISA used by the test * code and calls the C function kprobes_test_case_end(). * * For each run through the test case, test_case_run_count is incremented * by one. For even runs, kprobes_test_case_end() saves a copy of the * register and stack buffer contents from the test case just run. It then * inserts a kprobe on the test case instruction 'test_insn' and returns a * value to cause the test case code to be re-run. * * For odd numbered runs, kprobes_test_case_end() compares the register and * stack buffer contents to those that were saved on the previous even * numbered run (the one without the kprobe on test_insn). These should be * the same if the kprobe instruction simulation routine is correct. * * The pair of test case runs is repeated with different combinations of * flag values in CPSR and, for Thumb, different ITState. This is * controlled by test_context_cpsr(). * * BUILDING TEST CASES * ------------------- * * * As an aid to building test cases, the stack buffer is initialised with * some special values: * * [SP+13*4] Contains SP+120. This can be used to test instructions * which load a value into SP. * * [SP+15*4] When testing branching instructions using TEST_BRANCH_{F,B}, * this holds the target address of the branch, 'test_after2'. * This can be used to test instructions which load a PC value * from memory.
*/
staticint test_kretprobe(long (*func)(long, long))
{ int ret;
the_kretprobe.kp.addr = (kprobe_opcode_t *)func;
ret = register_kretprobe(&the_kretprobe); if (ret < 0) {
pr_err("FAIL: register_kretprobe failed with %d\n", ret); return ret;
}
ret = call_test_func(func, true);
unregister_kretprobe(&the_kretprobe);
the_kretprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
if (!ret) return -EINVAL; if (kretprobe_handler_called != test_func_instance) {
pr_err("FAIL: kretprobe handler not called\n"); return -EINVAL;
} if (!call_test_func(func, false)) return -EINVAL; if (kretprobe_handler_called == test_func_instance) {
pr_err("FAIL: kretprobe called after unregistering\n"); return -EINVAL;
}
return 0;
}
staticint run_api_tests(long (*func)(long, long))
{ int ret;
pr_info(" kprobe\n");
ret = test_kprobe(func); if (ret < 0) return ret;
pr_info(" kretprobe\n");
ret = test_kretprobe(func); if (ret < 0) return ret;
staticint benchmark(void(*fn)(void))
{ unsigned n, i, t, t0;
for (n = 1000; ; n *= 2) {
t0 = sched_clock(); for (i = n; i > 0; --i)
fn();
t = sched_clock() - t0; if (t >= 250000000) break; /* Stop once we took more than 0.25 seconds */
} return t / n; /* Time for one iteration in nanoseconds */
};
/* * Decoding table test coverage analysis * * coverage_start() builds a coverage_table which contains a list of * coverage_entry's to match each entry in the specified kprobes instruction * decoding table. * * When test cases are run, coverage_add() is called to process each case. * This looks up the corresponding entry in the coverage_table and sets it as * being matched, as well as clearing the regs flag appropriate for the test. * * After all test cases have been run, coverage_end() is called to check that * all entries in coverage_table have been matched and that all regs flags are * cleared. I.e. that all possible combinations of instructions described by * the kprobes decoding tables have had a test case executed for them.
*/
} else { /* Testing Thumb code with several combinations of ITSTATE */ switch (scenario) { case 16: /* Clear NZCV flags and 'it eq' state (false as Z=0) */
cpsr = 0x00000800;
probe_should_run = 0; break; case 17: /* Set NZCV flags and 'it vc' state (false as V=1) */
cpsr = 0xf0007800;
probe_should_run = 0; break; case 18: /* Clear NZCV flags and 'it ls' state (true as C=0) */
cpsr = 0x00009800; break; case 19: /* Set NZCV flags and 'it cs' state (true as C=1) */
cpsr = 0xf0002800;
is_last_scenario = true; break;
}
}
return cpsr;
}
staticvoid setup_test_context(struct pt_regs *regs)
{ int scenario = test_case_run_count>>1; unsignedlong val; struct test_arg *args; int i;
/* Initialise test memory on stack */
val = (scenario & 1) ? VALM : ~VALM; for (i = 0; i < TEST_MEMORY_SIZE / sizeof(current_stack[0]); ++i)
current_stack[i] = val + (i << 8); /* Put target of branch on stack for tests which load PC from memory */ if (current_branch_target)
current_stack[15] = current_branch_target; /* Put a value for SP on stack for tests which load SP from memory */
current_stack[13] = (u32)current_stack + 120;
/* Initialise register values to their default state */
val = (scenario & 2) ? VALR : ~VALR; for (i = 0; i < 13; ++i)
regs->uregs[i] = val ^ (i << 8);
regs->ARM_lr = val ^ (14 << 8);
regs->ARM_cpsr &= ~(APSR_MASK | PSR_IT_MASK);
regs->ARM_cpsr |= test_context_cpsr(scenario);
/* Perform testcase specific register setup */
args = current_args; for (; args[0].type != ARG_TYPE_END; ++args) switch (args[0].type) { case ARG_TYPE_REG: { struct test_arg_regptr *arg =
(struct test_arg_regptr *)args;
regs->uregs[arg->reg] = arg->val; break;
} case ARG_TYPE_PTR: { struct test_arg_regptr *arg =
(struct test_arg_regptr *)args;
regs->uregs[arg->reg] =
(unsignedlong)current_stack + arg->val;
memory_needs_checking = true; /* * Test memory at an address below SP is in danger of * being altered by an interrupt occurring and pushing * data onto the stack. Disable interrupts to stop this.
*/ if (arg->reg == 13)
regs->ARM_cpsr |= PSR_I_BIT; break;
} case ARG_TYPE_MEM: { struct test_arg_mem *arg = (struct test_arg_mem *)args;
current_stack[arg->index] = arg->val; break;
} default: break;
}
}
if (container_of(p, struct test_probe, kprobe)->hit == test_instance) return 0; /* Already run for this test instance */
result_regs = *regs;
/* Mask out results which are indeterminate */
result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS; for (args = current_args; args[0].type != ARG_TYPE_END; ++args) if (args[0].type == ARG_TYPE_REG_MASKED) { struct test_arg_regptr *arg =
(struct test_arg_regptr *)args;
result_regs.uregs[arg->reg] &= arg->val;
}
/* Undo any changes done to SP by the test case */
regs->ARM_sp = (unsignedlong)current_stack; /* Enable interrupts in case setup_test_context disabled them */
regs->ARM_cpsr &= ~PSR_I_BIT;
if (mem) {
pr_err("expected_memory:\n");
print_memory(expected_memory, mem_size);
pr_err("result_memory:\n");
print_memory(mem, mem_size);
}
returnfalse;
}
static uintptr_t __used kprobes_test_case_end(void)
{ if (test_case_run_count < 0) { if (test_case_run_count == TEST_CASE_PASSED) /* kprobes_test_case_start did all the needed testing */ goto pass; else /* kprobes_test_case_start failed */ goto fail;
}
if (test_before_probe.hit != test_instance) {
test_case_failed("test_before_handler not run"); goto fail;
}
if (test_after_probe.hit != test_instance &&
test_after2_probe.hit != test_instance) {
test_case_failed("test_after_handler not run"); goto fail;
}
/* * Even numbered test runs ran without a probe on the test case so * we can gather reference results. The subsequent odd numbered run * will have the probe inserted.
*/ if ((test_case_run_count & 1) == 0) { /* Save results from run without probe */
u32 *mem = (u32 *)result_regs.ARM_sp;
expected_regs = result_regs;
memcpy(expected_memory, mem, expected_memory_size(mem));
/* Insert probe onto test case instruction */ if (register_test_probe(&test_case_probe) < 0) {
test_case_failed("register test_case_probe failed"); goto fail;
}
} else { /* Check probe ran as expected */ if (probe_should_run == 1) { if (test_case_probe.hit != test_instance) {
test_case_failed("test_case_handler not run"); goto fail;
}
} elseif (probe_should_run == 0) { if (test_case_probe.hit == test_instance) {
test_case_failed("test_case_handler ran"); goto fail;
}
}
/* Remove probe for any subsequent reference run */
unregister_test_probe(&test_case_probe);
if (!check_test_results()) goto fail;
if (is_last_scenario) goto pass;
}
/* Do next test run */
++test_case_run_count;
++test_instance; return current_code_start;
fail:
++test_fail_count; goto end;
pass:
++test_pass_count;
end:
test_case_cleanup(); return 0;
}
/* * Top level test functions
*/
staticint run_test_cases(void (*tests)(void), constunion decode_item *table)
{ int ret;
pr_info(" Check decoding tables\n");
ret = table_test(table); if (ret) return ret;
pr_info(" Run test cases\n");
ret = coverage_start(table); if (ret) return ret;
tests();
coverage_end(); return 0;
}
staticint __init run_all_tests(void)
{ int ret = 0;
pr_info("Beginning kprobe tests...\n");
#ifndef CONFIG_THUMB2_KERNEL
pr_info("Probe ARM code\n");
ret = run_api_tests(arm_func); if (ret) goto out;
pr_info("ARM instruction simulation\n");
ret = run_test_cases(kprobe_arm_test_cases, probes_decode_arm_table); if (ret) goto out;
#else/* CONFIG_THUMB2_KERNEL */
pr_info("Probe 16-bit Thumb code\n");
ret = run_api_tests(thumb16_func); if (ret) goto out;
pr_info("Probe 32-bit Thumb code, even halfword\n");
ret = run_api_tests(thumb32even_func); if (ret) goto out;
pr_info("Probe 32-bit Thumb code, odd halfword\n");
ret = run_api_tests(thumb32odd_func); if (ret) goto out;
pr_info("16-bit Thumb instruction simulation\n");
ret = run_test_cases(kprobe_thumb16_test_cases,
probes_decode_thumb16_table); if (ret) goto out;
pr_info("32-bit Thumb instruction simulation\n");
ret = run_test_cases(kprobe_thumb32_test_cases,
probes_decode_thumb32_table); if (ret) goto out; #endif
pr_info("Total instruction simulation tests=%d, pass=%d fail=%d\n",
test_try_count, test_pass_count, test_fail_count); if (test_fail_count) {
ret = -EINVAL; goto out;
}
#if BENCHMARKING
pr_info("Benchmarks\n");
ret = run_benchmarks(); if (ret) goto out; #endif
#if __LINUX_ARM_ARCH__ >= 7 /* We are able to run all test cases so coverage should be complete */ if (coverage_fail) {
pr_err("FAIL: Test coverage checks failed\n");
ret = -EINVAL; goto out;
} #endif
out: if (ret == 0)
ret = tests_failed; if (ret == 0)
pr_info("Finished kprobe tests OK\n"); else
pr_err("kprobe tests failed\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.