1939 lines · 61.4 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0 #ifndef _LINUX_KERNEL_TRACE_H#define _LINUX_KERNEL_TRACE_H #include <linux/fs.h>#include <linux/atomic.h>#include <linux/sched.h>#include <linux/clocksource.h>#include <linux/ring_buffer.h>#include <linux/mmiotrace.h>#include <linux/tracepoint.h>#include <linux/ftrace.h>#include <linux/trace.h>#include <linux/hw_breakpoint.h>#include <linux/trace_seq.h>#include <linux/trace_events.h>#include <linux/compiler.h>#include <linux/glob.h>#include <linux/irq_work.h>#include <linux/workqueue.h>#include <linux/ctype.h>#include <linux/once_lite.h> #ifdef CONFIG_FTRACE_SYSCALLS#include <asm/unistd.h>		/* For NR_SYSCALLS	     */#include <asm/syscall.h>	/* some archs define it here */#endif enum trace_type {	__TRACE_FIRST_TYPE = 0, 	TRACE_FN,	TRACE_CTX,	TRACE_WAKE,	TRACE_STACK,	TRACE_PRINT,	TRACE_BPRINT,	TRACE_MMIO_RW,	TRACE_MMIO_MAP,	TRACE_BRANCH,	TRACE_GRAPH_RET,	TRACE_GRAPH_ENT,	TRACE_USER_STACK,	TRACE_BLK,	TRACE_BPUTS,	TRACE_HWLAT,	TRACE_OSNOISE,	TRACE_TIMERLAT,	TRACE_RAW_DATA,	TRACE_FUNC_REPEATS, 	__TRACE_LAST_TYPE,};  #undef __field#define __field(type, item)		type	item; #undef __field_fn#define __field_fn(type, item)		type	item; #undef __field_struct#define __field_struct(type, item)	__field(type, item) #undef __field_desc#define __field_desc(type, container, item) #undef __field_packed#define __field_packed(type, container, item) #undef __array#define __array(type, item, size)	type	item[size]; #undef __array_desc#define __array_desc(type, container, item, size) #undef __dynamic_array#define __dynamic_array(type, item)	type	item[]; #undef F_STRUCT#define F_STRUCT(args...)		args #undef FTRACE_ENTRY#define FTRACE_ENTRY(name, struct_name, id, tstruct, print)		\	struct struct_name {						\		struct trace_entry	ent;				\		tstruct							\	} #undef FTRACE_ENTRY_DUP#define FTRACE_ENTRY_DUP(name, name_struct, id, tstruct, printk) #undef FTRACE_ENTRY_REG#define FTRACE_ENTRY_REG(name, struct_name, id, tstruct, print,	regfn)	\	FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print)) #undef FTRACE_ENTRY_PACKED#define FTRACE_ENTRY_PACKED(name, struct_name, id, tstruct, print)	\	FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print)) __packed #include "trace_entries.h" /* Use this for memory failure errors */#define MEM_FAIL(condition, fmt, ...)					\	DO_ONCE_LITE_IF(condition, pr_err, "ERROR: " fmt, ##__VA_ARGS__) /* * syscalls are special, and need special handling, this is why * they are not included in trace_entries.h */struct syscall_trace_enter {	struct trace_entry	ent;	int			nr;	unsigned long		args[];}; struct syscall_trace_exit {	struct trace_entry	ent;	int			nr;	long			ret;}; struct kprobe_trace_entry_head {	struct trace_entry	ent;	unsigned long		ip;}; struct kretprobe_trace_entry_head {	struct trace_entry	ent;	unsigned long		func;	unsigned long		ret_ip;}; #define TRACE_BUF_SIZE		1024 struct trace_array; /* * The CPU trace array - it consists of thousands of trace entries * plus some other descriptor data: (for example which task started * the trace, etc.) */struct trace_array_cpu {	atomic_t		disabled;	void			*buffer_page;	/* ring buffer spare */ 	unsigned long		entries;	unsigned long		saved_latency;	unsigned long		critical_start;	unsigned long		critical_end;	unsigned long		critical_sequence;	unsigned long		nice;	unsigned long		policy;	unsigned long		rt_priority;	unsigned long		skipped_entries;	u64			preempt_timestamp;	pid_t			pid;	kuid_t			uid;	char			comm[TASK_COMM_LEN]; #ifdef CONFIG_FUNCTION_TRACER	int			ftrace_ignore_pid;#endif	bool			ignore_pid;}; struct tracer;struct trace_option_dentry; struct array_buffer {	struct trace_array		*tr;	struct trace_buffer		*buffer;	struct trace_array_cpu __percpu	*data;	u64				time_start;	int				cpu;}; #define TRACE_FLAGS_MAX_SIZE		32 struct trace_options {	struct tracer			*tracer;	struct trace_option_dentry	*topts;}; struct trace_pid_list {	int				pid_max;	unsigned long			*pids;}; enum {	TRACE_PIDS		= BIT(0),	TRACE_NO_PIDS		= BIT(1),}; static inline bool pid_type_enabled(int type, struct trace_pid_list *pid_list,				    struct trace_pid_list *no_pid_list){	/* Return true if the pid list in type has pids */	return ((type & TRACE_PIDS) && pid_list) ||		((type & TRACE_NO_PIDS) && no_pid_list);} static inline bool still_need_pid_events(int type, struct trace_pid_list *pid_list,					 struct trace_pid_list *no_pid_list){	/*	 * Turning off what is in @type, return true if the "other"	 * pid list, still has pids in it.	 */	return (!(type & TRACE_PIDS) && pid_list) ||		(!(type & TRACE_NO_PIDS) && no_pid_list);} typedef bool (*cond_update_fn_t)(struct trace_array *tr, void *cond_data); /** * struct cond_snapshot - conditional snapshot data and callback * * The cond_snapshot structure encapsulates a callback function and * data associated with the snapshot for a given tracing instance. * * When a snapshot is taken conditionally, by invoking * tracing_snapshot_cond(tr, cond_data), the cond_data passed in is * passed in turn to the cond_snapshot.update() function.  That data * can be compared by the update() implementation with the cond_data * contained within the struct cond_snapshot instance associated with * the trace_array.  Because the tr->max_lock is held throughout the * update() call, the update() function can directly retrieve the * cond_snapshot and cond_data associated with the per-instance * snapshot associated with the trace_array. * * The cond_snapshot.update() implementation can save data to be * associated with the snapshot if it decides to, and returns 'true' * in that case, or it returns 'false' if the conditional snapshot * shouldn't be taken. * * The cond_snapshot instance is created and associated with the * user-defined cond_data by tracing_cond_snapshot_enable(). * Likewise, the cond_snapshot instance is destroyed and is no longer * associated with the trace instance by * tracing_cond_snapshot_disable(). * * The method below is required. * * @update: When a conditional snapshot is invoked, the update() *	callback function is invoked with the tr->max_lock held.  The *	update() implementation signals whether or not to actually *	take the snapshot, by returning 'true' if so, 'false' if no *	snapshot should be taken.  Because the max_lock is held for *	the duration of update(), the implementation is safe to *	directly retrieved and save any implementation data it needs *	to in association with the snapshot. */struct cond_snapshot {	void				*cond_data;	cond_update_fn_t		update;}; /* * struct trace_func_repeats - used to keep track of the consecutive * (on the same CPU) calls of a single function. */struct trace_func_repeats {	unsigned long	ip;	unsigned long	parent_ip;	unsigned long	count;	u64		ts_last_call;}; /* * The trace array - an array of per-CPU trace arrays. This is the * highest level data structure that individual tracers deal with. * They have on/off state as well: */struct trace_array {	struct list_head	list;	char			*name;	struct array_buffer	array_buffer;#ifdef CONFIG_TRACER_MAX_TRACE	/*	 * The max_buffer is used to snapshot the trace when a maximum	 * latency is reached, or when the user initiates a snapshot.	 * Some tracers will use this to store a maximum trace while	 * it continues examining live traces.	 *	 * The buffers for the max_buffer are set up the same as the array_buffer	 * When a snapshot is taken, the buffer of the max_buffer is swapped	 * with the buffer of the array_buffer and the buffers are reset for	 * the array_buffer so the tracing can continue.	 */	struct array_buffer	max_buffer;	bool			allocated_snapshot;#endif#if defined(CONFIG_TRACER_MAX_TRACE) || defined(CONFIG_HWLAT_TRACER) \	|| defined(CONFIG_OSNOISE_TRACER)	unsigned long		max_latency;#ifdef CONFIG_FSNOTIFY	struct dentry		*d_max_latency;	struct work_struct	fsnotify_work;	struct irq_work		fsnotify_irqwork;#endif#endif	struct trace_pid_list	__rcu *filtered_pids;	struct trace_pid_list	__rcu *filtered_no_pids;	/*	 * max_lock is used to protect the swapping of buffers	 * when taking a max snapshot. The buffers themselves are	 * protected by per_cpu spinlocks. But the action of the swap	 * needs its own lock.	 *	 * This is defined as a arch_spinlock_t in order to help	 * with performance when lockdep debugging is enabled.	 *	 * It is also used in other places outside the update_max_tr	 * so it needs to be defined outside of the	 * CONFIG_TRACER_MAX_TRACE.	 */	arch_spinlock_t		max_lock;	int			buffer_disabled;#ifdef CONFIG_FTRACE_SYSCALLS	int			sys_refcount_enter;	int			sys_refcount_exit;	struct trace_event_file __rcu *enter_syscall_files[NR_syscalls];	struct trace_event_file __rcu *exit_syscall_files[NR_syscalls];#endif	int			stop_count;	int			clock_id;	int			nr_topts;	bool			clear_trace;	int			buffer_percent;	unsigned int		n_err_log_entries;	struct tracer		*current_trace;	unsigned int		trace_flags;	unsigned char		trace_flags_index[TRACE_FLAGS_MAX_SIZE];	unsigned int		flags;	raw_spinlock_t		start_lock;	struct list_head	err_log;	struct dentry		*dir;	struct dentry		*options;	struct dentry		*percpu_dir;	struct dentry		*event_dir;	struct trace_options	*topts;	struct list_head	systems;	struct list_head	events;	struct trace_event_file *trace_marker_file;	cpumask_var_t		tracing_cpumask; /* only trace on set CPUs */	int			ref;	int			trace_ref;#ifdef CONFIG_FUNCTION_TRACER	struct ftrace_ops	*ops;	struct trace_pid_list	__rcu *function_pids;	struct trace_pid_list	__rcu *function_no_pids;#ifdef CONFIG_DYNAMIC_FTRACE	/* All of these are protected by the ftrace_lock */	struct list_head	func_probes;	struct list_head	mod_trace;	struct list_head	mod_notrace;#endif	/* function tracing enabled */	int			function_enabled;#endif	int			no_filter_buffering_ref;	struct list_head	hist_vars;#ifdef CONFIG_TRACER_SNAPSHOT	struct cond_snapshot	*cond_snapshot;#endif	struct trace_func_repeats	__percpu *last_func_repeats;}; enum {	TRACE_ARRAY_FL_GLOBAL	= (1 << 0)}; extern struct list_head ftrace_trace_arrays; extern struct mutex trace_types_lock; extern int trace_array_get(struct trace_array *tr);extern int tracing_check_open_get_tr(struct trace_array *tr);extern struct trace_array *trace_array_find(const char *instance);extern struct trace_array *trace_array_find_get(const char *instance); extern u64 tracing_event_time_stamp(struct trace_buffer *buffer, struct ring_buffer_event *rbe);extern int tracing_set_filter_buffering(struct trace_array *tr, bool set);extern int tracing_set_clock(struct trace_array *tr, const char *clockstr); extern bool trace_clock_in_ns(struct trace_array *tr); /* * The global tracer (top) should be the first trace array added, * but we check the flag anyway. */static inline struct trace_array *top_trace_array(void){	struct trace_array *tr; 	if (list_empty(&ftrace_trace_arrays))		return NULL; 	tr = list_entry(ftrace_trace_arrays.prev,			typeof(*tr), list);	WARN_ON(!(tr->flags & TRACE_ARRAY_FL_GLOBAL));	return tr;} #define FTRACE_CMP_TYPE(var, type) \	__builtin_types_compatible_p(typeof(var), type *) #undef IF_ASSIGN#define IF_ASSIGN(var, entry, etype, id)			\	if (FTRACE_CMP_TYPE(var, etype)) {			\		var = (typeof(var))(entry);			\		WARN_ON(id != 0 && (entry)->type != id);	\		break;						\	} /* Will cause compile errors if type is not found. */extern void __ftrace_bad_type(void); /* * The trace_assign_type is a verifier that the entry type is * the same as the type being assigned. To add new types simply * add a line with the following format: * * IF_ASSIGN(var, ent, type, id); * *  Where "type" is the trace type that includes the trace_entry *  as the "ent" item. And "id" is the trace identifier that is *  used in the trace_type enum. * *  If the type can have more than one id, then use zero. */#define trace_assign_type(var, ent)					\	do {								\		IF_ASSIGN(var, ent, struct ftrace_entry, TRACE_FN);	\		IF_ASSIGN(var, ent, struct ctx_switch_entry, 0);	\		IF_ASSIGN(var, ent, struct stack_entry, TRACE_STACK);	\		IF_ASSIGN(var, ent, struct userstack_entry, TRACE_USER_STACK);\		IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT);	\		IF_ASSIGN(var, ent, struct bprint_entry, TRACE_BPRINT);	\		IF_ASSIGN(var, ent, struct bputs_entry, TRACE_BPUTS);	\		IF_ASSIGN(var, ent, struct hwlat_entry, TRACE_HWLAT);	\		IF_ASSIGN(var, ent, struct osnoise_entry, TRACE_OSNOISE);\		IF_ASSIGN(var, ent, struct timerlat_entry, TRACE_TIMERLAT);\		IF_ASSIGN(var, ent, struct raw_data_entry, TRACE_RAW_DATA);\		IF_ASSIGN(var, ent, struct trace_mmiotrace_rw,		\			  TRACE_MMIO_RW);				\		IF_ASSIGN(var, ent, struct trace_mmiotrace_map,		\			  TRACE_MMIO_MAP);				\		IF_ASSIGN(var, ent, struct trace_branch, TRACE_BRANCH); \		IF_ASSIGN(var, ent, struct ftrace_graph_ent_entry,	\			  TRACE_GRAPH_ENT);		\		IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry,	\			  TRACE_GRAPH_RET);		\		IF_ASSIGN(var, ent, struct func_repeats_entry,		\			  TRACE_FUNC_REPEATS);				\		__ftrace_bad_type();					\	} while (0) /* * An option specific to a tracer. This is a boolean value. * The bit is the bit index that sets its value on the * flags value in struct tracer_flags. */struct tracer_opt {	const char	*name; /* Will appear on the trace_options file */	u32		bit; /* Mask assigned in val field in tracer_flags */}; /* * The set of specific options for a tracer. Your tracer * have to set the initial value of the flags val. */struct tracer_flags {	u32			val;	struct tracer_opt	*opts;	struct tracer		*trace;}; /* Makes more easy to define a tracer opt */#define TRACER_OPT(s, b)	.name = #s, .bit = b  struct trace_option_dentry {	struct tracer_opt		*opt;	struct tracer_flags		*flags;	struct trace_array		*tr;	struct dentry			*entry;}; /** * struct tracer - a specific tracer and its callbacks to interact with tracefs * @name: the name chosen to select it on the available_tracers file * @init: called when one switches to this tracer (echo name > current_tracer) * @reset: called when one switches to another tracer * @start: called when tracing is unpaused (echo 1 > tracing_on) * @stop: called when tracing is paused (echo 0 > tracing_on) * @update_thresh: called when tracing_thresh is updated * @open: called when the trace file is opened

Lines 1–500 of 1939.