diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace.h | 27 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 155 |
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 | ||
704 | struct filter_pred; | 704 | struct filter_pred; |
705 | struct regex; | ||
705 | 706 | ||
706 | typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, | 707 | typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, |
707 | int val1, int val2); | 708 | int val1, int val2); |
708 | 709 | ||
710 | typedef int (*regex_match_func)(char *str, struct regex *r, int len); | ||
711 | |||
712 | struct regex { | ||
713 | char pattern[MAX_FILTER_STR_VAL]; | ||
714 | int len; | ||
715 | int field_len; | ||
716 | regex_match_func match; | ||
717 | }; | ||
718 | |||
709 | struct filter_pred { | 719 | struct 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 | ||
721 | extern void print_event_filter(struct ftrace_event_call *call, | 730 | extern 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 */ | ||
252 | static 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 | |||
259 | static 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 | |||
266 | static 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 | |||
273 | static 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 | |||
282 | enum 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 | */ | ||
300 | static enum regex_type | ||
301 | filter_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 | |||
334 | static 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, ¬); | ||
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) */ |
252 | int filter_match_preds(struct ftrace_event_call *call, void *rec) | 372 | int 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 | ||
400 | static int filter_set_pred(struct filter_pred *dest, | 520 | static 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 | ||