9224 lines · 221.7 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * ring buffer based function tracer * * Copyright (C) 2007-2012 Steven Rostedt <srostedt@redhat.com> * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com> * * Originally taken from the RT patch by: *    Arnaldo Carvalho de Melo <acme@redhat.com> * * Based on code from the latency_tracer, that is: *  Copyright (C) 2004-2006 Ingo Molnar *  Copyright (C) 2004 Nadia Yvette Chambers */#include <linux/ring_buffer.h>#include <generated/utsrelease.h>#include <linux/stacktrace.h>#include <linux/writeback.h>#include <linux/kallsyms.h>#include <linux/seq_file.h>#include <linux/notifier.h>#include <linux/irqflags.h>#include <linux/debugfs.h>#include <linux/tracefs.h>#include <linux/pagemap.h>#include <linux/hardirq.h>#include <linux/linkage.h>#include <linux/uaccess.h>#include <linux/vmalloc.h>#include <linux/ftrace.h>#include <linux/module.h>#include <linux/percpu.h>#include <linux/splice.h>#include <linux/kdebug.h>#include <linux/string.h>#include <linux/mount.h>#include <linux/rwsem.h>#include <linux/slab.h>#include <linux/ctype.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/nmi.h>#include <linux/fs.h>#include <linux/trace.h>#include <linux/sched/clock.h>#include <linux/sched/rt.h> #include "trace.h"#include "trace_output.h" /* * On boot up, the ring buffer is set to the minimum size, so that * we do not waste memory on systems that are not using tracing. */bool ring_buffer_expanded; /* * We need to change this state when a selftest is running. * A selftest will lurk into the ring-buffer to count the * entries inserted during the selftest although some concurrent * insertions into the ring-buffer such as trace_printk could occurred * at the same time, giving false positive or negative results. */static bool __read_mostly tracing_selftest_running; /* * If a tracer is running, we do not want to run SELFTEST. */bool __read_mostly tracing_selftest_disabled; /* Pipe tracepoints to printk */struct trace_iterator *tracepoint_print_iter;int tracepoint_printk;static DEFINE_STATIC_KEY_FALSE(tracepoint_printk_key); /* For tracers that don't implement custom flags */static struct tracer_opt dummy_tracer_opt[] = {	{ }}; static intdummy_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set){	return 0;} /* * To prevent the comm cache from being overwritten when no * tracing is active, only save the comm when a trace event * occurred. */static DEFINE_PER_CPU(bool, trace_taskinfo_save); /* * Kill all tracing for good (never come back). * It is initialized to 1 but will turn to zero if the initialization * of the tracer is successful. But that is the only place that sets * this back to zero. */static int tracing_disabled = 1; cpumask_var_t __read_mostly	tracing_buffer_mask; /* * ftrace_dump_on_oops - variable to dump ftrace buffer on oops * * If there is an oops (or kernel panic) and the ftrace_dump_on_oops * is set, then ftrace_dump is called. This will output the contents * of the ftrace buffers to the console.  This is very useful for * capturing traces that lead to crashes and outputing it to a * serial console. * * It is default off, but you can enable it with either specifying * "ftrace_dump_on_oops" in the kernel command line, or setting * /proc/sys/kernel/ftrace_dump_on_oops * Set 1 if you want to dump buffers of all CPUs * Set 2 if you want to dump the buffer of the CPU that triggered oops */ enum ftrace_dump_mode ftrace_dump_on_oops; /* When set, tracing will stop when a WARN*() is hit */int __disable_trace_on_warning; #ifdef CONFIG_TRACE_EVAL_MAP_FILE/* Map of enums to their values, for "eval_map" file */struct trace_eval_map_head {	struct module			*mod;	unsigned long			length;}; union trace_eval_map_item; struct trace_eval_map_tail {	/*	 * "end" is first and points to NULL as it must be different	 * than "mod" or "eval_string"	 */	union trace_eval_map_item	*next;	const char			*end;	/* points to NULL */}; static DEFINE_MUTEX(trace_eval_mutex); /* * The trace_eval_maps are saved in an array with two extra elements, * one at the beginning, and one at the end. The beginning item contains * the count of the saved maps (head.length), and the module they * belong to if not built in (head.mod). The ending item contains a * pointer to the next array of saved eval_map items. */union trace_eval_map_item {	struct trace_eval_map		map;	struct trace_eval_map_head	head;	struct trace_eval_map_tail	tail;}; static union trace_eval_map_item *trace_eval_maps;#endif /* CONFIG_TRACE_EVAL_MAP_FILE */ static int tracing_set_tracer(struct trace_array *tr, const char *buf);static void ftrace_trace_userstack(struct ring_buffer *buffer,				   unsigned long flags, int pc); #define MAX_TRACER_SIZE		100static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata;static char *default_bootup_tracer; static bool allocate_snapshot; static int __init set_cmdline_ftrace(char *str){	strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE);	default_bootup_tracer = bootup_tracer_buf;	/* We are using ftrace early, expand it */	ring_buffer_expanded = true;	return 1;}__setup("ftrace=", set_cmdline_ftrace); static int __init set_ftrace_dump_on_oops(char *str){	if (*str++ != '=' || !*str) {		ftrace_dump_on_oops = DUMP_ALL;		return 1;	} 	if (!strcmp("orig_cpu", str)) {		ftrace_dump_on_oops = DUMP_ORIG;                return 1;        }         return 0;}__setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops); static int __init stop_trace_on_warning(char *str){	if ((strcmp(str, "=0") != 0 && strcmp(str, "=off") != 0))		__disable_trace_on_warning = 1;	return 1;}__setup("traceoff_on_warning", stop_trace_on_warning); static int __init boot_alloc_snapshot(char *str){	allocate_snapshot = true;	/* We also need the main ring buffer expanded */	ring_buffer_expanded = true;	return 1;}__setup("alloc_snapshot", boot_alloc_snapshot);  static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata; static int __init set_trace_boot_options(char *str){	strlcpy(trace_boot_options_buf, str, MAX_TRACER_SIZE);	return 0;}__setup("trace_options=", set_trace_boot_options); static char trace_boot_clock_buf[MAX_TRACER_SIZE] __initdata;static char *trace_boot_clock __initdata; static int __init set_trace_boot_clock(char *str){	strlcpy(trace_boot_clock_buf, str, MAX_TRACER_SIZE);	trace_boot_clock = trace_boot_clock_buf;	return 0;}__setup("trace_clock=", set_trace_boot_clock); static int __init set_tracepoint_printk(char *str){	if ((strcmp(str, "=0") != 0 && strcmp(str, "=off") != 0))		tracepoint_printk = 1;	return 1;}__setup("tp_printk", set_tracepoint_printk); unsigned long long ns2usecs(u64 nsec){	nsec += 500;	do_div(nsec, 1000);	return nsec;} /* trace_flags holds trace_options default values */#define TRACE_DEFAULT_FLAGS						\	(FUNCTION_DEFAULT_FLAGS |					\	 TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |			\	 TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO |		\	 TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE |			\	 TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS) /* trace_options that are only supported by global_trace */#define TOP_LEVEL_TRACE_FLAGS (TRACE_ITER_PRINTK |			\	       TRACE_ITER_PRINTK_MSGONLY | TRACE_ITER_RECORD_CMD) /* trace_flags that are default zero for instances */#define ZEROED_TRACE_FLAGS \	(TRACE_ITER_EVENT_FORK | TRACE_ITER_FUNC_FORK) /* * The global_trace is the descriptor that holds the top-level tracing * buffers for the live tracing. */static struct trace_array global_trace = {	.trace_flags = TRACE_DEFAULT_FLAGS,}; LIST_HEAD(ftrace_trace_arrays); int trace_array_get(struct trace_array *this_tr){	struct trace_array *tr;	int ret = -ENODEV; 	mutex_lock(&trace_types_lock);	list_for_each_entry(tr, &ftrace_trace_arrays, list) {		if (tr == this_tr) {			tr->ref++;			ret = 0;			break;		}	}	mutex_unlock(&trace_types_lock); 	return ret;} static void __trace_array_put(struct trace_array *this_tr){	WARN_ON(!this_tr->ref);	this_tr->ref--;} void trace_array_put(struct trace_array *this_tr){	mutex_lock(&trace_types_lock);	__trace_array_put(this_tr);	mutex_unlock(&trace_types_lock);} int call_filter_check_discard(struct trace_event_call *call, void *rec,			      struct ring_buffer *buffer,			      struct ring_buffer_event *event){	if (unlikely(call->flags & TRACE_EVENT_FL_FILTERED) &&	    !filter_match_preds(call->filter, rec)) {		__trace_event_discard_commit(buffer, event);		return 1;	} 	return 0;} void trace_free_pid_list(struct trace_pid_list *pid_list){	vfree(pid_list->pids);	kfree(pid_list);} /** * trace_find_filtered_pid - check if a pid exists in a filtered_pid list * @filtered_pids: The list of pids to check * @search_pid: The PID to find in @filtered_pids * * Returns true if @search_pid is fonud in @filtered_pids, and false otherwis. */booltrace_find_filtered_pid(struct trace_pid_list *filtered_pids, pid_t search_pid){	/*	 * If pid_max changed after filtered_pids was created, we	 * by default ignore all pids greater than the previous pid_max.	 */	if (search_pid >= filtered_pids->pid_max)		return false; 	return test_bit(search_pid, filtered_pids->pids);} /** * trace_ignore_this_task - should a task be ignored for tracing * @filtered_pids: The list of pids to check * @task: The task that should be ignored if not filtered * * Checks if @task should be traced or not from @filtered_pids. * Returns true if @task should *NOT* be traced. * Returns false if @task should be traced. */booltrace_ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct *task){	/*	 * Return false, because if filtered_pids does not exist,	 * all pids are good to trace.	 */	if (!filtered_pids)		return false; 	return !trace_find_filtered_pid(filtered_pids, task->pid);} /** * trace_filter_add_remove_task - Add or remove a task from a pid_list * @pid_list: The list to modify * @self: The current task for fork or NULL for exit * @task: The task to add or remove * * If adding a task, if @self is defined, the task is only added if @self * is also included in @pid_list. This happens on fork and tasks should * only be added when the parent is listed. If @self is NULL, then the * @task pid will be removed from the list, which would happen on exit * of a task. */void trace_filter_add_remove_task(struct trace_pid_list *pid_list,				  struct task_struct *self,				  struct task_struct *task){	if (!pid_list)		return; 	/* For forks, we only add if the forking task is listed */	if (self) {		if (!trace_find_filtered_pid(pid_list, self->pid))			return;	} 	/* Sorry, but we don't support pid_max changing after setting */	if (task->pid >= pid_list->pid_max)		return; 	/* "self" is set for forks, and NULL for exits */	if (self)		set_bit(task->pid, pid_list->pids);	else		clear_bit(task->pid, pid_list->pids);} /** * trace_pid_next - Used for seq_file to get to the next pid of a pid_list * @pid_list: The pid list to show * @v: The last pid that was shown (+1 the actual pid to let zero be displayed) * @pos: The position of the file * * This is used by the seq_file "next" operation to iterate the pids * listed in a trace_pid_list structure. * * Returns the pid+1 as we want to display pid of zero, but NULL would * stop the iteration. */void *trace_pid_next(struct trace_pid_list *pid_list, void *v, loff_t *pos){	unsigned long pid = (unsigned long)v; 	(*pos)++; 	/* pid already is +1 of the actual prevous bit */	pid = find_next_bit(pid_list->pids, pid_list->pid_max, pid); 	/* Return pid + 1 to allow zero to be represented */	if (pid < pid_list->pid_max)		return (void *)(pid + 1); 	return NULL;} /** * trace_pid_start - Used for seq_file to start reading pid lists * @pid_list: The pid list to show * @pos: The position of the file * * This is used by seq_file "start" operation to start the iteration * of listing pids. * * Returns the pid+1 as we want to display pid of zero, but NULL would * stop the iteration. */void *trace_pid_start(struct trace_pid_list *pid_list, loff_t *pos){	unsigned long pid;	loff_t l = 0; 	pid = find_first_bit(pid_list->pids, pid_list->pid_max);	if (pid >= pid_list->pid_max)		return NULL; 	/* Return pid + 1 so that zero can be the exit value */	for (pid++; pid && l < *pos;	     pid = (unsigned long)trace_pid_next(pid_list, (void *)pid, &l))		;	return (void *)pid;} /** * trace_pid_show - show the current pid in seq_file processing * @m: The seq_file structure to write into * @v: A void pointer of the pid (+1) value to display * * Can be directly used by seq_file operations to display the current * pid value. */int trace_pid_show(struct seq_file *m, void *v){	unsigned long pid = (unsigned long)v - 1; 	seq_printf(m, "%lu\n", pid);	return 0;} /* 128 should be much more than enough */#define PID_BUF_SIZE		127 int trace_pid_write(struct trace_pid_list *filtered_pids,		    struct trace_pid_list **new_pid_list,		    const char __user *ubuf, size_t cnt){	struct trace_pid_list *pid_list;	struct trace_parser parser;	unsigned long val;	int nr_pids = 0;	ssize_t read = 0;	ssize_t ret = 0;	loff_t pos;	pid_t pid; 	if (trace_parser_get_init(&parser, PID_BUF_SIZE + 1))		return -ENOMEM; 	/*	 * Always recreate a new array. The write is an all or nothing	 * operation. Always create a new array when adding new pids by	 * the user. If the operation fails, then the current list is	 * not modified.	 */	pid_list = kmalloc(sizeof(*pid_list), GFP_KERNEL);

Lines 1–500 of 9224.