0001
0002
0003
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
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
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
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
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");