cregit-Linux how code gets into the kernel

Release 4.15 kernel/trace/trace.h

Directory: kernel/trace
/* SPDX-License-Identifier: GPL-2.0 */



#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/hw_breakpoint.h>
#include <linux/trace_seq.h>
#include <linux/trace_events.h>
#include <linux/compiler.h>
#include <linux/trace_seq.h>
#include <linux/glob.h>

#include <asm/unistd.h>		/* For NR_SYSCALLS           */
#include <asm/syscall.h>	/* some archs define it here */

enum trace_type {



#undef __field

#define __field(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 __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


#define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter)	\
	struct struct_name {                                            \
                struct trace_entry      ent;                            \
                tstruct                                                 \


#define FTRACE_ENTRY_DUP(name, name_struct, id, tstruct, printk, filter)


#define FTRACE_ENTRY_REG(name, struct_name, id, tstruct, print,       \
			 filter, regfn) \
	FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \


#define FTRACE_ENTRY_PACKED(name, struct_name, id, tstruct, print,       \
			    filter)					\
	FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \
                     filter) __packed

#include "trace_entries.h"

 * 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;

 * trace_flag_type is an enumeration that holds different
 * states when a trace occurs. These are:
 *  IRQS_OFF            - interrupts were disabled
 *  IRQS_NOSUPPORT      - arch does not support irqs_disabled_flags
 *  NEED_RESCHED        - reschedule is requested
 *  HARDIRQ             - inside an interrupt handler
 *  SOFTIRQ             - inside a softirq handler

enum trace_flag_type {
TRACE_FLAG_NMI			= 0x40,

#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];

bool			ignore_pid;
bool			ftrace_ignore_pid;

struct tracer;
struct trace_option_dentry;

struct trace_buffer {
struct trace_array		*tr;
struct ring_buffer		*buffer;
struct trace_array_cpu __percpu	*data;
u64				time_start;
int				cpu;


struct trace_options {
struct tracer			*tracer;
struct trace_option_dentry	*topts;

struct trace_pid_list {
int				pid_max;
unsigned long			*pids;

 * 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 trace_buffer	trace_buffer;
         * 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 trace_buffer
         * When a snapshot is taken, the buffer of the max_buffer is swapped
         * with the buffer of the trace_buffer and the buffers are reset for
         * the trace_buffer so the tracing can continue.
struct trace_buffer	max_buffer;
bool			allocated_snapshot;
unsigned long		max_latency;
struct trace_pid_list	__rcu *filtered_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
arch_spinlock_t		max_lock;
int			buffer_disabled;
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];
int			stop_count;
int			clock_id;
int			nr_topts;
bool			clear_trace;
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 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;
cpumask_var_t		tracing_cpumask; /* only trace on set CPUs */
int			ref;
struct ftrace_ops	*ops;
struct trace_pid_list	__rcu *function_pids;
	/* All of these are protected by the ftrace_lock */
struct list_head	func_probes;
struct list_head	mod_trace;
struct list_head	mod_notrace;
	/* function tracing enabled */
int			function_enabled;

enum {

extern struct list_head ftrace_trace_arrays;

extern struct mutex trace_types_lock;

extern int trace_array_get(struct trace_array *tr);
extern void trace_array_put(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; }


Steven Rostedt4983.05%266.67%
Yoshihiro Yunomae1016.95%133.33%

#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 && (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 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); \ __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 * @pipe_open: called when the trace_pipe file is opened * @close: called when the trace file is released * @pipe_close: called when the trace_pipe file is released * @read: override the default read callback on trace_pipe * @splice_read: override the default splice_read callback on trace_pipe * @selftest: selftest to run on boot (see trace_selftest.c) * @print_headers: override the first lines that describe your columns * @print_line: callback that prints a trace * @set_flag: signals one of your private flags changed (trace_options file) * @flags: your private flags */ struct tracer { const char *name; int (*init)(struct trace_array *tr); void (*reset)(struct trace_array *tr); void (*start)(struct trace_array *tr); void (*stop)(struct trace_array *tr); int (*update_thresh)(struct trace_array *tr); void (*open)(struct trace_iterator *iter); void (*pipe_open)(struct trace_iterator *iter); void (*close)(struct trace_iterator *iter); void (*pipe_close)(struct trace_iterator *iter); ssize_t (*read)(struct trace_iterator *iter, struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos); ssize_t (*splice_read)(struct trace_iterator *iter, struct file *filp, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); #ifdef CONFIG_FTRACE_STARTUP_TEST int (*selftest)(struct tracer *trace, struct trace_array *tr); #endif void (*print_header)(struct seq_file *m); enum print_line_t (*print_line)(struct trace_iterator *iter); /* If you handled the flag setting, return 0 */ int (*set_flag)(struct trace_array *tr, u32 old_flags, u32 bit, int set); /* Return 0 if OK with change, else return non-zero */ int (*flag_changed)(struct trace_array *tr, u32 mask, int set); struct tracer *next; struct tracer_flags *flags; int enabled; int ref; bool print_max; bool allow_instances; #ifdef CONFIG_TRACER_MAX_TRACE bool use_max_tr; #endif /* True if tracer cannot be enabled in kernel param */ bool noboot; }; /* Only current can touch trace_recursion */ /* * For function tracing recursion: * The order of these bits are important. * * When function tracing occurs, the following steps are made: * If arch does not support a ftrace feature: * call internal function (uses INTERNAL bits) which calls... * If callback is registered to the "global" list, the list * function is called and recursion checks the GLOBAL bits. * then this function calls... * The function callback, which can use the FTRACE bits to * check for recursion. * * Now if the arch does not suppport a feature, and it calls * the global list function which calls the ftrace callback * all three of these steps will do a recursion protection. * There's no reason to do one if the previous caller already * did. The recursion that we are protecting against will * go through the same steps again. * * To prevent the multiple recursion checks, if a recursion * bit is set that is higher than the MAX bit of the current * check, then we know that the check was made by the previous * caller, and we can skip the current check. */ enum { TRACE_BUFFER_BIT, TRACE_BUFFER_NMI_BIT, TRACE_BUFFER_IRQ_BIT, TRACE_BUFFER_SIRQ_BIT, /* Start of function recursion bits */ TRACE_FTRACE_BIT, TRACE_FTRACE_NMI_BIT, TRACE_FTRACE_IRQ_BIT, TRACE_FTRACE_SIRQ_BIT, /* INTERNAL_BITs must be greater than FTRACE_BITs */ TRACE_INTERNAL_BIT, TRACE_INTERNAL_NMI_BIT, TRACE_INTERNAL_IRQ_BIT, TRACE_INTERNAL_SIRQ_BIT, TRACE_BRANCH_BIT, /* * Abuse of the trace_recursion. * As we need a way to maintain state if we are tracing the function * graph in irq because we want to trace a particular function that * was called in irq context but we have irq tracing off. Since this * can only be modified by current, we can reuse trace_recursion. */ TRACE_IRQ_BIT, }; #define trace_recursion_set(bit) do { (current)->trace_recursion |= (1<<(bit)); } while (0) #define trace_recursion_clear(bit) do { (current)->trace_recursion &= ~(1<<(bit)); } while (0) #define trace_recursion_test(bit) ((current)->trace_recursion & (1<<(bit))) #define TRACE_CONTEXT_BITS 4 #define TRACE_FTRACE_START TRACE_FTRACE_BIT #define TRACE_FTRACE_MAX ((1 << (TRACE_FTRACE_START + TRACE_CONTEXT_BITS)) - 1) #define TRACE_LIST_START TRACE_INTERNAL_BIT #define TRACE_LIST_MAX ((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1) #define TRACE_CONTEXT_MASK TRACE_LIST_MAX
static __always_inline int trace_get_context_bit(void) { int bit; if (in_interrupt()) { if (in_nmi()) bit = 0; else if (in_irq()) bit = 1; else bit = 2; } else bit = 3; return bit; }


Steven Rostedt51100.00%1100.00%

static __always_inline int trace_test_and_set_recursion(int start, int max) { unsigned int val = current->trace_recursion; int bit; /* A previous recursion check was made */ if ((val & TRACE_CONTEXT_MASK) > max) return 0; bit = trace_get_context_bit() + start; if (unlikely(val & (1 << bit))) return -1; val |= 1 << bit; current->trace_recursion = val; barrier(); return bit; }


Steven Rostedt80100.00%1100.00%

static __always_inline void trace_clear_recursion(int bit) { unsigned int val = current->trace_recursion; if (!bit) return; bit = 1 << bit; val &= ~bit; barrier(); current->trace_recursion = val; }


Steven Rostedt44100.00%1100.00%

static inline struct ring_buffer_iter * trace_buffer_iter(struct trace_iterator *iter, int cpu) { if (iter->buffer_iter && iter->buffer_iter[cpu]) return iter->buffer_iter[cpu]; return NULL; }


Steven Rostedt41100.00%1100.00%

int tracer_init(struct tracer *t, struct trace_array *tr); int tracing_is_enabled(void); void tracing_reset(struct trace_buffer *buf, int cpu); void tracing_reset_online_cpus(struct trace_buffer *buf); void tracing_reset_current(int cpu); void tracing_reset_all_online_cpus(void); int tracing_open_generic(struct inode *inode, struct file *filp); bool tracing_is_disabled(void); int tracer_tracing_is_on(struct trace_array *tr); void tracer_tracing_on(struct trace_array *tr); void tracer_tracing_off(struct trace_array *tr); struct dentry *trace_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops); struct dentry *tracing_init_dentry(void); struct ring_buffer_event; struct ring_buffer_event * trace_buffer_lock_reserve(struct ring_buffer *buffer, int type, unsigned long len, unsigned long flags, int pc); struct trace_entry *tracing_get_trace_entry(struct trace_array *tr, struct trace_array_cpu *data); struct trace_entry *trace_find_next_entry(struct trace_iterator *iter, int *ent_cpu, u64 *ent_ts); void trace_buffer_unlock_commit_nostack(struct ring_buffer *buffer, struct ring_buffer_event *event); int trace_empty(struct trace_iterator *iter); void *trace_find_next_entry_inc(struct trace_iterator *iter); void trace_init_global_iter(struct trace_iterator *iter); void tracing_iter_reset(struct trace_iterator *iter, int cpu); void trace_function(struct trace_array *tr, unsigned long ip, unsigned long parent_ip, unsigned long flags, int pc); void trace_graph_function(struct trace_array *tr, unsigned long ip, unsigned long parent_ip, unsigned long flags, int pc); void trace_latency_header(struct seq_file *m); void trace_default_header(struct seq_file *m); void print_trace_header(struct seq_file *m, struct trace_iterator *iter); int trace_empty(struct trace_iterator *iter); void trace_graph_return(struct ftrace_graph_ret *trace); int trace_graph_entry(struct ftrace_graph_ent *trace); void set_graph_array(struct trace_array *tr); void tracing_start_cmdline_record(void); void tracing_stop_cmdline_record(void); void tracing_start_tgid_record(void); void tracing_stop_tgid_record(void); int register_tracer(struct tracer *type); int is_tracing_stopped(void); loff_t tracing_lseek(struct file *file, loff_t offset, int whence); extern cpumask_var_t __read_mostly tracing_buffer_mask; #define for_each_tracing_cpu(cpu) \ for_each_cpu(cpu, tracing_buffer_mask) extern unsigned long nsecs_to_usecs(unsigned long nsecs); extern unsigned long tracing_thresh; /* PID filtering */ extern int pid_max; bool trace_find_filtered_pid(struct trace_pid_list *filtered_pids, pid_t search_pid); bool trace_ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct *task); void trace_filter_add_remove_task(struct trace_pid_list *pid_list, struct task_struct *self, struct task_struct *task); void *trace_pid_next(struct trace_pid_list *pid_list, void *v, loff_t *pos); void *trace_pid_start(struct trace_pid_list *pid_list, loff_t *pos); int trace_pid_show(struct seq_file *m, void *v); void trace_free_pid_list(struct trace_pid_list *pid_list); int trace_pid_write(struct trace_pid_list *filtered_pids, struct trace_pid_list **new_pid_list, const char __user *ubuf, size_t cnt); #ifdef CONFIG_TRACER_MAX_TRACE void update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu); void update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu); #endif /* CONFIG_TRACER_MAX_TRACE */ #ifdef CONFIG_STACKTRACE void ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc); void __trace_stack(struct trace_array *tr, unsigned long flags, int skip, int pc); #else
static inline void ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc) { }


Frédéric Weisbecker1688.89%150.00%
Li Zefan211.11%150.00%

static inline void __trace_stack(struct trace_array *tr, unsigned long flags, int skip, int pc) { }


Frédéric Weisbecker21100.00%1100.00%

#endif /* CONFIG_STACKTRACE */ extern u64 ftrace_now(int cpu); extern void trace_find_cmdline(int pid, char comm[]); extern int trace_find_tgid(int pid); extern void trace_event_follow_fork(struct trace_array *tr, bool enable); #ifdef CONFIG_DYNAMIC_FTRACE extern unsigned long ftrace_update_tot_cnt; void ftrace_init_trace_array(struct trace_array *tr); #else
static inline void ftrace_init_trace_array(struct trace_array *tr) { }


Steven Rostedt11100.00%1100.00%

#endif #define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func extern int DYN_FTRACE_TEST_NAME(void); #define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2 extern int DYN_FTRACE_TEST_NAME2(void); extern bool ring_buffer_expanded; extern bool tracing_selftest_disabled; #ifdef CONFIG_FTRACE_STARTUP_TEST extern int trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr); extern int trace_selftest_startup_function_graph(struct tracer *trace, struct trace_array *tr); extern int trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr); extern int trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr); extern int trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *tr); extern int trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr); extern int trace_selftest_startup_nop(struct tracer *trace, struct trace_array *tr); extern int trace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr); /* * Tracer data references selftest functions that only occur * on boot up. These can be __init functions. Thus, when selftests * are enabled, then the tracers need to reference __init functions. */ #define __tracer_data __refdata #else /* Tracers are seldom changed. Optimize when selftests are disabled. */ #define __tracer_data __read_mostly #endif /* CONFIG_FTRACE_STARTUP_TEST */ extern void *head_page(struct trace_array_cpu *data); extern unsigned long long ns2usecs(u64 nsec); extern int trace_vbprintk(unsigned long ip, const char *fmt, va_list args); extern int trace_vprintk(unsigned long ip, const char *fmt, va_list args); extern int trace_array_vprintk(struct trace_array *tr, unsigned long ip, const char *fmt, va_list args); int trace_array_printk(struct trace_array *tr, unsigned long ip, const char *fmt, ...); int trace_array_printk_buf(struct ring_buffer *buffer, unsigned long ip, const char *fmt, ...); void trace_printk_seq(struct trace_seq *s); enum