Merge tag 'probes-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull probes updates from Masami Hiramatsu:

 - fprobe: Pass return address to the fprobe entry/exit callbacks so
   that the callbacks don't need to analyze pt_regs/stack to find the
   function return address.

 - kprobe events: cleanup usage of TPARG_FL_FENTRY and TPARG_FL_RETURN
   flags so that those are not set at once.

 - fprobe events:
      - Add a new fprobe events for tracing arbitrary function entry and
        exit as a trace event.
      - Add a new tracepoint events for tracing raw tracepoint as a
        trace event. This allows user to trace non user-exposed
        tracepoints.
      - Move eprobe's event parser code into probe event common file.
      - Introduce BTF (BPF type format) support to kernel probe (kprobe,
        fprobe and tracepoint probe) events so that user can specify
        traced function arguments by name. This also applies the type of
        argument when fetching the argument.
      - Introduce '$arg*' wildcard support if BTF is available. This
        expands the '$arg*' meta argument to all function argument
        automatically.
      - Check the return value types by BTF. If the function returns
        'void', '$retval' is rejected.
      - Add some selftest script for fprobe events, tracepoint events
        and BTF support.
      - Update documentation about the fprobe events.
      - Some fixes for above features, document and selftests.

 - selftests for ftrace (in addition to the new fprobe events):
      - Add a test case for multiple consecutive probes in a function
        which checks if ftrace based kprobe, optimized kprobe and normal
        kprobe can be defined in the same target function.
      - Add a test case for optimized probe, which checks whether kprobe
        can be optimized or not.

* tag 'probes-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  tracing/probes: Fix tracepoint event with $arg* to fetch correct argument
  Documentation: Fix typo of reference file name
  tracing/probes: Fix to return NULL and keep using current argc
  selftests/ftrace: Add new test case which checks for optimized probes
  selftests/ftrace: Add new test case which adds multiple consecutive probes in a function
  Documentation: tracing/probes: Add fprobe event tracing document
  selftests/ftrace: Add BTF arguments test cases
  selftests/ftrace: Add tracepoint probe test case
  tracing/probes: Add BTF retval type support
  tracing/probes: Add $arg* meta argument for all function args
  tracing/probes: Support function parameters if BTF is available
  tracing/probes: Move event parameter fetching code to common parser
  tracing/probes: Add tracepoint support on fprobe_events
  selftests/ftrace: Add fprobe related testcases
  tracing/probes: Add fprobe events for tracing function entry and exit.
  tracing/probes: Avoid setting TPARG_FL_FENTRY and TPARG_FL_RETURN
  fprobe: Pass return address to the handlers
This commit is contained in:
Linus Torvalds
2023-06-30 10:44:53 -07:00
31 changed files with 2482 additions and 170 deletions

View File

@@ -0,0 +1,58 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove probes with BTF arguments
# requires: dynamic_events "<argname>":README
KPROBES=
FPROBES=
if grep -qF "p[:[<group>/][<event>]] <place> [<args>]" README ; then
KPROBES=yes
fi
if grep -qF "f[:[<group>/][<event>]] <func-name>[%return] [<args>]" README ; then
FPROBES=yes
fi
if [ -z "$KPROBES" -a "$FPROBES" ] ; then
exit_unsupported
fi
echo 0 > events/enable
echo > dynamic_events
TP=kfree
if [ "$FPROBES" ] ; then
echo "f:fpevent $TP object" >> dynamic_events
echo "t:tpevent $TP ptr" >> dynamic_events
grep -q "fpevent.*object=object" dynamic_events
grep -q "tpevent.*ptr=ptr" dynamic_events
echo > dynamic_events
echo "f:fpevent $TP "'$arg1' >> dynamic_events
grep -q "fpevent.*object=object" dynamic_events
echo > dynamic_events
echo "f:fpevent $TP "'$arg*' >> dynamic_events
echo "t:tpevent $TP "'$arg*' >> dynamic_events
grep -q "fpevent.*object=object" dynamic_events
grep -q "tpevent.*ptr=ptr" dynamic_events
! grep -q "tpevent.*_data" dynamic_events
fi
echo > dynamic_events
if [ "$KPROBES" ] ; then
echo "p:kpevent $TP object" >> dynamic_events
grep -q "kpevent.*object=object" dynamic_events
echo > dynamic_events
echo "p:kpevent $TP "'$arg*' >> dynamic_events
grep -q "kpevent.*object=object" dynamic_events
fi
clear_trace

View File

@@ -0,0 +1,26 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove fprobe events
# requires: dynamic_events "f[:[<group>/][<event>]] <func-name>[%return] [<args>]":README
echo 0 > events/enable
echo > dynamic_events
PLACE=$FUNCTION_FORK
echo "f:myevent1 $PLACE" >> dynamic_events
echo "f:myevent2 $PLACE%return" >> dynamic_events
grep -q myevent1 dynamic_events
grep -q myevent2 dynamic_events
test -d events/fprobes/myevent1
test -d events/fprobes/myevent2
echo "-:myevent2" >> dynamic_events
grep -q myevent1 dynamic_events
! grep -q myevent2 dynamic_events
echo > dynamic_events
clear_trace

View File

@@ -0,0 +1,27 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove tracepoint probe events
# requires: dynamic_events "t[:[<group>/][<event>]] <tracepoint> [<args>]":README
echo 0 > events/enable
echo > dynamic_events
TRACEPOINT1=kmem_cache_alloc
TRACEPOINT2=kmem_cache_free
echo "t:myevent1 $TRACEPOINT1" >> dynamic_events
echo "t:myevent2 $TRACEPOINT2" >> dynamic_events
grep -q myevent1 dynamic_events
grep -q myevent2 dynamic_events
test -d events/tracepoints/myevent1
test -d events/tracepoints/myevent2
echo "-:myevent2" >> dynamic_events
grep -q myevent1 dynamic_events
! grep -q myevent2 dynamic_events
echo > dynamic_events
clear_trace

View File

@@ -0,0 +1,111 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Fprobe event parser error log check
# requires: dynamic_events "f[:[<group>/][<event>]] <func-name>[%return] [<args>]":README
check_error() { # command-with-error-pos-by-^
ftrace_errlog_check 'trace_fprobe' "$1" 'dynamic_events'
}
case `uname -m` in
x86_64|i[3456]86)
REG=%ax ;;
aarch64)
REG=%x0 ;;
*)
REG=%r0 ;;
esac
check_error 'f^100 vfs_read' # MAXACT_NO_KPROBE
check_error 'f^1a111 vfs_read' # BAD_MAXACT
check_error 'f^100000 vfs_read' # MAXACT_TOO_BIG
check_error 'f ^non_exist_func' # BAD_PROBE_ADDR (enoent)
check_error 'f ^vfs_read+10' # BAD_PROBE_ADDR
check_error 'f:^/bar vfs_read' # NO_GROUP_NAME
check_error 'f:^12345678901234567890123456789012345678901234567890123456789012345/bar vfs_read' # GROUP_TOO_LONG
check_error 'f:^foo.1/bar vfs_read' # BAD_GROUP_NAME
check_error 'f:^ vfs_read' # NO_EVENT_NAME
check_error 'f:foo/^12345678901234567890123456789012345678901234567890123456789012345 vfs_read' # EVENT_TOO_LONG
check_error 'f:foo/^bar.1 vfs_read' # BAD_EVENT_NAME
check_error 'f vfs_read ^$retval' # RETVAL_ON_PROBE
check_error 'f vfs_read ^$stack10000' # BAD_STACK_NUM
check_error 'f vfs_read ^$arg10000' # BAD_ARG_NUM
check_error 'f vfs_read ^$none_var' # BAD_VAR
check_error 'f vfs_read ^'$REG # BAD_VAR
check_error 'f vfs_read ^@12345678abcde' # BAD_MEM_ADDR
check_error 'f vfs_read ^@+10' # FILE_ON_KPROBE
grep -q "imm-value" README && \
check_error 'f vfs_read arg1=\^x' # BAD_IMM
grep -q "imm-string" README && \
check_error 'f vfs_read arg1=\"abcd^' # IMMSTR_NO_CLOSE
check_error 'f vfs_read ^+0@0)' # DEREF_NEED_BRACE
check_error 'f vfs_read ^+0ab1(@0)' # BAD_DEREF_OFFS
check_error 'f vfs_read +0(+0(@0^)' # DEREF_OPEN_BRACE
if grep -A1 "fetcharg:" README | grep -q '\$comm' ; then
check_error 'f vfs_read +0(^$comm)' # COMM_CANT_DEREF
fi
check_error 'f vfs_read ^&1' # BAD_FETCH_ARG
# We've introduced this limitation with array support
if grep -q ' <type>\\\[<array-size>\\\]' README; then
check_error 'f vfs_read +0(^+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(@0))))))))))))))' # TOO_MANY_OPS?
check_error 'f vfs_read +0(@11):u8[10^' # ARRAY_NO_CLOSE
check_error 'f vfs_read +0(@11):u8[10]^a' # BAD_ARRAY_SUFFIX
check_error 'f vfs_read +0(@11):u8[^10a]' # BAD_ARRAY_NUM
check_error 'f vfs_read +0(@11):u8[^256]' # ARRAY_TOO_BIG
fi
check_error 'f vfs_read @11:^unknown_type' # BAD_TYPE
check_error 'f vfs_read $stack0:^string' # BAD_STRING
check_error 'f vfs_read @11:^b10@a/16' # BAD_BITFIELD
check_error 'f vfs_read ^arg123456789012345678901234567890=@11' # ARG_NAME_TOO_LOG
check_error 'f vfs_read ^=@11' # NO_ARG_NAME
check_error 'f vfs_read ^var.1=@11' # BAD_ARG_NAME
check_error 'f vfs_read var1=@11 ^var1=@12' # USED_ARG_NAME
check_error 'f vfs_read ^+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(@1234))))))' # ARG_TOO_LONG
check_error 'f vfs_read arg1=^' # NO_ARG_BODY
# multiprobe errors
if grep -q "Create/append/" README && grep -q "imm-value" README; then
echo "f:fprobes/testevent $FUNCTION_FORK" > dynamic_events
check_error '^f:fprobes/testevent do_exit%return' # DIFF_PROBE_TYPE
# Explicitly use printf "%s" to not interpret \1
printf "%s" "f:fprobes/testevent $FUNCTION_FORK abcd=\\1" > dynamic_events
check_error "f:fprobes/testevent $FUNCTION_FORK ^bcd=\\1" # DIFF_ARG_TYPE
check_error "f:fprobes/testevent $FUNCTION_FORK ^abcd=\\1:u8" # DIFF_ARG_TYPE
check_error "f:fprobes/testevent $FUNCTION_FORK ^abcd=\\\"foo\"" # DIFF_ARG_TYPE
check_error "^f:fprobes/testevent $FUNCTION_FORK abcd=\\1" # SAME_PROBE
fi
# %return suffix errors
check_error 'f vfs_read^%hoge' # BAD_ADDR_SUFFIX
# BTF arguments errors
if grep -q "<argname>" README; then
check_error 'f vfs_read args=^$arg*' # BAD_VAR_ARGS
check_error 'f vfs_read +0(^$arg*)' # BAD_VAR_ARGS
check_error 'f vfs_read $arg* ^$arg*' # DOUBLE_ARGS
check_error 'f vfs_read%return ^$arg*' # NOFENTRY_ARGS
check_error 'f vfs_read ^hoge' # NO_BTFARG
check_error 'f kfree ^$arg10' # NO_BTFARG (exceed the number of parameters)
check_error 'f kfree%return ^$retval' # NO_RETVAL
else
check_error 'f vfs_read ^$arg*' # NOSUP_BTFARG
check_error 't kfree ^$arg*' # NOSUP_BTFARG
fi
exit 0

View File

@@ -0,0 +1,82 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Tracepoint probe event parser error log check
# requires: dynamic_events "t[:[<group>/][<event>]] <tracepoint> [<args>]":README
check_error() { # command-with-error-pos-by-^
ftrace_errlog_check 'trace_fprobe' "$1" 'dynamic_events'
}
check_error 't^100 kfree' # BAD_MAXACT_TYPE
check_error 't ^non_exist_tracepoint' # NO_TRACEPOINT
check_error 't:^/bar kfree' # NO_GROUP_NAME
check_error 't:^12345678901234567890123456789012345678901234567890123456789012345/bar kfree' # GROUP_TOO_LONG
check_error 't:^foo.1/bar kfree' # BAD_GROUP_NAME
check_error 't:^ kfree' # NO_EVENT_NAME
check_error 't:foo/^12345678901234567890123456789012345678901234567890123456789012345 kfree' # EVENT_TOO_LONG
check_error 't:foo/^bar.1 kfree' # BAD_EVENT_NAME
check_error 't kfree ^$retval' # RETVAL_ON_PROBE
check_error 't kfree ^$stack10000' # BAD_STACK_NUM
check_error 't kfree ^$arg10000' # BAD_ARG_NUM
check_error 't kfree ^$none_var' # BAD_VAR
check_error 't kfree ^%rax' # BAD_VAR
check_error 't kfree ^@12345678abcde' # BAD_MEM_ADDR
check_error 't kfree ^@+10' # FILE_ON_KPROBE
grep -q "imm-value" README && \
check_error 't kfree arg1=\^x' # BAD_IMM
grep -q "imm-string" README && \
check_error 't kfree arg1=\"abcd^' # IMMSTR_NO_CLOSE
check_error 't kfree ^+0@0)' # DEREF_NEED_BRACE
check_error 't kfree ^+0ab1(@0)' # BAD_DEREF_OFFS
check_error 't kfree +0(+0(@0^)' # DEREF_OPEN_BRACE
if grep -A1 "fetcharg:" README | grep -q '\$comm' ; then
check_error 't kfree +0(^$comm)' # COMM_CANT_DEREF
fi
check_error 't kfree ^&1' # BAD_FETCH_ARG
# We've introduced this limitation with array support
if grep -q ' <type>\\\[<array-size>\\\]' README; then
check_error 't kfree +0(^+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(@0))))))))))))))' # TOO_MANY_OPS?
check_error 't kfree +0(@11):u8[10^' # ARRAY_NO_CLOSE
check_error 't kfree +0(@11):u8[10]^a' # BAD_ARRAY_SUFFIX
check_error 't kfree +0(@11):u8[^10a]' # BAD_ARRAY_NUM
check_error 't kfree +0(@11):u8[^256]' # ARRAY_TOO_BIG
fi
check_error 't kfree @11:^unknown_type' # BAD_TYPE
check_error 't kfree $stack0:^string' # BAD_STRING
check_error 't kfree @11:^b10@a/16' # BAD_BITFIELD
check_error 't kfree ^arg123456789012345678901234567890=@11' # ARG_NAME_TOO_LOG
check_error 't kfree ^=@11' # NO_ARG_NAME
check_error 't kfree ^var.1=@11' # BAD_ARG_NAME
check_error 't kfree var1=@11 ^var1=@12' # USED_ARG_NAME
check_error 't kfree ^+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(@1234))))))' # ARG_TOO_LONG
check_error 't kfree arg1=^' # NO_ARG_BODY
# multiprobe errors
if grep -q "Create/append/" README && grep -q "imm-value" README; then
echo "t:tracepoint/testevent kfree" > dynamic_events
check_error '^f:tracepoint/testevent kfree' # DIFF_PROBE_TYPE
# Explicitly use printf "%s" to not interpret \1
printf "%s" "t:tracepoints/testevent kfree abcd=\\1" > dynamic_events
check_error "t:tracepoints/testevent kfree ^bcd=\\1" # DIFF_ARG_TYPE
check_error "t:tracepoints/testevent kfree ^abcd=\\1:u8" # DIFF_ARG_TYPE
check_error "t:tracepoints/testevent kfree ^abcd=\\\"foo\"" # DIFF_ARG_TYPE
check_error "^t:tracepoints/testevent kfree abcd=\\1" # SAME_PROBE
fi
exit 0

View File

@@ -0,0 +1,19 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2023 Akanksha J N, IBM corporation
# description: Register multiple kprobe events in a function
# requires: kprobe_events
for i in `seq 0 255`; do
echo p $FUNCTION_FORK+${i} >> kprobe_events || continue
done
cat kprobe_events >> $testlog
echo 1 > events/kprobes/enable
( echo "forked" )
echo 0 > events/kprobes/enable
echo > kprobe_events
echo "Waiting for unoptimizing & freeing"
sleep 5
echo "Done"

View File

@@ -8,7 +8,7 @@ check_error() { # command-with-error-pos-by-^
}
if grep -q 'r\[maxactive\]' README; then
check_error 'p^100 vfs_read' # MAXACT_NO_KPROBE
check_error 'p^100 vfs_read' # BAD_MAXACT_TYPE
check_error 'r^1a111 vfs_read' # BAD_MAXACT
check_error 'r^100000 vfs_read' # MAXACT_TOO_BIG
fi
@@ -103,4 +103,18 @@ check_error 'p vfs_read^%hoge' # BAD_ADDR_SUFFIX
check_error 'p ^vfs_read+10%return' # BAD_RETPROBE
fi
# BTF arguments errors
if grep -q "<argname>" README; then
check_error 'p vfs_read args=^$arg*' # BAD_VAR_ARGS
check_error 'p vfs_read +0(^$arg*)' # BAD_VAR_ARGS
check_error 'p vfs_read $arg* ^$arg*' # DOUBLE_ARGS
check_error 'r vfs_read ^$arg*' # NOFENTRY_ARGS
check_error 'p vfs_read+8 ^$arg*' # NOFENTRY_ARGS
check_error 'p vfs_read ^hoge' # NO_BTFARG
check_error 'p kfree ^$arg10' # NO_BTFARG (exceed the number of parameters)
check_error 'r kfree ^$retval' # NO_RETVAL
else
check_error 'p vfs_read ^$arg*' # NOSUP_BTFARG
fi
exit 0