5976 lines · 142.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * trace_events_hist - trace event hist triggers * * Copyright (C) 2015 Tom Zanussi <tom.zanussi@linux.intel.com> */ #include <linux/module.h>#include <linux/kallsyms.h>#include <linux/security.h>#include <linux/mutex.h>#include <linux/slab.h>#include <linux/stacktrace.h>#include <linux/rculist.h>#include <linux/tracefs.h> /* for gfp flag names */#include <linux/trace_events.h>#include <trace/events/mmflags.h> #include "tracing_map.h"#include "trace_synth.h" #define ERRORS								\	C(NONE,			"No error"),				\	C(DUPLICATE_VAR,	"Variable already defined"),		\	C(VAR_NOT_UNIQUE,	"Variable name not unique, need to use fully qualified name (subsys.event.var) for variable"), \	C(TOO_MANY_VARS,	"Too many variables defined"),		\	C(MALFORMED_ASSIGNMENT,	"Malformed assignment"),		\	C(NAMED_MISMATCH,	"Named hist trigger doesn't match existing named trigger (includes variables)"), \	C(TRIGGER_EEXIST,	"Hist trigger already exists"),		\	C(TRIGGER_ENOENT_CLEAR,	"Can't clear or continue a nonexistent hist trigger"), \	C(SET_CLOCK_FAIL,	"Couldn't set trace_clock"),		\	C(BAD_FIELD_MODIFIER,	"Invalid field modifier"),		\	C(TOO_MANY_SUBEXPR,	"Too many subexpressions (3 max)"),	\	C(TIMESTAMP_MISMATCH,	"Timestamp units in expression don't match"), \	C(TOO_MANY_FIELD_VARS,	"Too many field variables defined"),	\	C(EVENT_FILE_NOT_FOUND,	"Event file not found"),		\	C(HIST_NOT_FOUND,	"Matching event histogram not found"),	\	C(HIST_CREATE_FAIL,	"Couldn't create histogram for field"),	\	C(SYNTH_VAR_NOT_FOUND,	"Couldn't find synthetic variable"),	\	C(SYNTH_EVENT_NOT_FOUND,"Couldn't find synthetic event"),	\	C(SYNTH_TYPE_MISMATCH,	"Param type doesn't match synthetic event field type"), \	C(SYNTH_COUNT_MISMATCH,	"Param count doesn't match synthetic event field count"), \	C(FIELD_VAR_PARSE_FAIL,	"Couldn't parse field variable"),	\	C(VAR_CREATE_FIND_FAIL,	"Couldn't create or find variable"),	\	C(ONX_NOT_VAR,		"For onmax(x) or onchange(x), x must be a variable"), \	C(ONX_VAR_NOT_FOUND,	"Couldn't find onmax or onchange variable"), \	C(ONX_VAR_CREATE_FAIL,	"Couldn't create onmax or onchange variable"), \	C(FIELD_VAR_CREATE_FAIL,"Couldn't create field variable"),	\	C(TOO_MANY_PARAMS,	"Too many action params"),		\	C(PARAM_NOT_FOUND,	"Couldn't find param"),			\	C(INVALID_PARAM,	"Invalid action param"),		\	C(ACTION_NOT_FOUND,	"No action found"),			\	C(NO_SAVE_PARAMS,	"No params found for save()"),		\	C(TOO_MANY_SAVE_ACTIONS,"Can't have more than one save() action per hist"), \	C(ACTION_MISMATCH,	"Handler doesn't support action"),	\	C(NO_CLOSING_PAREN,	"No closing paren found"),		\	C(SUBSYS_NOT_FOUND,	"Missing subsystem"),			\	C(INVALID_SUBSYS_EVENT,	"Invalid subsystem or event name"),	\	C(INVALID_REF_KEY,	"Using variable references in keys not supported"), \	C(VAR_NOT_FOUND,	"Couldn't find variable"),		\	C(FIELD_NOT_FOUND,	"Couldn't find field"),			\	C(EMPTY_ASSIGNMENT,	"Empty assignment"),			\	C(INVALID_SORT_MODIFIER,"Invalid sort modifier"),		\	C(EMPTY_SORT_FIELD,	"Empty sort field"),			\	C(TOO_MANY_SORT_FIELDS,	"Too many sort fields (Max = 2)"),	\	C(INVALID_SORT_FIELD,	"Sort field must be a key or a val"), #undef C#define C(a, b)		HIST_ERR_##a enum { ERRORS }; #undef C#define C(a, b)		b static const char *err_text[] = { ERRORS }; struct hist_field; typedef u64 (*hist_field_fn_t) (struct hist_field *field,				struct tracing_map_elt *elt,				struct trace_buffer *buffer,				struct ring_buffer_event *rbe,				void *event); #define HIST_FIELD_OPERANDS_MAX	2#define HIST_FIELDS_MAX		(TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX)#define HIST_ACTIONS_MAX	8 enum field_op_id {	FIELD_OP_NONE,	FIELD_OP_PLUS,	FIELD_OP_MINUS,	FIELD_OP_UNARY_MINUS,}; /* * A hist_var (histogram variable) contains variable information for * hist_fields having the HIST_FIELD_FL_VAR or HIST_FIELD_FL_VAR_REF * flag set.  A hist_var has a variable name e.g. ts0, and is * associated with a given histogram trigger, as specified by * hist_data.  The hist_var idx is the unique index assigned to the * variable by the hist trigger's tracing_map.  The idx is what is * used to set a variable's value and, by a variable reference, to * retrieve it. */struct hist_var {	char				*name;	struct hist_trigger_data	*hist_data;	unsigned int			idx;}; struct hist_field {	struct ftrace_event_field	*field;	unsigned long			flags;	hist_field_fn_t			fn;	unsigned int			ref;	unsigned int			size;	unsigned int			offset;	unsigned int                    is_signed;	const char			*type;	struct hist_field		*operands[HIST_FIELD_OPERANDS_MAX];	struct hist_trigger_data	*hist_data; 	/*	 * Variable fields contain variable-specific info in var.	 */	struct hist_var			var;	enum field_op_id		operator;	char				*system;	char				*event_name; 	/*	 * The name field is used for EXPR and VAR_REF fields.  VAR	 * fields contain the variable name in var.name.	 */	char				*name; 	/*	 * When a histogram trigger is hit, if it has any references	 * to variables, the values of those variables are collected	 * into a var_ref_vals array by resolve_var_refs().  The	 * current value of each variable is read from the tracing_map	 * using the hist field's hist_var.idx and entered into the	 * var_ref_idx entry i.e. var_ref_vals[var_ref_idx].	 */	unsigned int			var_ref_idx;	bool                            read_once; 	unsigned int			var_str_idx;}; static u64 hist_field_none(struct hist_field *field,			   struct tracing_map_elt *elt,			   struct trace_buffer *buffer,			   struct ring_buffer_event *rbe,			   void *event){	return 0;} static u64 hist_field_counter(struct hist_field *field,			      struct tracing_map_elt *elt,			      struct trace_buffer *buffer,			      struct ring_buffer_event *rbe,			      void *event){	return 1;} static u64 hist_field_string(struct hist_field *hist_field,			     struct tracing_map_elt *elt,			     struct trace_buffer *buffer,			     struct ring_buffer_event *rbe,			     void *event){	char *addr = (char *)(event + hist_field->field->offset); 	return (u64)(unsigned long)addr;} static u64 hist_field_dynstring(struct hist_field *hist_field,				struct tracing_map_elt *elt,				struct trace_buffer *buffer,				struct ring_buffer_event *rbe,				void *event){	u32 str_item = *(u32 *)(event + hist_field->field->offset);	int str_loc = str_item & 0xffff;	char *addr = (char *)(event + str_loc); 	return (u64)(unsigned long)addr;} static u64 hist_field_pstring(struct hist_field *hist_field,			      struct tracing_map_elt *elt,			      struct trace_buffer *buffer,			      struct ring_buffer_event *rbe,			      void *event){	char **addr = (char **)(event + hist_field->field->offset); 	return (u64)(unsigned long)*addr;} static u64 hist_field_log2(struct hist_field *hist_field,			   struct tracing_map_elt *elt,			   struct trace_buffer *buffer,			   struct ring_buffer_event *rbe,			   void *event){	struct hist_field *operand = hist_field->operands[0]; 	u64 val = operand->fn(operand, elt, buffer, rbe, event); 	return (u64) ilog2(roundup_pow_of_two(val));} static u64 hist_field_plus(struct hist_field *hist_field,			   struct tracing_map_elt *elt,			   struct trace_buffer *buffer,			   struct ring_buffer_event *rbe,			   void *event){	struct hist_field *operand1 = hist_field->operands[0];	struct hist_field *operand2 = hist_field->operands[1]; 	u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);	u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event); 	return val1 + val2;} static u64 hist_field_minus(struct hist_field *hist_field,			    struct tracing_map_elt *elt,			    struct trace_buffer *buffer,			    struct ring_buffer_event *rbe,			    void *event){	struct hist_field *operand1 = hist_field->operands[0];	struct hist_field *operand2 = hist_field->operands[1]; 	u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);	u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event); 	return val1 - val2;} static u64 hist_field_unary_minus(struct hist_field *hist_field,				  struct tracing_map_elt *elt,				  struct trace_buffer *buffer,				  struct ring_buffer_event *rbe,				  void *event){	struct hist_field *operand = hist_field->operands[0]; 	s64 sval = (s64)operand->fn(operand, elt, buffer, rbe, event);	u64 val = (u64)-sval; 	return val;} #define DEFINE_HIST_FIELD_FN(type)					\	static u64 hist_field_##type(struct hist_field *hist_field,	\				     struct tracing_map_elt *elt,	\				     struct trace_buffer *buffer,	\				     struct ring_buffer_event *rbe,	\				     void *event)			\{									\	type *addr = (type *)(event + hist_field->field->offset);	\									\	return (u64)(unsigned long)*addr;				\} DEFINE_HIST_FIELD_FN(s64);DEFINE_HIST_FIELD_FN(u64);DEFINE_HIST_FIELD_FN(s32);DEFINE_HIST_FIELD_FN(u32);DEFINE_HIST_FIELD_FN(s16);DEFINE_HIST_FIELD_FN(u16);DEFINE_HIST_FIELD_FN(s8);DEFINE_HIST_FIELD_FN(u8); #define for_each_hist_field(i, hist_data)	\	for ((i) = 0; (i) < (hist_data)->n_fields; (i)++) #define for_each_hist_val_field(i, hist_data)	\	for ((i) = 0; (i) < (hist_data)->n_vals; (i)++) #define for_each_hist_key_field(i, hist_data)	\	for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++) #define HIST_STACKTRACE_DEPTH	16#define HIST_STACKTRACE_SIZE	(HIST_STACKTRACE_DEPTH * sizeof(unsigned long))#define HIST_STACKTRACE_SKIP	5 #define HITCOUNT_IDX		0#define HIST_KEY_SIZE_MAX	(MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE) enum hist_field_flags {	HIST_FIELD_FL_HITCOUNT		= 1 << 0,	HIST_FIELD_FL_KEY		= 1 << 1,	HIST_FIELD_FL_STRING		= 1 << 2,	HIST_FIELD_FL_HEX		= 1 << 3,	HIST_FIELD_FL_SYM		= 1 << 4,	HIST_FIELD_FL_SYM_OFFSET	= 1 << 5,	HIST_FIELD_FL_EXECNAME		= 1 << 6,	HIST_FIELD_FL_SYSCALL		= 1 << 7,	HIST_FIELD_FL_STACKTRACE	= 1 << 8,	HIST_FIELD_FL_LOG2		= 1 << 9,	HIST_FIELD_FL_TIMESTAMP		= 1 << 10,	HIST_FIELD_FL_TIMESTAMP_USECS	= 1 << 11,	HIST_FIELD_FL_VAR		= 1 << 12,	HIST_FIELD_FL_EXPR		= 1 << 13,	HIST_FIELD_FL_VAR_REF		= 1 << 14,	HIST_FIELD_FL_CPU		= 1 << 15,	HIST_FIELD_FL_ALIAS		= 1 << 16,}; struct var_defs {	unsigned int	n_vars;	char		*name[TRACING_MAP_VARS_MAX];	char		*expr[TRACING_MAP_VARS_MAX];}; struct hist_trigger_attrs {	char		*keys_str;	char		*vals_str;	char		*sort_key_str;	char		*name;	char		*clock;	bool		pause;	bool		cont;	bool		clear;	bool		ts_in_usecs;	unsigned int	map_bits; 	char		*assignment_str[TRACING_MAP_VARS_MAX];	unsigned int	n_assignments; 	char		*action_str[HIST_ACTIONS_MAX];	unsigned int	n_actions; 	struct var_defs	var_defs;}; struct field_var {	struct hist_field	*var;	struct hist_field	*val;}; struct field_var_hist {	struct hist_trigger_data	*hist_data;	char				*cmd;}; struct hist_trigger_data {	struct hist_field               *fields[HIST_FIELDS_MAX];	unsigned int			n_vals;	unsigned int			n_keys;	unsigned int			n_fields;	unsigned int			n_vars;	unsigned int			n_var_str;	unsigned int			key_size;	struct tracing_map_sort_key	sort_keys[TRACING_MAP_SORT_KEYS_MAX];	unsigned int			n_sort_keys;	struct trace_event_file		*event_file;	struct hist_trigger_attrs	*attrs;	struct tracing_map		*map;	bool				enable_timestamps;	bool				remove;	struct hist_field               *var_refs[TRACING_MAP_VARS_MAX];	unsigned int			n_var_refs; 	struct action_data		*actions[HIST_ACTIONS_MAX];	unsigned int			n_actions; 	struct field_var		*field_vars[SYNTH_FIELDS_MAX];	unsigned int			n_field_vars;	unsigned int			n_field_var_str;	struct field_var_hist		*field_var_hists[SYNTH_FIELDS_MAX];	unsigned int			n_field_var_hists; 	struct field_var		*save_vars[SYNTH_FIELDS_MAX];	unsigned int			n_save_vars;	unsigned int			n_save_var_str;}; struct action_data; typedef void (*action_fn_t) (struct hist_trigger_data *hist_data,			     struct tracing_map_elt *elt,			     struct trace_buffer *buffer, void *rec,			     struct ring_buffer_event *rbe, void *key,			     struct action_data *data, u64 *var_ref_vals); typedef bool (*check_track_val_fn_t) (u64 track_val, u64 var_val); enum handler_id {	HANDLER_ONMATCH = 1,	HANDLER_ONMAX,	HANDLER_ONCHANGE,}; enum action_id {	ACTION_SAVE = 1,	ACTION_TRACE,	ACTION_SNAPSHOT,}; struct action_data {	enum handler_id		handler;	enum action_id		action;	char			*action_name;	action_fn_t		fn; 	unsigned int		n_params;	char			*params[SYNTH_FIELDS_MAX]; 	/*	 * When a histogram trigger is hit, the values of any	 * references to variables, including variables being passed	 * as parameters to synthetic events, are collected into a	 * var_ref_vals array.  This var_ref_idx array is an array of	 * indices into the var_ref_vals array, one for each synthetic	 * event param, and is passed to the synthetic event	 * invocation.	 */	unsigned int		var_ref_idx[TRACING_MAP_VARS_MAX];	struct synth_event	*synth_event;	bool			use_trace_keyword;	char			*synth_event_name; 	union {		struct {			char			*event;			char			*event_system;		} match_data; 		struct {			/*			 * var_str contains the $-unstripped variable			 * name referenced by var_ref, and used when			 * printing the action.  Because var_ref			 * creation is deferred to create_actions(),			 * we need a per-action way to save it until			 * then, thus var_str.			 */			char			*var_str; 			/*			 * var_ref refers to the variable being			 * tracked e.g onmax($var).			 */			struct hist_field	*var_ref; 			/*			 * track_var contains the 'invisible' tracking			 * variable created to keep the current			 * e.g. max value.			 */			struct hist_field	*track_var; 			check_track_val_fn_t	check_val;			action_fn_t		save_data;		} track_data;	};}; struct track_data {	u64				track_val;	bool				updated; 	unsigned int			key_len;	void				*key;	struct tracing_map_elt		elt; 	struct action_data		*action_data;	struct hist_trigger_data	*hist_data;}; struct hist_elt_data {	char *comm;	u64 *var_ref_vals;	char *field_var_str[SYNTH_FIELDS_MAX];}; struct snapshot_context {	struct tracing_map_elt	*elt;	void			*key;}; static void track_data_free(struct track_data *track_data){	struct hist_elt_data *elt_data; 	if (!track_data)		return;

Lines 1–500 of 5976.