]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
tracing/probe: Add immediate string parameter support
authorMasami Hiramatsu <mhiramat@kernel.org>
Wed, 19 Jun 2019 15:08:37 +0000 (00:08 +0900)
committerSteven Rostedt (VMware) <rostedt@goodmis.org>
Sat, 31 Aug 2019 16:19:39 +0000 (12:19 -0400)
Add immediate string parameter (\"string") support to
probe events. This allows you to specify an immediate
(or dummy) parameter instead of fetching a string from
memory.

This feature looks odd, but imagine that you put a probe
on a code to trace some string data. If the code is
compiled into 2 instructions and 1 instruction has a
string on memory but other has no string since it is
optimized out. In that case, you can not fold those into
one event, even if ftrace supported multiple probes on
one event. With this feature, you can set a dummy string
like foo=\"(optimized)":string instead of something
like foo=+0(+0(%bp)):string.

Link: http://lkml.kernel.org/r/156095691687.28024.13372712423865047991.stgit@devnote2
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
kernel/trace/trace.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_probe.c
kernel/trace/trace_probe.h
kernel/trace/trace_uprobe.c

index fb4003c10151fba23332f163a383a60b06261535..3916b72de715e058bc03eadcb26f6a2f56b90168 100644 (file)
@@ -4848,7 +4848,7 @@ static const char readme_msg[] =
 #else
        "\t           $stack<index>, $stack, $retval, $comm,\n"
 #endif
-       "\t           +|-[u]<offset>(<fetcharg>), \\imm-value\n"
+       "\t           +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
        "\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
        "\t           b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
        "\t           <type>\\[<array-size>\\]\n"
index 18c4175b6585976f052e8c16290eb36df2ea7007..7579c53bb053c92df92d2c6438eed7e10e8141b8 100644 (file)
@@ -1083,6 +1083,9 @@ retry:
        case FETCH_OP_COMM:
                val = (unsigned long)current->comm;
                break;
+       case FETCH_OP_DATA:
+               val = (unsigned long)code->data;
+               break;
 #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
        case FETCH_OP_ARG:
                val = regs_get_kernel_argument(regs, code->param);
index fb90baec3cd83509b9c09a38903b4f7cab1778a0..1e67fef06e535f464994c31d08c665adfc31d212 100644 (file)
@@ -327,6 +327,18 @@ static int str_to_immediate(char *str, unsigned long *imm)
        return -EINVAL;
 }
 
+static int __parse_imm_string(char *str, char **pbuf, int offs)
+{
+       size_t len = strlen(str);
+
+       if (str[len - 1] != '"') {
+               trace_probe_log_err(offs + len, IMMSTR_NO_CLOSE);
+               return -EINVAL;
+       }
+       *pbuf = kstrndup(str, len - 1, GFP_KERNEL);
+       return 0;
+}
+
 /* Recursive argument parser */
 static int
 parse_probe_arg(char *arg, const struct fetch_type *type,
@@ -441,7 +453,8 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                        ret = parse_probe_arg(arg, t2, &code, end, flags, offs);
                        if (ret)
                                break;
-                       if (code->op == FETCH_OP_COMM) {
+                       if (code->op == FETCH_OP_COMM ||
+                           code->op == FETCH_OP_DATA) {
                                trace_probe_log_err(offs, COMM_CANT_DEREF);
                                return -EINVAL;
                        }
@@ -456,11 +469,19 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                }
                break;
        case '\\':      /* Immediate value */
-               ret = str_to_immediate(arg + 1, &code->immediate);
-               if (ret)
-                       trace_probe_log_err(offs + 1, BAD_IMM);
-               else
-                       code->op = FETCH_OP_IMM;
+               if (arg[1] == '"') {    /* Immediate string */
+                       ret = __parse_imm_string(arg + 2, &tmp, offs + 2);
+                       if (ret)
+                               break;
+                       code->op = FETCH_OP_DATA;
+                       code->data = tmp;
+               } else {
+                       ret = str_to_immediate(arg + 1, &code->immediate);
+                       if (ret)
+                               trace_probe_log_err(offs + 1, BAD_IMM);
+                       else
+                               code->op = FETCH_OP_IMM;
+               }
                break;
        }
        if (!ret && code->op == FETCH_OP_NOP) {
@@ -560,8 +581,11 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
                }
        }
 
-       /* Since $comm can not be dereferred, we can find $comm by strcmp */
-       if (strcmp(arg, "$comm") == 0) {
+       /*
+        * Since $comm and immediate string can not be dereferred,
+        * we can find those by strcmp.
+        */
+       if (strcmp(arg, "$comm") == 0 || strncmp(arg, "\\\"", 2) == 0) {
                /* The type of $comm must be "string", and not an array. */
                if (parg->count || (t && strcmp(t, "string")))
                        return -EINVAL;
@@ -598,7 +622,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
        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_IMM && code->op != FETCH_OP_COMM &&
+                   code->op != FETCH_OP_DATA) {
                        trace_probe_log_err(offset + (t ? (t - arg) : 0),
                                            BAD_STRING);
                        ret = -EINVAL;
@@ -607,9 +632,10 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
                if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM) ||
                     parg->count) {
                        /*
-                        * IMM and COMM is pointing actual address, those must
-                        * be kept, and if parg->count != 0, this is an array
-                        * of string pointers instead of string address itself.
+                        * IMM, DATA and COMM is pointing actual address, those
+                        * must be kept, and if parg->count != 0, this is an
+                        * array of string pointers instead of string address
+                        * itself.
                         */
                        code++;
                        if (code->op != FETCH_OP_NOP) {
@@ -683,7 +709,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
 fail:
        if (ret) {
                for (code = tmp; code < tmp + FETCH_INSN_MAX; code++)
-                       if (code->op == FETCH_NOP_SYMBOL)
+                       if (code->op == FETCH_NOP_SYMBOL ||
+                           code->op == FETCH_OP_DATA)
                                kfree(code->data);
        }
        kfree(tmp);
@@ -754,7 +781,8 @@ void traceprobe_free_probe_arg(struct probe_arg *arg)
        struct fetch_insn *code = arg->code;
 
        while (code && code->op != FETCH_OP_END) {
-               if (code->op == FETCH_NOP_SYMBOL)
+               if (code->op == FETCH_NOP_SYMBOL ||
+                   code->op == FETCH_OP_DATA)
                        kfree(code->data);
                code++;
        }
index cc113b82a4ce030ab5de1fbc7f62101d4cff7671..f805cc4cbe7c9d72c7f2a0496f0940728d799e95 100644 (file)
@@ -89,6 +89,7 @@ enum fetch_op {
        FETCH_OP_COMM,          /* Current comm */
        FETCH_OP_ARG,           /* Function argument : .param */
        FETCH_OP_FOFFS,         /* File offset: .immediate */
+       FETCH_OP_DATA,          /* Allocated data: .data */
        // Stage 2 (dereference) op
        FETCH_OP_DEREF,         /* Dereference: .offset */
        FETCH_OP_UDEREF,        /* User-space Dereference: .offset */
@@ -409,6 +410,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
        C(BAD_REG_NAME,         "Invalid register name"),               \
        C(BAD_MEM_ADDR,         "Invalid memory address"),              \
        C(BAD_IMM,              "Invalid immediate value"),             \
+       C(IMMSTR_NO_CLOSE,      "String is not closed with '\"'"),      \
        C(FILE_ON_KPROBE,       "File offset is not available with kprobe"), \
        C(BAD_FILE_OFFS,        "Invalid file offset value"),           \
        C(SYM_ON_UPROBE,        "Symbol is not available with uprobe"), \
index 84925b5b6db5a88004adfec0dd700df800801237..cbf4da4bf3675003454f6765fb672263045afb33 100644 (file)
@@ -248,6 +248,9 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
        case FETCH_OP_COMM:
                val = FETCH_TOKEN_COMM;
                break;
+       case FETCH_OP_DATA:
+               val = (unsigned long)code->data;
+               break;
        case FETCH_OP_FOFFS:
                val = translate_user_vaddr(code->immediate);
                break;