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 static int entry_return_value; 23 24 static noinline u32 fprobe_selftest_target(u32 value) 25 { 26 return (value / div_factor); 27 } 28 29 static noinline u32 fprobe_selftest_target2(u32 value) 30 { 31 return (value / div_factor) + 1; 32 } 33 34 static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip, 35 unsigned long ret_ip, 36 struct ftrace_regs *fregs, void *data) 37 { 38 KUNIT_EXPECT_FALSE(current_test, preemptible()); 39 /* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */ 40 if (ip != target_ip) 41 KUNIT_EXPECT_EQ(current_test, ip, target2_ip); 42 entry_val = (rand1 / div_factor); 43 if (fp->entry_data_size) { 44 KUNIT_EXPECT_NOT_NULL(current_test, data); 45 if (data) 46 *(u32 *)data = entry_val; 47 } else 48 KUNIT_EXPECT_NULL(current_test, data); 49 50 return entry_return_value; 51 } 52 53 static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip, 54 unsigned long ret_ip, 55 struct ftrace_regs *fregs, void *data) 56 { 57 unsigned long ret = ftrace_regs_get_return_value(fregs); 58 59 KUNIT_EXPECT_FALSE(current_test, preemptible()); 60 if (ip != target_ip) { 61 KUNIT_EXPECT_EQ(current_test, ip, target2_ip); 62 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor) + 1); 63 } else 64 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor)); 65 KUNIT_EXPECT_EQ(current_test, entry_val, (rand1 / div_factor)); 66 exit_val = entry_val + div_factor; 67 if (fp->entry_data_size) { 68 KUNIT_EXPECT_NOT_NULL(current_test, data); 69 if (data) 70 KUNIT_EXPECT_EQ(current_test, *(u32 *)data, entry_val); 71 } else 72 KUNIT_EXPECT_NULL(current_test, data); 73 } 74 75 /* Test entry only (no rethook) */ 76 static void test_fprobe_entry(struct kunit *test) 77 { 78 struct fprobe fp_entry = { 79 .entry_handler = fp_entry_handler, 80 }; 81 82 current_test = test; 83 84 /* Before register, unregister should be failed. */ 85 KUNIT_EXPECT_NE(test, 0, unregister_fprobe(&fp_entry)); 86 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp_entry, "fprobe_selftest_target*", NULL)); 87 88 entry_val = 0; 89 exit_val = 0; 90 target(rand1); 91 KUNIT_EXPECT_NE(test, 0, entry_val); 92 KUNIT_EXPECT_EQ(test, 0, exit_val); 93 94 entry_val = 0; 95 exit_val = 0; 96 target2(rand1); 97 KUNIT_EXPECT_NE(test, 0, entry_val); 98 KUNIT_EXPECT_EQ(test, 0, exit_val); 99 100 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp_entry)); 101 } 102 103 static void test_fprobe(struct kunit *test) 104 { 105 struct fprobe fp = { 106 .entry_handler = fp_entry_handler, 107 .exit_handler = fp_exit_handler, 108 }; 109 110 current_test = test; 111 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target*", NULL)); 112 113 entry_val = 0; 114 exit_val = 0; 115 target(rand1); 116 KUNIT_EXPECT_NE(test, 0, entry_val); 117 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 118 119 entry_val = 0; 120 exit_val = 0; 121 target2(rand1); 122 KUNIT_EXPECT_NE(test, 0, entry_val); 123 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 124 125 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); 126 } 127 128 static void test_fprobe_syms(struct kunit *test) 129 { 130 static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_target2"}; 131 struct fprobe fp = { 132 .entry_handler = fp_entry_handler, 133 .exit_handler = fp_exit_handler, 134 }; 135 136 current_test = test; 137 KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2)); 138 139 entry_val = 0; 140 exit_val = 0; 141 target(rand1); 142 KUNIT_EXPECT_NE(test, 0, entry_val); 143 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 144 145 entry_val = 0; 146 exit_val = 0; 147 target2(rand1); 148 KUNIT_EXPECT_NE(test, 0, entry_val); 149 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 150 151 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); 152 } 153 154 /* Test private entry_data */ 155 static void test_fprobe_data(struct kunit *test) 156 { 157 struct fprobe fp = { 158 .entry_handler = fp_entry_handler, 159 .exit_handler = fp_exit_handler, 160 .entry_data_size = sizeof(u32), 161 }; 162 163 current_test = test; 164 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL)); 165 166 target(rand1); 167 168 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); 169 } 170 171 static void test_fprobe_skip(struct kunit *test) 172 { 173 struct fprobe fp = { 174 .entry_handler = fp_entry_handler, 175 .exit_handler = fp_exit_handler, 176 }; 177 178 current_test = test; 179 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL)); 180 181 entry_return_value = 1; 182 entry_val = 0; 183 exit_val = 0; 184 target(rand1); 185 KUNIT_EXPECT_NE(test, 0, entry_val); 186 KUNIT_EXPECT_EQ(test, 0, exit_val); 187 KUNIT_EXPECT_EQ(test, 0, fp.nmissed); 188 entry_return_value = 0; 189 190 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); 191 } 192 193 static unsigned long get_ftrace_location(void *func) 194 { 195 unsigned long size, addr = (unsigned long)func; 196 197 if (!kallsyms_lookup_size_offset(addr, &size, NULL) || !size) 198 return 0; 199 200 return ftrace_location_range(addr, addr + size - 1); 201 } 202 203 static int fprobe_test_init(struct kunit *test) 204 { 205 rand1 = get_random_u32_above(div_factor); 206 target = fprobe_selftest_target; 207 target2 = fprobe_selftest_target2; 208 target_ip = get_ftrace_location(target); 209 target2_ip = get_ftrace_location(target2); 210 211 return 0; 212 } 213 214 static struct kunit_case fprobe_testcases[] = { 215 KUNIT_CASE(test_fprobe_entry), 216 KUNIT_CASE(test_fprobe), 217 KUNIT_CASE(test_fprobe_syms), 218 KUNIT_CASE(test_fprobe_data), 219 KUNIT_CASE(test_fprobe_skip), 220 {} 221 }; 222 223 static struct kunit_suite fprobe_test_suite = { 224 .name = "fprobe_test", 225 .init = fprobe_test_init, 226 .test_cases = fprobe_testcases, 227 }; 228 229 kunit_test_suites(&fprobe_test_suite); 230 231