Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * test_fprobe.c - simple sanity test for fprobe
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/fprobe.h>
0008 #include <linux/random.h>
0009 #include <kunit/test.h>
0010 
0011 #define div_factor 3
0012 
0013 static struct kunit *current_test;
0014 
0015 static u32 rand1, entry_val, exit_val;
0016 
0017 /* Use indirect calls to avoid inlining the target functions */
0018 static u32 (*target)(u32 value);
0019 static u32 (*target2)(u32 value);
0020 static unsigned long target_ip;
0021 static unsigned long target2_ip;
0022 
0023 static noinline u32 fprobe_selftest_target(u32 value)
0024 {
0025     return (value / div_factor);
0026 }
0027 
0028 static noinline u32 fprobe_selftest_target2(u32 value)
0029 {
0030     return (value / div_factor) + 1;
0031 }
0032 
0033 static notrace void fp_entry_handler(struct fprobe *fp, unsigned long ip, struct pt_regs *regs)
0034 {
0035     KUNIT_EXPECT_FALSE(current_test, preemptible());
0036     /* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */
0037     if (ip != target_ip)
0038         KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
0039     entry_val = (rand1 / div_factor);
0040 }
0041 
0042 static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip, struct pt_regs *regs)
0043 {
0044     unsigned long ret = regs_return_value(regs);
0045 
0046     KUNIT_EXPECT_FALSE(current_test, preemptible());
0047     if (ip != target_ip) {
0048         KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
0049         KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor) + 1);
0050     } else
0051         KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor));
0052     KUNIT_EXPECT_EQ(current_test, entry_val, (rand1 / div_factor));
0053     exit_val = entry_val + div_factor;
0054 }
0055 
0056 /* Test entry only (no rethook) */
0057 static void test_fprobe_entry(struct kunit *test)
0058 {
0059     struct fprobe fp_entry = {
0060         .entry_handler = fp_entry_handler,
0061     };
0062 
0063     current_test = test;
0064 
0065     /* Before register, unregister should be failed. */
0066     KUNIT_EXPECT_NE(test, 0, unregister_fprobe(&fp_entry));
0067     KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp_entry, "fprobe_selftest_target*", NULL));
0068 
0069     entry_val = 0;
0070     exit_val = 0;
0071     target(rand1);
0072     KUNIT_EXPECT_NE(test, 0, entry_val);
0073     KUNIT_EXPECT_EQ(test, 0, exit_val);
0074 
0075     entry_val = 0;
0076     exit_val = 0;
0077     target2(rand1);
0078     KUNIT_EXPECT_NE(test, 0, entry_val);
0079     KUNIT_EXPECT_EQ(test, 0, exit_val);
0080 
0081     KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp_entry));
0082 }
0083 
0084 static void test_fprobe(struct kunit *test)
0085 {
0086     struct fprobe fp = {
0087         .entry_handler = fp_entry_handler,
0088         .exit_handler = fp_exit_handler,
0089     };
0090 
0091     current_test = test;
0092     KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target*", NULL));
0093 
0094     entry_val = 0;
0095     exit_val = 0;
0096     target(rand1);
0097     KUNIT_EXPECT_NE(test, 0, entry_val);
0098     KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
0099 
0100     entry_val = 0;
0101     exit_val = 0;
0102     target2(rand1);
0103     KUNIT_EXPECT_NE(test, 0, entry_val);
0104     KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
0105 
0106     KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
0107 }
0108 
0109 static void test_fprobe_syms(struct kunit *test)
0110 {
0111     static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_target2"};
0112     struct fprobe fp = {
0113         .entry_handler = fp_entry_handler,
0114         .exit_handler = fp_exit_handler,
0115     };
0116 
0117     current_test = test;
0118     KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2));
0119 
0120     entry_val = 0;
0121     exit_val = 0;
0122     target(rand1);
0123     KUNIT_EXPECT_NE(test, 0, entry_val);
0124     KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
0125 
0126     entry_val = 0;
0127     exit_val = 0;
0128     target2(rand1);
0129     KUNIT_EXPECT_NE(test, 0, entry_val);
0130     KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
0131 
0132     KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
0133 }
0134 
0135 static unsigned long get_ftrace_location(void *func)
0136 {
0137     unsigned long size, addr = (unsigned long)func;
0138 
0139     if (!kallsyms_lookup_size_offset(addr, &size, NULL) || !size)
0140         return 0;
0141 
0142     return ftrace_location_range(addr, addr + size - 1);
0143 }
0144 
0145 static int fprobe_test_init(struct kunit *test)
0146 {
0147     do {
0148         rand1 = prandom_u32();
0149     } while (rand1 <= div_factor);
0150 
0151     target = fprobe_selftest_target;
0152     target2 = fprobe_selftest_target2;
0153     target_ip = get_ftrace_location(target);
0154     target2_ip = get_ftrace_location(target2);
0155 
0156     return 0;
0157 }
0158 
0159 static struct kunit_case fprobe_testcases[] = {
0160     KUNIT_CASE(test_fprobe_entry),
0161     KUNIT_CASE(test_fprobe),
0162     KUNIT_CASE(test_fprobe_syms),
0163     {}
0164 };
0165 
0166 static struct kunit_suite fprobe_test_suite = {
0167     .name = "fprobe_test",
0168     .init = fprobe_test_init,
0169     .test_cases = fprobe_testcases,
0170 };
0171 
0172 kunit_test_suites(&fprobe_test_suite);
0173 
0174 MODULE_LICENSE("GPL");