mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-17 02:15:57 +00:00
ftrace: startup tester on dynamic tracing.
This patch adds a startup self test on dynamic code modification and filters. The test filters on a specific function, makes sure that no other function is traced, exectutes the function, then makes sure that the function is traced. This patch also fixes a slight bug with the ftrace selftest, where tracer_enabled was not being set. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
parent
7bd2f24c2f
commit
77a2b37d22
@ -55,6 +55,7 @@ struct dyn_ftrace {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int ftrace_force_update(void);
|
int ftrace_force_update(void);
|
||||||
|
void ftrace_set_filter(unsigned char *buf, int len, int reset);
|
||||||
|
|
||||||
/* defined in arch */
|
/* defined in arch */
|
||||||
extern int ftrace_ip_converted(unsigned long ip);
|
extern int ftrace_ip_converted(unsigned long ip);
|
||||||
@ -70,6 +71,7 @@ extern void ftrace_call(void);
|
|||||||
extern void mcount_call(void);
|
extern void mcount_call(void);
|
||||||
#else
|
#else
|
||||||
# define ftrace_force_update() ({ 0; })
|
# define ftrace_force_update() ({ 0; })
|
||||||
|
# define ftrace_set_filter(buf, len, reset) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void tracer_disable(void)
|
static inline void tracer_disable(void)
|
||||||
|
@ -1010,6 +1010,25 @@ ftrace_filter_write(struct file *file, const char __user *ubuf,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ftrace_set_filter - set a function to filter on in ftrace
|
||||||
|
* @buf - the string that holds the function filter text.
|
||||||
|
* @len - the length of the string.
|
||||||
|
* @reset - non zero to reset all filters before applying this filter.
|
||||||
|
*
|
||||||
|
* Filters denote which functions should be enabled when tracing is enabled.
|
||||||
|
* If @buf is NULL and reset is set, all functions will be enabled for tracing.
|
||||||
|
*/
|
||||||
|
notrace void ftrace_set_filter(unsigned char *buf, int len, int reset)
|
||||||
|
{
|
||||||
|
mutex_lock(&ftrace_filter_lock);
|
||||||
|
if (reset)
|
||||||
|
ftrace_filter_reset();
|
||||||
|
if (buf)
|
||||||
|
ftrace_match(buf, len);
|
||||||
|
mutex_unlock(&ftrace_filter_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static int notrace
|
static int notrace
|
||||||
ftrace_filter_release(struct inode *inode, struct file *file)
|
ftrace_filter_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
|
@ -99,6 +99,100 @@ static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_FTRACE
|
#ifdef CONFIG_FTRACE
|
||||||
|
|
||||||
|
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||||
|
|
||||||
|
#define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
|
||||||
|
#define __STR(x) #x
|
||||||
|
#define STR(x) __STR(x)
|
||||||
|
static int DYN_FTRACE_TEST_NAME(void)
|
||||||
|
{
|
||||||
|
/* used to call mcount */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test dynamic code modification and ftrace filters */
|
||||||
|
int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
|
||||||
|
struct trace_array *tr,
|
||||||
|
int (*func)(void))
|
||||||
|
{
|
||||||
|
unsigned long count;
|
||||||
|
int ret;
|
||||||
|
int save_ftrace_enabled = ftrace_enabled;
|
||||||
|
int save_tracer_enabled = tracer_enabled;
|
||||||
|
|
||||||
|
/* The ftrace test PASSED */
|
||||||
|
printk(KERN_CONT "PASSED\n");
|
||||||
|
pr_info("Testing dynamic ftrace: ");
|
||||||
|
|
||||||
|
/* enable tracing, and record the filter function */
|
||||||
|
ftrace_enabled = 1;
|
||||||
|
tracer_enabled = 1;
|
||||||
|
|
||||||
|
/* passed in by parameter to fool gcc from optimizing */
|
||||||
|
func();
|
||||||
|
|
||||||
|
/* update the records */
|
||||||
|
ret = ftrace_force_update();
|
||||||
|
if (ret) {
|
||||||
|
printk(KERN_CONT ".. ftraced failed .. ");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* filter only on our function */
|
||||||
|
ftrace_set_filter(STR(DYN_FTRACE_TEST_NAME),
|
||||||
|
sizeof(STR(DYN_FTRACE_TEST_NAME)), 1);
|
||||||
|
|
||||||
|
/* enable tracing */
|
||||||
|
tr->ctrl = 1;
|
||||||
|
trace->init(tr);
|
||||||
|
/* Sleep for a 1/10 of a second */
|
||||||
|
msleep(100);
|
||||||
|
|
||||||
|
/* we should have nothing in the buffer */
|
||||||
|
ret = trace_test_buffer(tr, &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. */
|
||||||
|
tr->ctrl = 0;
|
||||||
|
trace->ctrl_update(tr);
|
||||||
|
ftrace_enabled = 0;
|
||||||
|
|
||||||
|
/* check the trace buffer */
|
||||||
|
ret = trace_test_buffer(tr, &count);
|
||||||
|
trace->reset(tr);
|
||||||
|
|
||||||
|
/* we should only have one item */
|
||||||
|
if (!ret && count != 1) {
|
||||||
|
printk(KERN_CONT ".. filter failed ..");
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
ftrace_enabled = save_ftrace_enabled;
|
||||||
|
tracer_enabled = save_tracer_enabled;
|
||||||
|
|
||||||
|
/* Enable tracing on all functions again */
|
||||||
|
ftrace_set_filter(NULL, 0, 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; })
|
||||||
|
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||||
/*
|
/*
|
||||||
* Simple verification test of ftrace function tracer.
|
* Simple verification test of ftrace function tracer.
|
||||||
* Enable ftrace, sleep 1/10 second, and then read the trace
|
* Enable ftrace, sleep 1/10 second, and then read the trace
|
||||||
@ -109,8 +203,13 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
|
|||||||
{
|
{
|
||||||
unsigned long count;
|
unsigned long count;
|
||||||
int ret;
|
int ret;
|
||||||
|
int save_ftrace_enabled = ftrace_enabled;
|
||||||
|
int save_tracer_enabled = tracer_enabled;
|
||||||
|
|
||||||
/* make sure functions have been recorded */
|
/* make sure msleep has been recorded */
|
||||||
|
msleep(1);
|
||||||
|
|
||||||
|
/* force the recorded functions to be traced */
|
||||||
ret = ftrace_force_update();
|
ret = ftrace_force_update();
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_CONT ".. ftraced failed .. ");
|
printk(KERN_CONT ".. ftraced failed .. ");
|
||||||
@ -119,6 +218,7 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
|
|||||||
|
|
||||||
/* start the tracing */
|
/* start the tracing */
|
||||||
ftrace_enabled = 1;
|
ftrace_enabled = 1;
|
||||||
|
tracer_enabled = 1;
|
||||||
|
|
||||||
tr->ctrl = 1;
|
tr->ctrl = 1;
|
||||||
trace->init(tr);
|
trace->init(tr);
|
||||||
@ -136,8 +236,16 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
|
|||||||
if (!ret && !count) {
|
if (!ret && !count) {
|
||||||
printk(KERN_CONT ".. no entries found ..");
|
printk(KERN_CONT ".. no entries found ..");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = trace_selftest_startup_dynamic_tracing(trace, tr,
|
||||||
|
DYN_FTRACE_TEST_NAME);
|
||||||
|
|
||||||
|
out:
|
||||||
|
ftrace_enabled = save_ftrace_enabled;
|
||||||
|
tracer_enabled = save_tracer_enabled;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_FTRACE */
|
#endif /* CONFIG_FTRACE */
|
||||||
@ -415,6 +523,3 @@ trace_selftest_startup_sched_switch(struct tracer *trace, struct trace_array *tr
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_CONTEXT_SWITCH_TRACER */
|
#endif /* CONFIG_CONTEXT_SWITCH_TRACER */
|
||||||
|
|
||||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
|
||||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user