diff options
author | Steven Rostedt <srostedt@redhat.com> | 2009-02-13 17:08:48 -0500 |
---|---|---|
committer | Steven Rostedt <srostedt@redhat.com> | 2009-02-16 16:55:50 -0500 |
commit | 64e7c440618998fd69eee6ab490b042d12248021 (patch) | |
tree | 384246f895f2697dd6927b776c67755cc13e901d /kernel/trace/ftrace.c | |
parent | 9f4801e30ad291e27284e873696da1ead92d68fa (diff) |
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: Steven Rostedt <srostedt@redhat.com>
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 115 |
1 files changed, 109 insertions, 6 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index fcec31323a10..9e60ae423af9 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -1067,7 +1067,7 @@ enum { | |||
1067 | * 0 otherwise. | 1067 | * 0 otherwise. |
1068 | */ | 1068 | */ |
1069 | static int | 1069 | static int |
1070 | ftrace_setup_glob(unsigned char *buff, int len, char **search, int *not) | 1070 | ftrace_setup_glob(char *buff, int len, char **search, int *not) |
1071 | { | 1071 | { |
1072 | int type = MATCH_FULL; | 1072 | int type = MATCH_FULL; |
1073 | int i; | 1073 | int i; |
@@ -1100,14 +1100,11 @@ ftrace_setup_glob(unsigned char *buff, int len, char **search, int *not) | |||
1100 | return type; | 1100 | return type; |
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | static int | 1103 | static int ftrace_match(char *str, char *regex, int len, int type) |
1104 | ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type) | ||
1105 | { | 1104 | { |
1106 | char str[KSYM_SYMBOL_LEN]; | ||
1107 | int matched = 0; | 1105 | int matched = 0; |
1108 | char *ptr; | 1106 | char *ptr; |
1109 | 1107 | ||
1110 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); | ||
1111 | switch (type) { | 1108 | switch (type) { |
1112 | case MATCH_FULL: | 1109 | case MATCH_FULL: |
1113 | if (strcmp(str, regex) == 0) | 1110 | if (strcmp(str, regex) == 0) |
@@ -1131,6 +1128,15 @@ ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type) | |||
1131 | return matched; | 1128 | return matched; |
1132 | } | 1129 | } |
1133 | 1130 | ||
1131 | static int | ||
1132 | ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type) | ||
1133 | { | ||
1134 | char str[KSYM_SYMBOL_LEN]; | ||
1135 | |||
1136 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); | ||
1137 | return ftrace_match(str, regex, len, type); | ||
1138 | } | ||
1139 | |||
1134 | static void ftrace_match_records(char *buff, int len, int enable) | 1140 | static void ftrace_match_records(char *buff, int len, int enable) |
1135 | { | 1141 | { |
1136 | char *search; | 1142 | char *search; |
@@ -1165,6 +1171,100 @@ static void ftrace_match_records(char *buff, int len, int enable) | |||
1165 | spin_unlock(&ftrace_lock); | 1171 | spin_unlock(&ftrace_lock); |
1166 | } | 1172 | } |
1167 | 1173 | ||
1174 | static int | ||
1175 | ftrace_match_module_record(struct dyn_ftrace *rec, char *mod, | ||
1176 | char *regex, int len, int type) | ||
1177 | { | ||
1178 | char str[KSYM_SYMBOL_LEN]; | ||
1179 | char *modname; | ||
1180 | |||
1181 | kallsyms_lookup(rec->ip, NULL, NULL, &modname, str); | ||
1182 | |||
1183 | if (!modname || strcmp(modname, mod)) | ||
1184 | return 0; | ||
1185 | |||
1186 | /* blank search means to match all funcs in the mod */ | ||
1187 | if (len) | ||
1188 | return ftrace_match(str, regex, len, type); | ||
1189 | else | ||
1190 | return 1; | ||
1191 | } | ||
1192 | |||
1193 | static void ftrace_match_module_records(char *buff, char *mod, int enable) | ||
1194 | { | ||
1195 | char *search = buff; | ||
1196 | struct ftrace_page *pg; | ||
1197 | struct dyn_ftrace *rec; | ||
1198 | int type = MATCH_FULL; | ||
1199 | unsigned long flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; | ||
1200 | unsigned search_len = 0; | ||
1201 | int not = 0; | ||
1202 | |||
1203 | /* blank or '*' mean the same */ | ||
1204 | if (strcmp(buff, "*") == 0) | ||
1205 | buff[0] = 0; | ||
1206 | |||
1207 | /* handle the case of 'dont filter this module' */ | ||
1208 | if (strcmp(buff, "!") == 0 || strcmp(buff, "!*") == 0) { | ||
1209 | buff[0] = 0; | ||
1210 | not = 1; | ||
1211 | } | ||
1212 | |||
1213 | if (strlen(buff)) { | ||
1214 | type = ftrace_setup_glob(buff, strlen(buff), &search, ¬); | ||
1215 | search_len = strlen(search); | ||
1216 | } | ||
1217 | |||
1218 | /* should not be called from interrupt context */ | ||
1219 | spin_lock(&ftrace_lock); | ||
1220 | if (enable) | ||
1221 | ftrace_filtered = 1; | ||
1222 | |||
1223 | do_for_each_ftrace_rec(pg, rec) { | ||
1224 | |||
1225 | if (rec->flags & FTRACE_FL_FAILED) | ||
1226 | continue; | ||
1227 | |||
1228 | if (ftrace_match_module_record(rec, mod, | ||
1229 | search, search_len, type)) { | ||
1230 | if (not) | ||
1231 | rec->flags &= ~flag; | ||
1232 | else | ||
1233 | rec->flags |= flag; | ||
1234 | } | ||
1235 | |||
1236 | } while_for_each_ftrace_rec(); | ||
1237 | spin_unlock(&ftrace_lock); | ||
1238 | } | ||
1239 | |||
1240 | static int ftrace_process_regex(char *buff, int len, int enable) | ||
1241 | { | ||
1242 | char *func, *mod, *command, *next = buff; | ||
1243 | |||
1244 | func = strsep(&next, ":"); | ||
1245 | |||
1246 | if (!next) { | ||
1247 | ftrace_match_records(func, len, enable); | ||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1251 | /* command fonud */ | ||
1252 | |||
1253 | command = strsep(&next, ":"); | ||
1254 | |||
1255 | if (strcmp(command, "mod") == 0) { | ||
1256 | /* only match modules */ | ||
1257 | if (!next) | ||
1258 | return -EINVAL; | ||
1259 | |||
1260 | mod = strsep(&next, ":"); | ||
1261 | ftrace_match_module_records(func, mod, enable); | ||
1262 | return 0; | ||
1263 | } | ||
1264 | |||
1265 | return -EINVAL; | ||
1266 | } | ||
1267 | |||
1168 | static ssize_t | 1268 | static ssize_t |
1169 | ftrace_regex_write(struct file *file, const char __user *ubuf, | 1269 | ftrace_regex_write(struct file *file, const char __user *ubuf, |
1170 | size_t cnt, loff_t *ppos, int enable) | 1270 | size_t cnt, loff_t *ppos, int enable) |
@@ -1232,7 +1332,10 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
1232 | if (isspace(ch)) { | 1332 | if (isspace(ch)) { |
1233 | iter->filtered++; | 1333 | iter->filtered++; |
1234 | iter->buffer[iter->buffer_idx] = 0; | 1334 | iter->buffer[iter->buffer_idx] = 0; |
1235 | ftrace_match_records(iter->buffer, iter->buffer_idx, enable); | 1335 | ret = ftrace_process_regex(iter->buffer, |
1336 | iter->buffer_idx, enable); | ||
1337 | if (ret) | ||
1338 | goto out; | ||
1236 | iter->buffer_idx = 0; | 1339 | iter->buffer_idx = 0; |
1237 | } else | 1340 | } else |
1238 | iter->flags |= FTRACE_ITER_CONT; | 1341 | iter->flags |= FTRACE_ITER_CONT; |