Commit 64e7c440 authored by Steven Rostedt's avatar Steven Rostedt

ftrace: add module command function filter selection

This patch adds a "command" syntax to the function filtering files:

  /debugfs/tracing/set_ftrace_filter
  /debugfs/tracing/set_ftrace_notrace

Of the format:  <function>:<command>:<parameter>

The command is optional, and dependent on the command, so are
the parameters.

 echo do_fork > set_ftrace_filter

Will only trace 'do_fork'.

 echo 'sched_*' > set_ftrace_filter

Will only trace functions starting with the letters 'sched_'.

 echo '*:mod:ext3' > set_ftrace_filter

Will trace only the ext3 module functions.

 echo '*write*:mod:ext3' > set_ftrace_notrace

Will prevent the ext3 functions with the letters 'write' in
the name from being traced.

 echo '!*_allocate:mod:ext3' > set_ftrace_filter

Will remove the functions in ext3 that end with the letters
'_allocate' from the ftrace filter.

Although this patch implements the 'command' format, only the
'mod' command is supported. More commands to follow.
Signed-off-by: default avatarSteven Rostedt <srostedt@redhat.com>
parent 9f4801e3
...@@ -1067,7 +1067,7 @@ enum { ...@@ -1067,7 +1067,7 @@ enum {
* 0 otherwise. * 0 otherwise.
*/ */
static int static int
ftrace_setup_glob(unsigned char *buff, int len, char **search, int *not) ftrace_setup_glob(char *buff, int len, char **search, int *not)
{ {
int type = MATCH_FULL; int type = MATCH_FULL;
int i; int i;
...@@ -1100,14 +1100,11 @@ ftrace_setup_glob(unsigned char *buff, int len, char **search, int *not) ...@@ -1100,14 +1100,11 @@ ftrace_setup_glob(unsigned char *buff, int len, char **search, int *not)
return type; return type;
} }
static int static int ftrace_match(char *str, char *regex, int len, int type)
ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type)
{ {
char str[KSYM_SYMBOL_LEN];
int matched = 0; int matched = 0;
char *ptr; char *ptr;
kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
switch (type) { switch (type) {
case MATCH_FULL: case MATCH_FULL:
if (strcmp(str, regex) == 0) if (strcmp(str, regex) == 0)
...@@ -1131,6 +1128,15 @@ ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type) ...@@ -1131,6 +1128,15 @@ ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type)
return matched; return matched;
} }
static int
ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type)
{
char str[KSYM_SYMBOL_LEN];
kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
return ftrace_match(str, regex, len, type);
}
static void ftrace_match_records(char *buff, int len, int enable) static void ftrace_match_records(char *buff, int len, int enable)
{ {
char *search; char *search;
...@@ -1165,6 +1171,100 @@ static void ftrace_match_records(char *buff, int len, int enable) ...@@ -1165,6 +1171,100 @@ static void ftrace_match_records(char *buff, int len, int enable)
spin_unlock(&ftrace_lock); spin_unlock(&ftrace_lock);
} }
static int
ftrace_match_module_record(struct dyn_ftrace *rec, char *mod,
char *regex, int len, int type)
{
char str[KSYM_SYMBOL_LEN];
char *modname;
kallsyms_lookup(rec->ip, NULL, NULL, &modname, str);
if (!modname || strcmp(modname, mod))
return 0;
/* blank search means to match all funcs in the mod */
if (len)
return ftrace_match(str, regex, len, type);
else
return 1;
}
static void ftrace_match_module_records(char *buff, char *mod, int enable)
{
char *search = buff;
struct ftrace_page *pg;
struct dyn_ftrace *rec;
int type = MATCH_FULL;
unsigned long flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
unsigned search_len = 0;
int not = 0;
/* blank or '*' mean the same */
if (strcmp(buff, "*") == 0)
buff[0] = 0;
/* handle the case of 'dont filter this module' */
if (strcmp(buff, "!") == 0 || strcmp(buff, "!*") == 0) {
buff[0] = 0;
not = 1;
}
if (strlen(buff)) {
type = ftrace_setup_glob(buff, strlen(buff), &search, &not);
search_len = strlen(search);
}
/* should not be called from interrupt context */
spin_lock(&ftrace_lock);
if (enable)
ftrace_filtered = 1;
do_for_each_ftrace_rec(pg, rec) {
if (rec->flags & FTRACE_FL_FAILED)
continue;
if (ftrace_match_module_record(rec, mod,
search, search_len, type)) {
if (not)
rec->flags &= ~flag;
else
rec->flags |= flag;
}
} while_for_each_ftrace_rec();
spin_unlock(&ftrace_lock);
}
static int ftrace_process_regex(char *buff, int len, int enable)
{
char *func, *mod, *command, *next = buff;
func = strsep(&next, ":");
if (!next) {
ftrace_match_records(func, len, enable);
return 0;
}
/* command fonud */
command = strsep(&next, ":");
if (strcmp(command, "mod") == 0) {
/* only match modules */
if (!next)
return -EINVAL;
mod = strsep(&next, ":");
ftrace_match_module_records(func, mod, enable);
return 0;
}
return -EINVAL;
}
static ssize_t static ssize_t
ftrace_regex_write(struct file *file, const char __user *ubuf, ftrace_regex_write(struct file *file, const char __user *ubuf,
size_t cnt, loff_t *ppos, int enable) size_t cnt, loff_t *ppos, int enable)
...@@ -1232,7 +1332,10 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, ...@@ -1232,7 +1332,10 @@ ftrace_regex_write(struct file *file, const char __user *ubuf,
if (isspace(ch)) { if (isspace(ch)) {
iter->filtered++; iter->filtered++;
iter->buffer[iter->buffer_idx] = 0; iter->buffer[iter->buffer_idx] = 0;
ftrace_match_records(iter->buffer, iter->buffer_idx, enable); ret = ftrace_process_regex(iter->buffer,
iter->buffer_idx, enable);
if (ret)
goto out;
iter->buffer_idx = 0; iter->buffer_idx = 0;
} else } else
iter->flags |= FTRACE_ITER_CONT; iter->flags |= FTRACE_ITER_CONT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment