Merge tag 'trace-probes-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[sfrench/cifs-2.6.git] / kernel / trace / trace_probe.c
index bb2f95d7175c299597b9bc1c0a5f0f20719f7685..01ebabbbe8c9f39223a90f27ae869f82b25df6dc 100644 (file)
@@ -76,9 +76,11 @@ const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
 /* Fetch type information table */
 static const struct fetch_type probe_fetch_types[] = {
        /* Special types */
-       __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1,
+       __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1, 1,
                            "__data_loc char[]"),
-       __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1,
+       __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1, 1,
+                           "__data_loc char[]"),
+       __ASSIGN_FETCH_TYPE("symstr", string, string, sizeof(u32), 1, 1,
                            "__data_loc char[]"),
        /* Basic types */
        ASSIGN_FETCH_TYPE(u8,  u8,  0),
@@ -98,10 +100,15 @@ static const struct fetch_type probe_fetch_types[] = {
        ASSIGN_FETCH_TYPE_END
 };
 
-static const struct fetch_type *find_fetch_type(const char *type)
+static const struct fetch_type *find_fetch_type(const char *type, unsigned long flags)
 {
        int i;
 
+       /* Reject the symbol/symstr for uprobes */
+       if (type && (flags & TPARG_FL_USER) &&
+           (!strcmp(type, "symbol") || !strcmp(type, "symstr")))
+               return NULL;
+
        if (!type)
                type = DEFAULT_FETCH_TYPE_STR;
 
@@ -119,13 +126,13 @@ static const struct fetch_type *find_fetch_type(const char *type)
 
                switch (bs) {
                case 8:
-                       return find_fetch_type("u8");
+                       return find_fetch_type("u8", flags);
                case 16:
-                       return find_fetch_type("u16");
+                       return find_fetch_type("u16", flags);
                case 32:
-                       return find_fetch_type("u32");
+                       return find_fetch_type("u32", flags);
                case 64:
-                       return find_fetch_type("u64");
+                       return find_fetch_type("u64", flags);
                default:
                        goto fail;
                }
@@ -478,7 +485,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                                            DEREF_OPEN_BRACE);
                        return -EINVAL;
                } else {
-                       const struct fetch_type *t2 = find_fetch_type(NULL);
+                       const struct fetch_type *t2 = find_fetch_type(NULL, flags);
 
                        *tmp = '\0';
                        ret = parse_probe_arg(arg, t2, &code, end, flags, offs);
@@ -630,9 +637,9 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
                /* The type of $comm must be "string", and not an array. */
                if (parg->count || (t && strcmp(t, "string")))
                        goto out;
-               parg->type = find_fetch_type("string");
+               parg->type = find_fetch_type("string", flags);
        } else
-               parg->type = find_fetch_type(t);
+               parg->type = find_fetch_type(t, flags);
        if (!parg->type) {
                trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_TYPE);
                goto out;
@@ -662,16 +669,26 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
 
        ret = -EINVAL;
        /* Store operation */
-       if (!strcmp(parg->type->name, "string") ||
-           !strcmp(parg->type->name, "ustring")) {
-               if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
-                   code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
-                   code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {
-                       trace_probe_log_err(offset + (t ? (t - arg) : 0),
-                                           BAD_STRING);
-                       goto fail;
+       if (parg->type->is_string) {
+               if (!strcmp(parg->type->name, "symstr")) {
+                       if (code->op != FETCH_OP_REG && code->op != FETCH_OP_STACK &&
+                           code->op != FETCH_OP_RETVAL && code->op != FETCH_OP_ARG &&
+                           code->op != FETCH_OP_DEREF && code->op != FETCH_OP_TP_ARG) {
+                               trace_probe_log_err(offset + (t ? (t - arg) : 0),
+                                                   BAD_SYMSTRING);
+                               goto fail;
+                       }
+               } else {
+                       if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
+                           code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
+                           code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {
+                               trace_probe_log_err(offset + (t ? (t - arg) : 0),
+                                                   BAD_STRING);
+                               goto fail;
+                       }
                }
-               if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||
+               if (!strcmp(parg->type->name, "symstr") ||
+                   (code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||
                     code->op == FETCH_OP_DATA) || code->op == FETCH_OP_TP_ARG ||
                     parg->count) {
                        /*
@@ -679,6 +696,8 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
                         * must be kept, and if parg->count != 0, this is an
                         * array of string pointers instead of string address
                         * itself.
+                        * For the symstr, it doesn't need to dereference, thus
+                        * it just get the value.
                         */
                        code++;
                        if (code->op != FETCH_OP_NOP) {
@@ -690,6 +709,8 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
                if (!strcmp(parg->type->name, "ustring") ||
                    code->op == FETCH_OP_UDEREF)
                        code->op = FETCH_OP_ST_USTRING;
+               else if (!strcmp(parg->type->name, "symstr"))
+                       code->op = FETCH_OP_ST_SYMSTR;
                else
                        code->op = FETCH_OP_ST_STRING;
                code->size = parg->type->size;
@@ -919,8 +940,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
        for (i = 0; i < tp->nr_args; i++) {
                parg = tp->args + i;
                if (parg->count) {
-                       if ((strcmp(parg->type->name, "string") == 0) ||
-                           (strcmp(parg->type->name, "ustring") == 0))
+                       if (parg->type->is_string)
                                fmt = ", __get_str(%s[%d])";
                        else
                                fmt = ", REC->%s[%d]";
@@ -928,8 +948,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
                                pos += snprintf(buf + pos, LEN_OR_ZERO,
                                                fmt, parg->name, j);
                } else {
-                       if ((strcmp(parg->type->name, "string") == 0) ||
-                           (strcmp(parg->type->name, "ustring") == 0))
+                       if (parg->type->is_string)
                                fmt = ", __get_str(%s)";
                        else
                                fmt = ", REC->%s";