1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * test_fprobe.c - simple sanity test for fprobe 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/fprobe.h> 8 #include <linux/random.h> 9 #include <kunit/test.h> 10 11 #define div_factor 3 12 13 static struct kunit *current_test; 14 15 static u32 rand1, entry_val, exit_val; 16 17 /* Use indirect calls to avoid inlining the target functions */ 18 static u32 (*target)(u32 value); 19 static u32 (*target2)(u32 value); 20 static unsigned long target_ip; 21 static unsigned long target2_ip; 22 23 static noinline u32 fprobe_selftest_target(u32 value) 24 { 25 return (value / div_factor); 26 } 27 28 static noinline u32 fprobe_selftest_target2(u32 value) 29 { 30 return (value / div_factor) + 1; 31 } 32 33 static notrace void fp_entry_handler(struct fprobe *fp, unsigned long ip, struct pt_regs *regs) 34 { 35 KUNIT_EXPECT_FALSE(current_test, preemptible()); 36 /* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */ 37 if (ip != target_ip) 38 KUNIT_EXPECT_EQ(current_test, ip, target2_ip); 39 entry_val = (rand1 / div_factor); 40 } 41 42 static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip, struct pt_regs *regs) 43 { 44 unsigned long ret = regs_return_value(regs); 45 46 KUNIT_EXPECT_FALSE(current_test, preemptible()); 47 if (ip != target_ip) { 48 KUNIT_EXPECT_EQ(current_test, ip, target2_ip); 49 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor) + 1); 50 } else 51 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor)); 52 KUNIT_EXPECT_EQ(current_test, entry_val, (rand1 / div_factor)); 53 exit_val = entry_val + div_factor; 54 } 55 56 /* Test entry only (no rethook) */ 57 static void test_fprobe_entry(struct kunit *test) 58 { 59 struct fprobe fp_entry = { 60 .entry_handler = fp_entry_handler, 61 }; 62 63 current_test = test; 64 65 /* Before register, unregister should be failed. */ 66 KUNIT_EXPECT_NE(test, 0, unregister_fprobe(&fp_entry)); 67 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp_entry, "fprobe_selftest_target*", NULL)); 68 69 entry_val = 0; 70 exit_val = 0; 71 target(rand1); 72 KUNIT_EXPECT_NE(test, 0, entry_val); 73 KUNIT_EXPECT_EQ(test, 0, exit_val); 74 75 entry_val = 0; 76 exit_val = 0; 77 target2(rand1); 78 KUNIT_EXPECT_NE(test, 0, entry_val); 79 KUNIT_EXPECT_EQ(test, 0, exit_val); 80 81 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp_entry)); 82 } 83 84 static void test_fprobe(struct kunit *test) 85 { 86 struct fprobe fp = { 87 .entry_handler = fp_entry_handler, 88 .exit_handler = fp_exit_handler, 89 }; 90 91 current_test = test; 92 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target*", NULL)); 93 94 entry_val = 0; 95 exit_val = 0; 96 target(rand1); 97 KUNIT_EXPECT_NE(test, 0, entry_val); 98 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 99 100 entry_val = 0; 101 exit_val = 0; 102 target2(rand1); 103 KUNIT_EXPECT_NE(test, 0, entry_val); 104 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 105 106 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); 107 } 108 109 static void test_fprobe_syms(struct kunit *test) 110 { 111 static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_target2"}; 112 struct fprobe fp = { 113 .entry_handler = fp_entry_handler, 114 .exit_handler = fp_exit_handler, 115 }; 116 117 current_test = test; 118 KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2)); 119 120 entry_val = 0; 121 exit_val = 0; 122 target(rand1); 123 KUNIT_EXPECT_NE(test, 0, entry_val); 124 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 125 126 entry_val = 0; 127 exit_val = 0; 128 target2(rand1); 129 KUNIT_EXPECT_NE(test, 0, entry_val); 130 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 131 132 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); 133 } 134 135 static unsigned long get_ftrace_location(void *func) 136 { 137 unsigned long size, addr = (unsigned long)func; 138 139 if (!kallsyms_lookup_size_offset(addr, &size, NULL) || !size) 140 return 0; 141 142 return ftrace_location_range(addr, addr + size - 1); 143 } 144 145 static int fprobe_test_init(struct kunit *test) 146 { 147 do { 148 rand1 = get_random_u32(); 149 } while (rand1 <= div_factor); 150 151 target = fprobe_selftest_target; 152 target2 = fprobe_selftest_target2; 153 target_ip = get_ftrace_location(target); 154 target2_ip = get_ftrace_location(target2); 155 156 return 0; 157 } 158 159 static struct kunit_case fprobe_testcases[] = { 160 KUNIT_CASE(test_fprobe_entry), 161 KUNIT_CASE(test_fprobe), 162 KUNIT_CASE(test_fprobe_syms), 163 {} 164 }; 165 166 static struct kunit_suite fprobe_test_suite = { 167 .name = "fprobe_test", 168 .init = fprobe_test_init, 169 .test_cases = fprobe_testcases, 170 }; 171 172 kunit_test_suites(&fprobe_test_suite); 173 174 MODULE_LICENSE("GPL"); 175