diff options
author | Dmitry Safonov <0x7f454c46@gmail.com> | 2015-09-29 12:46:15 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2015-10-20 20:02:03 -0400 |
commit | 0b507e1ed1b7364def464cfb348ea7c9e87e6e18 (patch) | |
tree | 0cad422579c4050ce223256fb45aafe30032d723 /kernel | |
parent | 3ba009297149fa45956c33ab5de7c5f4da1f28b8 (diff) |
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.com
Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com>
[ Made format changes ]
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/ftrace.c | 51 |
1 files changed, 36 insertions, 15 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 450a5f5676ae..ea2725053771 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -3485,19 +3485,37 @@ enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int clear_filter) | |||
3485 | } | 3485 | } |
3486 | 3486 | ||
3487 | static int | 3487 | static int |
3488 | ftrace_match_record(struct dyn_ftrace *rec, | 3488 | ftrace_match_record(struct dyn_ftrace *rec, struct ftrace_glob *func_g, |
3489 | char *mod, struct ftrace_glob *func_g) | 3489 | struct ftrace_glob *mod_g, int exclude_mod) |
3490 | { | 3490 | { |
3491 | char str[KSYM_SYMBOL_LEN]; | 3491 | char str[KSYM_SYMBOL_LEN]; |
3492 | char *modname; | 3492 | char *modname; |
3493 | 3493 | ||
3494 | kallsyms_lookup(rec->ip, NULL, NULL, &modname, str); | 3494 | kallsyms_lookup(rec->ip, NULL, NULL, &modname, str); |
3495 | 3495 | ||
3496 | if (mod) { | 3496 | if (mod_g) { |
3497 | /* module lookup requires matching the module */ | 3497 | int mod_matches = (modname) ? ftrace_match(modname, mod_g) : 0; |
3498 | if (!modname || strcmp(modname, mod)) | 3498 | |
3499 | /* blank module name to match all modules */ | ||
3500 | if (!mod_g->len) { | ||
3501 | /* blank module globbing: modname xor exclude_mod */ | ||
3502 | if ((!exclude_mod) != (!modname)) | ||
3503 | goto func_match; | ||
3504 | return 0; | ||
3505 | } | ||
3506 | |||
3507 | /* not matching the module */ | ||
3508 | if (!modname || !mod_matches) { | ||
3509 | if (exclude_mod) | ||
3510 | goto func_match; | ||
3511 | else | ||
3512 | return 0; | ||
3513 | } | ||
3514 | |||
3515 | if (mod_matches && exclude_mod) | ||
3499 | return 0; | 3516 | return 0; |
3500 | 3517 | ||
3518 | func_match: | ||
3501 | /* blank search means to match all funcs in the mod */ | 3519 | /* blank search means to match all funcs in the mod */ |
3502 | if (!func_g->len) | 3520 | if (!func_g->len) |
3503 | return 1; | 3521 | return 1; |
@@ -3512,23 +3530,32 @@ match_records(struct ftrace_hash *hash, char *func, int len, char *mod) | |||
3512 | struct ftrace_page *pg; | 3530 | struct ftrace_page *pg; |
3513 | struct dyn_ftrace *rec; | 3531 | struct dyn_ftrace *rec; |
3514 | struct ftrace_glob func_g = { .type = MATCH_FULL }; | 3532 | struct ftrace_glob func_g = { .type = MATCH_FULL }; |
3533 | struct ftrace_glob mod_g = { .type = MATCH_FULL }; | ||
3534 | struct ftrace_glob *mod_match = (mod) ? &mod_g : NULL; | ||
3535 | int exclude_mod = 0; | ||
3515 | int found = 0; | 3536 | int found = 0; |
3516 | int ret; | 3537 | int ret; |
3517 | int clear_filter; | 3538 | int clear_filter; |
3518 | 3539 | ||
3519 | if (len) { | 3540 | if (func) { |
3520 | func_g.type = filter_parse_regex(func, len, &func_g.search, | 3541 | func_g.type = filter_parse_regex(func, len, &func_g.search, |
3521 | &clear_filter); | 3542 | &clear_filter); |
3522 | func_g.len = strlen(func_g.search); | 3543 | func_g.len = strlen(func_g.search); |
3523 | } | 3544 | } |
3524 | 3545 | ||
3546 | if (mod) { | ||
3547 | mod_g.type = filter_parse_regex(mod, strlen(mod), | ||
3548 | &mod_g.search, &exclude_mod); | ||
3549 | mod_g.len = strlen(mod_g.search); | ||
3550 | } | ||
3551 | |||
3525 | mutex_lock(&ftrace_lock); | 3552 | mutex_lock(&ftrace_lock); |
3526 | 3553 | ||
3527 | if (unlikely(ftrace_disabled)) | 3554 | if (unlikely(ftrace_disabled)) |
3528 | goto out_unlock; | 3555 | goto out_unlock; |
3529 | 3556 | ||
3530 | do_for_each_ftrace_rec(pg, rec) { | 3557 | do_for_each_ftrace_rec(pg, rec) { |
3531 | if (ftrace_match_record(rec, mod, &func_g)) { | 3558 | if (ftrace_match_record(rec, &func_g, mod_match, exclude_mod)) { |
3532 | ret = enter_record(hash, rec, clear_filter); | 3559 | ret = enter_record(hash, rec, clear_filter); |
3533 | if (ret < 0) { | 3560 | if (ret < 0) { |
3534 | found = ret; | 3561 | found = ret; |
@@ -3568,17 +3595,11 @@ ftrace_mod_callback(struct ftrace_hash *hash, | |||
3568 | * you can tell which command was used by the cmd | 3595 | * you can tell which command was used by the cmd |
3569 | * parameter. | 3596 | * parameter. |
3570 | */ | 3597 | */ |
3571 | |||
3572 | /* we must have a module name */ | ||
3573 | if (!module || !strlen(module)) | ||
3574 | return -EINVAL; | ||
3575 | |||
3576 | ret = match_records(hash, func, strlen(func), module); | 3598 | ret = match_records(hash, func, strlen(func), module); |
3577 | if (!ret) | 3599 | if (!ret) |
3578 | return -EINVAL; | 3600 | return -EINVAL; |
3579 | if (ret < 0) | 3601 | if (ret < 0) |
3580 | return ret; | 3602 | return ret; |
3581 | |||
3582 | return 0; | 3603 | return 0; |
3583 | } | 3604 | } |
3584 | 3605 | ||
@@ -3729,7 +3750,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
3729 | 3750 | ||
3730 | do_for_each_ftrace_rec(pg, rec) { | 3751 | do_for_each_ftrace_rec(pg, rec) { |
3731 | 3752 | ||
3732 | if (!ftrace_match_record(rec, NULL, &func_g)) | 3753 | if (!ftrace_match_record(rec, &func_g, NULL, 0)) |
3733 | continue; | 3754 | continue; |
3734 | 3755 | ||
3735 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | 3756 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
@@ -4621,7 +4642,7 @@ ftrace_set_func(unsigned long *array, int *idx, int size, char *buffer) | |||
4621 | 4642 | ||
4622 | do_for_each_ftrace_rec(pg, rec) { | 4643 | do_for_each_ftrace_rec(pg, rec) { |
4623 | 4644 | ||
4624 | if (ftrace_match_record(rec, NULL, &func_g)) { | 4645 | if (ftrace_match_record(rec, &func_g, NULL, 0)) { |
4625 | /* if it is in the array */ | 4646 | /* if it is in the array */ |
4626 | exists = false; | 4647 | exists = false; |
4627 | for (i = 0; i < *idx; i++) { | 4648 | for (i = 0; i < *idx; i++) { |