123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Test module for in-kernel kprobe event creation and generation.
- *
- * Copyright (C) 2019 Tom Zanussi <[email protected]>
- */
- #include <linux/module.h>
- #include <linux/trace_events.h>
- /*
- * This module is a simple test of basic functionality for in-kernel
- * kprobe/kretprobe event creation. The first test uses
- * kprobe_event_gen_cmd_start(), kprobe_event_add_fields() and
- * kprobe_event_gen_cmd_end() to create a kprobe event, which is then
- * enabled in order to generate trace output. The second creates a
- * kretprobe event using kretprobe_event_gen_cmd_start() and
- * kretprobe_event_gen_cmd_end(), and is also then enabled.
- *
- * To test, select CONFIG_KPROBE_EVENT_GEN_TEST and build the module.
- * Then:
- *
- * # insmod kernel/trace/kprobe_event_gen_test.ko
- * # cat /sys/kernel/debug/tracing/trace
- *
- * You should see many instances of the "gen_kprobe_test" and
- * "gen_kretprobe_test" events in the trace buffer.
- *
- * To remove the events, remove the module:
- *
- * # rmmod kprobe_event_gen_test
- *
- */
- static struct trace_event_file *gen_kprobe_test;
- static struct trace_event_file *gen_kretprobe_test;
- #define KPROBE_GEN_TEST_FUNC "do_sys_open"
- /* X86 */
- #if defined(CONFIG_X86_64) || defined(CONFIG_X86_32)
- #define KPROBE_GEN_TEST_ARG0 "dfd=%ax"
- #define KPROBE_GEN_TEST_ARG1 "filename=%dx"
- #define KPROBE_GEN_TEST_ARG2 "flags=%cx"
- #define KPROBE_GEN_TEST_ARG3 "mode=+4($stack)"
- /* ARM64 */
- #elif defined(CONFIG_ARM64)
- #define KPROBE_GEN_TEST_ARG0 "dfd=%x0"
- #define KPROBE_GEN_TEST_ARG1 "filename=%x1"
- #define KPROBE_GEN_TEST_ARG2 "flags=%x2"
- #define KPROBE_GEN_TEST_ARG3 "mode=%x3"
- /* ARM */
- #elif defined(CONFIG_ARM)
- #define KPROBE_GEN_TEST_ARG0 "dfd=%r0"
- #define KPROBE_GEN_TEST_ARG1 "filename=%r1"
- #define KPROBE_GEN_TEST_ARG2 "flags=%r2"
- #define KPROBE_GEN_TEST_ARG3 "mode=%r3"
- /* RISCV */
- #elif defined(CONFIG_RISCV)
- #define KPROBE_GEN_TEST_ARG0 "dfd=%a0"
- #define KPROBE_GEN_TEST_ARG1 "filename=%a1"
- #define KPROBE_GEN_TEST_ARG2 "flags=%a2"
- #define KPROBE_GEN_TEST_ARG3 "mode=%a3"
- /* others */
- #else
- #define KPROBE_GEN_TEST_ARG0 NULL
- #define KPROBE_GEN_TEST_ARG1 NULL
- #define KPROBE_GEN_TEST_ARG2 NULL
- #define KPROBE_GEN_TEST_ARG3 NULL
- #endif
- static bool trace_event_file_is_valid(struct trace_event_file *input)
- {
- return input && !IS_ERR(input);
- }
- /*
- * Test to make sure we can create a kprobe event, then add more
- * fields.
- */
- static int __init test_gen_kprobe_cmd(void)
- {
- struct dynevent_cmd cmd;
- char *buf;
- int ret;
- /* Create a buffer to hold the generated command */
- buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- /* Before generating the command, initialize the cmd object */
- kprobe_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
- /*
- * Define the gen_kprobe_test event with the first 2 kprobe
- * fields.
- */
- ret = kprobe_event_gen_cmd_start(&cmd, "gen_kprobe_test",
- KPROBE_GEN_TEST_FUNC,
- KPROBE_GEN_TEST_ARG0, KPROBE_GEN_TEST_ARG1);
- if (ret)
- goto out;
- /* Use kprobe_event_add_fields to add the rest of the fields */
- ret = kprobe_event_add_fields(&cmd, KPROBE_GEN_TEST_ARG2, KPROBE_GEN_TEST_ARG3);
- if (ret)
- goto out;
- /*
- * This actually creates the event.
- */
- ret = kprobe_event_gen_cmd_end(&cmd);
- if (ret)
- goto out;
- /*
- * Now get the gen_kprobe_test event file. We need to prevent
- * the instance and event from disappearing from underneath
- * us, which trace_get_event_file() does (though in this case
- * we're using the top-level instance which never goes away).
- */
- gen_kprobe_test = trace_get_event_file(NULL, "kprobes",
- "gen_kprobe_test");
- if (IS_ERR(gen_kprobe_test)) {
- ret = PTR_ERR(gen_kprobe_test);
- goto delete;
- }
- /* Enable the event or you won't see anything */
- ret = trace_array_set_clr_event(gen_kprobe_test->tr,
- "kprobes", "gen_kprobe_test", true);
- if (ret) {
- trace_put_event_file(gen_kprobe_test);
- goto delete;
- }
- out:
- kfree(buf);
- return ret;
- delete:
- if (trace_event_file_is_valid(gen_kprobe_test))
- gen_kprobe_test = NULL;
- /* We got an error after creating the event, delete it */
- kprobe_event_delete("gen_kprobe_test");
- goto out;
- }
- /*
- * Test to make sure we can create a kretprobe event.
- */
- static int __init test_gen_kretprobe_cmd(void)
- {
- struct dynevent_cmd cmd;
- char *buf;
- int ret;
- /* Create a buffer to hold the generated command */
- buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- /* Before generating the command, initialize the cmd object */
- kprobe_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
- /*
- * Define the kretprobe event.
- */
- ret = kretprobe_event_gen_cmd_start(&cmd, "gen_kretprobe_test",
- KPROBE_GEN_TEST_FUNC,
- "$retval");
- if (ret)
- goto out;
- /*
- * This actually creates the event.
- */
- ret = kretprobe_event_gen_cmd_end(&cmd);
- if (ret)
- goto out;
- /*
- * Now get the gen_kretprobe_test event file. We need to
- * prevent the instance and event from disappearing from
- * underneath us, which trace_get_event_file() does (though in
- * this case we're using the top-level instance which never
- * goes away).
- */
- gen_kretprobe_test = trace_get_event_file(NULL, "kprobes",
- "gen_kretprobe_test");
- if (IS_ERR(gen_kretprobe_test)) {
- ret = PTR_ERR(gen_kretprobe_test);
- goto delete;
- }
- /* Enable the event or you won't see anything */
- ret = trace_array_set_clr_event(gen_kretprobe_test->tr,
- "kprobes", "gen_kretprobe_test", true);
- if (ret) {
- trace_put_event_file(gen_kretprobe_test);
- goto delete;
- }
- out:
- kfree(buf);
- return ret;
- delete:
- if (trace_event_file_is_valid(gen_kretprobe_test))
- gen_kretprobe_test = NULL;
- /* We got an error after creating the event, delete it */
- kprobe_event_delete("gen_kretprobe_test");
- goto out;
- }
- static int __init kprobe_event_gen_test_init(void)
- {
- int ret;
- ret = test_gen_kprobe_cmd();
- if (ret)
- return ret;
- ret = test_gen_kretprobe_cmd();
- if (ret) {
- if (trace_event_file_is_valid(gen_kretprobe_test)) {
- WARN_ON(trace_array_set_clr_event(gen_kretprobe_test->tr,
- "kprobes",
- "gen_kretprobe_test", false));
- trace_put_event_file(gen_kretprobe_test);
- }
- WARN_ON(kprobe_event_delete("gen_kretprobe_test"));
- }
- return ret;
- }
- static void __exit kprobe_event_gen_test_exit(void)
- {
- if (trace_event_file_is_valid(gen_kprobe_test)) {
- /* Disable the event or you can't remove it */
- WARN_ON(trace_array_set_clr_event(gen_kprobe_test->tr,
- "kprobes",
- "gen_kprobe_test", false));
- /* Now give the file and instance back */
- trace_put_event_file(gen_kprobe_test);
- }
- /* Now unregister and free the event */
- WARN_ON(kprobe_event_delete("gen_kprobe_test"));
- if (trace_event_file_is_valid(gen_kretprobe_test)) {
- /* Disable the event or you can't remove it */
- WARN_ON(trace_array_set_clr_event(gen_kretprobe_test->tr,
- "kprobes",
- "gen_kretprobe_test", false));
- /* Now give the file and instance back */
- trace_put_event_file(gen_kretprobe_test);
- }
- /* Now unregister and free the event */
- WARN_ON(kprobe_event_delete("gen_kretprobe_test"));
- }
- module_init(kprobe_event_gen_test_init)
- module_exit(kprobe_event_gen_test_exit)
- MODULE_AUTHOR("Tom Zanussi");
- MODULE_DESCRIPTION("kprobe event generation test");
- MODULE_LICENSE("GPL v2");
|