2019-05-19 15:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2008-03-05 01:28:38 +03:00
/*
* kretprobe_example . c
*
* Here ' s a sample kernel module showing the use of return probes to
* report the return value and total time taken for probed function
* to run .
*
* usage : insmod kretprobe_example . ko func = < func_name >
*
2020-08-19 13:46:54 +03:00
* If no func_name is specified , kernel_clone is instrumented
2008-03-05 01:28:38 +03:00
*
* For more information on theory of operation of kretprobes , see
2020-09-09 17:10:37 +03:00
* Documentation / trace / kprobes . rst
2008-03-05 01:28:38 +03:00
*
* Build and insert the kernel module as done in the kprobe example .
* You will see the trace data in / var / log / messages and on the console
* whenever the probed function returns . ( Some messages may be suppressed
* if syslogd is configured to eliminate duplicate messages . )
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/kprobes.h>
# include <linux/ktime.h>
2009-08-13 14:05:43 +04:00
# include <linux/sched.h>
2008-03-05 01:28:38 +03:00
2022-06-08 04:23:22 +03:00
static char func_name [ KSYM_NAME_LEN ] = " kernel_clone " ;
module_param_string ( func , func_name , KSYM_NAME_LEN , 0644 ) ;
2008-03-05 01:28:38 +03:00
MODULE_PARM_DESC ( func , " Function to kretprobe; this module will report the "
" function's execution time " ) ;
/* per-instance private data */
struct my_data {
ktime_t entry_stamp ;
} ;
2023-08-17 20:08:19 +03:00
/* Here we use the entry_handler to timestamp function entry */
2008-03-05 01:28:38 +03:00
static int entry_handler ( struct kretprobe_instance * ri , struct pt_regs * regs )
{
struct my_data * data ;
if ( ! current - > mm )
return 1 ; /* Skip kernel threads */
data = ( struct my_data * ) ri - > data ;
data - > entry_stamp = ktime_get ( ) ;
return 0 ;
}
2020-03-26 17:50:11 +03:00
NOKPROBE_SYMBOL ( entry_handler ) ;
2008-03-05 01:28:38 +03:00
/*
* Return - probe handler : Log the return value and duration . Duration may turn
* out to be zero consistently , depending upon the granularity of time
* accounting on the platform .
*/
static int ret_handler ( struct kretprobe_instance * ri , struct pt_regs * regs )
{
2016-08-03 23:46:12 +03:00
unsigned long retval = regs_return_value ( regs ) ;
2008-03-05 01:28:38 +03:00
struct my_data * data = ( struct my_data * ) ri - > data ;
s64 delta ;
ktime_t now ;
now = ktime_get ( ) ;
delta = ktime_to_ns ( ktime_sub ( now , data - > entry_stamp ) ) ;
2016-08-03 23:46:12 +03:00
pr_info ( " %s returned %lu and took %lld ns to execute \n " ,
2008-03-05 01:28:38 +03:00
func_name , retval , ( long long ) delta ) ;
return 0 ;
}
2020-03-26 17:50:11 +03:00
NOKPROBE_SYMBOL ( ret_handler ) ;
2008-03-05 01:28:38 +03:00
static struct kretprobe my_kretprobe = {
. handler = ret_handler ,
. entry_handler = entry_handler ,
. data_size = sizeof ( struct my_data ) ,
/* Probe up to 20 instances concurrently. */
. maxactive = 20 ,
} ;
static int __init kretprobe_init ( void )
{
int ret ;
my_kretprobe . kp . symbol_name = func_name ;
ret = register_kretprobe ( & my_kretprobe ) ;
if ( ret < 0 ) {
2016-08-03 23:46:09 +03:00
pr_err ( " register_kretprobe failed, returned %d \n " , ret ) ;
2021-10-26 04:51:28 +03:00
return ret ;
2008-03-05 01:28:38 +03:00
}
2016-08-03 23:46:09 +03:00
pr_info ( " Planted return probe at %s: %p \n " ,
2008-03-05 01:28:38 +03:00
my_kretprobe . kp . symbol_name , my_kretprobe . kp . addr ) ;
return 0 ;
}
static void __exit kretprobe_exit ( void )
{
unregister_kretprobe ( & my_kretprobe ) ;
2016-08-03 23:46:09 +03:00
pr_info ( " kretprobe at %p unregistered \n " , my_kretprobe . kp . addr ) ;
2008-03-05 01:28:38 +03:00
/* nmissed > 0 suggests that maxactive was set too low. */
2016-08-03 23:46:09 +03:00
pr_info ( " Missed probing %d instances of %s \n " ,
2008-03-05 01:28:38 +03:00
my_kretprobe . nmissed , my_kretprobe . kp . symbol_name ) ;
}
module_init ( kretprobe_init )
module_exit ( kretprobe_exit )
2024-06-12 02:44:27 +03:00
MODULE_DESCRIPTION ( " sample kernel module showing the use of return probes " ) ;
2008-03-05 01:28:38 +03:00
MODULE_LICENSE ( " GPL " ) ;