tracing: use the new trace_entries.h to create format files
[safe/jmp/linux-2.6] / kernel / trace / trace_events_filter.c
index 490337a..2324578 100644 (file)
@@ -121,6 +121,47 @@ struct filter_parse_state {
        } operand;
 };
 
+#define DEFINE_COMPARISON_PRED(type)                                   \
+static int filter_pred_##type(struct filter_pred *pred, void *event,   \
+                             int val1, int val2)                       \
+{                                                                      \
+       type *addr = (type *)(event + pred->offset);                    \
+       type val = (type)pred->val;                                     \
+       int match = 0;                                                  \
+                                                                       \
+       switch (pred->op) {                                             \
+       case OP_LT:                                                     \
+               match = (*addr < val);                                  \
+               break;                                                  \
+       case OP_LE:                                                     \
+               match = (*addr <= val);                                 \
+               break;                                                  \
+       case OP_GT:                                                     \
+               match = (*addr > val);                                  \
+               break;                                                  \
+       case OP_GE:                                                     \
+               match = (*addr >= val);                                 \
+               break;                                                  \
+       default:                                                        \
+               break;                                                  \
+       }                                                               \
+                                                                       \
+       return match;                                                   \
+}
+
+#define DEFINE_EQUALITY_PRED(size)                                     \
+static int filter_pred_##size(struct filter_pred *pred, void *event,   \
+                             int val1, int val2)                       \
+{                                                                      \
+       u##size *addr = (u##size *)(event + pred->offset);              \
+       u##size val = (u##size)pred->val;                               \
+       int match;                                                      \
+                                                                       \
+       match = (val == *addr) ^ pred->not;                             \
+                                                                       \
+       return match;                                                   \
+}
+
 DEFINE_COMPARISON_PRED(s64);
 DEFINE_COMPARISON_PRED(u64);
 DEFINE_COMPARISON_PRED(s32);
@@ -163,6 +204,20 @@ static int filter_pred_string(struct filter_pred *pred, void *event,
        return match;
 }
 
+/* Filter predicate for char * pointers */
+static int filter_pred_pchar(struct filter_pred *pred, void *event,
+                            int val1, int val2)
+{
+       char **addr = (char **)(event + pred->offset);
+       int cmp, match;
+
+       cmp = strncmp(*addr, pred->str_val, pred->str_len);
+
+       match = (!cmp) ^ pred->not;
+
+       return match;
+}
+
 /*
  * Filter predicate for dynamic sized arrays of characters.
  * These are implemented through a list of strings at the end
@@ -295,7 +350,7 @@ void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)
        struct event_filter *filter = call->filter;
 
        mutex_lock(&event_mutex);
-       if (filter->filter_string)
+       if (filter && filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
                trace_seq_printf(s, "none\n");
@@ -308,7 +363,7 @@ void print_subsystem_event_filter(struct event_subsystem *system,
        struct event_filter *filter = system->filter;
 
        mutex_lock(&event_mutex);
-       if (filter->filter_string)
+       if (filter && filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
                trace_seq_printf(s, "none\n");
@@ -376,6 +431,9 @@ void destroy_preds(struct ftrace_event_call *call)
        struct event_filter *filter = call->filter;
        int i;
 
+       if (!filter)
+               return;
+
        for (i = 0; i < MAX_FILTER_PRED; i++) {
                if (filter->preds[i])
                        filter_free_pred(filter->preds[i]);
@@ -386,17 +444,19 @@ void destroy_preds(struct ftrace_event_call *call)
        call->filter = NULL;
 }
 
-int init_preds(struct ftrace_event_call *call)
+static int init_preds(struct ftrace_event_call *call)
 {
        struct event_filter *filter;
        struct filter_pred *pred;
        int i;
 
+       if (call->filter)
+               return 0;
+
        filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL);
        if (!call->filter)
                return -ENOMEM;
 
-       call->filter_active = 0;
        filter->n_preds = 0;
 
        filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL);
@@ -418,7 +478,26 @@ oom:
 
        return -ENOMEM;
 }
-EXPORT_SYMBOL_GPL(init_preds);
+
+static int init_subsystem_preds(struct event_subsystem *system)
+{
+       struct ftrace_event_call *call;
+       int err;
+
+       list_for_each_entry(call, &ftrace_events, list) {
+               if (!call->define_fields)
+                       continue;
+
+               if (strcmp(call->system, system->name) != 0)
+                       continue;
+
+               err = init_preds(call);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
 
 enum {
        FILTER_DISABLE_ALL,
@@ -435,6 +514,9 @@ static void filter_free_subsystem_preds(struct event_subsystem *system,
                if (!call->define_fields)
                        continue;
 
+               if (strcmp(call->system, system->name) != 0)
+                       continue;
+
                if (flag == FILTER_INIT_NO_RESET) {
                        call->filter->no_reset = false;
                        continue;
@@ -443,10 +525,8 @@ static void filter_free_subsystem_preds(struct event_subsystem *system,
                if (flag == FILTER_SKIP_NO_RESET && call->filter->no_reset)
                        continue;
 
-               if (!strcmp(call->system, system->name)) {
-                       filter_disable_preds(call);
-                       remove_filter_string(call->filter);
-               }
+               filter_disable_preds(call);
+               remove_filter_string(call->filter);
        }
 }
 
@@ -475,12 +555,7 @@ static int filter_add_pred_fn(struct filter_parse_state *ps,
        return 0;
 }
 
-enum {
-       FILTER_STATIC_STRING = 1,
-       FILTER_DYN_STRING
-};
-
-static int is_string_field(const char *type)
+int filter_assign_type(const char *type)
 {
        if (strstr(type, "__data_loc") && strstr(type, "char"))
                return FILTER_DYN_STRING;
@@ -488,12 +563,19 @@ static int is_string_field(const char *type)
        if (strchr(type, '[') && strstr(type, "char"))
                return FILTER_STATIC_STRING;
 
-       return 0;
+       return FILTER_OTHER;
+}
+
+static bool is_string_field(struct ftrace_event_field *field)
+{
+       return field->filter_type == FILTER_DYN_STRING ||
+              field->filter_type == FILTER_STATIC_STRING ||
+              field->filter_type == FILTER_PTR_STRING;
 }
 
 static int is_legal_op(struct ftrace_event_field *field, int op)
 {
-       if (is_string_field(field->type) && (op != OP_EQ && op != OP_NE))
+       if (is_string_field(field) && (op != OP_EQ && op != OP_NE))
                return 0;
 
        return 1;
@@ -550,7 +632,6 @@ static int filter_add_pred(struct filter_parse_state *ps,
        struct ftrace_event_field *field;
        filter_pred_fn_t fn;
        unsigned long long val;
-       int string_type;
        int ret;
 
        pred->fn = filter_pred_none;
@@ -578,13 +659,17 @@ static int filter_add_pred(struct filter_parse_state *ps,
                return -EINVAL;
        }
 
-       string_type = is_string_field(field->type);
-       if (string_type) {
-               if (string_type == FILTER_STATIC_STRING)
+       if (is_string_field(field)) {
+               pred->str_len = field->size;
+
+               if (field->filter_type == FILTER_STATIC_STRING)
                        fn = filter_pred_string;
-               else
+               else if (field->filter_type == FILTER_DYN_STRING)
                        fn = filter_pred_strloc;
-               pred->str_len = field->size;
+               else {
+                       fn = filter_pred_pchar;
+                       pred->str_len = strlen(pred->str_val);
+               }
        } else {
                if (field->is_signed)
                        ret = strict_strtoll(pred->str_val, 0, &val);
@@ -1075,6 +1160,10 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
 
        mutex_lock(&event_mutex);
 
+       err = init_preds(call);
+       if (err)
+               goto out_unlock;
+
        if (!strcmp(strstrip(filter_string), "0")) {
                filter_disable_preds(call);
                remove_filter_string(call->filter);
@@ -1120,6 +1209,10 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
 
        mutex_lock(&event_mutex);
 
+       err = init_subsystem_preds(system);
+       if (err)
+               goto out_unlock;
+
        if (!strcmp(strstrip(filter_string), "0")) {
                filter_free_subsystem_preds(system, FILTER_DISABLE_ALL);
                remove_filter_string(system->filter);