Commit 0b507e1e authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Steven Rostedt

ftrace: add module globbing

Extend module command for function filter selection with globbing.
It uses the same globbing as function filter.

  sh# echo '*alloc*:mod:*' > set_ftrace_filter

Will trace any function with the letters 'alloc' in the name in any
module but not in kernel.

  sh# echo '!*alloc*:mod:ipv6' >> set_ftrace_filter

Will prevent from tracing functions with 'alloc' in the name from module
ipv6 (do not forget to append to set_ftrace_filter file).

  sh# echo '*alloc*:mod:!ipv6' > set_ftrace_filter

Will trace functions with 'alloc' in the name from kernel and any
module except ipv6.

  sh# echo '*alloc*:mod:!*' > set_ftrace_filter

Will trace any function with the letters 'alloc' in the name only from
kernel, but not from any module.

  sh# echo '*:mod:!*' > set_ftrace_filter
or
  sh# echo ':mod:!' > set_ftrace_filter

Will trace every function in the kernel, but will not trace functions
from any module.

  sh# echo '*:mod:*' > set_ftrace_filter
or
  sh# echo ':mod:' > set_ftrace_filter

As the opposite will trace all functions from all modules, but not from
kernel.

  sh# echo '*:mod:*snd*' > set_ftrace_filter

Will trace your sound drivers only (if any).

Link: http://lkml.kernel.org/r/1443545176-3215-4-git-send-email-0x7f454c46@gmail.comSigned-off-by: default avatarDmitry Safonov <0x7f454c46@gmail.com>
[ Made format changes ]
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent 3ba00929
...@@ -3485,19 +3485,37 @@ enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int clear_filter) ...@@ -3485,19 +3485,37 @@ enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int clear_filter)
} }
static int static int
ftrace_match_record(struct dyn_ftrace *rec, ftrace_match_record(struct dyn_ftrace *rec, struct ftrace_glob *func_g,
char *mod, struct ftrace_glob *func_g) struct ftrace_glob *mod_g, int exclude_mod)
{ {
char str[KSYM_SYMBOL_LEN]; char str[KSYM_SYMBOL_LEN];
char *modname; char *modname;
kallsyms_lookup(rec->ip, NULL, NULL, &modname, str); kallsyms_lookup(rec->ip, NULL, NULL, &modname, str);
if (mod) { if (mod_g) {
/* module lookup requires matching the module */ int mod_matches = (modname) ? ftrace_match(modname, mod_g) : 0;
if (!modname || strcmp(modname, mod))
/* blank module name to match all modules */
if (!mod_g->len) {
/* blank module globbing: modname xor exclude_mod */
if ((!exclude_mod) != (!modname))
goto func_match;
return 0;
}
/* not matching the module */
if (!modname || !mod_matches) {
if (exclude_mod)
goto func_match;
else
return 0;
}
if (mod_matches && exclude_mod)
return 0; return 0;
func_match:
/* blank search means to match all funcs in the mod */ /* blank search means to match all funcs in the mod */
if (!func_g->len) if (!func_g->len)
return 1; return 1;
...@@ -3512,23 +3530,32 @@ match_records(struct ftrace_hash *hash, char *func, int len, char *mod) ...@@ -3512,23 +3530,32 @@ match_records(struct ftrace_hash *hash, char *func, int len, char *mod)
struct ftrace_page *pg; struct ftrace_page *pg;
struct dyn_ftrace *rec; struct dyn_ftrace *rec;
struct ftrace_glob func_g = { .type = MATCH_FULL }; struct ftrace_glob func_g = { .type = MATCH_FULL };
struct ftrace_glob mod_g = { .type = MATCH_FULL };
struct ftrace_glob *mod_match = (mod) ? &mod_g : NULL;
int exclude_mod = 0;
int found = 0; int found = 0;
int ret; int ret;
int clear_filter; int clear_filter;
if (len) { if (func) {
func_g.type = filter_parse_regex(func, len, &func_g.search, func_g.type = filter_parse_regex(func, len, &func_g.search,
&clear_filter); &clear_filter);
func_g.len = strlen(func_g.search); func_g.len = strlen(func_g.search);
} }
if (mod) {
mod_g.type = filter_parse_regex(mod, strlen(mod),
&mod_g.search, &exclude_mod);
mod_g.len = strlen(mod_g.search);
}
mutex_lock(&ftrace_lock); mutex_lock(&ftrace_lock);
if (unlikely(ftrace_disabled)) if (unlikely(ftrace_disabled))
goto out_unlock; goto out_unlock;
do_for_each_ftrace_rec(pg, rec) { do_for_each_ftrace_rec(pg, rec) {
if (ftrace_match_record(rec, mod, &func_g)) { if (ftrace_match_record(rec, &func_g, mod_match, exclude_mod)) {
ret = enter_record(hash, rec, clear_filter); ret = enter_record(hash, rec, clear_filter);
if (ret < 0) { if (ret < 0) {
found = ret; found = ret;
...@@ -3568,17 +3595,11 @@ ftrace_mod_callback(struct ftrace_hash *hash, ...@@ -3568,17 +3595,11 @@ ftrace_mod_callback(struct ftrace_hash *hash,
* you can tell which command was used by the cmd * you can tell which command was used by the cmd
* parameter. * parameter.
*/ */
/* we must have a module name */
if (!module || !strlen(module))
return -EINVAL;
ret = match_records(hash, func, strlen(func), module); ret = match_records(hash, func, strlen(func), module);
if (!ret) if (!ret)
return -EINVAL; return -EINVAL;
if (ret < 0) if (ret < 0)
return ret; return ret;
return 0; return 0;
} }
...@@ -3729,7 +3750,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, ...@@ -3729,7 +3750,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
do_for_each_ftrace_rec(pg, rec) { do_for_each_ftrace_rec(pg, rec) {
if (!ftrace_match_record(rec, NULL, &func_g)) if (!ftrace_match_record(rec, &func_g, NULL, 0))
continue; continue;
entry = kmalloc(sizeof(*entry), GFP_KERNEL); entry = kmalloc(sizeof(*entry), GFP_KERNEL);
...@@ -4621,7 +4642,7 @@ ftrace_set_func(unsigned long *array, int *idx, int size, char *buffer) ...@@ -4621,7 +4642,7 @@ ftrace_set_func(unsigned long *array, int *idx, int size, char *buffer)
do_for_each_ftrace_rec(pg, rec) { do_for_each_ftrace_rec(pg, rec) {
if (ftrace_match_record(rec, NULL, &func_g)) { if (ftrace_match_record(rec, &func_g, NULL, 0)) {
/* if it is in the array */ /* if it is in the array */
exists = false; exists = false;
for (i = 0; i < *idx; i++) { for (i = 0; i < *idx; i++) {
......
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