1567 lines · 34.3 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* Include in trace.c */ #include <uapi/linux/sched/types.h>#include <linux/stringify.h>#include <linux/kthread.h>#include <linux/delay.h>#include <linux/slab.h> static inline int trace_valid_entry(struct trace_entry *entry){	switch (entry->type) {	case TRACE_FN:	case TRACE_CTX:	case TRACE_WAKE:	case TRACE_STACK:	case TRACE_PRINT:	case TRACE_BRANCH:	case TRACE_GRAPH_ENT:	case TRACE_GRAPH_RETADDR_ENT:	case TRACE_GRAPH_RET:		return 1;	}	return 0;} static int trace_test_buffer_cpu(struct array_buffer *buf, int cpu){	struct ring_buffer_event *event;	struct trace_entry *entry;	unsigned int loops = 0; 	while ((event = ring_buffer_consume(buf->buffer, cpu, NULL, NULL))) {		entry = ring_buffer_event_data(event); 		/*		 * The ring buffer is a size of trace_buf_size, if		 * we loop more than the size, there's something wrong		 * with the ring buffer.		 */		if (loops++ > trace_buf_size) {			printk(KERN_CONT ".. bad ring buffer ");			goto failed;		}		if (!trace_valid_entry(entry)) {			printk(KERN_CONT ".. invalid entry %d ",				entry->type);			goto failed;		}	}	return 0;  failed:	/* disable tracing */	tracing_disabled = 1;	printk(KERN_CONT ".. corrupted trace buffer .. ");	return -1;} /* * Test the trace buffer to see if all the elements * are still sane. */static int __maybe_unused trace_test_buffer(struct array_buffer *buf, unsigned long *count){	unsigned long flags, cnt = 0;	int cpu, ret = 0; 	/* Don't allow flipping of max traces now */	local_irq_save(flags);	arch_spin_lock(&buf->tr->max_lock); 	cnt = ring_buffer_entries(buf->buffer); 	/*	 * The trace_test_buffer_cpu runs a while loop to consume all data.	 * If the calling tracer is broken, and is constantly filling	 * the buffer, this will run forever, and hard lock the box.	 * We disable the ring buffer while we do this test to prevent	 * a hard lock up.	 */	tracing_off();	for_each_possible_cpu(cpu) {		ret = trace_test_buffer_cpu(buf, cpu);		if (ret)			break;	}	tracing_on();	arch_spin_unlock(&buf->tr->max_lock);	local_irq_restore(flags); 	if (count)		*count = cnt; 	return ret;} static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret){	printk(KERN_WARNING "Failed to init %s tracer, init returned %d\n",		trace->name, init_ret);}#ifdef CONFIG_FUNCTION_TRACER #ifdef CONFIG_DYNAMIC_FTRACE static int trace_selftest_test_probe1_cnt;static void trace_selftest_test_probe1_func(unsigned long ip,					    unsigned long pip,					    struct ftrace_ops *op,					    struct ftrace_regs *fregs){	trace_selftest_test_probe1_cnt++;} static int trace_selftest_test_probe2_cnt;static void trace_selftest_test_probe2_func(unsigned long ip,					    unsigned long pip,					    struct ftrace_ops *op,					    struct ftrace_regs *fregs){	trace_selftest_test_probe2_cnt++;} static int trace_selftest_test_probe3_cnt;static void trace_selftest_test_probe3_func(unsigned long ip,					    unsigned long pip,					    struct ftrace_ops *op,					    struct ftrace_regs *fregs){	trace_selftest_test_probe3_cnt++;} static int trace_selftest_test_global_cnt;static void trace_selftest_test_global_func(unsigned long ip,					    unsigned long pip,					    struct ftrace_ops *op,					    struct ftrace_regs *fregs){	trace_selftest_test_global_cnt++;} static int trace_selftest_test_dyn_cnt;static void trace_selftest_test_dyn_func(unsigned long ip,					 unsigned long pip,					 struct ftrace_ops *op,					 struct ftrace_regs *fregs){	trace_selftest_test_dyn_cnt++;} static struct ftrace_ops test_probe1 = {	.func			= trace_selftest_test_probe1_func,}; static struct ftrace_ops test_probe2 = {	.func			= trace_selftest_test_probe2_func,}; static struct ftrace_ops test_probe3 = {	.func			= trace_selftest_test_probe3_func,}; static void print_counts(void){	printk("(%d %d %d %d %d) ",	       trace_selftest_test_probe1_cnt,	       trace_selftest_test_probe2_cnt,	       trace_selftest_test_probe3_cnt,	       trace_selftest_test_global_cnt,	       trace_selftest_test_dyn_cnt);} static void reset_counts(void){	trace_selftest_test_probe1_cnt = 0;	trace_selftest_test_probe2_cnt = 0;	trace_selftest_test_probe3_cnt = 0;	trace_selftest_test_global_cnt = 0;	trace_selftest_test_dyn_cnt = 0;} static int trace_selftest_ops(struct trace_array *tr, int cnt){	int save_ftrace_enabled = ftrace_enabled;	struct ftrace_ops *dyn_ops;	char *func1_name;	char *func2_name;	int len1;	int len2;	int ret = -1; 	printk(KERN_CONT "PASSED\n");	pr_info("Testing dynamic ftrace ops #%d: ", cnt); 	ftrace_enabled = 1;	reset_counts(); 	/* Handle PPC64 '.' name */	func1_name = "*" __stringify(DYN_FTRACE_TEST_NAME);	func2_name = "*" __stringify(DYN_FTRACE_TEST_NAME2);	len1 = strlen(func1_name);	len2 = strlen(func2_name); 	/*	 * Probe 1 will trace function 1.	 * Probe 2 will trace function 2.	 * Probe 3 will trace functions 1 and 2.	 */	ftrace_set_filter(&test_probe1, func1_name, len1, 1);	ftrace_set_filter(&test_probe2, func2_name, len2, 1);	ftrace_set_filter(&test_probe3, func1_name, len1, 1);	ftrace_set_filter(&test_probe3, func2_name, len2, 0); 	register_ftrace_function(&test_probe1);	register_ftrace_function(&test_probe2);	register_ftrace_function(&test_probe3);	/* First time we are running with main function */	if (cnt > 1) {		ftrace_init_array_ops(tr, trace_selftest_test_global_func);		register_ftrace_function(tr->ops);	} 	DYN_FTRACE_TEST_NAME(); 	print_counts(); 	if (trace_selftest_test_probe1_cnt != 1)		goto out;	if (trace_selftest_test_probe2_cnt != 0)		goto out;	if (trace_selftest_test_probe3_cnt != 1)		goto out;	if (cnt > 1) {		if (trace_selftest_test_global_cnt == 0)			goto out;	} 	DYN_FTRACE_TEST_NAME2(); 	print_counts(); 	if (trace_selftest_test_probe1_cnt != 1)		goto out;	if (trace_selftest_test_probe2_cnt != 1)		goto out;	if (trace_selftest_test_probe3_cnt != 2)		goto out; 	/* Add a dynamic probe */	dyn_ops = kzalloc_obj(*dyn_ops);	if (!dyn_ops) {		printk("MEMORY ERROR ");		goto out;	} 	dyn_ops->func = trace_selftest_test_dyn_func; 	register_ftrace_function(dyn_ops); 	trace_selftest_test_global_cnt = 0; 	DYN_FTRACE_TEST_NAME(); 	print_counts(); 	if (trace_selftest_test_probe1_cnt != 2)		goto out_free;	if (trace_selftest_test_probe2_cnt != 1)		goto out_free;	if (trace_selftest_test_probe3_cnt != 3)		goto out_free;	if (cnt > 1) {		if (trace_selftest_test_global_cnt == 0)			goto out_free;	}	if (trace_selftest_test_dyn_cnt == 0)		goto out_free; 	DYN_FTRACE_TEST_NAME2(); 	print_counts(); 	if (trace_selftest_test_probe1_cnt != 2)		goto out_free;	if (trace_selftest_test_probe2_cnt != 2)		goto out_free;	if (trace_selftest_test_probe3_cnt != 4)		goto out_free; 	/* Remove trace function from probe 3 */	func1_name = "!" __stringify(DYN_FTRACE_TEST_NAME);	len1 = strlen(func1_name); 	ftrace_set_filter(&test_probe3, func1_name, len1, 0); 	DYN_FTRACE_TEST_NAME(); 	print_counts(); 	if (trace_selftest_test_probe1_cnt != 3)		goto out_free;	if (trace_selftest_test_probe2_cnt != 2)		goto out_free;	if (trace_selftest_test_probe3_cnt != 4)		goto out_free;	if (cnt > 1) {		if (trace_selftest_test_global_cnt == 0)			goto out_free;	}	if (trace_selftest_test_dyn_cnt == 0)		goto out_free; 	DYN_FTRACE_TEST_NAME2(); 	print_counts(); 	if (trace_selftest_test_probe1_cnt != 3)		goto out_free;	if (trace_selftest_test_probe2_cnt != 3)		goto out_free;	if (trace_selftest_test_probe3_cnt != 5)		goto out_free; 	ret = 0; out_free:	unregister_ftrace_function(dyn_ops);	kfree(dyn_ops);  out:	/* Purposely unregister in the same order */	unregister_ftrace_function(&test_probe1);	unregister_ftrace_function(&test_probe2);	unregister_ftrace_function(&test_probe3);	if (cnt > 1)		unregister_ftrace_function(tr->ops);	ftrace_reset_array_ops(tr); 	/* Make sure everything is off */	reset_counts();	DYN_FTRACE_TEST_NAME();	DYN_FTRACE_TEST_NAME(); 	if (trace_selftest_test_probe1_cnt ||	    trace_selftest_test_probe2_cnt ||	    trace_selftest_test_probe3_cnt ||	    trace_selftest_test_global_cnt ||	    trace_selftest_test_dyn_cnt)		ret = -1; 	ftrace_enabled = save_ftrace_enabled; 	return ret;} /* Test dynamic code modification and ftrace filters */static int trace_selftest_startup_dynamic_tracing(struct tracer *trace,						  struct trace_array *tr,						  int (*func)(void)){	int save_ftrace_enabled = ftrace_enabled;	unsigned long count;	char *func_name;	int ret; 	/* The ftrace test PASSED */	printk(KERN_CONT "PASSED\n");	pr_info("Testing dynamic ftrace: "); 	/* enable tracing, and record the filter function */	ftrace_enabled = 1; 	/* passed in by parameter to fool gcc from optimizing */	func(); 	/*	 * Some archs *cough*PowerPC*cough* add characters to the	 * start of the function names. We simply put a '*' to	 * accommodate them.	 */	func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); 	/* filter only on our function */	ftrace_set_global_filter(func_name, strlen(func_name), 1); 	/* enable tracing */	ret = tracer_init(trace, tr);	if (ret) {		warn_failed_init_tracer(trace, ret);		goto out;	} 	/* Sleep for a 1/10 of a second */	msleep(100); 	/* we should have nothing in the buffer */	ret = trace_test_buffer(&tr->array_buffer, &count);	if (ret)		goto out; 	if (count) {		ret = -1;		printk(KERN_CONT ".. filter did not filter .. ");		goto out;	} 	/* call our function again */	func(); 	/* sleep again */	msleep(100); 	/* stop the tracing. */	tracing_stop();	ftrace_enabled = 0; 	/* check the trace buffer */	ret = trace_test_buffer(&tr->array_buffer, &count); 	ftrace_enabled = 1;	tracing_start(); 	/* we should only have one item */	if (!ret && count != 1) {		trace->reset(tr);		printk(KERN_CONT ".. filter failed count=%ld ..", count);		ret = -1;		goto out;	} 	/* Test the ops with global tracing running */	ret = trace_selftest_ops(tr, 1);	trace->reset(tr);  out:	ftrace_enabled = save_ftrace_enabled; 	/* Enable tracing on all functions again */	ftrace_set_global_filter(NULL, 0, 1); 	/* Test the ops with global tracing off */	if (!ret)		ret = trace_selftest_ops(tr, 2); 	return ret;} static int trace_selftest_recursion_cnt;static void trace_selftest_test_recursion_func(unsigned long ip,					       unsigned long pip,					       struct ftrace_ops *op,					       struct ftrace_regs *fregs){	/*	 * This function is registered without the recursion safe flag.	 * The ftrace infrastructure should provide the recursion	 * protection. If not, this will crash the kernel!	 */	if (trace_selftest_recursion_cnt++ > 10)		return;	DYN_FTRACE_TEST_NAME();} static void trace_selftest_test_recursion_safe_func(unsigned long ip,						    unsigned long pip,						    struct ftrace_ops *op,						    struct ftrace_regs *fregs){	/*	 * We said we would provide our own recursion. By calling	 * this function again, we should recurse back into this function	 * and count again. But this only happens if the arch supports	 * all of ftrace features and nothing else is using the function	 * tracing utility.	 */	if (trace_selftest_recursion_cnt++)		return;	DYN_FTRACE_TEST_NAME();} static struct ftrace_ops test_rec_probe = {	.func			= trace_selftest_test_recursion_func,	.flags			= FTRACE_OPS_FL_RECURSION,}; static struct ftrace_ops test_recsafe_probe = {	.func			= trace_selftest_test_recursion_safe_func,}; static inttrace_selftest_function_recursion(void){	int save_ftrace_enabled = ftrace_enabled;	char *func_name;	int len;	int ret; 	/* The previous test PASSED */	pr_cont("PASSED\n");	pr_info("Testing ftrace recursion: ");

Lines 1–500 of 1567.