4040
4141#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
4242#include <stdlib.h>
43+ #include <string.h>
4344#include <linux/err.h>
4445#include <linux/filter.h>
4546#include <linux/audit.h>
@@ -2699,6 +2700,91 @@ static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
26992700 evsel -> handler = handler ;
27002701}
27012702
2703+ /*
2704+ * XXX: Hackish, just splitting the combined -e+--event (syscalls
2705+ * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2706+ * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2707+ *
2708+ * It'd be better to introduce a parse_options() variant that would return a
2709+ * list with the terms it didn't match to an event...
2710+ */
2711+ static int trace__parse_events_option (const struct option * opt , const char * str ,
2712+ int unset __maybe_unused )
2713+ {
2714+ struct trace * trace = (struct trace * )opt -> value ;
2715+ const char * s = str ;
2716+ char * sep = NULL , * lists [2 ] = { NULL , NULL , };
2717+ int len = strlen (str ), err = -1 , list ;
2718+ char * strace_groups_dir = system_path (STRACE_GROUPS_DIR );
2719+ char group_name [PATH_MAX ];
2720+
2721+ if (strace_groups_dir == NULL )
2722+ return -1 ;
2723+
2724+ if (* s == '!' ) {
2725+ ++ s ;
2726+ trace -> not_ev_qualifier = true;
2727+ }
2728+
2729+ while (1 ) {
2730+ if ((sep = strchr (s , ',' )) != NULL )
2731+ * sep = '\0' ;
2732+
2733+ list = 0 ;
2734+ if (syscalltbl__id (trace -> sctbl , s ) >= 0 ) {
2735+ list = 1 ;
2736+ } else {
2737+ path__join (group_name , sizeof (group_name ), strace_groups_dir , s );
2738+ if (access (group_name , R_OK ) == 0 )
2739+ list = 1 ;
2740+ }
2741+
2742+ if (lists [list ]) {
2743+ sprintf (lists [list ] + strlen (lists [list ]), ",%s" , s );
2744+ } else {
2745+ lists [list ] = malloc (len );
2746+ if (lists [list ] == NULL )
2747+ goto out ;
2748+ strcpy (lists [list ], s );
2749+ }
2750+
2751+ if (!sep )
2752+ break ;
2753+
2754+ * sep = ',' ;
2755+ s = sep + 1 ;
2756+ }
2757+
2758+ if (lists [1 ] != NULL ) {
2759+ struct strlist_config slist_config = {
2760+ .dirname = strace_groups_dir ,
2761+ };
2762+
2763+ trace -> ev_qualifier = strlist__new (lists [1 ], & slist_config );
2764+ if (trace -> ev_qualifier == NULL ) {
2765+ fputs ("Not enough memory to parse event qualifier" , trace -> output );
2766+ goto out ;
2767+ }
2768+
2769+ if (trace__validate_ev_qualifier (trace ))
2770+ goto out ;
2771+ }
2772+
2773+ err = 0 ;
2774+
2775+ if (lists [0 ]) {
2776+ struct option o = OPT_CALLBACK ('e' , "event" , & trace -> evlist , "event" ,
2777+ "event selector. use 'perf list' to list available events" ,
2778+ parse_events_option );
2779+ err = parse_events_option (& o , lists [0 ], 0 );
2780+ }
2781+ out :
2782+ if (sep )
2783+ * sep = ',' ;
2784+
2785+ return err ;
2786+ }
2787+
27022788int cmd_trace (int argc , const char * * argv , const char * prefix __maybe_unused )
27032789{
27042790 const char * trace_usage [] = {
@@ -2730,15 +2816,15 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
27302816 .max_stack = UINT_MAX ,
27312817 };
27322818 const char * output_name = NULL ;
2733- const char * ev_qualifier_str = NULL ;
27342819 const struct option trace_options [] = {
2735- OPT_CALLBACK (0 , "event" , & trace . evlist , "event" ,
2736- "event selector. use 'perf list' to list available events" ,
2737- parse_events_option ),
2820+ OPT_CALLBACK ('e' , "event" , & trace , "event" ,
2821+ "event/syscall selector. use 'perf list' to list available events" ,
2822+ trace__parse_events_option ),
27382823 OPT_BOOLEAN (0 , "comm" , & trace .show_comm ,
27392824 "show the thread COMM next to its id" ),
27402825 OPT_BOOLEAN (0 , "tool_stats" , & trace .show_tool_stats , "show tool stats" ),
2741- OPT_STRING ('e' , "expr" , & ev_qualifier_str , "expr" , "list of syscalls to trace" ),
2826+ OPT_CALLBACK (0 , "expr" , & trace , "expr" , "list of syscalls/events to trace" ,
2827+ trace__parse_events_option ),
27422828 OPT_STRING ('o' , "output" , & output_name , "file" , "output file name" ),
27432829 OPT_STRING ('i' , "input" , & input_name , "file" , "Analyze events in file" ),
27442830 OPT_STRING ('p' , "pid" , & trace .opts .target .pid , "pid" ,
@@ -2863,7 +2949,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
28632949 return -1 ;
28642950 }
28652951
2866- if (!trace .trace_syscalls && ev_qualifier_str ) {
2952+ if (!trace .trace_syscalls && trace . ev_qualifier ) {
28672953 pr_err ("The -e option can't be used with --no-syscalls.\n" );
28682954 goto out ;
28692955 }
@@ -2878,28 +2964,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
28782964
28792965 trace .open_id = syscalltbl__id (trace .sctbl , "open" );
28802966
2881- if (ev_qualifier_str != NULL ) {
2882- const char * s = ev_qualifier_str ;
2883- struct strlist_config slist_config = {
2884- .dirname = system_path (STRACE_GROUPS_DIR ),
2885- };
2886-
2887- trace .not_ev_qualifier = * s == '!' ;
2888- if (trace .not_ev_qualifier )
2889- ++ s ;
2890- trace .ev_qualifier = strlist__new (s , & slist_config );
2891- if (trace .ev_qualifier == NULL ) {
2892- fputs ("Not enough memory to parse event qualifier" ,
2893- trace .output );
2894- err = - ENOMEM ;
2895- goto out_close ;
2896- }
2897-
2898- err = trace__validate_ev_qualifier (& trace );
2899- if (err )
2900- goto out_close ;
2901- }
2902-
29032967 err = target__validate (& trace .opts .target );
29042968 if (err ) {
29052969 target__strerror (& trace .opts .target , err , bf , sizeof (bf ));
0 commit comments