]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - kernel/trace/trace_probe.c
tracing: probeevent: Add $argN for accessing function args
[linux.git] / kernel / trace / trace_probe.c
index dfd09603130514d85c6a136867f032eae5d5e432..333cda6d263364f3f5525d281e6ec294220d96f3 100644 (file)
@@ -157,14 +157,13 @@ int traceprobe_split_symbol_offset(char *symbol, 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_insn *code, bool is_return,
-                           bool is_kprobe)
+                           struct fetch_insn *code, unsigned int flags)
 {
        int ret = 0;
        unsigned long param;
 
        if (strcmp(arg, "retval") == 0) {
-               if (is_return)
+               if (flags & TPARG_FL_RETURN)
                        code->op = FETCH_OP_RETVAL;
                else
                        ret = -EINVAL;
@@ -173,7 +172,8 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
                        code->op = FETCH_OP_STACKP;
                } else if (isdigit(arg[5])) {
                        ret = kstrtoul(arg + 5, 10, &param);
-                       if (ret || (is_kprobe && param > PARAM_MAX_STACK))
+                       if (ret || ((flags & TPARG_FL_KERNEL) &&
+                                   param > PARAM_MAX_STACK))
                                ret = -EINVAL;
                        else {
                                code->op = FETCH_OP_STACK;
@@ -183,6 +183,18 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
                        ret = -EINVAL;
        } else if (strcmp(arg, "comm") == 0) {
                code->op = FETCH_OP_COMM;
+#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
+       } else if (((flags & TPARG_FL_MASK) ==
+                   (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) &&
+                  strncmp(arg, "arg", 3) == 0) {
+               if (!isdigit(arg[3]))
+                       return -EINVAL;
+               ret = kstrtoul(arg + 3, 10, &param);
+               if (ret || !param || param > PARAM_MAX_STACK)
+                       return -EINVAL;
+               code->op = FETCH_OP_ARG;
+               code->param = (unsigned int)param - 1;
+#endif
        } else
                ret = -EINVAL;
 
@@ -193,7 +205,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 static int
 parse_probe_arg(char *arg, const struct fetch_type *type,
                struct fetch_insn **pcode, struct fetch_insn *end,
-               bool is_return, bool is_kprobe)
+               unsigned int flags)
 {
        struct fetch_insn *code = *pcode;
        unsigned long param;
@@ -203,8 +215,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 
        switch (arg[0]) {
        case '$':
-               ret = parse_probe_vars(arg + 1, type, code,
-                                       is_return, is_kprobe);
+               ret = parse_probe_vars(arg + 1, type, code, flags);
                break;
 
        case '%':       /* named register */
@@ -226,7 +237,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                        code->immediate = param;
                } else if (arg[1] == '+') {
                        /* kprobes don't support file offsets */
-                       if (is_kprobe)
+                       if (flags & TPARG_FL_KERNEL)
                                return -EINVAL;
 
                        ret = kstrtol(arg + 2, 0, &offset);
@@ -237,7 +248,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                        code->immediate = (unsigned long)offset;  // imm64?
                } else {
                        /* uprobes don't support symbols */
-                       if (!is_kprobe)
+                       if (!(flags & TPARG_FL_KERNEL))
                                return -EINVAL;
 
                        ret = traceprobe_split_symbol_offset(arg + 1, &offset);
@@ -278,8 +289,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                        const struct fetch_type *t2 = find_fetch_type(NULL);
 
                        *tmp = '\0';
-                       ret = parse_probe_arg(arg, t2, &code, end, is_return,
-                                             is_kprobe);
+                       ret = parse_probe_arg(arg, t2, &code, end, flags);
                        if (ret)
                                break;
                        if (code->op == FETCH_OP_COMM)
@@ -339,7 +349,7 @@ static int __parse_bitfield_probe_arg(const char *bf,
 
 /* String length checking wrapper */
 int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
-               struct probe_arg *parg, bool is_return, bool is_kprobe)
+               struct probe_arg *parg, unsigned int flags)
 {
        struct fetch_insn *code, *scode, *tmp = NULL;
        char *t, *t2;
@@ -397,7 +407,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
        code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
 
        ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],
-                             is_return, is_kprobe);
+                             flags);
        if (ret)
                goto fail;