^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * kretprobe_example.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Here's a sample kernel module showing the use of return probes to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * report the return value and total time taken for probed function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * to run.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * usage: insmod kretprobe_example.ko func=<func_name>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * If no func_name is specified, kernel_clone is instrumented
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * For more information on theory of operation of kretprobes, see
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Documentation/trace/kprobes.rst
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Build and insert the kernel module as done in the kprobe example.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * You will see the trace data in /var/log/messages and on the console
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * whenever the probed function returns. (Some messages may be suppressed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * if syslogd is configured to eliminate duplicate messages.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/kprobes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/ktime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/limits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static char func_name[NAME_MAX] = "kernel_clone";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) module_param_string(func, func_name, NAME_MAX, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) MODULE_PARM_DESC(func, "Function to kretprobe; this module will report the"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) " function's execution time");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* per-instance private data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct my_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) ktime_t entry_stamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /* Here we use the entry_hanlder to timestamp function entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct my_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (!current->mm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return 1; /* Skip kernel threads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) data = (struct my_data *)ri->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) data->entry_stamp = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) NOKPROBE_SYMBOL(entry_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * Return-probe handler: Log the return value and duration. Duration may turn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * out to be zero consistently, depending upon the granularity of time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * accounting on the platform.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned long retval = regs_return_value(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct my_data *data = (struct my_data *)ri->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) s64 delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) ktime_t now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) now = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) delta = ktime_to_ns(ktime_sub(now, data->entry_stamp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) pr_info("%s returned %lu and took %lld ns to execute\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) func_name, retval, (long long)delta);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) NOKPROBE_SYMBOL(ret_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static struct kretprobe my_kretprobe = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) .handler = ret_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) .entry_handler = entry_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) .data_size = sizeof(struct my_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /* Probe up to 20 instances concurrently. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .maxactive = 20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int __init kretprobe_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) my_kretprobe.kp.symbol_name = func_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) ret = register_kretprobe(&my_kretprobe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) pr_err("register_kretprobe failed, returned %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) pr_info("Planted return probe at %s: %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) my_kretprobe.kp.symbol_name, my_kretprobe.kp.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static void __exit kretprobe_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) unregister_kretprobe(&my_kretprobe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) pr_info("kretprobe at %p unregistered\n", my_kretprobe.kp.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* nmissed > 0 suggests that maxactive was set too low. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) pr_info("Missed probing %d instances of %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) my_kretprobe.nmissed, my_kretprobe.kp.symbol_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) module_init(kretprobe_init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) module_exit(kretprobe_exit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) MODULE_LICENSE("GPL");