164836248STom Zanussi // SPDX-License-Identifier: GPL-2.0
264836248STom Zanussi /*
364836248STom Zanussi  * Test module for in-kernel kprobe event creation and generation.
464836248STom Zanussi  *
564836248STom Zanussi  * Copyright (C) 2019 Tom Zanussi <zanussi@kernel.org>
664836248STom Zanussi  */
764836248STom Zanussi 
864836248STom Zanussi #include <linux/module.h>
964836248STom Zanussi #include <linux/trace_events.h>
1064836248STom Zanussi 
1164836248STom Zanussi /*
1264836248STom Zanussi  * This module is a simple test of basic functionality for in-kernel
1364836248STom Zanussi  * kprobe/kretprobe event creation.  The first test uses
1464836248STom Zanussi  * kprobe_event_gen_cmd_start(), kprobe_event_add_fields() and
1564836248STom Zanussi  * kprobe_event_gen_cmd_end() to create a kprobe event, which is then
1664836248STom Zanussi  * enabled in order to generate trace output.  The second creates a
1764836248STom Zanussi  * kretprobe event using kretprobe_event_gen_cmd_start() and
1864836248STom Zanussi  * kretprobe_event_gen_cmd_end(), and is also then enabled.
1964836248STom Zanussi  *
2064836248STom Zanussi  * To test, select CONFIG_KPROBE_EVENT_GEN_TEST and build the module.
2164836248STom Zanussi  * Then:
2264836248STom Zanussi  *
2364836248STom Zanussi  * # insmod kernel/trace/kprobe_event_gen_test.ko
242455f0e1SRoss Zwisler  * # cat /sys/kernel/tracing/trace
2564836248STom Zanussi  *
2664836248STom Zanussi  * You should see many instances of the "gen_kprobe_test" and
2764836248STom Zanussi  * "gen_kretprobe_test" events in the trace buffer.
2864836248STom Zanussi  *
2964836248STom Zanussi  * To remove the events, remove the module:
3064836248STom Zanussi  *
3164836248STom Zanussi  * # rmmod kprobe_event_gen_test
3264836248STom Zanussi  *
3364836248STom Zanussi  */
3464836248STom Zanussi 
3564836248STom Zanussi static struct trace_event_file *gen_kprobe_test;
3664836248STom Zanussi static struct trace_event_file *gen_kretprobe_test;
3764836248STom Zanussi 
38d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_FUNC	"do_sys_open"
39d8ef45d6SYipeng Zou 
40d8ef45d6SYipeng Zou /* X86 */
41d8ef45d6SYipeng Zou #if defined(CONFIG_X86_64) || defined(CONFIG_X86_32)
42d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG0	"dfd=%ax"
43d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG1	"filename=%dx"
44d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG2	"flags=%cx"
45d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG3	"mode=+4($stack)"
46d8ef45d6SYipeng Zou 
47d8ef45d6SYipeng Zou /* ARM64 */
48d8ef45d6SYipeng Zou #elif defined(CONFIG_ARM64)
49d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG0	"dfd=%x0"
50d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG1	"filename=%x1"
51d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG2	"flags=%x2"
52d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG3	"mode=%x3"
53d8ef45d6SYipeng Zou 
54d8ef45d6SYipeng Zou /* ARM */
55d8ef45d6SYipeng Zou #elif defined(CONFIG_ARM)
56d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG0	"dfd=%r0"
57d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG1	"filename=%r1"
58d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG2	"flags=%r2"
59d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG3	"mode=%r3"
60d8ef45d6SYipeng Zou 
61d8ef45d6SYipeng Zou /* RISCV */
62d8ef45d6SYipeng Zou #elif defined(CONFIG_RISCV)
63d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG0	"dfd=%a0"
64d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG1	"filename=%a1"
65d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG2	"flags=%a2"
66d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG3	"mode=%a3"
67d8ef45d6SYipeng Zou 
68d8ef45d6SYipeng Zou /* others */
69d8ef45d6SYipeng Zou #else
70d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG0	NULL
71d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG1	NULL
72d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG2	NULL
73d8ef45d6SYipeng Zou #define KPROBE_GEN_TEST_ARG3	NULL
74d8ef45d6SYipeng Zou #endif
75d8ef45d6SYipeng Zou 
trace_event_file_is_valid(struct trace_event_file * input)76e0d75267SShang XiaoJing static bool trace_event_file_is_valid(struct trace_event_file *input)
77e0d75267SShang XiaoJing {
78e0d75267SShang XiaoJing 	return input && !IS_ERR(input);
79e0d75267SShang XiaoJing }
80d8ef45d6SYipeng Zou 
8164836248STom Zanussi /*
8264836248STom Zanussi  * Test to make sure we can create a kprobe event, then add more
8364836248STom Zanussi  * fields.
8464836248STom Zanussi  */
test_gen_kprobe_cmd(void)8564836248STom Zanussi static int __init test_gen_kprobe_cmd(void)
8664836248STom Zanussi {
8764836248STom Zanussi 	struct dynevent_cmd cmd;
8864836248STom Zanussi 	char *buf;
8964836248STom Zanussi 	int ret;
9064836248STom Zanussi 
9164836248STom Zanussi 	/* Create a buffer to hold the generated command */
9264836248STom Zanussi 	buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
9364836248STom Zanussi 	if (!buf)
9464836248STom Zanussi 		return -ENOMEM;
9564836248STom Zanussi 
9664836248STom Zanussi 	/* Before generating the command, initialize the cmd object */
9764836248STom Zanussi 	kprobe_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
9864836248STom Zanussi 
9964836248STom Zanussi 	/*
10064836248STom Zanussi 	 * Define the gen_kprobe_test event with the first 2 kprobe
10164836248STom Zanussi 	 * fields.
10264836248STom Zanussi 	 */
10364836248STom Zanussi 	ret = kprobe_event_gen_cmd_start(&cmd, "gen_kprobe_test",
104d8ef45d6SYipeng Zou 					 KPROBE_GEN_TEST_FUNC,
105d8ef45d6SYipeng Zou 					 KPROBE_GEN_TEST_ARG0, KPROBE_GEN_TEST_ARG1);
10664836248STom Zanussi 	if (ret)
10766f0919cSShang XiaoJing 		goto out;
10864836248STom Zanussi 
10964836248STom Zanussi 	/* Use kprobe_event_add_fields to add the rest of the fields */
11064836248STom Zanussi 
111d8ef45d6SYipeng Zou 	ret = kprobe_event_add_fields(&cmd, KPROBE_GEN_TEST_ARG2, KPROBE_GEN_TEST_ARG3);
11264836248STom Zanussi 	if (ret)
11366f0919cSShang XiaoJing 		goto out;
11464836248STom Zanussi 
11564836248STom Zanussi 	/*
11664836248STom Zanussi 	 * This actually creates the event.
11764836248STom Zanussi 	 */
11864836248STom Zanussi 	ret = kprobe_event_gen_cmd_end(&cmd);
11964836248STom Zanussi 	if (ret)
12066f0919cSShang XiaoJing 		goto out;
12164836248STom Zanussi 
12264836248STom Zanussi 	/*
12364836248STom Zanussi 	 * Now get the gen_kprobe_test event file.  We need to prevent
12464836248STom Zanussi 	 * the instance and event from disappearing from underneath
12564836248STom Zanussi 	 * us, which trace_get_event_file() does (though in this case
12664836248STom Zanussi 	 * we're using the top-level instance which never goes away).
12764836248STom Zanussi 	 */
12864836248STom Zanussi 	gen_kprobe_test = trace_get_event_file(NULL, "kprobes",
12964836248STom Zanussi 					       "gen_kprobe_test");
13064836248STom Zanussi 	if (IS_ERR(gen_kprobe_test)) {
13164836248STom Zanussi 		ret = PTR_ERR(gen_kprobe_test);
13264836248STom Zanussi 		goto delete;
13364836248STom Zanussi 	}
13464836248STom Zanussi 
13564836248STom Zanussi 	/* Enable the event or you won't see anything */
13664836248STom Zanussi 	ret = trace_array_set_clr_event(gen_kprobe_test->tr,
13764836248STom Zanussi 					"kprobes", "gen_kprobe_test", true);
13864836248STom Zanussi 	if (ret) {
13964836248STom Zanussi 		trace_put_event_file(gen_kprobe_test);
14064836248STom Zanussi 		goto delete;
14164836248STom Zanussi 	}
14264836248STom Zanussi  out:
14366f0919cSShang XiaoJing 	kfree(buf);
14464836248STom Zanussi 	return ret;
14564836248STom Zanussi  delete:
14622ea4ca9SShang XiaoJing 	if (trace_event_file_is_valid(gen_kprobe_test))
14722ea4ca9SShang XiaoJing 		gen_kprobe_test = NULL;
14864836248STom Zanussi 	/* We got an error after creating the event, delete it */
149*bc4f359bSAnton Gusev 	kprobe_event_delete("gen_kprobe_test");
15064836248STom Zanussi 	goto out;
15164836248STom Zanussi }
15264836248STom Zanussi 
15364836248STom Zanussi /*
15464836248STom Zanussi  * Test to make sure we can create a kretprobe event.
15564836248STom Zanussi  */
test_gen_kretprobe_cmd(void)15664836248STom Zanussi static int __init test_gen_kretprobe_cmd(void)
15764836248STom Zanussi {
15864836248STom Zanussi 	struct dynevent_cmd cmd;
15964836248STom Zanussi 	char *buf;
16064836248STom Zanussi 	int ret;
16164836248STom Zanussi 
16264836248STom Zanussi 	/* Create a buffer to hold the generated command */
16364836248STom Zanussi 	buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
16464836248STom Zanussi 	if (!buf)
16564836248STom Zanussi 		return -ENOMEM;
16664836248STom Zanussi 
16764836248STom Zanussi 	/* Before generating the command, initialize the cmd object */
16864836248STom Zanussi 	kprobe_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
16964836248STom Zanussi 
17064836248STom Zanussi 	/*
17164836248STom Zanussi 	 * Define the kretprobe event.
17264836248STom Zanussi 	 */
17364836248STom Zanussi 	ret = kretprobe_event_gen_cmd_start(&cmd, "gen_kretprobe_test",
174d8ef45d6SYipeng Zou 					    KPROBE_GEN_TEST_FUNC,
17564836248STom Zanussi 					    "$retval");
17664836248STom Zanussi 	if (ret)
17766f0919cSShang XiaoJing 		goto out;
17864836248STom Zanussi 
17964836248STom Zanussi 	/*
18064836248STom Zanussi 	 * This actually creates the event.
18164836248STom Zanussi 	 */
18264836248STom Zanussi 	ret = kretprobe_event_gen_cmd_end(&cmd);
18364836248STom Zanussi 	if (ret)
18466f0919cSShang XiaoJing 		goto out;
18564836248STom Zanussi 
18664836248STom Zanussi 	/*
18764836248STom Zanussi 	 * Now get the gen_kretprobe_test event file.  We need to
18864836248STom Zanussi 	 * prevent the instance and event from disappearing from
18964836248STom Zanussi 	 * underneath us, which trace_get_event_file() does (though in
19064836248STom Zanussi 	 * this case we're using the top-level instance which never
19164836248STom Zanussi 	 * goes away).
19264836248STom Zanussi 	 */
19364836248STom Zanussi 	gen_kretprobe_test = trace_get_event_file(NULL, "kprobes",
19464836248STom Zanussi 						  "gen_kretprobe_test");
19564836248STom Zanussi 	if (IS_ERR(gen_kretprobe_test)) {
19664836248STom Zanussi 		ret = PTR_ERR(gen_kretprobe_test);
19764836248STom Zanussi 		goto delete;
19864836248STom Zanussi 	}
19964836248STom Zanussi 
20064836248STom Zanussi 	/* Enable the event or you won't see anything */
20164836248STom Zanussi 	ret = trace_array_set_clr_event(gen_kretprobe_test->tr,
20264836248STom Zanussi 					"kprobes", "gen_kretprobe_test", true);
20364836248STom Zanussi 	if (ret) {
20464836248STom Zanussi 		trace_put_event_file(gen_kretprobe_test);
20564836248STom Zanussi 		goto delete;
20664836248STom Zanussi 	}
20764836248STom Zanussi  out:
20866f0919cSShang XiaoJing 	kfree(buf);
20964836248STom Zanussi 	return ret;
21064836248STom Zanussi  delete:
21122ea4ca9SShang XiaoJing 	if (trace_event_file_is_valid(gen_kretprobe_test))
21222ea4ca9SShang XiaoJing 		gen_kretprobe_test = NULL;
21364836248STom Zanussi 	/* We got an error after creating the event, delete it */
214*bc4f359bSAnton Gusev 	kprobe_event_delete("gen_kretprobe_test");
21564836248STom Zanussi 	goto out;
21664836248STom Zanussi }
21764836248STom Zanussi 
kprobe_event_gen_test_init(void)21864836248STom Zanussi static int __init kprobe_event_gen_test_init(void)
21964836248STom Zanussi {
22064836248STom Zanussi 	int ret;
22164836248STom Zanussi 
22264836248STom Zanussi 	ret = test_gen_kprobe_cmd();
22364836248STom Zanussi 	if (ret)
22464836248STom Zanussi 		return ret;
22564836248STom Zanussi 
22664836248STom Zanussi 	ret = test_gen_kretprobe_cmd();
22764836248STom Zanussi 	if (ret) {
228e0d75267SShang XiaoJing 		if (trace_event_file_is_valid(gen_kretprobe_test)) {
22964836248STom Zanussi 			WARN_ON(trace_array_set_clr_event(gen_kretprobe_test->tr,
23064836248STom Zanussi 							  "kprobes",
23164836248STom Zanussi 							  "gen_kretprobe_test", false));
23264836248STom Zanussi 			trace_put_event_file(gen_kretprobe_test);
233e0d75267SShang XiaoJing 		}
23464836248STom Zanussi 		WARN_ON(kprobe_event_delete("gen_kretprobe_test"));
23564836248STom Zanussi 	}
23664836248STom Zanussi 
23764836248STom Zanussi 	return ret;
23864836248STom Zanussi }
23964836248STom Zanussi 
kprobe_event_gen_test_exit(void)24064836248STom Zanussi static void __exit kprobe_event_gen_test_exit(void)
24164836248STom Zanussi {
242e0d75267SShang XiaoJing 	if (trace_event_file_is_valid(gen_kprobe_test)) {
24364836248STom Zanussi 		/* Disable the event or you can't remove it */
24464836248STom Zanussi 		WARN_ON(trace_array_set_clr_event(gen_kprobe_test->tr,
24564836248STom Zanussi 						  "kprobes",
24664836248STom Zanussi 						  "gen_kprobe_test", false));
24764836248STom Zanussi 
24864836248STom Zanussi 		/* Now give the file and instance back */
24964836248STom Zanussi 		trace_put_event_file(gen_kprobe_test);
250e0d75267SShang XiaoJing 	}
251e0d75267SShang XiaoJing 
25264836248STom Zanussi 
25364836248STom Zanussi 	/* Now unregister and free the event */
25464836248STom Zanussi 	WARN_ON(kprobe_event_delete("gen_kprobe_test"));
25564836248STom Zanussi 
256e0d75267SShang XiaoJing 	if (trace_event_file_is_valid(gen_kretprobe_test)) {
25764836248STom Zanussi 		/* Disable the event or you can't remove it */
258ac48e189SYipeng Zou 		WARN_ON(trace_array_set_clr_event(gen_kretprobe_test->tr,
25964836248STom Zanussi 						  "kprobes",
26064836248STom Zanussi 						  "gen_kretprobe_test", false));
26164836248STom Zanussi 
26264836248STom Zanussi 		/* Now give the file and instance back */
26364836248STom Zanussi 		trace_put_event_file(gen_kretprobe_test);
264e0d75267SShang XiaoJing 	}
265e0d75267SShang XiaoJing 
26664836248STom Zanussi 
26764836248STom Zanussi 	/* Now unregister and free the event */
26864836248STom Zanussi 	WARN_ON(kprobe_event_delete("gen_kretprobe_test"));
26964836248STom Zanussi }
27064836248STom Zanussi 
27164836248STom Zanussi module_init(kprobe_event_gen_test_init)
27264836248STom Zanussi module_exit(kprobe_event_gen_test_exit)
27364836248STom Zanussi 
27464836248STom Zanussi MODULE_AUTHOR("Tom Zanussi");
27564836248STom Zanussi MODULE_DESCRIPTION("kprobe event generation test");
27664836248STom Zanussi MODULE_LICENSE("GPL v2");
277