Extend the kprobes KUnit test with a function containing an LR/SC sequence and assert that register_kprobe() accepts a probe placed right before or right after the sequence, and rejects a probe placed on the LR, on an instruction inside the sequence, or on the SC.
Signed-off-by: Xiaofeng Yuan <[email protected]> --- .../kernel/tests/kprobes/test-kprobes-asm.S | 24 +++++++++++++++++ .../riscv/kernel/tests/kprobes/test-kprobes.c | 26 +++++++++++++++++++ .../riscv/kernel/tests/kprobes/test-kprobes.h | 3 +++ 3 files changed, 53 insertions(+) diff --git a/arch/riscv/kernel/tests/kprobes/test-kprobes-asm.S b/arch/riscv/kernel/tests/kprobes/test-kprobes-asm.S index 15e50934b..6625a960c 100644 --- a/arch/riscv/kernel/tests/kprobes/test-kprobes-asm.S +++ b/arch/riscv/kernel/tests/kprobes/test-kprobes-asm.S @@ -100,6 +100,21 @@ test_kprobes_branch_addr8: .option pop SYM_FUNC_END(test_kprobes_branch) +SYM_FUNC_START(test_kprobes_lrsc) +.Llrsc_before: + nop +1: +.Llrsc_lr: + lr.w t0, 0(x0) +.Llrsc_inside: + addi t0, t0, 1 +.Llrsc_sc: + sc.w t0, t0, 0(x0) + bnez t0, 1b +.Llrsc_after: + ret +SYM_FUNC_END(test_kprobes_lrsc) + #ifdef CONFIG_RISCV_ISA_C SYM_FUNC_START(test_kprobes_c_j) @@ -253,3 +268,12 @@ SYM_DATA_START(test_kprobes_functions) #endif /* CONFIG_RISCV_ISA_C */ RISCV_PTR 0 SYM_DATA_END(test_kprobes_functions) + +.section .rodata +SYM_DATA_START(test_kprobes_lrsc_offsets) + RISCV_PTR .Llrsc_before + RISCV_PTR .Llrsc_lr + RISCV_PTR .Llrsc_inside + RISCV_PTR .Llrsc_sc + RISCV_PTR .Llrsc_after +SYM_DATA_END(test_kprobes_lrsc_offsets) diff --git a/arch/riscv/kernel/tests/kprobes/test-kprobes.c b/arch/riscv/kernel/tests/kprobes/test-kprobes.c index 027424a3f..272753756 100644 --- a/arch/riscv/kernel/tests/kprobes/test-kprobes.c +++ b/arch/riscv/kernel/tests/kprobes/test-kprobes.c @@ -43,8 +43,34 @@ static void test_kprobe_riscv(struct kunit *test) kfree(kp); } +static void test_kprobe_lrsc(struct kunit *test) +{ + /* + * test_kprobes_lrsc_offsets[] points, in order, at an instruction + * right before an LR/SC sequence, the LR itself, an instruction + * inside the sequence, the SC, and an instruction right after it. + */ + bool reject[] = { false, true, true, true, false }; + int i; + + for (i = 0; i < ARRAY_SIZE(reject); i++) { + struct kprobe kp = {}; + + kp.pre_handler = kprobe_dummy_handler; + kp.addr = (kprobe_opcode_t *)test_kprobes_lrsc_offsets[i]; + + if (reject[i]) { + KUNIT_EXPECT_LT(test, register_kprobe(&kp), 0); + } else { + KUNIT_EXPECT_EQ(test, register_kprobe(&kp), 0); + unregister_kprobe(&kp); + } + } +} + static struct kunit_case kprobes_testcases[] = { KUNIT_CASE(test_kprobe_riscv), + KUNIT_CASE(test_kprobe_lrsc), {} }; diff --git a/arch/riscv/kernel/tests/kprobes/test-kprobes.h b/arch/riscv/kernel/tests/kprobes/test-kprobes.h index 537f44aa9..65a8e7217 100644 --- a/arch/riscv/kernel/tests/kprobes/test-kprobes.h +++ b/arch/riscv/kernel/tests/kprobes/test-kprobes.h @@ -19,6 +19,9 @@ extern void *test_kprobes_addresses[]; /* array of functions that return KPROBE_TEST_MAGIC */ extern long (*test_kprobes_functions[])(void); +/* offsets of the probe points inside test_kprobes_lrsc() */ +extern void *test_kprobes_lrsc_offsets[]; + #endif /* __ASSEMBLER__ */ #endif /* TEST_KPROBES_H */ -- 2.34.1
