lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1322510824.17003.18.camel@frodo>
Date:	Mon, 28 Nov 2011 15:07:04 -0500
From:	Steven Rostedt <rostedt@...dmis.org>
To:	Jiri Olsa <jolsa@...hat.com>
Cc:	fweisbec@...il.com, mingo@...hat.com, paulus@...ba.org,
	acme@...stprotocols.net, linux-kernel@...r.kernel.org
Subject: Re: [PATCH 9/9] ftrace, perf: Add filter support for function
 trace event

On Sun, 2011-11-27 at 19:04 +0100, Jiri Olsa wrote:
> Adding support to filter function trace event via perf
> interface. It is now possible to use filter interface
> in the perf tool like:
> 
>   perf record -e ftrace:function --filter="(ip == mm_*)" ls
> 
> The filter syntax is restricted to the the 'ip' field only,
> and following operators are accepted '==' '!=' '&&', ending
> up with the filter strings like:
> 
>   "ip == f1 f2 ..." && "ip != f3 f4 ..." ...
> 
> The '==' operator adds trace filter with same efect as would

effect

> be added via set_ftrace_filter file.
> 
> The '!=' operator adds trace filter with same efect as would

effect

> be added via set_ftrace_notrace file.
> 
> The right side of the '!=', '==' operators is list of functions
> or regexp. to be added to filter separated by space. Same syntax
> is supported/required as for the set_ftrace_filter and
> set_ftrace_notrace files.
> 
> The '&&' operator is used for connecting multiple filter definitions
> together. It is possible to have more than one '==' and '!='
> opearators within one filter string.

operators


Interesting way to handle it. I'll have to test it out. I wonder if we
could also make this work the same way with ftrace too.

-- Steve

> 
> Signed-off-by: Jiri Olsa <jolsa@...hat.com>
> ---
>  kernel/trace/trace.h               |    4 +-
>  kernel/trace/trace_events_filter.c |  111 +++++++++++++++++++++++++++++++++---
>  kernel/trace/trace_export.c        |    5 ++
>  3 files changed, 110 insertions(+), 10 deletions(-)
> 
> diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
> index c4330dc..fde4d2a 100644
> --- a/kernel/trace/trace.h
> +++ b/kernel/trace/trace.h
> @@ -589,6 +589,8 @@ static inline int ftrace_trace_task(struct task_struct *task)
>  static inline int ftrace_is_dead(void) { return 0; }
>  #endif
>  
> +int ftrace_event_is_function(struct ftrace_event_call *call);
> +
>  /*
>   * struct trace_parser - servers for reading the user input separated by spaces
>   * @cont: set if the input is not complete - no final space char was found
> @@ -765,9 +767,7 @@ struct filter_pred {
>  	u64 			val;
>  	struct regex		regex;
>  	unsigned short		*ops;
> -#ifdef CONFIG_FTRACE_STARTUP_TEST
>  	struct ftrace_event_field *field;
> -#endif
>  	int 			offset;
>  	int 			not;
>  	int 			op;
> diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
> index 7b0b04c..7434f50 100644
> --- a/kernel/trace/trace_events_filter.c
> +++ b/kernel/trace/trace_events_filter.c
> @@ -54,6 +54,13 @@ struct filter_op {
>  	int precedence;
>  };
>  
> +static struct filter_op filter_ftrace_ops[] = {
> +	{ OP_AND,	"&&",		1 },
> +	{ OP_NE,	"!=",		2 },
> +	{ OP_EQ,	"==",		2 },
> +	{ OP_NONE,	"OP_NONE",	0 },
> +};
> +
>  static struct filter_op filter_ops[] = {
>  	{ OP_OR,	"||",		1 },
>  	{ OP_AND,	"&&",		2 },
> @@ -81,6 +88,7 @@ enum {
>  	FILT_ERR_TOO_MANY_PREDS,
>  	FILT_ERR_MISSING_FIELD,
>  	FILT_ERR_INVALID_FILTER,
> +	FILT_ERR_IP_FIELD_ONLY,
>  };
>  
>  static char *err_text[] = {
> @@ -96,6 +104,7 @@ static char *err_text[] = {
>  	"Too many terms in predicate expression",
>  	"Missing field name and/or value",
>  	"Meaningless filter expression",
> +	"Only 'ip' field is supported for function trace",
>  };
>  
>  struct opstack_op {
> @@ -992,7 +1001,12 @@ static int init_pred(struct filter_parse_state *ps,
>  			fn = filter_pred_strloc;
>  		else
>  			fn = filter_pred_pchar;
> -	} else if (!is_function_field(field)) {
> +	} else if (is_function_field(field)) {
> +		if (strcmp(field->name, "ip")) {
> +			parse_error(ps, FILT_ERR_IP_FIELD_ONLY, 0);
> +			return -EINVAL;
> +		}
> +	} else {
>  		if (field->is_signed)
>  			ret = strict_strtoll(pred->regex.pattern, 0, &val);
>  		else
> @@ -1339,10 +1353,8 @@ static struct filter_pred *create_pred(struct filter_parse_state *ps,
>  
>  	strcpy(pred.regex.pattern, operand2);
>  	pred.regex.len = strlen(pred.regex.pattern);
> -
> -#ifdef CONFIG_FTRACE_STARTUP_TEST
>  	pred.field = field;
> -#endif
> +
>  	return init_pred(ps, field, &pred) ? NULL : &pred;
>  }
>  
> @@ -1894,6 +1906,81 @@ void ftrace_profile_free_filter(struct perf_event *event)
>  	__free_filter(filter);
>  }
>  
> +struct function_filter_data {
> +	struct ftrace_ops *ops;
> +	int first_filter;
> +	int first_notrace;
> +};
> +
> +static int __ftrace_function_set_filter(int filter, char *buf, int len,
> +					struct function_filter_data *data)
> +{
> +	int *reset;
> +
> +	reset = filter ? &data->first_filter : &data->first_notrace;
> +
> +	if (filter)
> +		ftrace_set_filter(data->ops, buf, len, *reset);
> +	else
> +		ftrace_set_notrace(data->ops, buf, len, *reset);
> +
> +	if (*reset)
> +		*reset = 0;
> +
> +	return WALK_PRED_DEFAULT;
> +}
> +
> +static int ftrace_function_check_pred(struct filter_pred *pred)
> +{
> +	struct ftrace_event_field *field = pred->field;
> +
> +	/*
> +	  Check the predicate for function trace, verify:
> +	   - only '==' and '!=' is used
> +	   - the 'ip' field is used
> +	*/
> +	if (WARN((pred->op != OP_EQ) && (pred->op != OP_NE),
> +		 "wrong operator for function filter: %d\n", pred->op))
> +		return -EINVAL;
> +
> +	if (strcmp(field->name, "ip"))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int ftrace_function_set_filter_cb(enum move_type move,
> +					 struct filter_pred *pred,
> +					 int *err, void *data)
> +{
> +	if ((move != MOVE_DOWN) ||
> +	    (pred->left != FILTER_PRED_INVALID))
> +		return WALK_PRED_DEFAULT;
> +
> +	/* Double checking the predicate is valid for function trace. */
> +	*err = ftrace_function_check_pred(pred);
> +	if (*err)
> +		return WALK_PRED_ABORT;
> +
> +	return __ftrace_function_set_filter(pred->op == OP_EQ,
> +					    pred->regex.pattern,
> +					    pred->regex.len,
> +					    data);
> +}
> +
> +static int ftrace_function_set_filter(struct perf_event *event,
> +				      struct event_filter *filter)
> +{
> +	struct function_filter_data data = {
> +		.first_filter  = 1,
> +		.first_notrace = 1,
> +		.ops           = &event->ftrace_ops,
> +	};
> +
> +	return walk_pred_tree(filter->preds, filter->root,
> +			      ftrace_function_set_filter_cb, &data);
> +}
> +
>  int ftrace_profile_set_filter(struct perf_event *event, int event_id,
>  			      char *filter_str)
>  {
> @@ -1901,6 +1988,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
>  	struct event_filter *filter;
>  	struct filter_parse_state *ps;
>  	struct ftrace_event_call *call;
> +	struct filter_op *fops = filter_ops;
>  
>  	mutex_lock(&event_mutex);
>  
> @@ -1925,14 +2013,21 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
>  	if (!ps)
>  		goto free_filter;
>  
> -	parse_init(ps, filter_ops, filter_str);
> +	if (ftrace_event_is_function(call))
> +		fops = filter_ftrace_ops;
> +
> +	parse_init(ps, fops, filter_str);
>  	err = filter_parse(ps);
>  	if (err)
>  		goto free_ps;
>  
>  	err = replace_preds(call, filter, ps, filter_str, false);
> -	if (!err)
> -		event->filter = filter;
> +	if (!err) {
> +		if (ftrace_event_is_function(call))
> +			err = ftrace_function_set_filter(event, filter);
> +		else
> +			event->filter = filter;
> +	}
>  
>  free_ps:
>  	filter_opstack_clear(ps);
> @@ -1940,7 +2035,7 @@ free_ps:
>  	kfree(ps);
>  
>  free_filter:
> -	if (err)
> +	if (err || ftrace_event_is_function(call))
>  		__free_filter(filter);
>  
>  out_unlock:
> diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
> index 7b035ab..46c35e2 100644
> --- a/kernel/trace/trace_export.c
> +++ b/kernel/trace/trace_export.c
> @@ -208,4 +208,9 @@ struct ftrace_event_call __used event_##call = {			\
>  struct ftrace_event_call __used						\
>  __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call;
>  
> +int ftrace_event_is_function(struct ftrace_event_call *call)
> +{
> +	return call == &event_function;
> +}
> +
>  #include "trace_entries.h"


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ