[RFC PATCH 8/8] tracing: probeevent: Add an array for basic types
Add an array for basic types. This allows user to get arraied basic types from memory address. The array type syntax is TYPE[N] Where TYPE is one of basic type (u8/16/32/64,s8/16/32/64, and x8/16/32/64) and N is a fixed value. Signed-off-by: Masami Hiramatsu--- Documentation/trace/kprobetrace.txt |7 ++ kernel/trace/trace_kprobe.c | 17 + kernel/trace/trace_probe.c | 111 ++- kernel/trace/trace_probe.h | 29 - kernel/trace/trace_uprobe.c | 17 + 5 files changed, 144 insertions(+), 37 deletions(-) diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index ec34640becbd..17d3e1a97d85 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt @@ -65,6 +65,13 @@ in decimal ('s' and 'u') or hexadecimal ('x'). Without type casting, 'x32' or 'x64' is used depends on the architecture (e.g. x86-32 uses x32, and x86-64 uses x64). +These value types can be an array. To record array data, you can add '[N]' +(where N is a fixed number, less than 64) to the base type. +E.g. 'x16[4]' means an array of x16 (2bytes hex) with 4 elements. +Note that the array can be applied to memory type fetchargs, you can not +apply it to registers/stack-entries etc. (for example, '$stack1:x8[8]' is +wrong, but '+8($stack):x8[8]' is OK.) + String type is a special type, which fetches a "null-terminated" string from kernel space. This means it will fail and store NULL if the string container has been paged out. diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index cab5efe0a66c..45e00de573d3 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -835,8 +835,9 @@ static int process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, bool pre) { + struct fetch_insn *s3 = NULL; unsigned long val; - int ret; + int ret, i = 0; /* 1st stage: get value from context */ switch (code->op) { @@ -877,6 +878,8 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, code++; } +stage3: + s3 = code; /* 3rd stage: store value to buffer */ switch (code->op) { case FETCH_OP_ST_RAW: @@ -902,6 +905,16 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, code++; } + /* the last stage: Loop on array */ + if (code->op == FETCH_OP_LP_ARRAY) { + if (++i < code->param) { + code = s3; + val += s3->size; + dest += s3->size; + goto stage3; + } + } + return code->op == FETCH_OP_END ? 0 : -EILSEQ; } NOKPROBE_SYMBOL(process_fetch_insn) @@ -1248,7 +1261,7 @@ static int register_kprobe_event(struct trace_kprobe *tk) call->event.funcs = _funcs; call->class->define_fields = kprobe_event_define_fields; } - if (set_print_fmt(>tp, trace_kprobe_is_return(tk)) < 0) + if (traceprobe_set_print_fmt(>tp, trace_kprobe_is_return(tk)) < 0) return -ENOMEM; ret = register_trace_event(>event); if (!ret) { diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 491a640a1a3e..ae96f98506f0 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -378,8 +378,8 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, struct probe_arg *parg, unsigned int flags) { struct fetch_insn *code, *tmp = NULL; - const char *t; - int ret; + char *t, *t2; + int ret, len; if (strlen(arg) > MAX_ARGSTR_LEN) { pr_info("Argument is too long.: %s\n", arg); @@ -390,24 +390,40 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, pr_info("Failed to allocate memory for command '%s'.\n", arg); return -ENOMEM; } - t = strchr(parg->comm, ':'); + t = strchr(arg, ':'); if (t) { - arg[t - parg->comm] = '\0'; - t++; + *t = '\0'; + t2 = strchr(++t, '['); + if (t2) { + *t2 = '\0'; + parg->count = simple_strtoul(t2 + 1, , 0); + if (strcmp(t2, "]") || parg->count == 0) + return -EINVAL; + } } /* * The default type of $comm should be "string", and it can't be * dereferenced. */ if (!t && strcmp(arg, "$comm") == 0) - t = "string"; - parg->type = find_fetch_type(t); + parg->type = find_fetch_type("string"); + else + parg->type = find_fetch_type(t); if (!parg->type) {
[RFC PATCH 8/8] tracing: probeevent: Add an array for basic types
Add an array for basic types. This allows user to get arraied basic types from memory address. The array type syntax is TYPE[N] Where TYPE is one of basic type (u8/16/32/64,s8/16/32/64, and x8/16/32/64) and N is a fixed value. Signed-off-by: Masami Hiramatsu --- Documentation/trace/kprobetrace.txt |7 ++ kernel/trace/trace_kprobe.c | 17 + kernel/trace/trace_probe.c | 111 ++- kernel/trace/trace_probe.h | 29 - kernel/trace/trace_uprobe.c | 17 + 5 files changed, 144 insertions(+), 37 deletions(-) diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index ec34640becbd..17d3e1a97d85 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt @@ -65,6 +65,13 @@ in decimal ('s' and 'u') or hexadecimal ('x'). Without type casting, 'x32' or 'x64' is used depends on the architecture (e.g. x86-32 uses x32, and x86-64 uses x64). +These value types can be an array. To record array data, you can add '[N]' +(where N is a fixed number, less than 64) to the base type. +E.g. 'x16[4]' means an array of x16 (2bytes hex) with 4 elements. +Note that the array can be applied to memory type fetchargs, you can not +apply it to registers/stack-entries etc. (for example, '$stack1:x8[8]' is +wrong, but '+8($stack):x8[8]' is OK.) + String type is a special type, which fetches a "null-terminated" string from kernel space. This means it will fail and store NULL if the string container has been paged out. diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index cab5efe0a66c..45e00de573d3 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -835,8 +835,9 @@ static int process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, bool pre) { + struct fetch_insn *s3 = NULL; unsigned long val; - int ret; + int ret, i = 0; /* 1st stage: get value from context */ switch (code->op) { @@ -877,6 +878,8 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, code++; } +stage3: + s3 = code; /* 3rd stage: store value to buffer */ switch (code->op) { case FETCH_OP_ST_RAW: @@ -902,6 +905,16 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, code++; } + /* the last stage: Loop on array */ + if (code->op == FETCH_OP_LP_ARRAY) { + if (++i < code->param) { + code = s3; + val += s3->size; + dest += s3->size; + goto stage3; + } + } + return code->op == FETCH_OP_END ? 0 : -EILSEQ; } NOKPROBE_SYMBOL(process_fetch_insn) @@ -1248,7 +1261,7 @@ static int register_kprobe_event(struct trace_kprobe *tk) call->event.funcs = _funcs; call->class->define_fields = kprobe_event_define_fields; } - if (set_print_fmt(>tp, trace_kprobe_is_return(tk)) < 0) + if (traceprobe_set_print_fmt(>tp, trace_kprobe_is_return(tk)) < 0) return -ENOMEM; ret = register_trace_event(>event); if (!ret) { diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 491a640a1a3e..ae96f98506f0 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -378,8 +378,8 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, struct probe_arg *parg, unsigned int flags) { struct fetch_insn *code, *tmp = NULL; - const char *t; - int ret; + char *t, *t2; + int ret, len; if (strlen(arg) > MAX_ARGSTR_LEN) { pr_info("Argument is too long.: %s\n", arg); @@ -390,24 +390,40 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, pr_info("Failed to allocate memory for command '%s'.\n", arg); return -ENOMEM; } - t = strchr(parg->comm, ':'); + t = strchr(arg, ':'); if (t) { - arg[t - parg->comm] = '\0'; - t++; + *t = '\0'; + t2 = strchr(++t, '['); + if (t2) { + *t2 = '\0'; + parg->count = simple_strtoul(t2 + 1, , 0); + if (strcmp(t2, "]") || parg->count == 0) + return -EINVAL; + } } /* * The default type of $comm should be "string", and it can't be * dereferenced. */ if (!t && strcmp(arg, "$comm") == 0) - t = "string"; - parg->type = find_fetch_type(t); + parg->type = find_fetch_type("string"); + else + parg->type = find_fetch_type(t); if (!parg->type) {