From: Omar Sandoval <[email protected]>

You'd only ever want $comm as a string, but the default is still u64.
Push the type parsing later so we can decide based on the actual
fetcharg and make "string" the default for $comm.

Signed-off-by: Omar Sandoval <[email protected]>
---
 Documentation/trace/kprobetrace.txt  |   6 +--
 Documentation/trace/uprobetracer.txt |   6 +--
 kernel/trace/trace_probe.c           | 102 +++++++++++++++++++++++------------
 3 files changed, 75 insertions(+), 39 deletions(-)

diff --git a/Documentation/trace/kprobetrace.txt 
b/Documentation/trace/kprobetrace.txt
index 0bf746656d06..da3b437d4e5e 100644
--- a/Documentation/trace/kprobetrace.txt
+++ b/Documentation/trace/kprobetrace.txt
@@ -40,7 +40,7 @@ Synopsis of kprobe_events
   $stackN      : Fetch Nth entry of stack (N >= 0)
   $stack       : Fetch stack address.
   $retval      : Fetch return value.(*)
-  $comm                : Fetch current task comm.(***)
+  $comm                : Fetch current task comm.
   +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
   NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
@@ -49,7 +49,6 @@ Synopsis of kprobe_events
 
   (*) only for return probe.
   (**) this is useful for fetching a field of data structures.
-  (***) you probably want this as a string, i.e., $comm:string
 
 Types
 -----
@@ -65,7 +64,8 @@ offset, and container-size (usually 32). The syntax is;
 
  b<bit-width>@<bit-offset>/<container-size>
 
-For $comm, the type must be either "string" or "string_size".
+For $comm, the type must be either "string" or "string_size". The default is
+"string".
 
 
 Per-Probe Event Filtering
diff --git a/Documentation/trace/uprobetracer.txt 
b/Documentation/trace/uprobetracer.txt
index 34754da46860..5daa61cf431a 100644
--- a/Documentation/trace/uprobetracer.txt
+++ b/Documentation/trace/uprobetracer.txt
@@ -36,7 +36,7 @@ Synopsis of uprobe_tracer
    $stackN     : Fetch Nth entry of stack (N >= 0)
    $stack      : Fetch stack address.
    $retval     : Fetch return value.(*)
-   $comm       : Fetch current task comm.(***)
+   $comm       : Fetch current task comm.
    +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
    NAME=FETCHARG     : Set NAME as the argument name of FETCHARG.
    FETCHARG:TYPE     : Set TYPE as the type of FETCHARG. Currently, basic types
@@ -45,7 +45,6 @@ Synopsis of uprobe_tracer
 
   (*) only for return probe.
   (**) this is useful for fetching a field of data structures.
-  (***) you probably want this as a string, i.e., $comm:string
 
 Types
 -----
@@ -60,7 +59,8 @@ offset, and container-size (usually 32). The syntax is;
 
  b<bit-width>@<bit-offset>/<container-size>
 
-For $comm, the type must be either "string" or "string_size".
+For $comm, the type must be either "string" or "string_size". The default is
+"string".
 
 
 Event Profiling
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 3900b6e4a05d..6b0a553308f9 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -296,6 +296,26 @@ static void fetch_user_stack_address(struct pt_regs *regs, 
void *dummy, void *de
 }
 NOKPROBE_SYMBOL(fetch_user_stack_address);
 
+static int parse_fetch_type(const char *t, ssize_t *size,
+                           const struct fetch_type **tp,
+                           const struct fetch_type *ftbl,
+                           const char *default_t)
+{
+       if (!t)
+               t = default_t;
+
+       *tp = find_fetch_type(t, ftbl);
+       if (!*tp) {
+               pr_info("Unsupported type: %s\n", t);
+               return -EINVAL;
+       }
+
+       if (size)
+               *size += (*tp)->size;
+
+       return 0;
+}
+
 static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
                                            fetch_func_t orig_fn,
                                            const struct fetch_type *ftbl)
@@ -339,21 +359,28 @@ int traceprobe_split_symbol_offset(char *symbol, unsigned 
long *offset)
 
 #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
 
-static int parse_probe_vars(char *arg, const struct fetch_type *t,
-                           struct fetch_param *f, bool is_return,
-                           bool is_kprobe)
+static int parse_probe_vars(char *arg, const char *t, ssize_t *size,
+                           const struct fetch_type **tp, struct fetch_param *f,
+                           bool is_return, bool is_kprobe,
+                           const struct fetch_type *ftbl)
 {
        int ret = 0;
        unsigned long param;
 
        if (strcmp(arg, "retval") == 0) {
+               ret = parse_fetch_type(t, size, tp, ftbl, NULL);
+               if (ret)
+                       return ret;
                if (is_return)
-                       f->fn = t->fetch[FETCH_MTD_retval];
+                       f->fn = (*tp)->fetch[FETCH_MTD_retval];
                else
                        ret = -EINVAL;
        } else if (strncmp(arg, "stack", 5) == 0) {
+               ret = parse_fetch_type(t, size, tp, ftbl, NULL);
+               if (ret)
+                       return ret;
                if (arg[5] == '\0') {
-                       if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR))
+                       if (strcmp((*tp)->name, DEFAULT_FETCH_TYPE_STR))
                                return -EINVAL;
 
                        if (is_kprobe)
@@ -365,16 +392,19 @@ static int parse_probe_vars(char *arg, const struct 
fetch_type *t,
                        if (ret || (is_kprobe && param > PARAM_MAX_STACK))
                                ret = -EINVAL;
                        else {
-                               f->fn = t->fetch[FETCH_MTD_stack];
+                               f->fn = (*tp)->fetch[FETCH_MTD_stack];
                                f->data = (void *)param;
                        }
                } else
                        ret = -EINVAL;
        } else if (strcmp(arg, "comm") == 0) {
-               if (strcmp(t->name, "string") != 0 &&
-                   strcmp(t->name, "string_size") != 0)
+               ret = parse_fetch_type(t, size, tp, ftbl, "string");
+               if (ret)
+                       return ret;
+               if (strcmp((*tp)->name, "string") != 0 &&
+                   strcmp((*tp)->name, "string_size") != 0)
                        return -EINVAL;
-               f->fn = t->fetch[FETCH_MTD_comm];
+               f->fn = (*tp)->fetch[FETCH_MTD_comm];
        } else
                ret = -EINVAL;
 
@@ -382,9 +412,10 @@ static int parse_probe_vars(char *arg, const struct 
fetch_type *t,
 }
 
 /* Recursive argument parser */
-static int parse_probe_arg(char *arg, const struct fetch_type *t,
-                    struct fetch_param *f, bool is_return, bool is_kprobe,
-                    const struct fetch_type *ftbl)
+static int parse_probe_arg(char *arg, const char *t, ssize_t *size,
+                          const struct fetch_type **tp,
+                          struct fetch_param *f, bool is_return,
+                          bool is_kprobe, const struct fetch_type *ftbl)
 {
        unsigned long param;
        long offset;
@@ -393,25 +424,32 @@ static int parse_probe_arg(char *arg, const struct 
fetch_type *t,
 
        switch (arg[0]) {
        case '$':
-               ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe);
+               ret = parse_probe_vars(arg + 1, t, size, tp, f, is_return,
+                                      is_kprobe, ftbl);
                break;
 
        case '%':       /* named register */
+               ret = parse_fetch_type(t, size, tp, ftbl, NULL);
+               if (ret)
+                       break;
                ret = regs_query_register_offset(arg + 1);
                if (ret >= 0) {
-                       f->fn = t->fetch[FETCH_MTD_reg];
+                       f->fn = (*tp)->fetch[FETCH_MTD_reg];
                        f->data = (void *)(unsigned long)ret;
                        ret = 0;
                }
                break;
 
        case '@':       /* memory, file-offset or symbol */
+               ret = parse_fetch_type(t, size, tp, ftbl, NULL);
+               if (ret)
+                       break;
                if (isdigit(arg[1])) {
                        ret = kstrtoul(arg + 1, 0, &param);
                        if (ret)
                                break;
 
-                       f->fn = t->fetch[FETCH_MTD_memory];
+                       f->fn = (*tp)->fetch[FETCH_MTD_memory];
                        f->data = (void *)param;
                } else if (arg[1] == '+') {
                        /* kprobes don't support file offsets */
@@ -422,7 +460,7 @@ static int parse_probe_arg(char *arg, const struct 
fetch_type *t,
                        if (ret)
                                break;
 
-                       f->fn = t->fetch[FETCH_MTD_file_offset];
+                       f->fn = (*tp)->fetch[FETCH_MTD_file_offset];
                        f->data = (void *)offset;
                } else {
                        /* uprobes don't support symbols */
@@ -435,13 +473,16 @@ static int parse_probe_arg(char *arg, const struct 
fetch_type *t,
 
                        f->data = alloc_symbol_cache(arg + 1, offset);
                        if (f->data)
-                               f->fn = t->fetch[FETCH_MTD_symbol];
+                               f->fn = (*tp)->fetch[FETCH_MTD_symbol];
                }
                break;
 
        case '+':       /* deref memory */
                arg++;  /* Skip '+', because kstrtol() rejects it. */
        case '-':
+               ret = parse_fetch_type(t, size, tp, ftbl, NULL);
+               if (ret)
+                       break;
                tmp = strchr(arg, '(');
                if (!tmp)
                        break;
@@ -459,7 +500,6 @@ static int parse_probe_arg(char *arg, const struct 
fetch_type *t,
                        struct deref_fetch_param        *dprm;
                        const struct fetch_type         *t2;
 
-                       t2 = find_fetch_type(NULL, ftbl);
                        *tmp = '\0';
                        dprm = kzalloc(sizeof(struct deref_fetch_param), 
GFP_KERNEL);
 
@@ -467,22 +507,24 @@ static int parse_probe_arg(char *arg, const struct 
fetch_type *t,
                                return -ENOMEM;
 
                        dprm->offset = offset;
-                       dprm->fetch = t->fetch[FETCH_MTD_memory];
-                       dprm->fetch_size = get_fetch_size_function(t,
-                                                       dprm->fetch, ftbl);
-                       ret = parse_probe_arg(arg, t2, &dprm->orig, is_return,
-                                                       is_kprobe, ftbl);
+                       dprm->fetch = (*tp)->fetch[FETCH_MTD_memory];
+                       dprm->fetch_size = get_fetch_size_function((*tp),
+                                                                  dprm->fetch,
+                                                                  ftbl);
+                       ret = parse_probe_arg(arg, NULL, NULL, &t2, &dprm->orig,
+                                             is_return, is_kprobe, ftbl);
                        if (ret)
                                kfree(dprm);
                        else {
-                               f->fn = t->fetch[FETCH_MTD_deref];
+                               f->fn = (*tp)->fetch[FETCH_MTD_deref];
                                f->data = (void *)dprm;
                        }
                }
                break;
        }
        if (!ret && !f->fn) {   /* Parsed, but do not find fetch method */
-               pr_info("%s type has no corresponding fetch method.\n", 
t->name);
+               pr_info("%s type has no corresponding fetch method.\n",
+                       (*tp)->name);
                ret = -EINVAL;
        }
 
@@ -549,15 +591,9 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
                arg[t - parg->comm] = '\0';
                t++;
        }
-       parg->type = find_fetch_type(t, ftbl);
-       if (!parg->type) {
-               pr_info("Unsupported type: %s\n", t);
-               return -EINVAL;
-       }
        parg->offset = *size;
-       *size += parg->type->size;
-       ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return,
-                             is_kprobe, ftbl);
+       ret = parse_probe_arg(arg, t, size, &parg->type, &parg->fetch,
+                             is_return, is_kprobe, ftbl);
 
        if (ret >= 0 && t != NULL)
                ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
-- 
2.8.3

Reply via email to