9
9
#include <linux/module.h>
10
10
#include <linux/rculist.h>
11
11
#include <linux/security.h>
12
+ #include <linux/tracepoint.h>
12
13
#include <linux/uaccess.h>
13
14
14
15
#include "trace_dynevent.h"
17
18
#include "trace_probe_tmpl.h"
18
19
19
20
#define FPROBE_EVENT_SYSTEM "fprobes"
21
+ #define TRACEPOINT_EVENT_SYSTEM "tracepoints"
20
22
#define RETHOOK_MAXACTIVE_MAX 4096
21
23
22
24
static int trace_fprobe_create (const char * raw_command );
@@ -41,6 +43,8 @@ struct trace_fprobe {
41
43
struct dyn_event devent ;
42
44
struct fprobe fp ;
43
45
const char * symbol ;
46
+ struct tracepoint * tpoint ;
47
+ struct module * mod ;
44
48
struct trace_probe tp ;
45
49
};
46
50
@@ -68,6 +72,11 @@ static bool trace_fprobe_is_return(struct trace_fprobe *tf)
68
72
return tf -> fp .exit_handler != NULL ;
69
73
}
70
74
75
+ static bool trace_fprobe_is_tracepoint (struct trace_fprobe * tf )
76
+ {
77
+ return tf -> tpoint != NULL ;
78
+ }
79
+
71
80
static const char * trace_fprobe_symbol (struct trace_fprobe * tf )
72
81
{
73
82
return tf -> symbol ? tf -> symbol : "unknown" ;
@@ -668,6 +677,21 @@ static int __register_trace_fprobe(struct trace_fprobe *tf)
668
677
else
669
678
tf -> fp .flags |= FPROBE_FL_DISABLED ;
670
679
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
+
671
695
/* TODO: handle filter, nofilter or symbol list */
672
696
return register_fprobe (& tf -> fp , tf -> symbol , NULL );
673
697
}
@@ -678,6 +702,12 @@ static void __unregister_trace_fprobe(struct trace_fprobe *tf)
678
702
if (trace_fprobe_is_registered (tf )) {
679
703
unregister_fprobe (& tf -> fp );
680
704
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
+ }
681
711
}
682
712
}
683
713
@@ -741,7 +771,8 @@ static int append_trace_fprobe(struct trace_fprobe *tf, struct trace_fprobe *to)
741
771
{
742
772
int ret ;
743
773
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 )) {
745
776
trace_probe_log_set_index (0 );
746
777
trace_probe_log_err (0 , DIFF_PROBE_TYPE );
747
778
return - EEXIST ;
@@ -811,6 +842,60 @@ static int register_trace_fprobe(struct trace_fprobe *tf)
811
842
return ret ;
812
843
}
813
844
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
+
814
899
static int __trace_fprobe_create (int argc , const char * argv [])
815
900
{
816
901
/*
@@ -819,6 +904,8 @@ static int __trace_fprobe_create(int argc, const char *argv[])
819
904
* f[:[GRP/][EVENT]] [MOD:]KSYM [FETCHARGS]
820
905
* - Add fexit probe:
821
906
* f[N][:[GRP/][EVENT]] [MOD:]KSYM%return [FETCHARGS]
907
+ * - Add tracepoint probe:
908
+ * t[:[GRP/][EVENT]] TRACEPOINT [FETCHARGS]
822
909
*
823
910
* Fetch args:
824
911
* $retval : fetch return value
@@ -844,10 +931,16 @@ static int __trace_fprobe_create(int argc, const char *argv[])
844
931
char buf [MAX_EVENT_NAME_LEN ];
845
932
char gbuf [MAX_EVENT_NAME_LEN ];
846
933
unsigned int flags = TPARG_FL_KERNEL | TPARG_FL_FPROBE ;
934
+ bool is_tracepoint = false;
847
935
848
- if (argv [0 ][0 ] != 'f' || argc < 2 )
936
+ if (( argv [0 ][0 ] != 'f' && argv [ 0 ][ 0 ] != 't' ) || argc < 2 )
849
937
return - ECANCELED ;
850
938
939
+ if (argv [0 ][0 ] == 't' ) {
940
+ is_tracepoint = true;
941
+ group = TRACEPOINT_EVENT_SYSTEM ;
942
+ }
943
+
851
944
trace_probe_log_init ("trace_fprobe" , argc , argv );
852
945
853
946
event = strchr (& argv [0 ][1 ], ':' );
@@ -881,14 +974,14 @@ static int __trace_fprobe_create(int argc, const char *argv[])
881
974
882
975
trace_probe_log_set_index (1 );
883
976
884
- /* a symbol specified */
977
+ /* a symbol(or tracepoint) must be specified */
885
978
symbol = kstrdup (argv [1 ], GFP_KERNEL );
886
979
if (!symbol )
887
980
return - ENOMEM ;
888
981
889
982
tmp = strchr (symbol , '%' );
890
983
if (tmp ) {
891
- if (!strcmp (tmp , "%return" )) {
984
+ if (!is_tracepoint && ! strcmp (tmp , "%return" )) {
892
985
* tmp = '\0' ;
893
986
is_return = true;
894
987
} else {
@@ -907,6 +1000,9 @@ static int __trace_fprobe_create(int argc, const char *argv[])
907
1000
else
908
1001
flags |= TPARG_FL_FENTRY ;
909
1002
1003
+ if (is_tracepoint )
1004
+ flags |= TPARG_FL_TPOINT ;
1005
+
910
1006
trace_probe_log_set_index (0 );
911
1007
if (event ) {
912
1008
ret = traceprobe_parse_event_name (& event , & group , gbuf ,
@@ -917,8 +1013,11 @@ static int __trace_fprobe_create(int argc, const char *argv[])
917
1013
918
1014
if (!event ) {
919
1015
/* 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" );
922
1021
sanitize_event_name (buf );
923
1022
event = buf ;
924
1023
}
@@ -932,6 +1031,18 @@ static int __trace_fprobe_create(int argc, const char *argv[])
932
1031
WARN_ON_ONCE (ret != - ENOMEM );
933
1032
goto out ; /* We know tf is not allocated */
934
1033
}
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
+
935
1046
argc -= 2 ; argv += 2 ;
936
1047
937
1048
/* parse arguments */
@@ -991,7 +1102,10 @@ static int trace_fprobe_show(struct seq_file *m, struct dyn_event *ev)
991
1102
struct trace_fprobe * tf = to_trace_fprobe (ev );
992
1103
int i ;
993
1104
994
- seq_putc (m , 'f' );
1105
+ if (trace_fprobe_is_tracepoint (tf ))
1106
+ seq_putc (m , 't' );
1107
+ else
1108
+ seq_putc (m , 'f' );
995
1109
if (trace_fprobe_is_return (tf ) && tf -> fp .nr_maxactive )
996
1110
seq_printf (m , "%d" , tf -> fp .nr_maxactive );
997
1111
seq_printf (m , ":%s/%s" , trace_probe_group_name (& tf -> tp ),
@@ -1048,6 +1162,12 @@ static __init int init_fprobe_trace_early(void)
1048
1162
if (ret )
1049
1163
return ret ;
1050
1164
1165
+ #ifdef CONFIG_MODULES
1166
+ ret = register_tracepoint_module_notifier (& tracepoint_module_nb );
1167
+ if (ret )
1168
+ return ret ;
1169
+ #endif
1170
+
1051
1171
return 0 ;
1052
1172
}
1053
1173
core_initcall (init_fprobe_trace_early );
0 commit comments