aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-09-24 15:10:44 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2009-09-24 15:39:27 -0400
commit1889d20922d14a97b2099fa4d47587217c0ba48b (patch)
tree5980f8473f3482aff577ad262e00d06d0745dcf1
parentf3f3f0092477d0165f3f1bf0fd518550b2abd097 (diff)
tracing/filters: Provide basic regex support
This patch provides basic support for regular expressions in filters. It supports the following types of regexp: - *match_beginning - *match_middle* - match_end* - !don't match Example: cd /debug/tracing/events/bkl/lock_kernel echo 'file == "*reiserfs*"' > filter echo 1 > enable gedit-4941 [000] 457.735437: lock_kernel: depth: 0, fs/reiserfs/namei.c:334 reiserfs_lookup() sync_supers-227 [001] 461.379985: lock_kernel: depth: 0, fs/reiserfs/super.c:69 reiserfs_sync_fs() sync_supers-227 [000] 461.383096: lock_kernel: depth: 0, fs/reiserfs/journal.c:1069 flush_commit_list() reiserfs/1-1369 [001] 461.479885: lock_kernel: depth: 0, fs/reiserfs/journal.c:3509 flush_async_commits() Every string is now handled as a regexp in the filter framework, which helps to factorize the code for handling both simple strings and regexp comparisons. (The regexp parsing code has been wildly cherry picked from ftrace.c written by Steve.) v2: Simplify the whole and drop the filter_regex file Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Li Zefan <lizf@cn.fujitsu.com>
-rw-r--r--kernel/trace/trace.h27
-rw-r--r--kernel/trace/trace_events_filter.c155
2 files changed, 157 insertions, 25 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 86bcff94791a..8d0db6018fe4 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -702,20 +702,29 @@ struct event_subsystem {
702}; 702};
703 703
704struct filter_pred; 704struct filter_pred;
705struct regex;
705 706
706typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, 707typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
707 int val1, int val2); 708 int val1, int val2);
708 709
710typedef int (*regex_match_func)(char *str, struct regex *r, int len);
711
712struct regex {
713 char pattern[MAX_FILTER_STR_VAL];
714 int len;
715 int field_len;
716 regex_match_func match;
717};
718
709struct filter_pred { 719struct filter_pred {
710 filter_pred_fn_t fn; 720 filter_pred_fn_t fn;
711 u64 val; 721 u64 val;
712 char str_val[MAX_FILTER_STR_VAL]; 722 struct regex regex;
713 int str_len; 723 char *field_name;
714 char *field_name; 724 int offset;
715 int offset; 725 int not;
716 int not; 726 int op;
717 int op; 727 int pop_n;
718 int pop_n;
719}; 728};
720 729
721extern void print_event_filter(struct ftrace_event_call *call, 730extern void print_event_filter(struct ftrace_event_call *call,
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 189663d82aa7..d3c94c139567 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -195,9 +195,9 @@ static int filter_pred_string(struct filter_pred *pred, void *event,
195 char *addr = (char *)(event + pred->offset); 195 char *addr = (char *)(event + pred->offset);
196 int cmp, match; 196 int cmp, match;
197 197
198 cmp = strncmp(addr, pred->str_val, pred->str_len); 198 cmp = pred->regex.match(addr, &pred->regex, pred->regex.field_len);
199 199
200 match = (!cmp) ^ pred->not; 200 match = cmp ^ pred->not;
201 201
202 return match; 202 return match;
203} 203}
@@ -209,9 +209,9 @@ static int filter_pred_pchar(struct filter_pred *pred, void *event,
209 char **addr = (char **)(event + pred->offset); 209 char **addr = (char **)(event + pred->offset);
210 int cmp, match; 210 int cmp, match;
211 211
212 cmp = strncmp(*addr, pred->str_val, pred->str_len); 212 cmp = pred->regex.match(*addr, &pred->regex, pred->regex.field_len);
213 213
214 match = (!cmp) ^ pred->not; 214 match = cmp ^ pred->not;
215 215
216 return match; 216 return match;
217} 217}
@@ -235,9 +235,9 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event,
235 char *addr = (char *)(event + str_loc); 235 char *addr = (char *)(event + str_loc);
236 int cmp, match; 236 int cmp, match;
237 237
238 cmp = strncmp(addr, pred->str_val, str_len); 238 cmp = pred->regex.match(addr, &pred->regex, str_len);
239 239
240 match = (!cmp) ^ pred->not; 240 match = cmp ^ pred->not;
241 241
242 return match; 242 return match;
243} 243}
@@ -248,6 +248,126 @@ static int filter_pred_none(struct filter_pred *pred, void *event,
248 return 0; 248 return 0;
249} 249}
250 250
251/* Basic regex callbacks */
252static int regex_match_full(char *str, struct regex *r, int len)
253{
254 if (strncmp(str, r->pattern, len) == 0)
255 return 1;
256 return 0;
257}
258
259static int regex_match_front(char *str, struct regex *r, int len)
260{
261 if (strncmp(str, r->pattern, len) == 0)
262 return 1;
263 return 0;
264}
265
266static int regex_match_middle(char *str, struct regex *r, int len)
267{
268 if (strstr(str, r->pattern))
269 return 1;
270 return 0;
271}
272
273static int regex_match_end(char *str, struct regex *r, int len)
274{
275 char *ptr = strstr(str, r->pattern);
276
277 if (ptr && (ptr[r->len] == 0))
278 return 1;
279 return 0;
280}
281
282enum regex_type {
283 MATCH_FULL,
284 MATCH_FRONT_ONLY,
285 MATCH_MIDDLE_ONLY,
286 MATCH_END_ONLY,
287};
288
289/*
290 * Pass in a buffer containing a regex and this function will
291 * set search to point to the search part of the buffer and
292 * return the type of search it is (see enum above).
293 * This does modify buff.
294 *
295 * Returns enum type.
296 * search returns the pointer to use for comparison.
297 * not returns 1 if buff started with a '!'
298 * 0 otherwise.
299 */
300static enum regex_type
301filter_parse_regex(char *buff, int len, char **search, int *not)
302{
303 int type = MATCH_FULL;
304 int i;
305
306 if (buff[0] == '!') {
307 *not = 1;
308 buff++;
309 len--;
310 } else
311 *not = 0;
312
313 *search = buff;
314
315 for (i = 0; i < len; i++) {
316 if (buff[i] == '*') {
317 if (!i) {
318 *search = buff + 1;
319 type = MATCH_END_ONLY;
320 } else {
321 if (type == MATCH_END_ONLY)
322 type = MATCH_MIDDLE_ONLY;
323 else
324 type = MATCH_FRONT_ONLY;
325 buff[i] = 0;
326 break;
327 }
328 }
329 }
330
331 return type;
332}
333
334static int filter_build_regex(struct filter_pred *pred)
335{
336 struct regex *r = &pred->regex;
337 char *search, *dup;
338 enum regex_type type;
339 int not;
340
341 type = filter_parse_regex(r->pattern, r->len, &search, &not);
342 dup = kstrdup(search, GFP_KERNEL);
343 if (!dup)
344 return -ENOMEM;
345
346 strcpy(r->pattern, dup);
347 kfree(dup);
348
349 r->len = strlen(r->pattern);
350
351 switch (type) {
352 case MATCH_FULL:
353 r->match = regex_match_full;
354 break;
355 case MATCH_FRONT_ONLY:
356 r->match = regex_match_front;
357 break;
358 case MATCH_MIDDLE_ONLY:
359 r->match = regex_match_middle;
360 break;
361 case MATCH_END_ONLY:
362 r->match = regex_match_end;
363 break;
364 }
365
366 pred->not ^= not;
367
368 return 0;
369}
370
251/* return 1 if event matches, 0 otherwise (discard) */ 371/* return 1 if event matches, 0 otherwise (discard) */
252int filter_match_preds(struct ftrace_event_call *call, void *rec) 372int filter_match_preds(struct ftrace_event_call *call, void *rec)
253{ 373{
@@ -394,7 +514,7 @@ static void filter_clear_pred(struct filter_pred *pred)
394{ 514{
395 kfree(pred->field_name); 515 kfree(pred->field_name);
396 pred->field_name = NULL; 516 pred->field_name = NULL;
397 pred->str_len = 0; 517 pred->regex.len = 0;
398} 518}
399 519
400static int filter_set_pred(struct filter_pred *dest, 520static int filter_set_pred(struct filter_pred *dest,
@@ -658,21 +778,24 @@ static int filter_add_pred(struct filter_parse_state *ps,
658 } 778 }
659 779
660 if (is_string_field(field)) { 780 if (is_string_field(field)) {
661 pred->str_len = field->size; 781 ret = filter_build_regex(pred);
782 if (ret)
783 return ret;
662 784
663 if (field->filter_type == FILTER_STATIC_STRING) 785 if (field->filter_type == FILTER_STATIC_STRING) {
664 fn = filter_pred_string; 786 fn = filter_pred_string;
665 else if (field->filter_type == FILTER_DYN_STRING) 787 pred->regex.field_len = field->size;
666 fn = filter_pred_strloc; 788 } else if (field->filter_type == FILTER_DYN_STRING)
789 fn = filter_pred_strloc;
667 else { 790 else {
668 fn = filter_pred_pchar; 791 fn = filter_pred_pchar;
669 pred->str_len = strlen(pred->str_val); 792 pred->regex.field_len = strlen(pred->regex.pattern);
670 } 793 }
671 } else { 794 } else {
672 if (field->is_signed) 795 if (field->is_signed)
673 ret = strict_strtoll(pred->str_val, 0, &val); 796 ret = strict_strtoll(pred->regex.pattern, 0, &val);
674 else 797 else
675 ret = strict_strtoull(pred->str_val, 0, &val); 798 ret = strict_strtoull(pred->regex.pattern, 0, &val);
676 if (ret) { 799 if (ret) {
677 parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0); 800 parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0);
678 return -EINVAL; 801 return -EINVAL;
@@ -1042,8 +1165,8 @@ static struct filter_pred *create_pred(int op, char *operand1, char *operand2)
1042 return NULL; 1165 return NULL;
1043 } 1166 }
1044 1167
1045 strcpy(pred->str_val, operand2); 1168 strcpy(pred->regex.pattern, operand2);
1046 pred->str_len = strlen(operand2); 1169 pred->regex.len = strlen(pred->regex.pattern);
1047 1170
1048 pred->op = op; 1171 pred->op = op;
1049 1172