diff options
| -rw-r--r-- | kernel/trace/trace_kprobe.c | 4 | ||||
| -rw-r--r-- | kernel/trace/trace_probe.c | 8 | ||||
| -rw-r--r-- | kernel/trace/trace_probe.h | 2 | ||||
| -rw-r--r-- | tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc | 46 | ||||
| -rw-r--r-- | tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc | 97 | ||||
| -rw-r--r-- | tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc | 43 |
6 files changed, 192 insertions, 8 deletions
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 1fad24acd444..ae4147eaebd4 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
| @@ -659,7 +659,7 @@ static int create_trace_kprobe(int argc, char **argv) | |||
| 659 | char *symbol = NULL, *event = NULL, *group = NULL; | 659 | char *symbol = NULL, *event = NULL, *group = NULL; |
| 660 | int maxactive = 0; | 660 | int maxactive = 0; |
| 661 | char *arg; | 661 | char *arg; |
| 662 | unsigned long offset = 0; | 662 | long offset = 0; |
| 663 | void *addr = NULL; | 663 | void *addr = NULL; |
| 664 | char buf[MAX_EVENT_NAME_LEN]; | 664 | char buf[MAX_EVENT_NAME_LEN]; |
| 665 | 665 | ||
| @@ -747,7 +747,7 @@ static int create_trace_kprobe(int argc, char **argv) | |||
| 747 | symbol = argv[1]; | 747 | symbol = argv[1]; |
| 748 | /* TODO: support .init module functions */ | 748 | /* TODO: support .init module functions */ |
| 749 | ret = traceprobe_split_symbol_offset(symbol, &offset); | 749 | ret = traceprobe_split_symbol_offset(symbol, &offset); |
| 750 | if (ret) { | 750 | if (ret || offset < 0 || offset > UINT_MAX) { |
| 751 | pr_info("Failed to parse either an address or a symbol.\n"); | 751 | pr_info("Failed to parse either an address or a symbol.\n"); |
| 752 | return ret; | 752 | return ret; |
| 753 | } | 753 | } |
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index d59357308677..daf54bda4dc8 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c | |||
| @@ -320,7 +320,7 @@ static fetch_func_t get_fetch_size_function(const struct fetch_type *type, | |||
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | /* Split symbol and offset. */ | 322 | /* Split symbol and offset. */ |
| 323 | int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset) | 323 | int traceprobe_split_symbol_offset(char *symbol, long *offset) |
| 324 | { | 324 | { |
| 325 | char *tmp; | 325 | char *tmp; |
| 326 | int ret; | 326 | int ret; |
| @@ -328,13 +328,11 @@ int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset) | |||
| 328 | if (!offset) | 328 | if (!offset) |
| 329 | return -EINVAL; | 329 | return -EINVAL; |
| 330 | 330 | ||
| 331 | tmp = strchr(symbol, '+'); | 331 | tmp = strpbrk(symbol, "+-"); |
| 332 | if (tmp) { | 332 | if (tmp) { |
| 333 | /* skip sign because kstrtoul doesn't accept '+' */ | 333 | ret = kstrtol(tmp, 0, offset); |
| 334 | ret = kstrtoul(tmp + 1, 0, offset); | ||
| 335 | if (ret) | 334 | if (ret) |
| 336 | return ret; | 335 | return ret; |
| 337 | |||
| 338 | *tmp = '\0'; | 336 | *tmp = '\0'; |
| 339 | } else | 337 | } else |
| 340 | *offset = 0; | 338 | *offset = 0; |
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index e101c5bb9eda..6a4d3fa94042 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h | |||
| @@ -365,7 +365,7 @@ extern int traceprobe_conflict_field_name(const char *name, | |||
| 365 | extern void traceprobe_update_arg(struct probe_arg *arg); | 365 | extern void traceprobe_update_arg(struct probe_arg *arg); |
| 366 | extern void traceprobe_free_probe_arg(struct probe_arg *arg); | 366 | extern void traceprobe_free_probe_arg(struct probe_arg *arg); |
| 367 | 367 | ||
| 368 | extern int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset); | 368 | extern int traceprobe_split_symbol_offset(char *symbol, long *offset); |
| 369 | 369 | ||
| 370 | /* Sum up total data length for dynamic arraies (strings) */ | 370 | /* Sum up total data length for dynamic arraies (strings) */ |
| 371 | static nokprobe_inline int | 371 | static nokprobe_inline int |
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc new file mode 100644 index 000000000000..5ba73035e1d9 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | # description: Kprobe event string type argument | ||
| 4 | |||
| 5 | [ -f kprobe_events ] || exit_unsupported # this is configurable | ||
| 6 | |||
| 7 | echo 0 > events/enable | ||
| 8 | echo > kprobe_events | ||
| 9 | |||
| 10 | case `uname -m` in | ||
| 11 | x86_64) | ||
| 12 | ARG2=%si | ||
| 13 | OFFS=8 | ||
| 14 | ;; | ||
| 15 | i[3456]86) | ||
| 16 | ARG2=%cx | ||
| 17 | OFFS=4 | ||
| 18 | ;; | ||
| 19 | aarch64) | ||
| 20 | ARG2=%x1 | ||
| 21 | OFFS=8 | ||
| 22 | ;; | ||
| 23 | arm*) | ||
| 24 | ARG2=%r1 | ||
| 25 | OFFS=4 | ||
| 26 | ;; | ||
| 27 | *) | ||
| 28 | echo "Please implement other architecture here" | ||
| 29 | exit_untested | ||
| 30 | esac | ||
| 31 | |||
| 32 | : "Test get argument (1)" | ||
| 33 | echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string" > kprobe_events | ||
| 34 | echo 1 > events/kprobes/testprobe/enable | ||
| 35 | ! echo test >> kprobe_events | ||
| 36 | tail -n 1 trace | grep -qe "testprobe.* arg1=\"test\"" | ||
| 37 | |||
| 38 | echo 0 > events/kprobes/testprobe/enable | ||
| 39 | : "Test get argument (2)" | ||
| 40 | echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string arg2=+0(+${OFFS}(${ARG2})):string" > kprobe_events | ||
| 41 | echo 1 > events/kprobes/testprobe/enable | ||
| 42 | ! echo test1 test2 >> kprobe_events | ||
| 43 | tail -n 1 trace | grep -qe "testprobe.* arg1=\"test1\" arg2=\"test2\"" | ||
| 44 | |||
| 45 | echo 0 > events/enable | ||
| 46 | echo > kprobe_events | ||
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc new file mode 100644 index 000000000000..231bcd2c4eb5 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | # description: Kprobe event argument syntax | ||
| 4 | |||
| 5 | [ -f kprobe_events ] || exit_unsupported # this is configurable | ||
| 6 | |||
| 7 | grep "x8/16/32/64" README > /dev/null || exit_unsupported # version issue | ||
| 8 | |||
| 9 | echo 0 > events/enable | ||
| 10 | echo > kprobe_events | ||
| 11 | |||
| 12 | PROBEFUNC="vfs_read" | ||
| 13 | GOODREG= | ||
| 14 | BADREG= | ||
| 15 | GOODSYM="_sdata" | ||
| 16 | if ! grep -qw ${GOODSYM} /proc/kallsyms ; then | ||
| 17 | GOODSYM=$PROBEFUNC | ||
| 18 | fi | ||
| 19 | BADSYM="deaqswdefr" | ||
| 20 | SYMADDR=0x`grep -w ${GOODSYM} /proc/kallsyms | cut -f 1 -d " "` | ||
| 21 | GOODTYPE="x16" | ||
| 22 | BADTYPE="y16" | ||
| 23 | |||
| 24 | case `uname -m` in | ||
| 25 | x86_64|i[3456]86) | ||
| 26 | GOODREG=%ax | ||
| 27 | BADREG=%ex | ||
| 28 | ;; | ||
| 29 | aarch64) | ||
| 30 | GOODREG=%x0 | ||
| 31 | BADREG=%ax | ||
| 32 | ;; | ||
| 33 | arm*) | ||
| 34 | GOODREG=%r0 | ||
| 35 | BADREG=%ax | ||
| 36 | ;; | ||
| 37 | esac | ||
| 38 | |||
| 39 | test_goodarg() # Good-args | ||
| 40 | { | ||
| 41 | while [ "$1" ]; do | ||
| 42 | echo "p ${PROBEFUNC} $1" > kprobe_events | ||
| 43 | shift 1 | ||
| 44 | done; | ||
| 45 | } | ||
| 46 | |||
| 47 | test_badarg() # Bad-args | ||
| 48 | { | ||
| 49 | while [ "$1" ]; do | ||
| 50 | ! echo "p ${PROBEFUNC} $1" > kprobe_events | ||
| 51 | shift 1 | ||
| 52 | done; | ||
| 53 | } | ||
| 54 | |||
| 55 | echo > kprobe_events | ||
| 56 | |||
| 57 | : "Register access" | ||
| 58 | test_goodarg ${GOODREG} | ||
| 59 | test_badarg ${BADREG} | ||
| 60 | |||
| 61 | : "Symbol access" | ||
| 62 | test_goodarg "@${GOODSYM}" "@${SYMADDR}" "@${GOODSYM}+10" "@${GOODSYM}-10" | ||
| 63 | test_badarg "@" "@${BADSYM}" "@${GOODSYM}*10" "@${GOODSYM}/10" \ | ||
| 64 | "@${GOODSYM}%10" "@${GOODSYM}&10" "@${GOODSYM}|10" | ||
| 65 | |||
| 66 | : "Stack access" | ||
| 67 | test_goodarg "\$stack" "\$stack0" "\$stack1" | ||
| 68 | test_badarg "\$stackp" "\$stack0+10" "\$stack1-10" | ||
| 69 | |||
| 70 | : "Retval access" | ||
| 71 | echo "r ${PROBEFUNC} \$retval" > kprobe_events | ||
| 72 | ! echo "p ${PROBEFUNC} \$retval" > kprobe_events | ||
| 73 | |||
| 74 | : "Comm access" | ||
| 75 | test_goodarg "\$comm" | ||
| 76 | |||
| 77 | : "Indirect memory access" | ||
| 78 | test_goodarg "+0(${GOODREG})" "-0(${GOODREG})" "+10(\$stack)" \ | ||
| 79 | "+0(\$stack1)" "+10(@${GOODSYM}-10)" "+0(+10(+20(\$stack)))" | ||
| 80 | test_badarg "+(${GOODREG})" "(${GOODREG}+10)" "-(${GOODREG})" "(${GOODREG})" \ | ||
| 81 | "+10(\$comm)" "+0(${GOODREG})+10" | ||
| 82 | |||
| 83 | : "Name assignment" | ||
| 84 | test_goodarg "varname=${GOODREG}" | ||
| 85 | test_badarg "varname=varname2=${GOODREG}" | ||
| 86 | |||
| 87 | : "Type syntax" | ||
| 88 | test_goodarg "${GOODREG}:${GOODTYPE}" | ||
| 89 | test_badarg "${GOODREG}::${GOODTYPE}" "${GOODREG}:${BADTYPE}" \ | ||
| 90 | "${GOODTYPE}:${GOODREG}" | ||
| 91 | |||
| 92 | : "Combination check" | ||
| 93 | |||
| 94 | test_goodarg "\$comm:string" "+0(\$stack):string" | ||
| 95 | test_badarg "\$comm:x64" "\$stack:string" "${GOODREG}:string" | ||
| 96 | |||
| 97 | echo > kprobe_events | ||
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc b/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc new file mode 100644 index 000000000000..4fda01a08da4 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | # description: Kprobe events - probe points | ||
| 4 | |||
| 5 | [ -f kprobe_events ] || exit_unsupported # this is configurable | ||
| 6 | |||
| 7 | TARGET_FUNC=create_trace_kprobe | ||
| 8 | |||
| 9 | dec_addr() { # hexaddr | ||
| 10 | printf "%d" "0x"`echo $1 | tail -c 8` | ||
| 11 | } | ||
| 12 | |||
| 13 | set_offs() { # prev target next | ||
| 14 | A1=`dec_addr $1` | ||
| 15 | A2=`dec_addr $2` | ||
| 16 | A3=`dec_addr $3` | ||
| 17 | TARGET="0x$2" # an address | ||
| 18 | PREV=`expr $A1 - $A2` # offset to previous symbol | ||
| 19 | NEXT=+`expr $A3 - $A2` # offset to next symbol | ||
| 20 | OVERFLOW=+`printf "0x%x" ${PREV}` # overflow offset to previous symbol | ||
| 21 | } | ||
| 22 | |||
| 23 | # We have to decode symbol addresses to get correct offsets. | ||
| 24 | # If the offset is not an instruction boundary, it cause -EILSEQ. | ||
| 25 | set_offs `grep -A1 -B1 ${TARGET_FUNC} /proc/kallsyms | cut -f 1 -d " " | xargs` | ||
| 26 | |||
| 27 | UINT_TEST=no | ||
| 28 | # printf "%x" -1 returns (unsigned long)-1. | ||
| 29 | if [ `printf "%x" -1 | wc -c` != 9 ]; then | ||
| 30 | UINT_TEST=yes | ||
| 31 | fi | ||
| 32 | |||
| 33 | echo 0 > events/enable | ||
| 34 | echo > kprobe_events | ||
| 35 | echo "p:testprobe ${TARGET_FUNC}" > kprobe_events | ||
| 36 | echo "p:testprobe ${TARGET}" > kprobe_events | ||
| 37 | echo "p:testprobe ${TARGET_FUNC}${NEXT}" > kprobe_events | ||
| 38 | ! echo "p:testprobe ${TARGET_FUNC}${PREV}" > kprobe_events | ||
| 39 | if [ "${UINT_TEST}" = yes ]; then | ||
| 40 | ! echo "p:testprobe ${TARGET_FUNC}${OVERFLOW}" > kprobe_events | ||
| 41 | fi | ||
| 42 | echo > kprobe_events | ||
| 43 | clear_trace | ||
