99#include <linux/module.h>
1010#include <linux/rculist.h>
1111#include <linux/security.h>
12+ #include <linux/tracepoint.h>
1213#include <linux/uaccess.h>
1314
1415#include "trace_dynevent.h"
1718#include "trace_probe_tmpl.h"
1819
1920#define FPROBE_EVENT_SYSTEM "fprobes"
21+ #define TRACEPOINT_EVENT_SYSTEM "tracepoints"
2022#define RETHOOK_MAXACTIVE_MAX 4096
2123
2224static int trace_fprobe_create (const char * raw_command );
@@ -41,6 +43,8 @@ struct trace_fprobe {
4143 struct dyn_event devent ;
4244 struct fprobe fp ;
4345 const char * symbol ;
46+ struct tracepoint * tpoint ;
47+ struct module * mod ;
4448 struct trace_probe tp ;
4549};
4650
@@ -68,6 +72,11 @@ static bool trace_fprobe_is_return(struct trace_fprobe *tf)
6872 return tf -> fp .exit_handler != NULL ;
6973}
7074
75+ static bool trace_fprobe_is_tracepoint (struct trace_fprobe * tf )
76+ {
77+ return tf -> tpoint != NULL ;
78+ }
79+
7180static const char * trace_fprobe_symbol (struct trace_fprobe * tf )
7281{
7382 return tf -> symbol ? tf -> symbol : "unknown" ;
@@ -668,6 +677,21 @@ static int __register_trace_fprobe(struct trace_fprobe *tf)
668677 else
669678 tf -> fp .flags |= FPROBE_FL_DISABLED ;
670679
680+ if (trace_fprobe_is_tracepoint (tf )) {
681+ struct tracepoint * tpoint = tf -> tpoint ;
682+ unsigned long ip = (unsigned long )tpoint -> probestub ;
683+ /*
684+ * Here, we do 2 steps to enable fprobe on a tracepoint.
685+ * At first, put __probestub_##TP function on the tracepoint
686+ * and put a fprobe on the stub function.
687+ */
688+ ret = tracepoint_probe_register_prio_may_exist (tpoint ,
689+ tpoint -> probestub , NULL , 0 );
690+ if (ret < 0 )
691+ return ret ;
692+ return register_fprobe_ips (& tf -> fp , & ip , 1 );
693+ }
694+
671695 /* TODO: handle filter, nofilter or symbol list */
672696 return register_fprobe (& tf -> fp , tf -> symbol , NULL );
673697}
@@ -678,6 +702,12 @@ static void __unregister_trace_fprobe(struct trace_fprobe *tf)
678702 if (trace_fprobe_is_registered (tf )) {
679703 unregister_fprobe (& tf -> fp );
680704 memset (& tf -> fp , 0 , sizeof (tf -> fp ));
705+ if (trace_fprobe_is_tracepoint (tf )) {
706+ tracepoint_probe_unregister (tf -> tpoint ,
707+ tf -> tpoint -> probestub , NULL );
708+ tf -> tpoint = NULL ;
709+ tf -> mod = NULL ;
710+ }
681711 }
682712}
683713
@@ -741,7 +771,8 @@ static int append_trace_fprobe(struct trace_fprobe *tf, struct trace_fprobe *to)
741771{
742772 int ret ;
743773
744- if (trace_fprobe_is_return (tf ) != trace_fprobe_is_return (to )) {
774+ if (trace_fprobe_is_return (tf ) != trace_fprobe_is_return (to ) ||
775+ trace_fprobe_is_tracepoint (tf ) != trace_fprobe_is_tracepoint (to )) {
745776 trace_probe_log_set_index (0 );
746777 trace_probe_log_err (0 , DIFF_PROBE_TYPE );
747778 return - EEXIST ;
@@ -811,6 +842,60 @@ static int register_trace_fprobe(struct trace_fprobe *tf)
811842 return ret ;
812843}
813844
845+ #ifdef CONFIG_MODULES
846+ static int __tracepoint_probe_module_cb (struct notifier_block * self ,
847+ unsigned long val , void * data )
848+ {
849+ struct tp_module * tp_mod = data ;
850+ struct trace_fprobe * tf ;
851+ struct dyn_event * pos ;
852+
853+ if (val != MODULE_STATE_GOING )
854+ return NOTIFY_DONE ;
855+
856+ mutex_lock (& event_mutex );
857+ for_each_trace_fprobe (tf , pos ) {
858+ if (tp_mod -> mod == tf -> mod ) {
859+ tracepoint_probe_unregister (tf -> tpoint ,
860+ tf -> tpoint -> probestub , NULL );
861+ tf -> tpoint = NULL ;
862+ tf -> mod = NULL ;
863+ }
864+ }
865+ mutex_unlock (& event_mutex );
866+
867+ return NOTIFY_DONE ;
868+ }
869+
870+ static struct notifier_block tracepoint_module_nb = {
871+ .notifier_call = __tracepoint_probe_module_cb ,
872+ };
873+ #endif /* CONFIG_MODULES */
874+
875+ struct __find_tracepoint_cb_data {
876+ const char * tp_name ;
877+ struct tracepoint * tpoint ;
878+ };
879+
880+ static void __find_tracepoint_cb (struct tracepoint * tp , void * priv )
881+ {
882+ struct __find_tracepoint_cb_data * data = priv ;
883+
884+ if (!data -> tpoint && !strcmp (data -> tp_name , tp -> name ))
885+ data -> tpoint = tp ;
886+ }
887+
888+ static struct tracepoint * find_tracepoint (const char * tp_name )
889+ {
890+ struct __find_tracepoint_cb_data data = {
891+ .tp_name = tp_name ,
892+ };
893+
894+ for_each_kernel_tracepoint (__find_tracepoint_cb , & data );
895+
896+ return data .tpoint ;
897+ }
898+
814899static int __trace_fprobe_create (int argc , const char * argv [])
815900{
816901 /*
@@ -819,6 +904,8 @@ static int __trace_fprobe_create(int argc, const char *argv[])
819904 * f[:[GRP/][EVENT]] [MOD:]KSYM [FETCHARGS]
820905 * - Add fexit probe:
821906 * f[N][:[GRP/][EVENT]] [MOD:]KSYM%return [FETCHARGS]
907+ * - Add tracepoint probe:
908+ * t[:[GRP/][EVENT]] TRACEPOINT [FETCHARGS]
822909 *
823910 * Fetch args:
824911 * $retval : fetch return value
@@ -844,10 +931,16 @@ static int __trace_fprobe_create(int argc, const char *argv[])
844931 char buf [MAX_EVENT_NAME_LEN ];
845932 char gbuf [MAX_EVENT_NAME_LEN ];
846933 unsigned int flags = TPARG_FL_KERNEL | TPARG_FL_FPROBE ;
934+ bool is_tracepoint = false;
847935
848- if (argv [0 ][0 ] != 'f' || argc < 2 )
936+ if (( argv [0 ][0 ] != 'f' && argv [ 0 ][ 0 ] != 't' ) || argc < 2 )
849937 return - ECANCELED ;
850938
939+ if (argv [0 ][0 ] == 't' ) {
940+ is_tracepoint = true;
941+ group = TRACEPOINT_EVENT_SYSTEM ;
942+ }
943+
851944 trace_probe_log_init ("trace_fprobe" , argc , argv );
852945
853946 event = strchr (& argv [0 ][1 ], ':' );
@@ -881,14 +974,14 @@ static int __trace_fprobe_create(int argc, const char *argv[])
881974
882975 trace_probe_log_set_index (1 );
883976
884- /* a symbol specified */
977+ /* a symbol(or tracepoint) must be specified */
885978 symbol = kstrdup (argv [1 ], GFP_KERNEL );
886979 if (!symbol )
887980 return - ENOMEM ;
888981
889982 tmp = strchr (symbol , '%' );
890983 if (tmp ) {
891- if (!strcmp (tmp , "%return" )) {
984+ if (!is_tracepoint && ! strcmp (tmp , "%return" )) {
892985 * tmp = '\0' ;
893986 is_return = true;
894987 } else {
@@ -907,6 +1000,9 @@ static int __trace_fprobe_create(int argc, const char *argv[])
9071000 else
9081001 flags |= TPARG_FL_FENTRY ;
9091002
1003+ if (is_tracepoint )
1004+ flags |= TPARG_FL_TPOINT ;
1005+
9101006 trace_probe_log_set_index (0 );
9111007 if (event ) {
9121008 ret = traceprobe_parse_event_name (& event , & group , gbuf ,
@@ -917,8 +1013,11 @@ static int __trace_fprobe_create(int argc, const char *argv[])
9171013
9181014 if (!event ) {
9191015 /* Make a new event name */
920- snprintf (buf , MAX_EVENT_NAME_LEN , "%s__%s" , symbol ,
921- is_return ? "exit" : "entry" );
1016+ if (is_tracepoint )
1017+ strscpy (buf , symbol , MAX_EVENT_NAME_LEN );
1018+ else
1019+ snprintf (buf , MAX_EVENT_NAME_LEN , "%s__%s" , symbol ,
1020+ is_return ? "exit" : "entry" );
9221021 sanitize_event_name (buf );
9231022 event = buf ;
9241023 }
@@ -932,6 +1031,18 @@ static int __trace_fprobe_create(int argc, const char *argv[])
9321031 WARN_ON_ONCE (ret != - ENOMEM );
9331032 goto out ; /* We know tf is not allocated */
9341033 }
1034+
1035+ if (is_tracepoint ) {
1036+ tf -> tpoint = find_tracepoint (tf -> symbol );
1037+ if (!tf -> tpoint ) {
1038+ trace_probe_log_set_index (1 );
1039+ trace_probe_log_err (0 , NO_TRACEPOINT );
1040+ goto parse_error ;
1041+ }
1042+ tf -> mod = __module_text_address (
1043+ (unsigned long )tf -> tpoint -> probestub );
1044+ }
1045+
9351046 argc -= 2 ; argv += 2 ;
9361047
9371048 /* parse arguments */
@@ -991,7 +1102,10 @@ static int trace_fprobe_show(struct seq_file *m, struct dyn_event *ev)
9911102 struct trace_fprobe * tf = to_trace_fprobe (ev );
9921103 int i ;
9931104
994- seq_putc (m , 'f' );
1105+ if (trace_fprobe_is_tracepoint (tf ))
1106+ seq_putc (m , 't' );
1107+ else
1108+ seq_putc (m , 'f' );
9951109 if (trace_fprobe_is_return (tf ) && tf -> fp .nr_maxactive )
9961110 seq_printf (m , "%d" , tf -> fp .nr_maxactive );
9971111 seq_printf (m , ":%s/%s" , trace_probe_group_name (& tf -> tp ),
@@ -1048,6 +1162,12 @@ static __init int init_fprobe_trace_early(void)
10481162 if (ret )
10491163 return ret ;
10501164
1165+ #ifdef CONFIG_MODULES
1166+ ret = register_tracepoint_module_notifier (& tracepoint_module_nb );
1167+ if (ret )
1168+ return ret ;
1169+ #endif
1170+
10511171 return 0 ;
10521172}
10531173core_initcall (init_fprobe_trace_early );
0 commit comments