Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
logs
poll
@@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
all:
TEST_PROGS_EXTENDED := ftracetest
TEST_PROGS := ftracetest-ktap
TEST_FILES := test.d settings
EXTRA_CLEAN := $(OUTPUT)/logs/*
TEST_GEN_FILES := poll
include ../lib.mk
@@ -0,0 +1,82 @@
Linux Ftrace Testcases
This is a collection of testcases for ftrace tracing feature in the Linux
kernel. Since ftrace exports interfaces via the debugfs, we just need
shell scripts for testing. Feel free to add new test cases.
Running the ftrace testcases
============================
At first, you need to be the root user to run this script.
To run all testcases:
$ sudo ./ftracetest
To run specific testcases:
# ./ftracetest test.d/basic3.tc
Or you can also run testcases under given directory:
# ./ftracetest test.d/kprobe/
Contributing new testcases
==========================
Copy test.d/template to your testcase (whose filename must have *.tc
extension) and rewrite the test description line.
* The working directory of the script is <debugfs>/tracing/.
* Take care with side effects as the tests are run with root privilege.
* The tests should not run for a long period of time (more than 1 min.)
These are to be unit tests.
* You can add a directory for your testcases under test.d/ if needed.
* The test cases should run on dash (busybox shell) for testing on
minimal cross-build environments.
* Note that the tests are run with "set -e" (errexit) option. If any
command fails, the test will be terminated immediately.
* The tests can return some result codes instead of pass or fail by
using exit_unresolved, exit_untested, exit_unsupported and exit_xfail.
Result code
===========
Ftracetest supports following result codes.
* PASS: The test succeeded as expected. The test which exits with 0 is
counted as passed test.
* FAIL: The test failed, but was expected to succeed. The test which exits
with !0 is counted as failed test.
* UNRESOLVED: The test produced unclear or intermidiate results.
for example, the test was interrupted
or the test depends on a previous test, which failed.
or the test was set up incorrectly
The test which is in above situation, must call exit_unresolved.
* UNTESTED: The test was not run, currently just a placeholder.
In this case, the test must call exit_untested.
* UNSUPPORTED: The test failed because of lack of feature.
In this case, the test must call exit_unsupported.
* XFAIL: The test failed, and was expected to fail.
To return XFAIL, call exit_xfail from the test.
There are some sample test scripts for result code under samples/.
You can also run samples as below:
# ./ftracetest samples/
TODO
====
* Fancy colored output :)
@@ -0,0 +1,29 @@
CONFIG_BPF_SYSCALL=y
CONFIG_DEBUG_INFO_BTF=y
CONFIG_DEBUG_INFO_DWARF4=y
CONFIG_EPROBE_EVENTS=y
CONFIG_FPROBE=y
CONFIG_FPROBE_EVENTS=y
CONFIG_FTRACE=y
CONFIG_FTRACE_SYSCALLS=y
CONFIG_FUNCTION_GRAPH_RETVAL=y
CONFIG_FUNCTION_PROFILER=y
CONFIG_HIST_TRIGGERS=y
CONFIG_IRQSOFF_TRACER=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KPROBES=y
CONFIG_KPROBE_EVENTS=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_PREEMPTIRQ_DELAY_TEST=m
CONFIG_PREEMPT_TRACER=y
CONFIG_PROBE_EVENTS_BTF_ARGS=y
CONFIG_SAMPLES=y
CONFIG_SAMPLE_FTRACE_DIRECT=m
CONFIG_SAMPLE_TRACE_EVENTS=m
CONFIG_SAMPLE_TRACE_PRINTK=m
CONFIG_SCHED_TRACER=y
CONFIG_STACK_TRACER=y
CONFIG_TRACER_SNAPSHOT=y
CONFIG_UPROBES=y
CONFIG_UPROBE_EVENTS=y
+545
View File
@@ -0,0 +1,545 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only
# ftracetest - Ftrace test shell scripts
#
# Copyright (C) Hitachi Ltd., 2014
# Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
#
usage() { # errno [message]
[ ! -z "$2" ] && echo $2
echo "Usage: ftracetest [options] [testcase(s)] [testcase-directory(s)]"
echo " Options:"
echo " -h|--help Show help message"
echo " -k|--keep Keep passed test logs"
echo " -K|--ktap Output in KTAP format"
echo " -v|--verbose Increase verbosity of test messages"
echo " -vv Alias of -v -v (Show all results in stdout)"
echo " -vvv Alias of -v -v -v (Show all commands immediately)"
echo " --fail-unsupported Treat UNSUPPORTED as a failure"
echo " --fail-unresolved Treat UNRESOLVED as a failure"
echo " -d|--debug Debug mode (trace all shell commands)"
echo " -l|--logdir <dir> Save logs on the <dir>"
echo " If <dir> is -, all logs output in console only"
echo " --rv Run RV selftests instead of ftrace ones"
exit $1
}
# default error
err_ret=1
# kselftest skip code is 4
err_skip=4
# umount required
UMOUNT_DIR=""
# cgroup RT scheduling prevents chrt commands from succeeding, which
# induces failures in test wakeup tests. Disable for the duration of
# the tests.
readonly sched_rt_runtime=/proc/sys/kernel/sched_rt_runtime_us
sched_rt_runtime_orig=$(cat $sched_rt_runtime)
setup() {
echo -1 > $sched_rt_runtime
}
cleanup() {
echo $sched_rt_runtime_orig > $sched_rt_runtime
if [ -n "${UMOUNT_DIR}" ]; then
umount ${UMOUNT_DIR} ||:
fi
}
errexit() { # message
echo "Error: $1" 1>&2
cleanup
exit $err_ret
}
# Ensuring user privilege
if [ `id -u` -ne 0 ]; then
errexit "this must be run by root user"
fi
setup
# Utilities
absdir() { # file_path
(cd `dirname $1`; pwd)
}
abspath() {
echo `absdir $1`/`basename $1`
}
find_testcases() { #directory
echo `find $1 -name \*.tc | sort`
}
parse_opts() { # opts
local OPT_TEST_CASES=
local OPT_TEST_DIR=
while [ ! -z "$1" ]; do
case "$1" in
--help|-h)
usage 0
;;
--keep|-k)
KEEP_LOG=1
shift 1
;;
--ktap|-K)
KTAP=1
shift 1
;;
--verbose|-v|-vv|-vvv)
if [ $VERBOSE -eq -1 ]; then
usage "--console can not use with --verbose"
fi
VERBOSE=$((VERBOSE + 1))
[ $1 = '-vv' ] && VERBOSE=$((VERBOSE + 1))
[ $1 = '-vvv' ] && VERBOSE=$((VERBOSE + 2))
shift 1
;;
--console)
if [ $VERBOSE -ne 0 ]; then
usage "--console can not use with --verbose"
fi
VERBOSE=-1
shift 1
;;
--debug|-d)
DEBUG=1
shift 1
;;
--stop-fail)
STOP_FAILURE=1
shift 1
;;
--fail-unsupported)
UNSUPPORTED_RESULT=1
shift 1
;;
--fail-unresolved)
UNRESOLVED_RESULT=1
shift 1
;;
--logdir|-l)
USER_LOG_DIR=$2
shift 2
;;
--rv)
RV_TEST=1
shift 1
;;
*.tc)
if [ -f "$1" ]; then
OPT_TEST_CASES="$OPT_TEST_CASES `abspath $1`"
shift 1
else
usage 1 "$1 is not a testcase"
fi
;;
*)
if [ -d "$1" ]; then
OPT_TEST_DIR=`abspath $1`
OPT_TEST_CASES="$OPT_TEST_CASES `find_testcases $OPT_TEST_DIR`"
shift 1
else
usage 1 "Invalid option ($1)"
fi
;;
esac
done
if [ -n "$OPT_TEST_CASES" ]; then
TEST_CASES=$OPT_TEST_CASES
fi
if [ -n "$OPT_TEST_DIR" -a -f "$OPT_TEST_DIR"/test.d/functions ]; then
TOP_DIR=$OPT_TEST_DIR
TEST_DIR=$TOP_DIR/test.d
fi
}
# Parameters
TRACING_DIR=`grep tracefs /proc/mounts | cut -f2 -d' ' | head -1`
if [ -z "$TRACING_DIR" ]; then
DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' ' | head -1`
if [ -z "$DEBUGFS_DIR" ]; then
# If tracefs exists, then so does /sys/kernel/tracing
if [ -d "/sys/kernel/tracing" ]; then
mount -t tracefs nodev /sys/kernel/tracing ||
errexit "Failed to mount /sys/kernel/tracing"
TRACING_DIR="/sys/kernel/tracing"
UMOUNT_DIR=${TRACING_DIR}
# If debugfs exists, then so does /sys/kernel/debug
elif [ -d "/sys/kernel/debug" ]; then
mount -t debugfs nodev /sys/kernel/debug ||
errexit "Failed to mount /sys/kernel/debug"
TRACING_DIR="/sys/kernel/debug/tracing"
UMOUNT_DIR=${TRACING_DIR}
else
err_ret=$err_skip
errexit "debugfs and tracefs are not configured in this kernel"
fi
else
TRACING_DIR="$DEBUGFS_DIR/tracing"
fi
fi
if [ ! -d "$TRACING_DIR" ]; then
err_ret=$err_skip
errexit "ftrace is not configured in this kernel"
fi
TOP_DIR=`absdir $0`
TEST_DIR=$TOP_DIR/test.d
TEST_CASES=`find_testcases $TEST_DIR`
USER_LOG_DIR=
KEEP_LOG=0
KTAP=0
DEBUG=0
VERBOSE=0
UNSUPPORTED_RESULT=0
UNRESOLVED_RESULT=0
STOP_FAILURE=0
RV_TEST=0
# Parse command-line options
parse_opts $*
[ $DEBUG -ne 0 ] && set -x
# TOP_DIR can be changed for rv. Setting log directory.
LOG_TOP_DIR=$TOP_DIR/logs
LOG_DATE=`date +%Y%m%d-%H%M%S`
if [ -n "$USER_LOG_DIR" ]; then
LOG_DIR=$USER_LOG_DIR
LINK_PTR=
else
LOG_DIR=$LOG_TOP_DIR/$LOG_DATE/
LINK_PTR=$LOG_TOP_DIR/latest
fi
if [ $RV_TEST -ne 0 ]; then
TRACING_DIR=$TRACING_DIR/rv
if [ ! -d "$TRACING_DIR" ]; then
err_ret=$err_skip
errexit "rv is not configured in this kernel"
fi
fi
# Preparing logs
if [ "x$LOG_DIR" = "x-" ]; then
LOG_FILE=
date
else
LOG_FILE=$LOG_DIR/ftracetest.log
mkdir -p $LOG_DIR || errexit "Failed to make a log directory: $LOG_DIR"
date > $LOG_FILE
if [ "x-$LINK_PTR" != "x-" ]; then
unlink $LINK_PTR
ln -fs $LOG_DATE $LINK_PTR
fi
fi
# Define text colors
# Check available colors on the terminal, if any
ncolors=`tput colors 2>/dev/null || echo 0`
color_reset=
color_red=
color_green=
color_blue=
# If stdout exists and number of colors is eight or more, use them
if [ -t 1 -a "$ncolors" -ge 8 ]; then
color_reset="\033[0m"
color_red="\033[31m"
color_green="\033[32m"
color_blue="\033[34m"
fi
strip_esc() {
# busybox sed implementation doesn't accept "\x1B", so use [:cntrl:] instead.
sed -E "s/[[:cntrl:]]\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g"
}
prlog() { # messages
newline="\n"
if [ "$1" = "-n" ] ; then
newline=
shift
fi
[ "$KTAP" != "1" ] && printf "$*$newline"
[ "$LOG_FILE" ] && printf "$*$newline" | strip_esc >> $LOG_FILE
}
catlog() { #file
if [ "${KTAP}" = "1" ]; then
cat $1 | while read line ; do
echo "# $line"
done
else
cat $1
fi
[ "$LOG_FILE" ] && cat $1 | strip_esc >> $LOG_FILE
}
prlog "=== Ftrace unit tests ==="
# Testcase management
# Test result codes - Dejagnu extended code
PASS=0 # The test succeeded.
FAIL=1 # The test failed, but was expected to succeed.
UNRESOLVED=2 # The test produced indeterminate results. (e.g. interrupted)
UNTESTED=3 # The test was not run, currently just a placeholder.
UNSUPPORTED=4 # The test failed because of lack of feature.
XFAIL=5 # The test failed, and was expected to fail.
# Accumulations
PASSED_CASES=
FAILED_CASES=
UNRESOLVED_CASES=
UNTESTED_CASES=
UNSUPPORTED_CASES=
XFAILED_CASES=
UNDEFINED_CASES=
TOTAL_RESULT=0
INSTANCE=
CASENO=0
CASENAME=
testcase() { # testfile
CASENO=$((CASENO+1))
CASENAME=`grep "^#[ \t]*description:" $1 | cut -f2- -d:`
}
checkreq() { # testfile
requires=`grep "^#[ \t]*requires:" $1 | cut -f2- -d:`
# Use eval to pass quoted-patterns correctly.
eval check_requires "$requires"
}
test_on_instance() { # testfile
grep -q "^#[ \t]*flags:.*instance" $1
}
ktaptest() { # result comment
if [ "$KTAP" != "1" ]; then
return
fi
local result=
if [ "$1" = "1" ]; then
result="ok"
else
result="not ok"
fi
shift
local comment=$*
if [ "$comment" != "" ]; then
comment="# $comment"
fi
echo $result $CASENO $INSTANCE$CASENAME $comment
}
eval_result() { # sigval
case $1 in
$PASS)
prlog " [${color_green}PASS${color_reset}]"
ktaptest 1
PASSED_CASES="$PASSED_CASES $CASENO"
return 0
;;
$FAIL)
prlog " [${color_red}FAIL${color_reset}]"
ktaptest 0
FAILED_CASES="$FAILED_CASES $CASENO"
return 1 # this is a bug.
;;
$UNRESOLVED)
prlog " [${color_blue}UNRESOLVED${color_reset}]"
ktaptest 0 UNRESOLVED
UNRESOLVED_CASES="$UNRESOLVED_CASES $CASENO"
return $UNRESOLVED_RESULT # depends on use case
;;
$UNTESTED)
prlog " [${color_blue}UNTESTED${color_reset}]"
ktaptest 1 SKIP
UNTESTED_CASES="$UNTESTED_CASES $CASENO"
return 0
;;
$UNSUPPORTED)
prlog " [${color_blue}UNSUPPORTED${color_reset}]"
ktaptest 1 SKIP
UNSUPPORTED_CASES="$UNSUPPORTED_CASES $CASENO"
return $UNSUPPORTED_RESULT # depends on use case
;;
$XFAIL)
prlog " [${color_green}XFAIL${color_reset}]"
ktaptest 1 XFAIL
XFAILED_CASES="$XFAILED_CASES $CASENO"
return 0
;;
*)
prlog " [${color_blue}UNDEFINED${color_reset}]"
ktaptest 0 error
UNDEFINED_CASES="$UNDEFINED_CASES $CASENO"
return 1 # this must be a test bug
;;
esac
}
# Signal handling for result codes
SIG_RESULT=
SIG_BASE=36 # Use realtime signals
SIG_PID=$$
exit_pass () {
exit 0
}
SIG_FAIL=$((SIG_BASE + FAIL))
exit_fail () {
exit 1
}
trap 'SIG_RESULT=$FAIL' $SIG_FAIL
SIG_UNRESOLVED=$((SIG_BASE + UNRESOLVED))
exit_unresolved () {
kill -s $SIG_UNRESOLVED $SIG_PID
exit 0
}
trap 'SIG_RESULT=$UNRESOLVED' $SIG_UNRESOLVED
SIG_UNTESTED=$((SIG_BASE + UNTESTED))
exit_untested () {
kill -s $SIG_UNTESTED $SIG_PID
exit 0
}
trap 'SIG_RESULT=$UNTESTED' $SIG_UNTESTED
SIG_UNSUPPORTED=$((SIG_BASE + UNSUPPORTED))
exit_unsupported () {
kill -s $SIG_UNSUPPORTED $SIG_PID
exit 0
}
trap 'SIG_RESULT=$UNSUPPORTED' $SIG_UNSUPPORTED
SIG_XFAIL=$((SIG_BASE + XFAIL))
exit_xfail () {
kill -s $SIG_XFAIL $SIG_PID
exit 0
}
trap 'SIG_RESULT=$XFAIL' $SIG_XFAIL
__run_test() { # testfile
# setup PID and PPID, $$ is not updated.
(cd $TRACING_DIR; read PID _ < /proc/self/stat; set -e; set -x;
checkreq $1; initialize_system; . $1)
[ $? -ne 0 ] && kill -s $SIG_FAIL $SIG_PID
}
# Run one test case
run_test() { # testfile
local testname=`basename $1`
testcase $1
prlog -n "[$CASENO]$INSTANCE$CASENAME"
if [ ! -z "$LOG_FILE" ] ; then
local testlog=`mktemp $LOG_DIR/${CASENO}-${testname}-log.XXXXXX`
else
local testlog=/proc/self/fd/1
fi
export TMPDIR=`mktemp -d /tmp/ftracetest-dir.XXXXXX`
export FTRACETEST_ROOT=$TOP_DIR
echo "execute$INSTANCE: "$1 > $testlog
SIG_RESULT=0
if [ $VERBOSE -eq -1 ]; then
__run_test $1
elif [ -z "$LOG_FILE" ]; then
__run_test $1 2>&1
elif [ $VERBOSE -ge 3 ]; then
__run_test $1 | tee -a $testlog 2>&1
elif [ $VERBOSE -eq 2 ]; then
__run_test $1 2>> $testlog | tee -a $testlog
else
__run_test $1 >> $testlog 2>&1
fi
eval_result $SIG_RESULT
if [ $? -eq 0 ]; then
# Remove test log if the test was done as it was expected.
[ $KEEP_LOG -eq 0 -a ! -z "$LOG_FILE" ] && rm $testlog
else
[ $VERBOSE -eq 1 -o $VERBOSE -eq 2 ] && catlog $testlog
TOTAL_RESULT=1
fi
rm -rf $TMPDIR
}
# load in the helper functions
. $TEST_DIR/functions
if [ "$KTAP" = "1" ]; then
echo "TAP version 13"
casecount=`echo $TEST_CASES | wc -w`
for t in $TEST_CASES; do
test_on_instance $t || continue
casecount=$((casecount+1))
done
echo "1..${casecount}"
fi
# Main loop
for t in $TEST_CASES; do
run_test $t
if [ $STOP_FAILURE -ne 0 -a $TOTAL_RESULT -ne 0 ]; then
echo "A failure detected. Stop test."
exit 1
fi
done
# Test on instance loop
(cd $TRACING_DIR; initialize_system)
INSTANCE=" (instance) "
for t in $TEST_CASES; do
test_on_instance $t || continue
SAVED_TRACING_DIR=$TRACING_DIR
export TRACING_DIR=`mktemp -d $TRACING_DIR/instances/ftracetest.XXXXXX`
run_test $t
rmdir $TRACING_DIR
TRACING_DIR=$SAVED_TRACING_DIR
if [ $STOP_FAILURE -ne 0 -a $TOTAL_RESULT -ne 0 ]; then
echo "A failure detected. Stop test."
exit 1
fi
done
(cd $TRACING_DIR; finish_system) # for cleanup
prlog ""
prlog "# of passed: " `echo $PASSED_CASES | wc -w`
prlog "# of failed: " `echo $FAILED_CASES | wc -w`
prlog "# of unresolved: " `echo $UNRESOLVED_CASES | wc -w`
prlog "# of untested: " `echo $UNTESTED_CASES | wc -w`
prlog "# of unsupported: " `echo $UNSUPPORTED_CASES | wc -w`
prlog "# of xfailed: " `echo $XFAILED_CASES | wc -w`
prlog "# of undefined(test bug): " `echo $UNDEFINED_CASES | wc -w`
if [ "$KTAP" = "1" ]; then
echo -n "# Totals:"
echo -n " pass:"`echo $PASSED_CASES | wc -w`
echo -n " fail:"`echo $FAILED_CASES | wc -w`
echo -n " xfail:"`echo $XFAILED_CASES | wc -w`
echo -n " xpass:0"
echo -n " skip:"`echo $UNTESTED_CASES $UNSUPPORTED_CASES | wc -w`
echo -n " error:"`echo $UNRESOLVED_CASES $UNDEFINED_CASES | wc -w`
echo
fi
cleanup
# if no error, return 0
exit $TOTAL_RESULT
@@ -0,0 +1,8 @@
#!/bin/sh -e
# SPDX-License-Identifier: GPL-2.0-only
#
# ftracetest-ktap: Wrapper to integrate ftracetest with the kselftest runner
#
# Copyright (C) Arm Ltd., 2023
./ftracetest -K -v
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Simple poll on a file.
*
* Copyright (c) 2024 Google LLC.
*/
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define BUFSIZE 4096
/*
* Usage:
* poll [-I|-P] [-t timeout] FILE
*/
int main(int argc, char *argv[])
{
struct pollfd pfd = {.events = POLLIN};
char buf[BUFSIZE];
int timeout = -1;
int ret, opt;
while ((opt = getopt(argc, argv, "IPt:")) != -1) {
switch (opt) {
case 'I':
pfd.events = POLLIN;
break;
case 'P':
pfd.events = POLLPRI;
break;
case 't':
timeout = atoi(optarg);
break;
default:
fprintf(stderr, "Usage: %s [-I|-P] [-t timeout] FILE\n",
argv[0]);
return -1;
}
}
if (optind >= argc) {
fprintf(stderr, "Error: Polling file is not specified\n");
return -1;
}
pfd.fd = open(argv[optind], O_RDONLY);
if (pfd.fd < 0) {
fprintf(stderr, "failed to open %s", argv[optind]);
perror("open");
return -1;
}
/* Reset poll by read if POLLIN is specified. */
if (pfd.events & POLLIN)
do {} while (read(pfd.fd, buf, BUFSIZE) == BUFSIZE);
ret = poll(&pfd, 1, timeout);
if (ret < 0 && errno != EINTR) {
perror("poll");
return -1;
}
close(pfd.fd);
/* If timeout happned (ret == 0), exit code is 1 */
if (ret == 0)
return 1;
return 0;
}
@@ -0,0 +1,4 @@
#!/bin/sh
# description: failure-case example
cat non-exist-file
echo "this is not executed"
@@ -0,0 +1,3 @@
#!/bin/sh
# description: pass-case example
return 0
@@ -0,0 +1,4 @@
#!/bin/sh
# description: unresolved-case example
trap exit_unresolved INT
kill -INT $PID
@@ -0,0 +1,3 @@
#!/bin/sh
# description: unsupported-case example
exit_unsupported
@@ -0,0 +1,3 @@
#!/bin/sh
# description: untested-case example
exit_untested
@@ -0,0 +1,3 @@
#!/bin/sh
# description: xfail-case example
cat non-exist-file || exit_xfail
@@ -0,0 +1 @@
timeout=0
@@ -0,0 +1,3 @@
#!/bin/sh
# description: Basic trace file check
test -f README -a -f trace -a -f tracing_on -a -f trace_pipe
@@ -0,0 +1,9 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Basic test for tracers
# flags: instance
test -f available_tracers
for t in `cat available_tracers`; do
echo $t > current_tracer
done
echo nop > current_tracer
@@ -0,0 +1,10 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Basic trace clock test
# flags: instance
test -f trace_clock
for c in `cat trace_clock | tr -d \[\]`; do
echo $c > trace_clock
grep '\['$c'\]' trace_clock
done
echo local > trace_clock
@@ -0,0 +1,5 @@
#!/bin/sh
# description: Basic event tracing check
test -f available_events -a -f set_event -a -d events
# check scheduler events are available
grep -q sched available_events && exit_pass || exit_fail
@@ -0,0 +1,101 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Test tracefs GID mount option
# requires: "[gid=<gid>]":README
fail() {
local msg="$1"
echo "FAILED: $msg"
exit_fail
}
find_alternate_gid() {
local original_gid="$1"
tac /etc/group | grep -v ":$original_gid:" | head -1 | cut -d: -f3
}
remount_tracefs_with_options() {
local mount_point="$1"
local options="$2"
mount -t tracefs -o "remount,$options" nodev "$mount_point"
setup
}
unmount_tracefs() {
local mount_point="$1"
# Need to make sure the mount isn't busy so that we can umount it
(cd $mount_point; finish_system;)
cleanup
}
create_instance() {
local mount_point="$1"
local instance="$mount_point/instances/$(mktemp -u test-XXXXXX)"
mkdir "$instance"
echo "$instance"
}
remove_instance() {
local instance="$1"
rmdir "$instance"
}
check_gid() {
local mount_point="$1"
local expected_gid="$2"
echo "Checking permission group ..."
cd "$mount_point"
for file in "." "events" "events/sched" "events/sched/sched_switch" "events/sched/sched_switch/enable"; do
local gid=`stat -c "%g" $file`
if [ "$gid" -ne "$expected_gid" ]; then
cd - # Return to the previous working directory (tracefs root)
fail "$(realpath $file): Expected group $expected_gid; Got group $gid"
fi
done
cd - # Return to the previous working directory (tracefs root)
}
test_gid_mount_option() {
local mount_point=$(get_mount_point)
local mount_options=$(get_mnt_options "$mount_point")
local original_group=$(stat -c "%g" .)
local other_group=$(find_alternate_gid "$original_group")
# Set up mount options with new GID for testing
local new_options=`echo "$mount_options" | sed -e "s/gid=[0-9]*/gid=$other_group/"`
if [ "$new_options" = "$mount_options" ]; then
new_options="$mount_options,gid=$other_group"
mount_options="$mount_options,gid=$original_group"
fi
# Unmount existing tracefs instance and mount with new GID
unmount_tracefs "$mount_point"
remount_tracefs_with_options "$mount_point" "$new_options"
check_gid "$mount_point" "$other_group"
# Check that files created after the mount inherit the GID
local instance=$(create_instance "$mount_point")
check_gid "$instance" "$other_group"
remove_instance "$instance"
# Unmount and remount with the original GID
unmount_tracefs "$mount_point"
remount_tracefs_with_options "$mount_point" "$mount_options"
check_gid "$mount_point" "$original_group"
}
test_gid_mount_option
exit 0
@@ -0,0 +1,22 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Change the ringbuffer size
# flags: instance
rb_size_test() {
ORIG=`cat buffer_size_kb`
expr $ORIG / 2 > buffer_size_kb
expr $ORIG \* 2 > buffer_size_kb
echo $ORIG > buffer_size_kb
}
rb_size_test
: "If per-cpu buffer is supported, imbalance it"
if [ -d per_cpu/cpu0 ]; then
cd per_cpu/cpu0
rb_size_test
fi
@@ -0,0 +1,95 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Change the ringbuffer sub-buffer size
# requires: buffer_subbuf_size_kb
# flags: instance
get_buffer_data_size() {
sed -ne 's/^.*data.*size:\([0-9][0-9]*\).*/\1/p' events/header_page
}
get_buffer_data_offset() {
sed -ne 's/^.*data.*offset:\([0-9][0-9]*\).*/\1/p' events/header_page
}
get_event_header_size() {
type_len=`sed -ne 's/^.*type_len.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
time_len=`sed -ne 's/^.*time_delta.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
array_len=`sed -ne 's/^.*array.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
total_bits=$((type_len+time_len+array_len))
total_bits=$((total_bits+7))
echo $((total_bits/8))
}
get_print_event_buf_offset() {
sed -ne 's/^.*buf.*offset:\([0-9][0-9]*\).*/\1/p' events/ftrace/print/format
}
event_header_size=`get_event_header_size`
print_header_size=`get_print_event_buf_offset`
data_offset=`get_buffer_data_offset`
marker_meta=$((event_header_size+print_header_size))
make_str() {
cnt=$1
printf -- 'X%.0s' $(seq $cnt)
}
write_buffer() {
size=$1
str=`make_str $size`
# clear the buffer
echo > trace
# write the string into the marker
echo $str > trace_marker
echo $str
}
test_buffer() {
size_kb=$1
page_size=$((size_kb*1024))
size=`get_buffer_data_size`
# the size must be greater than or equal to page_size - data_offset
page_size=$((page_size-data_offset))
if [ $size -lt $page_size ]; then
exit fail
fi
# Now add a little more the meta data overhead will overflow
str=`write_buffer $size`
# Make sure the line was broken
new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; exit}' trace`
if [ "$new_str" = "$str" ]; then
exit fail;
fi
# Make sure the entire line can be found
new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; }' trace`
if [ "$new_str" != "$str" ]; then
exit fail;
fi
}
ORIG=`cat buffer_subbuf_size_kb`
# Could test bigger sizes than 32K, but then creating the string
# to write into the ring buffer takes too long
for a in 4 8 16 32 ; do
echo $a > buffer_subbuf_size_kb
test_buffer $a
done
echo $ORIG > buffer_subbuf_size_kb
@@ -0,0 +1,27 @@
#!/bin/sh
# description: Snapshot and tracing setting
# requires: snapshot
# flags: instance
echo "Set tracing off"
echo 0 > tracing_on
echo "Allocate and take a snapshot"
echo 1 > snapshot
# Since trace buffer is empty, snapshot is also empty, but allocated
grep -q "Snapshot is allocated" snapshot
echo "Ensure keep tracing off"
test `cat tracing_on` -eq 0
echo "Set tracing on"
echo 1 > tracing_on
echo "Take a snapshot again"
echo 1 > snapshot
echo "Ensure keep tracing on"
test `cat tracing_on` -eq 1
exit 0
@@ -0,0 +1,31 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Snapshot and tracing_cpumask
# requires: trace_marker tracing_cpumask snapshot
# flags: instance
# This testcase is constrived to reproduce a problem that the cpu buffers
# become unavailable which is due to 'record_disabled' of array_buffer and
# max_buffer being messed up.
# Store origin cpumask
ORIG_CPUMASK=`cat tracing_cpumask`
# Stop tracing all cpu
echo 0 > tracing_cpumask
# Take a snapshot of the main buffer
echo 1 > snapshot
# Restore origin cpumask, note that there should be some cpus being traced
echo ${ORIG_CPUMASK} > tracing_cpumask
# Set tracing on
echo 1 > tracing_on
# Write a log into buffer
echo "test input 1" > trace_marker
# Ensure the log writed so that cpu buffers are still available
grep -q "test input 1" trace
exit 0
@@ -0,0 +1,122 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Test file and directory ownership changes for eventfs
# requires: "[gid=<gid>]":README
original_group=`stat -c "%g" .`
original_owner=`stat -c "%u" .`
mount_point=$(get_mount_point)
mount_options=$(get_mnt_options "$mount_point")
# find another owner and group that is not the original
other_group=`tac /etc/group | grep -v ":$original_group:" | head -1 | cut -d: -f3`
other_owner=`tac /etc/passwd | grep -v ":$original_owner:" | head -1 | cut -d: -f3`
# Remove any group ownership already
new_options=`echo "$mount_options" | sed -e "s/gid=[0-9]*/gid=$other_group/"`
if [ "$new_options" = "$mount_options" ]; then
new_options="$mount_options,gid=$other_group"
mount_options="$mount_options,gid=$original_group"
fi
canary="events/timer events/timer/timer_cancel events/timer/timer_cancel/format"
test() {
file=$1
test_group=$2
owner=`stat -c "%u" $file`
group=`stat -c "%g" $file`
echo "testing $file $owner=$original_owner and $group=$test_group"
if [ $owner -ne $original_owner ]; then
exit_fail
fi
if [ $group -ne $test_group ]; then
exit_fail
fi
# Note, the remount does not update ownership so test going to and from owner
echo "test owner $file to $other_owner"
chown $other_owner $file
owner=`stat -c "%u" $file`
if [ $owner -ne $other_owner ]; then
exit_fail
fi
chown $original_owner $file
owner=`stat -c "%u" $file`
if [ $owner -ne $original_owner ]; then
exit_fail
fi
}
run_tests() {
for d in "." "events" "events/sched" "events/sched/sched_switch" "events/sched/sched_switch/enable" $canary; do
test "$d" $other_group
done
chgrp $original_group events
test "events" $original_group
for d in "." "events/sched" "events/sched/sched_switch" "events/sched/sched_switch/enable" $canary; do
test "$d" $other_group
done
chgrp $original_group events/sched
test "events/sched" $original_group
for d in "." "events/sched/sched_switch" "events/sched/sched_switch/enable" $canary; do
test "$d" $other_group
done
chgrp $original_group events/sched/sched_switch
test "events/sched/sched_switch" $original_group
for d in "." "events/sched/sched_switch/enable" $canary; do
test "$d" $other_group
done
chgrp $original_group events/sched/sched_switch/enable
test "events/sched/sched_switch/enable" $original_group
for d in "." $canary; do
test "$d" $other_group
done
}
# Run the tests twice as leftovers can cause issues
for loop in 1 2 ; do
echo "Running iteration $loop"
mount -o remount,"$new_options" .
run_tests
mount -o remount,"$mount_options" .
for d in "." "events" "events/sched" "events/sched/sched_switch" "events/sched/sched_switch/enable" $canary; do
test "$d" $original_group
done
# check instances as well
chgrp $other_group instances
instance="$(mktemp -u test-XXXXXX)"
mkdir instances/$instance
cd instances/$instance
run_tests
cd ../..
rmdir instances/$instance
chgrp $original_group instances
done
exit 0
@@ -0,0 +1,82 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Basic tests on writing to trace_marker
# requires: trace_marker
# flags: instance
get_buffer_data_size() {
sed -ne 's/^.*data.*size:\([0-9][0-9]*\).*/\1/p' events/header_page
}
get_buffer_data_offset() {
sed -ne 's/^.*data.*offset:\([0-9][0-9]*\).*/\1/p' events/header_page
}
get_event_header_size() {
type_len=`sed -ne 's/^.*type_len.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
time_len=`sed -ne 's/^.*time_delta.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
array_len=`sed -ne 's/^.*array.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
total_bits=$((type_len+time_len+array_len))
total_bits=$((total_bits+7))
echo $((total_bits/8))
}
get_print_event_buf_offset() {
sed -ne 's/^.*buf.*offset:\([0-9][0-9]*\).*/\1/p' events/ftrace/print/format
}
event_header_size=`get_event_header_size`
print_header_size=`get_print_event_buf_offset`
data_offset=`get_buffer_data_offset`
marker_meta=$((event_header_size+print_header_size))
make_str() {
cnt=$1
# subtract two for \n\0 as marker adds these
cnt=$((cnt-2))
printf -- 'X%.0s' $(seq $cnt)
}
write_buffer() {
size=$1
str=`make_str $size`
# clear the buffer
echo > trace
# write the string into the marker
echo -n $str > trace_marker
echo $str
}
test_buffer() {
size=`get_buffer_data_size`
oneline_size=$((size-marker_meta))
echo size = $size
echo meta size = $marker_meta
# Now add a little more the meta data overhead will overflow
str=`write_buffer $size`
# Make sure the line was broken
new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; exit}' trace`
if [ "$new_str" = "$str" ]; then
exit fail;
fi
# Make sure the entire line can be found
new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; }' trace`
if [ "$new_str" != "$str" ]; then
exit fail;
fi
}
test_buffer
@@ -0,0 +1,133 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Basic tests on writing to trace_marker_raw
# requires: trace_marker_raw
# flags: instance
check_awk_strtonum || exit_unresolved
is_little_endian() {
if lscpu | grep -q 'Little Endian'; then
echo 1;
else
echo 0;
fi
}
little=`is_little_endian`
make_str() {
id=$1
cnt=$2
if [ $little -eq 1 ]; then
val=`printf "\\%03o\\%03o\\%03o\\%03o" \
$(($id & 0xff)) \
$((($id >> 8) & 0xff)) \
$((($id >> 16) & 0xff)) \
$((($id >> 24) & 0xff))`
else
val=`printf "\\%03o\\%03o\\%03o\\%03o" \
$((($id >> 24) & 0xff)) \
$((($id >> 16) & 0xff)) \
$((($id >> 8) & 0xff)) \
$(($id & 0xff))`
fi
data=`printf -- 'X%.0s' $(seq $cnt)`
# Return escape-sequence text (e.g. "\003\000..."); the caller
# converts to binary. Shell command substitution strips NUL bytes,
# so the binary form cannot survive being captured into a variable.
printf '%s' "${val}${data}"
}
write_buffer() {
id=$1
size=$2
str=`make_str $id $size`
len=`printf "$str" | wc -c`
# Pipe through dd to ensure a single atomic write() syscall
# on architectures with 64K pages, where shell's printf builtin
# uses stdio buffering which may split the output into multiple
# writes.
printf "$str" | dd of=trace_marker_raw bs=$len iflag=fullblock
}
test_multiple_writes() {
# Write a bunch of data where the id is the count of
# data to write
for i in `seq 1 10` `seq 101 110` `seq 1001 1010`; do
write_buffer $i $i
done
# add a little buffer
echo stop > trace_marker
# Check to make sure the number of entries is the id (rounded up by 4)
awk '/.*: # [0-9a-f]* / {
print;
cnt = -1;
for (i = 0; i < NF; i++) {
# The counter is after the "#" marker
if ( $i == "#" ) {
i++;
cnt = strtonum("0x" $i);
num = NF - (i + 1);
# The number of items is always rounded up by 4
cnt2 = int((cnt + 3) / 4) * 4;
if (cnt2 != num) {
exit 1;
}
break;
}
}
}
// { if (NR > 30) { exit 0; } } ' trace_pipe;
}
get_buffer_data_size() {
sed -ne 's/^.*data.*size:\([0-9][0-9]*\).*/\1/p' events/header_page
}
test_buffer() {
# The id must be four bytes, test that 3 bytes fails a write
if echo -n abc > ./trace_marker_raw ; then
echo "Too small of write expected to fail but did not"
echo ${ORIG} > buffer_size_kb
exit_fail
fi
size=`get_buffer_data_size`
echo size = $size
# Now add a little more than what it can handle
if write_buffer 0xdeadbeef $size ; then
echo "Too big of write expected to fail but did not"
echo ${ORIG} > buffer_size_kb
exit_fail
fi
}
ORIG=`cat buffer_size_kb`
# test_multiple_writes test needs at least 12KB buffer
NEW_SIZE=12
if [ ${ORIG} -lt ${NEW_SIZE} ]; then
echo ${NEW_SIZE} > buffer_size_kb
fi
test_buffer
if ! test_multiple_writes; then
echo ${ORIG} > buffer_size_kb
exit_fail
fi
echo ${ORIG} > buffer_size_kb
@@ -0,0 +1,15 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: trace_pipe and trace_marker
# requires: trace_marker
# flags: instance
echo "test input 1" > trace_marker
: "trace interface never consume the ring buffer"
grep -q "test input 1" trace
grep -q "test input 1" trace
: "trace interface never consume the ring buffer"
head -n 1 trace_pipe | grep -q "test input 1"
! grep -q "test input 1" trace
@@ -0,0 +1,69 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Test ftrace direct functions against tracers
rmmod ftrace-direct ||:
if ! modprobe ftrace-direct ; then
echo "No ftrace-direct sample module - please make CONFIG_SAMPLE_FTRACE_DIRECT=m"
exit_unresolved;
fi
echo "Let the module run a little"
sleep 1
grep -q "my_direct_func: waking up" trace
rmmod ftrace-direct
test_tracer() {
tracer=$1
# tracer -> direct -> no direct > no tracer
echo $tracer > current_tracer
modprobe ftrace-direct
rmmod ftrace-direct
echo nop > current_tracer
# tracer -> direct -> no tracer > no direct
echo $tracer > current_tracer
modprobe ftrace-direct
echo nop > current_tracer
rmmod ftrace-direct
# direct -> tracer -> no tracer > no direct
modprobe ftrace-direct
echo $tracer > current_tracer
echo nop > current_tracer
rmmod ftrace-direct
# direct -> tracer -> no direct > no notracer
modprobe ftrace-direct
echo $tracer > current_tracer
rmmod ftrace-direct
echo nop > current_tracer
}
for t in `cat available_tracers`; do
if [ "$t" != "nop" ]; then
test_tracer $t
fi
done
echo nop > current_tracer
rmmod ftrace-direct ||:
# Now do the same thing with another direct function registered
echo "Running with another ftrace direct function"
rmmod ftrace-direct-too ||:
modprobe ftrace-direct-too
for t in `cat available_tracers`; do
if [ "$t" != "nop" ]; then
test_tracer $t
fi
done
echo nop > current_tracer
rmmod ftrace-direct ||:
rmmod ftrace-direct-too ||:
@@ -0,0 +1,80 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Test ftrace direct functions against kprobes
# requires: kprobe_events
rmmod ftrace-direct ||:
if ! modprobe ftrace-direct ; then
echo "No ftrace-direct sample module - please build with CONFIG_SAMPLE_FTRACE_DIRECT=m"
exit_unresolved;
fi
echo "Let the module run a little"
sleep 1
grep -q "my_direct_func: waking up" trace
rmmod ftrace-direct
echo 'p:kwake wake_up_process task=$arg1' > kprobe_events
start_direct() {
echo > trace
modprobe ftrace-direct
sleep 1
grep -q "my_direct_func: waking up" trace
}
stop_direct() {
rmmod ftrace-direct
}
enable_probe() {
echo > trace
echo 1 > events/kprobes/kwake/enable
sleep 1
grep -q "kwake:" trace
}
disable_probe() {
echo 0 > events/kprobes/kwake/enable
}
test_kprobes() {
# probe -> direct -> no direct > no probe
enable_probe
start_direct
stop_direct
disable_probe
# probe -> direct -> no probe > no direct
enable_probe
start_direct
disable_probe
stop_direct
# direct -> probe -> no probe > no direct
start_direct
enable_probe
disable_probe
stop_direct
# direct -> probe -> no direct > no noprobe
start_direct
enable_probe
stop_direct
disable_probe
}
test_kprobes
# Now do this with a second registered direct function
echo "Running with another ftrace direct function"
modprobe ftrace-direct-too
test_kprobes
rmmod ftrace-direct-too
echo > kprobe_events
@@ -0,0 +1,78 @@
#!/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=
FIELDS=
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 grep -qF "<argname>[->field[->field|.field...]]" README ; then
FIELDS=yes
fi
if [ -z "$KPROBES" -a -z "$FPROBES" ] ; then
exit_unsupported
fi
echo 0 > events/enable
echo > dynamic_events
TP=kfree
TP2=kmem_cache_alloc
TP3=getname_flags
TP4=sched_wakeup
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 [ "$FIELDS" -a "$FPROBES" ] ; then
echo "t:tpevent ${TP2} obj_size=s->object_size" >> dynamic_events
echo "f:fpevent ${TP3}%return path=\$retval->name:string" >> dynamic_events
echo "t:tpevent2 ${TP4} p->se.group_node.next->prev" >> dynamic_events
grep -q "tpevent .*obj_size=s->object_size" dynamic_events
grep -q "fpevent.*path=\$retval->name:string" dynamic_events
grep -q 'tpevent2 .*p->se.group_node.next->prev' dynamic_events
echo > dynamic_events
fi
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
@@ -0,0 +1,91 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove eprobe events
# requires: dynamic_events events/syscalls/sys_enter_chdir "<attached-group>.<attached-event> [<args>]":README
echo 0 > events/enable
clear_dynamic_events
SYSTEM="syscalls"
EVENT="sys_enter_chdir"
FIELD="filename"
EPROBE="eprobe_chdir"
OPTIONS="file=+0(\$filename):ustring"
echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
grep -q "$EPROBE" dynamic_events
test -d events/eprobes/$EPROBE
echo 1 > events/eprobes/$EPROBE/enable
cd /sys/kernel/tracing
echo 0 > events/eprobes/$EPROBE/enable
content=`grep -e 'file="/sys/kernel/tracing"\|(fault)' trace`
if [ -z "$content" ]; then
exit_fail
fi
echo "-:$EPROBE" >> dynamic_events
! grep -q "$EPROBE" dynamic_events
! test -d events/eprobes/$EPROBE
# test various ways to remove the probe (already tested with just event name)
# With group name
echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
grep -q "$EPROBE" dynamic_events
test -d events/eprobes/$EPROBE
echo "-:eprobes/$EPROBE" >> dynamic_events
! grep -q "$EPROBE" dynamic_events
! test -d events/eprobes/$EPROBE
# With group name and system/event
echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
grep -q "$EPROBE" dynamic_events
test -d events/eprobes/$EPROBE
echo "-:eprobes/$EPROBE $SYSTEM/$EVENT" >> dynamic_events
! grep -q "$EPROBE" dynamic_events
! test -d events/eprobes/$EPROBE
# With just event name and system/event
echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
grep -q "$EPROBE" dynamic_events
test -d events/eprobes/$EPROBE
echo "-:$EPROBE $SYSTEM/$EVENT" >> dynamic_events
! grep -q "$EPROBE" dynamic_events
! test -d events/eprobes/$EPROBE
# With just event name and system/event and options
echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
grep -q "$EPROBE" dynamic_events
test -d events/eprobes/$EPROBE
echo "-:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
! grep -q "$EPROBE" dynamic_events
! test -d events/eprobes/$EPROBE
# With group name and system/event and options
echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
grep -q "$EPROBE" dynamic_events
test -d events/eprobes/$EPROBE
echo "-:eprobes/$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
! grep -q "$EPROBE" dynamic_events
! test -d events/eprobes/$EPROBE
# Finally make sure what is in the dynamic_events file clears it too
echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
LINE=`sed -e '/$EPROBE/s/^e/-/' < dynamic_events`
test -d events/eprobes/$EPROBE
echo "-:eprobes/$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
! grep -q "$EPROBE" dynamic_events
! test -d events/eprobes/$EPROBE
if grep -q "e\[:\[<group>/]\[<event>]]" README; then
echo "e:mygroup/ $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
test -d events/mygroup
echo "-:mygroup/" >> dynamic_events
! test -d events/mygroup
fi
clear_trace
@@ -0,0 +1,82 @@
#!/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
PLACE2="kmem_cache_free"
PLACE3="schedule_timeout"
# Some functions may have BPF programs attached, therefore
# count already enabled_functions before tests start
ocnt=`cat enabled_functions | wc -l`
echo "f:myevent1 $PLACE" >> dynamic_events
echo "f:myevent2 $PLACE%return" >> dynamic_events
# add another event
echo "f:myevent3 $PLACE2" >> dynamic_events
grep -q myevent1 dynamic_events
grep -q myevent2 dynamic_events
grep -q myevent3 dynamic_events
test -d events/fprobes/myevent1
test -d events/fprobes/myevent2
echo 1 > events/fprobes/myevent1/enable
# Make sure the event is attached.
grep -q $PLACE enabled_functions
cnt=`cat enabled_functions | wc -l`
if [ $cnt -eq $ocnt ]; then
exit_fail
fi
echo 1 > events/fprobes/myevent2/enable
cnt2=`cat enabled_functions | wc -l`
echo 1 > events/fprobes/myevent3/enable
# If the function is different, the attached function should be increased
grep -q $PLACE2 enabled_functions
cnt=`cat enabled_functions | wc -l`
if [ $cnt -eq $cnt2 ]; then
exit_fail
fi
echo 0 > events/fprobes/myevent2/enable
echo "-:myevent2" >> dynamic_events
grep -q myevent1 dynamic_events
! grep -q myevent2 dynamic_events
echo 0 > events/fprobes/enable
echo > dynamic_events
# Should have none left
cnt=`cat enabled_functions | wc -l`
if [ $cnt -ne $ocnt ]; then
exit_fail
fi
echo "f:myevent4 $PLACE" >> dynamic_events
echo 1 > events/fprobes/myevent4/enable
# Should only have one enabled
cnt=`cat enabled_functions | wc -l`
if [ $cnt -ne $((ocnt + 1)) ]; then
exit_fail
fi
echo 0 > events/fprobes/enable
echo > dynamic_events
# Should have none left
cnt=`cat enabled_functions | wc -l`
if [ $cnt -ne $ocnt ]; then
exit_fail
fi
clear_trace
@@ -0,0 +1,96 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove fprobe events on module
# requires: dynamic_events "f[:[<group>/][<event>]] <func-name>[%return] [<args>]":README enabled_functions
rmmod trace-events-sample ||:
if ! modprobe trace-events-sample ; then
echo "No trace-events sample module - please make CONFIG_SAMPLE_TRACE_EVENTS=m"
exit_unresolved;
fi
trap "lsmod | grep -q trace_events_sample && rmmod trace-events-sample" EXIT
echo 0 > events/enable
echo > dynamic_events
FUNC1='foo_bar*'
FUNC2='vfs_read'
:;: "Save enabled functions count" ;:
ecount=`cat enabled_functions | wc -l`
count_enabled_functions() {
count=`cat enabled_functions | wc -l`
count=$(($count-$ecount))
echo $count
}
:;: "Add an event on the test module" ;:
echo "f:test1 $FUNC1" >> dynamic_events
echo 1 > events/fprobes/test1/enable
:;: "Ensure it is enabled" ;:
funcs=`count_enabled_functions`
test $funcs -ne 0
:;: "Check the enabled_functions is cleared on unloading" ;:
rmmod trace-events-sample
funcs=`count_enabled_functions`
test $funcs -eq 0
:;: "Check it is kept clean" ;:
modprobe trace-events-sample
echo 1 > events/fprobes/test1/enable || echo "OK"
funcs=`count_enabled_functions`
test $funcs -eq 0
:;: "Add another event not on the test module" ;:
echo "f:test2 $FUNC2" >> dynamic_events
echo 1 > events/fprobes/test2/enable
:;: "Ensure it is enabled" ;:
ofuncs=`count_enabled_functions`
test $ofuncs -ne 0
:;: "Disable and remove the first event"
echo 0 > events/fprobes/test1/enable
echo "-:fprobes/test1" >> dynamic_events
funcs=`count_enabled_functions`
test $ofuncs -eq $funcs
:;: "Disable and remove other events" ;:
echo 0 > events/fprobes/enable
echo > dynamic_events
funcs=`count_enabled_functions`
test $funcs -eq 0
rmmod trace-events-sample
:;: "Add events on kernel and test module" ;:
modprobe trace-events-sample
echo "f:test1 $FUNC1" >> dynamic_events
echo 1 > events/fprobes/test1/enable
echo "f:test2 $FUNC2" >> dynamic_events
echo 1 > events/fprobes/test2/enable
ofuncs=`count_enabled_functions`
test $ofuncs -ne 0
:;: "Unload module (ftrace entry should be removed)" ;:
rmmod trace-events-sample
funcs=`count_enabled_functions`
test $funcs -ne 0
test $ofuncs -ne $funcs
:;: "Disable and remove core-kernel fprobe event" ;:
echo 0 > events/fprobes/test2/enable
echo "-:fprobes/test2" >> dynamic_events
:;: "Ensure ftrace is disabled." ;:
funcs=`count_enabled_functions`
test $funcs -eq 0
echo 0 > events/fprobes/enable
echo > dynamic_events
trap "" EXIT
clear_trace
@@ -0,0 +1,19 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - Repeating 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
REPEAT_TIMES=64
for i in `seq 1 $REPEAT_TIMES`; do
echo "f:myevent $PLACE" >> dynamic_events
grep -q myevent dynamic_events
test -d events/fprobes/myevent
echo > dynamic_events
done
clear_trace
@@ -0,0 +1,33 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove kprobe events
# requires: dynamic_events "place: [<module>:]<symbol>":README "place (kretprobe): [<module>:]<symbol>":README
echo 0 > events/enable
echo > dynamic_events
PLACE=$FUNCTION_FORK
echo "p:myevent1 $PLACE" >> dynamic_events
echo "r:myevent2 $PLACE" >> dynamic_events
grep -q myevent1 dynamic_events
grep -q myevent2 dynamic_events
test -d events/kprobes/myevent1
test -d events/kprobes/myevent2
echo "-:myevent2" >> dynamic_events
grep -q myevent1 dynamic_events
! grep -q myevent2 dynamic_events
echo > dynamic_events
if grep -q "p\[:\[<group>/]\[<event>]]" README; then
echo "p:mygroup/ $PLACE" >> dynamic_events
test -d events/mygroup
echo "-:mygroup/" >> dynamic_events
! test -d events/mygroup
fi
clear_trace
@@ -0,0 +1,69 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove multiple fprobe events on the same function
# requires: dynamic_events "f[:[<group>/][<event>]] <func-name>[%return] [<args>]":README enabled_functions
echo 0 > events/enable
echo > dynamic_events
PLACE=vfs_read
PLACE2=vfs_open
:;: 'Ensure no other ftrace user' ;:
test `cat enabled_functions | wc -l` -eq 0 || exit_unresolved
:;: 'Test case 1: leave entry event' ;:
:;: 'Add entry and exit events on the same place' ;:
echo "f:event1 ${PLACE}" >> dynamic_events
echo "f:event2 ${PLACE}%return" >> dynamic_events
:;: 'Enable both of them' ;:
echo 1 > events/fprobes/enable
test `cat enabled_functions | wc -l` -eq 1
:;: 'Disable and remove exit event' ;:
echo 0 > events/fprobes/event2/enable
echo -:event2 >> dynamic_events
:;: 'Disable and remove all events' ;:
echo 0 > events/fprobes/enable
echo > dynamic_events
:;: 'Add another event' ;:
echo "f:event3 ${PLACE2}%return" > dynamic_events
echo 1 > events/fprobes/enable
test `cat enabled_functions | wc -l` -eq 1
:;: 'No other ftrace user' ;:
echo 0 > events/fprobes/enable
echo > dynamic_events
test `cat enabled_functions | wc -l` -eq 0
:;: 'Test case 2: leave exit event' ;:
:;: 'Add entry and exit events on the same place' ;:
echo "f:event1 ${PLACE}" >> dynamic_events
echo "f:event2 ${PLACE}%return" >> dynamic_events
:;: 'Enable both of them' ;:
echo 1 > events/fprobes/enable
test `cat enabled_functions | wc -l` -eq 1
:;: 'Disable and remove entry event' ;:
echo 0 > events/fprobes/event1/enable
echo -:event1 >> dynamic_events
:;: 'Disable and remove all events' ;:
echo 0 > events/fprobes/enable
echo > dynamic_events
:;: 'Add another event' ;:
echo "f:event3 ${PLACE2}" > dynamic_events
echo 1 > events/fprobes/enable
test `cat enabled_functions | wc -l` -eq 1
:;: 'No other ftrace user' ;:
echo 0 > events/fprobes/enable
echo > dynamic_events
test `cat enabled_functions | wc -l` -eq 0
clear_trace
@@ -0,0 +1,24 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove synthetic events
# requires: dynamic_events "s:[synthetic/]":README
echo 0 > events/enable
echo > dynamic_events
echo "s:latency1 u64 lat; pid_t pid;" >> dynamic_events
echo "s:latency2 u64 lat; pid_t pid;" >> dynamic_events
grep -q latency1 dynamic_events
grep -q latency2 dynamic_events
test -d events/synthetic/latency1
test -d events/synthetic/latency2
echo "-:synthetic/latency2" >> dynamic_events
grep -q latency1 dynamic_events
! grep -q latency2 dynamic_events
echo > dynamic_events
clear_trace
@@ -0,0 +1,41 @@
#!/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
SUBSYSTEM=kmem
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
# auto naming check
echo "t $TRACEPOINT1" >> dynamic_events
test -d events/tracepoints/$TRACEPOINT1
echo > dynamic_events
# SUBSYSTEM is not supported
echo "t $SUBSYSTEM/$TRACEPOINT1" >> dynamic_events && exit_fail ||:
echo "t $SUBSYSTEM:$TRACEPOINT1" >> dynamic_events && exit_fail ||:
echo "t:myevent3 $SUBSYSTEM/$TRACEPOINT1" >> dynamic_events && exit_fail ||:
echo "t:myevent3 $SUBSYSTEM:$TRACEPOINT1" >> dynamic_events && exit_fail ||:
clear_trace
@@ -0,0 +1,61 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove tracepoint probe events on module
# requires: dynamic_events "t[:[<group>/][<event>]] <tracepoint> [<args>]":README
rmmod trace-events-sample ||:
if ! modprobe trace-events-sample ; then
echo "No trace-events sample module - please make CONFIG_SAMPLE_TRACE_EVENTS=m"
exit_unresolved;
fi
trap "rmmod trace-events-sample" EXIT
echo 0 > events/enable
echo > dynamic_events
TRACEPOINT1=foo_bar
TRACEPOINT2=foo_bar_with_cond
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
:;: "Try to put a probe on a tracepoint in non-loaded module" ;:
rmmod trace-events-sample
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 1 > events/tracepoints/enable
modprobe trace-events-sample
sleep 2
grep -q "myevent1" trace
grep -q "myevent2" trace
rmmod trace-events-sample
trap "" EXIT
echo 0 > events/tracepoints/enable
echo > dynamic_events
clear_trace
@@ -0,0 +1,55 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove/test uprobe events
# requires: uprobe_events
if ! which readelf > /dev/null 2>&1 ; then
echo "No readelf found. skipped."
exit_unresolved
fi
echo 0 > events/enable
echo > dynamic_events
REALBIN=`readlink -f /bin/sh`
# Get the entry point virtual address from ELF header
ENTRY=`readelf -hW ${REALBIN} | grep "Entry point" | awk '{print $NF}'`
# Convert virtual address to file offset: find the LOAD segment containing
# the entry point, then compute file_offset = e_entry - p_vaddr + p_offset.
# For PIE binaries this is a no-op (vaddr == file offset), but for non-PIE
# executables the virtual address is much larger than the file size and
# must be converted, otherwise uprobe_register() rejects it with -EINVAL.
ENTRY_DEC=$(printf '%d' "$ENTRY")
OFFSET=$ENTRY
while IFS= read -r line; do
set -- $line
[ "$1" = "LOAD" ] || continue
VA_DEC=$(printf '%d' "$3")
OFF_DEC=$(printf '%d' "$2")
FSZ_DEC=$(printf '%d' "$5")
if [ "$ENTRY_DEC" -ge "$VA_DEC" ] && [ "$ENTRY_DEC" -lt "$((VA_DEC + FSZ_DEC))" ]; then
OFFSET=$(printf '0x%x' "$((ENTRY_DEC - VA_DEC + OFF_DEC))")
break
fi
done << EOF
$(readelf -lW ${REALBIN} | grep LOAD)
EOF
echo "p:myevent ${REALBIN}:${OFFSET}" >> uprobe_events
grep -q myevent uprobe_events
test -d events/uprobes/myevent
echo 1 > events/uprobes/myevent/enable
echo 'ls' | /bin/sh > /dev/null
echo 0 > events/uprobes/myevent/enable
grep -q myevent trace
echo "-:myevent" >> uprobe_events
! grep -q myevent uprobe_events
echo > uprobe_events
clear_trace
@@ -0,0 +1,41 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - selective clear (compatibility)
# requires: dynamic_events kprobe_events synthetic_events "place: [<module>:]<symbol>":README "place (kretprobe): [<module>:]<symbol>":README "s:[synthetic/]":README
echo 0 > events/enable
echo > dynamic_events
PLACE=$FUNCTION_FORK
setup_events() {
echo "p:myevent1 $PLACE" >> dynamic_events
echo "s:latency1 u64 lat; pid_t pid;" >> dynamic_events
echo "r:myevent2 $PLACE" >> dynamic_events
echo "s:latency2 u64 lat; pid_t pid;" >> dynamic_events
grep -q myevent1 dynamic_events
grep -q myevent2 dynamic_events
grep -q latency1 dynamic_events
grep -q latency2 dynamic_events
}
setup_events
echo > synthetic_events
grep -q myevent1 dynamic_events
grep -q myevent2 dynamic_events
! grep -q latency1 dynamic_events
! grep -q latency2 dynamic_events
echo > dynamic_events
setup_events
echo > kprobe_events
! grep -q myevent1 dynamic_events
! grep -q myevent2 dynamic_events
grep -q latency1 dynamic_events
grep -q latency2 dynamic_events
echo > dynamic_events
@@ -0,0 +1,63 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Checking dynamic events limitations
# requires: dynamic_events "imm-value":README
# Max arguments limitation
MAX_ARGS=128
EXCEED_ARGS=$((MAX_ARGS + 1))
# bash and dash evaluate variables differently.
# dash will evaluate '\\' every time it is read whereas bash does not.
#
# TEST_STRING="$TEST_STRING \\$i"
# echo $TEST_STRING
#
# With i=123
# On bash, that will print "\123"
# but on dash, that will print the escape sequence of \123 as the \ will
# be interpreted again in the echo.
#
# Set a variable "bs" to save a double backslash, then echo that
# to "ts" to see if $ts changed or not. If it changed, it's dash,
# if not, it's bash, and then bs can equal a single backslash.
bs='\\'
ts=`echo $bs`
if [ "$ts" = '\\' ]; then
# this is bash
bs='\'
fi
check_max_args() { # event_header
TEST_STRING=$1
# Acceptable
for i in `seq 1 $MAX_ARGS`; do
TEST_STRING="$TEST_STRING $bs$i"
done
echo "$TEST_STRING" >> dynamic_events
echo > dynamic_events
# Error
TEST_STRING="$TEST_STRING \\$EXCEED_ARGS"
! echo "$TEST_STRING" >> dynamic_events
return 0
}
# Kprobe max args limitation
if grep -q "kprobe_events" README; then
check_max_args "p vfs_read"
fi
# Fprobe max args limitation
if grep -q "f[:[<group>/][<event>]] <func-name>[%return] [<args>]" README; then
check_max_args "f vfs_read"
fi
# Tprobe max args limitation
if grep -q "t[:[<group>/][<event>]] <tracepoint> [<args>]" README; then
check_max_args "t kfree"
fi
# Uprobe max args limitation
if grep -q "uprobe_events" README; then
check_max_args "p /bin/sh:10"
fi
@@ -0,0 +1,40 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - enable/disable tracepoint probe events
# requires: dynamic_events "t[:[<group>/][<event>]] <tracepoint> [<args>]":README
echo 0 > events/enable
echo > dynamic_events
TRACEPOINT=sched_switch
ENABLEFILE=events/tracepoints/myprobe/enable
:;: "Add tracepoint event on $TRACEPOINT" ;:
echo "t:myprobe ${TRACEPOINT}" >> dynamic_events
:;: "Check enable/disable to ensure it works" ;:
echo 1 > $ENABLEFILE
grep -q $TRACEPOINT trace
echo 0 > $ENABLEFILE
echo > trace
! grep -q $TRACEPOINT trace
:;: "Repeat enable/disable to ensure it works" ;:
echo 1 > $ENABLEFILE
grep -q $TRACEPOINT trace
echo 0 > $ENABLEFILE
echo > trace
! grep -q $TRACEPOINT trace
exit 0
@@ -0,0 +1,29 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Event probe event parser error log check
# requires: dynamic_events events/syscalls/sys_enter_openat "<attached-group>.<attached-event> [<args>]":README error_log
check_error() { # command-with-error-pos-by-^
ftrace_errlog_check 'event_probe' "$1" 'dynamic_events'
}
check_error 'e ^a.' # NO_EVENT_INFO
check_error 'e ^.b' # NO_EVENT_INFO
check_error 'e ^a.b' # BAD_ATTACH_EVENT
check_error 'e syscalls/sys_enter_openat ^foo' # BAD_ATTACH_ARG
check_error 'e:^/bar syscalls/sys_enter_openat' # NO_GROUP_NAME
check_error 'e:^12345678901234567890123456789012345678901234567890123456789012345/bar syscalls/sys_enter_openat' # GROUP_TOO_LONG
check_error 'e:^foo.1/bar syscalls/sys_enter_openat' # BAD_GROUP_NAME
check_error 'e:^ syscalls/sys_enter_openat' # NO_EVENT_NAME
check_error 'e:foo/^12345678901234567890123456789012345678901234567890123456789012345 syscalls/sys_enter_openat' # EVENT_TOO_LONG
check_error 'e:foo/^bar.1 syscalls/sys_enter_openat' # BAD_EVENT_NAME
check_error 'e:foo/bar syscalls/sys_enter_openat arg=^dfd' # BAD_FETCH_ARG
check_error 'e:foo/bar syscalls/sys_enter_openat arg=^$foo' # BAD_ATTACH_ARG
if grep -q '<attached-group>\.<attached-event>.*\[if <filter>\]' README; then
check_error 'e:foo/bar syscalls/sys_enter_openat if ^' # NO_EP_FILTER
fi
exit 0
@@ -0,0 +1,41 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Fprobe event VFS type argument
# requires: dynamic_events "%pd/%pD":README "f[:[<group>/][<event>]] <func-name>[%return] [<args>]":README
: "Test argument %pd with name for fprobe"
echo 'f:testprobe dput name=$arg1:%pd' > dynamic_events
echo 1 > events/fprobes/testprobe/enable
grep -q "1" events/fprobes/testprobe/enable
echo 0 > events/fprobes/testprobe/enable
grep "dput" trace | grep -q "enable"
echo "" > dynamic_events
echo "" > trace
: "Test argument %pd without name for fprobe"
echo 'f:testprobe dput $arg1:%pd' > dynamic_events
echo 1 > events/fprobes/testprobe/enable
grep -q "1" events/fprobes/testprobe/enable
echo 0 > events/fprobes/testprobe/enable
grep "dput" trace | grep -q "enable"
echo "" > dynamic_events
echo "" > trace
: "Test argument %pD with name for fprobe"
echo 'f:testprobe vfs_read name=$arg1:%pD' > dynamic_events
echo 1 > events/fprobes/testprobe/enable
grep -q "1" events/fprobes/testprobe/enable
echo 0 > events/fprobes/testprobe/enable
grep "vfs_read" trace | grep -q "enable"
echo "" > dynamic_events
echo "" > trace
: "Test argument %pD without name for fprobe"
echo 'f:testprobe vfs_read $arg1:%pD' > dynamic_events
echo 1 > events/fprobes/testprobe/enable
grep -q "1" events/fprobes/testprobe/enable
echo 0 > events/fprobes/testprobe/enable
grep "vfs_read" trace | grep -q "enable"
echo "" > dynamic_events
echo "" > trace
@@ -0,0 +1,18 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Function return probe entry argument access
# requires: dynamic_events 'f[:[<group>/][<event>]] <func-name>':README 'kernel return probes support:':README
echo 'f:tests/myevent1 vfs_open arg=$arg1' >> dynamic_events
echo 'f:tests/myevent2 vfs_open%return arg=$arg1' >> dynamic_events
echo 1 > events/tests/enable
echo > trace
cat trace > /dev/null
streq() {
test $1 = $2
}
streq `grep -A 1 -m 1 myevent1 trace | sed -r 's/^.*(arg=.*)/\1/' `
@@ -0,0 +1,122 @@
#!/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' # BAD_MAXACT
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 't kmem^/kfree' # BAD_TP_NAME
check_error 'f vfs_read ^$stack10000' # BAD_STACK_NUM
check_error 'f vfs_read ^$arg10000' # BAD_ARG_NUM
if !grep -q 'kernel return probes support:' README; then
check_error 'f vfs_read $retval ^$arg1' # BAD_VAR
fi
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
if !grep -q 'kernel return probes support:' README; then
check_error 'f vfs_read%return ^$arg*' # NOFENTRY_ARGS
fi
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
if grep -qF "<argname>[->field[->field|.field...]]" README ; then
check_error 'f vfs_read%return $retval->^foo' # NO_PTR_STRCT
check_error 'f vfs_read file->^foo' # NO_BTF_FIELD
check_error 'f vfs_read file^-.foo' # BAD_HYPHEN
check_error 'f vfs_read ^file:string' # BAD_TYPE4STR
fi
else
check_error 'f vfs_read ^$arg*' # NOSUP_BTFARG
check_error 't kfree ^$arg*' # NOSUP_BTFARG
fi
exit 0
@@ -0,0 +1,43 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - generic clear event
# requires: dynamic_events "place: [<module>:]<symbol>":README "place (kretprobe): [<module>:]<symbol>":README "s:[synthetic/]":README
echo 0 > events/enable
echo > dynamic_events
PLACE=$FUNCTION_FORK
setup_events() {
echo "p:myevent1 $PLACE" >> dynamic_events
echo "s:latency1 u64 lat; pid_t pid;" >> dynamic_events
echo "r:myevent2 $PLACE" >> dynamic_events
echo "s:latency2 u64 lat; pid_t pid;" >> dynamic_events
grep -q myevent1 dynamic_events
grep -q myevent2 dynamic_events
grep -q latency1 dynamic_events
grep -q latency2 dynamic_events
}
setup_events
echo "!p:myevent1 $PLACE" >> dynamic_events
! grep -q myevent1 dynamic_events
grep -q myevent2 dynamic_events
grep -q latency1 dynamic_events
grep -q latency2 dynamic_events
echo "!s:latency1 u64 lat; pid_t pid;" >> dynamic_events
grep -q myevent2 dynamic_events
! grep -q latency1 dynamic_events
grep -q latency2 dynamic_events
echo "!r:myevent2 $PLACE" >> dynamic_events
! grep -q myevent2 dynamic_events
grep -q latency2 dynamic_events
echo "!s:latency2 u64 lat; pid_t pid;" >> dynamic_events
! grep -q latency2 dynamic_events
echo > dynamic_events
@@ -0,0 +1,38 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - check if duplicate events are caught
# requires: dynamic_events "e[:[<group>/][<event>]] <attached-group>.<attached-event> [<args>]":README events/syscalls/sys_enter_openat
echo 0 > events/enable
HAVE_KPROBES=0
if [ -f kprobe_events ]; then
HAVE_KPROBES=1
fi
clear_dynamic_events
# first create dynamic events for eprobes and kprobes.
echo 'e:egroup/eevent syscalls/sys_enter_openat file=+0($filename):ustring' >> dynamic_events
# Test eprobe for same eprobe, existing kprobe and existing event
! echo 'e:egroup/eevent syscalls/sys_enter_openat file=+0($filename):ustring' >> dynamic_events
! echo 'e:syscalls/sys_enter_open syscalls/sys_enter_openat file=+0($filename):ustring' >> dynamic_events
if [ $HAVE_KPROBES -eq 1 ]; then
echo 'p:kgroup/kevent vfs_open file=+0($arg2)' >> dynamic_events
! echo 'e:kgroup/kevent syscalls/sys_enter_openat file=+0($filename):ustring' >> dynamic_events
# Test kprobe for same kprobe, existing eprobe and existing event
! echo 'p:kgroup/kevent vfs_open file=+0($arg2)' >> dynamic_events
! echo 'p:egroup/eevent vfs_open file=+0($arg2)' >> dynamic_events
! echo 'p:syscalls/sys_enter_open vfs_open file=+0($arg2)' >> dynamic_events
echo '-:kgroup/kevent' >> dynamic_events
fi
echo '-:egroup/eevent' >> dynamic_events
clear_trace
@@ -0,0 +1,81 @@
#!/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:^/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
@@ -0,0 +1,48 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event tracing - enable/disable with event level files
# requires: set_event events/sched
# flags: instance
do_reset() {
echo > set_event
clear_trace
}
fail() { #msg
echo $1
exit_fail
}
echo 'sched:sched_switch' > set_event
yield
count=`cat trace | grep sched_switch | wc -l`
if [ $count -eq 0 ]; then
fail "sched_switch events are not recorded"
fi
do_reset
echo 1 > events/sched/sched_switch/enable
yield
count=`cat trace | grep sched_switch | wc -l`
if [ $count -eq 0 ]; then
fail "sched_switch events are not recorded"
fi
do_reset
echo 0 > events/sched/sched_switch/enable
yield
count=`cat trace | grep sched_switch | wc -l`
if [ $count -ne 0 ]; then
fail "sched_switch events should not be recorded"
fi
exit 0
@@ -0,0 +1,191 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event tracing - enable/disable with module event
# requires: set_event "Can enable module events via: :mod:":README
# flags: instance
rmmod trace-events-sample ||:
if ! modprobe trace-events-sample ; then
echo "No trace-events sample module - please make CONFIG_SAMPLE_TRACE_EVENTS=m"
exit_unresolved;
fi
trap "rmmod trace-events-sample" EXIT
# Set events for the module
echo ":mod:trace-events-sample" > set_event
test_all_enabled() {
# Check if more than one is enabled
grep -q sample-trace:foo_bar set_event
grep -q sample-trace:foo_bar_with_cond set_event
grep -q sample-trace:foo_bar_with_fn set_event
# All of them should be enabled. Check via the enable file
val=`cat events/sample-trace/enable`
if [ $val -ne 1 ]; then
exit_fail
fi
}
clear_events() {
echo > set_event
val=`cat events/enable`
if [ "$val" != "0" ]; then
exit_fail
fi
count=`cat set_event | wc -l`
if [ $count -ne 0 ]; then
exit_fail
fi
}
test_all_enabled
echo clear all events
echo 0 > events/enable
echo Confirm the events are disabled
val=`cat events/sample-trace/enable`
if [ $val -ne 0 ]; then
exit_fail
fi
echo And the set_event file is empty
cnt=`wc -l set_event`
if [ $cnt -ne 0 ]; then
exit_fail
fi
echo now enable all events
echo 1 > events/enable
echo Confirm the events are enabled again
val=`cat events/sample-trace/enable`
if [ $val -ne 1 ]; then
exit_fail
fi
echo disable just the module events
echo '!:mod:trace-events-sample' >> set_event
echo Should have mix of events enabled
val=`cat events/enable`
if [ "$val" != "X" ]; then
exit_fail
fi
echo Confirm the module events are disabled
val=`cat events/sample-trace/enable`
if [ $val -ne 0 ]; then
exit_fail
fi
echo 0 > events/enable
echo now enable the system events
echo 'sample-trace:mod:trace-events-sample' > set_event
test_all_enabled
echo clear all events
echo 0 > events/enable
echo Confirm the events are disabled
val=`cat events/sample-trace/enable`
if [ $val -ne 0 ]; then
exit_fail
fi
echo Test enabling foo_bar only
echo 'foo_bar:mod:trace-events-sample' > set_event
grep -q sample-trace:foo_bar set_event
echo make sure nothing is found besides foo_bar
if grep -q -v sample-trace:foo_bar set_event ; then
exit_fail
fi
echo Append another using the system and event name
echo 'sample-trace:foo_bar_with_cond:mod:trace-events-sample' >> set_event
grep -q sample-trace:foo_bar set_event
grep -q sample-trace:foo_bar_with_cond set_event
count=`cat set_event | wc -l`
if [ $count -ne 2 ]; then
exit_fail
fi
clear_events
rmmod trace-events-sample
echo ':mod:trace-events-sample' > set_event
echo make sure that the module shows up, and '-' is converted to '_'
grep -q '\*:\*:mod:trace_events_sample' set_event
modprobe trace-events-sample
test_all_enabled
clear_events
rmmod trace-events-sample
echo Enable just the system events
echo 'sample-trace:mod:trace-events-sample' > set_event
grep -q 'sample-trace:mod:trace_events_sample' set_event
modprobe trace-events-sample
test_all_enabled
clear_events
rmmod trace-events-sample
echo Enable event with just event name
echo 'foo_bar:mod:trace-events-sample' > set_event
grep -q 'foo_bar:mod:trace_events_sample' set_event
echo Enable another event with both system and event name
echo 'sample-trace:foo_bar_with_cond:mod:trace-events-sample' >> set_event
grep -q 'sample-trace:foo_bar_with_cond:mod:trace_events_sample' set_event
echo Make sure the other event was still there
grep -q 'foo_bar:mod:trace_events_sample' set_event
modprobe trace-events-sample
echo There should be no :mod: cached events
if grep -q ':mod:' set_event; then
exit_fail
fi
echo two events should be enabled
count=`cat set_event | wc -l`
if [ $count -ne 2 ]; then
exit_fail
fi
echo only two events should be enabled
val=`cat events/sample-trace/enable`
if [ "$val" != "X" ]; then
exit_fail
fi
val=`cat events/sample-trace/foo_bar/enable`
if [ "$val" != "1" ]; then
exit_fail
fi
val=`cat events/sample-trace/foo_bar_with_cond/enable`
if [ "$val" != "1" ]; then
exit_fail
fi
clear_trace
@@ -0,0 +1,123 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event tracing - restricts events based on pid notrace filtering
# requires: set_event events/sched set_event_pid set_event_notrace_pid
# flags: instance
do_reset() {
echo > set_event
echo > set_event_pid
echo > set_event_notrace_pid
echo 0 > options/event-fork
echo 0 > events/enable
clear_trace
echo 1 > tracing_on
}
fail() { #msg
cat trace
do_reset
echo $1
exit_fail
}
count_pid() {
pid=$@
cat trace | grep -v '^#' | sed -e 's/[^-]*-\([0-9]*\).*/\1/' | grep $pid | wc -l
}
count_no_pid() {
pid=$1
cat trace | grep -v '^#' | sed -e 's/[^-]*-\([0-9]*\).*/\1/' | grep -v $pid | wc -l
}
enable_system() {
system=$1
if [ -d events/$system ]; then
echo 1 > events/$system/enable
fi
}
enable_events() {
echo 0 > tracing_on
# Enable common groups of events, as all events can allow for
# events to be traced via scheduling that we don't care to test.
enable_system syscalls
enable_system rcu
enable_system block
enable_system exceptions
enable_system irq
enable_system net
enable_system power
enable_system signal
enable_system sock
enable_system timer
enable_system thermal
echo 1 > tracing_on
}
other_task() {
sleep .001 || usleep 1 || sleep 1
}
echo 0 > options/event-fork
do_reset
read mypid rest < /proc/self/stat
echo $mypid > set_event_notrace_pid
grep -q $mypid set_event_notrace_pid
enable_events
yield
echo 0 > tracing_on
cnt=`count_pid $mypid`
if [ $cnt -ne 0 ]; then
fail "Filtered out task has events"
fi
cnt=`count_no_pid $mypid`
if [ $cnt -eq 0 ]; then
fail "No other events were recorded"
fi
do_reset
echo $mypid > set_event_notrace_pid
echo 1 > options/event-fork
enable_events
yield &
child=$!
echo "child = $child"
wait $child
# Be sure some other events will happen for small systems (e.g. 1 core)
other_task
echo 0 > tracing_on
cnt=`count_pid $mypid`
if [ $cnt -ne 0 ]; then
fail "Filtered out task has events"
fi
cnt=`count_pid $child`
if [ $cnt -ne 0 ]; then
fail "Child of filtered out taskhas events"
fi
cnt=`count_no_pid $mypid`
if [ $cnt -eq 0 ]; then
fail "No other events were recorded"
fi
do_reset
exit 0
@@ -0,0 +1,61 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event tracing - restricts events based on pid
# requires: set_event set_event_pid events/sched
# flags: instance
do_reset() {
echo > set_event
echo > set_event_pid
echo 0 > options/event-fork
clear_trace
}
fail() { #msg
do_reset
echo $1
exit_fail
}
echo 0 > options/event-fork
echo 1 > events/sched/sched_switch/enable
yield
count=`cat trace | grep sched_switch | wc -l`
if [ $count -eq 0 ]; then
fail "sched_switch events are not recorded"
fi
do_reset
read mypid rest < /proc/self/stat
echo $mypid > set_event_pid
grep -q $mypid set_event_pid
echo 'sched:sched_switch' > set_event
yield
count=`cat trace | grep sched_switch | grep -v "pid=$mypid" | wc -l`
if [ $count -ne 0 ]; then
fail "sched_switch events from other task are recorded"
fi
do_reset
echo $mypid > set_event_pid
echo 1 > options/event-fork
echo 1 > events/sched/sched_switch/enable
yield
count=`cat trace | grep sched_switch | grep -v "pid=$mypid" | wc -l`
if [ $count -eq 0 ]; then
fail "sched_switch events from other task are not recorded"
fi
do_reset
exit 0
@@ -0,0 +1,72 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event tracing - enable/disable with subsystem level files
# requires: set_event events/sched/enable
# flags: instance
do_reset() {
echo > set_event
clear_trace
}
fail() { #msg
echo $1
exit_fail
}
# As reading trace can last forever, simply look for 3 different
# events then exit out of reading the file. If there's not 3 different
# events, then the test has failed.
check_unique() {
cat trace | grep -v '^#' | awk '
BEGIN { cnt = 0; }
{
for (i = 0; i < cnt; i++) {
if (event[i] == $5) {
break;
}
}
if (i == cnt) {
event[cnt++] = $5;
if (cnt > 2) {
exit;
}
}
}
END {
printf "%d", cnt;
}'
}
echo 'sched:*' > set_event
yield
count=`check_unique`
if [ $count -lt 3 ]; then
fail "at least fork, exec and exit events should be recorded"
fi
do_reset
echo 1 > events/sched/enable
yield
count=`check_unique`
if [ $count -lt 3 ]; then
fail "at least fork, exec and exit events should be recorded"
fi
do_reset
echo 0 > events/sched/enable
yield
count=`head -n 100 trace | grep -v ^# | awk '{ print $5 }' | sort -u | wc -l`
if [ $count -ne 0 ]; then
fail "any of scheduler events should not be recorded"
fi
exit 0
@@ -0,0 +1,52 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event tracing - enable/disable with top level files
# requires: set_event events/enable
# flags: instance
do_reset() {
echo > set_event
clear_trace
}
fail() { #msg
echo $1
exit_fail
}
echo '*:*' > set_event
yield
echo 0 > tracing_on
count=`head -n 128 trace | grep -v ^# | wc -l`
if [ $count -eq 0 ]; then
fail "none of events are recorded"
fi
do_reset
echo 1 > events/enable
echo 1 > tracing_on
yield
echo 0 > tracing_on
count=`head -n 128 trace | grep -v ^# | wc -l`
if [ $count -eq 0 ]; then
fail "none of events are recorded"
fi
do_reset
echo 0 > events/enable
yield
count=`cat trace | grep -v ^# | wc -l`
if [ $count -ne 0 ]; then
fail "any of events should not be recorded"
fi
exit 0
@@ -0,0 +1,27 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Test trace_printk from module
rmmod trace-printk ||:
if ! modprobe trace-printk ; then
echo "No trace-printk sample module - please make CONFIG_SAMPLE_TRACE_PRINTK=m"
exit_unresolved;
fi
echo "Waiting for irq work"
sleep 1
grep -q ": This .* trace_bputs" trace
grep -q ": This .* trace_puts" trace
grep -q ": This .* trace_bprintk" trace
grep -q ": This .* trace_printk" trace
grep -q ": (irq) .* trace_bputs" trace
grep -q ": (irq) .* trace_puts" trace
grep -q ": (irq) .* trace_bprintk" trace
grep -q ": (irq) .* trace_printk" trace
grep -q "This is a %s that will use trace_bprintk" printk_formats
grep -q "(irq) This is a static string that will use trace_bputs" printk_formats
rmmod trace-printk ||:
@@ -0,0 +1,109 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event filter function - test event filtering on functions
# requires: set_event events/kmem/kmem_cache_free/filter
# flags: instance
fail() { #msg
echo $1
exit_fail
}
sample_events() {
echo 1 > events/kmem/kmem_cache_free/enable
echo 1 > tracing_on
ls > /dev/null
echo 0 > tracing_on
echo 0 > events/kmem/kmem_cache_free/enable
}
echo 0 > tracing_on
echo 0 > events/enable
# Clear functions caused by page cache; run sample_events twice
sample_events
sample_events
echo "Get the most frequently calling function"
echo > trace
sample_events
target_func=`cat trace | grep -o 'call_site=\([^+]*\)' | sed 's/call_site=//' | sort | uniq -c | sort | tail -n 1 | sed 's/^[ 0-9]*//'`
if [ -z "$target_func" ]; then
exit_fail
fi
echo > trace
echo "Test event filter function name"
echo "call_site.function == $target_func" > events/kmem/kmem_cache_free/filter
sample_events
max_retry=10
while [ `grep kmem_cache_free trace| wc -l` -eq 0 ]; do
sample_events
max_retry=$((max_retry - 1))
if [ $max_retry -eq 0 ]; then
exit_fail
fi
done
hitcnt=`grep kmem_cache_free trace| grep $target_func | wc -l`
misscnt=`grep kmem_cache_free trace| grep -v $target_func | wc -l`
if [ $hitcnt -eq 0 ]; then
exit_fail
fi
if [ $misscnt -gt 0 ]; then
exit_fail
fi
address=`grep " ${target_func}\$" /proc/kallsyms | cut -d' ' -f1`
echo "Test event filter function address"
echo "call_site.function == 0x$address" > events/kmem/kmem_cache_free/filter
echo > trace
sample_events
max_retry=10
while [ `grep kmem_cache_free trace| wc -l` -eq 0 ]; do
sample_events
max_retry=$((max_retry - 1))
if [ $max_retry -eq 0 ]; then
exit_fail
fi
done
hitcnt=`grep kmem_cache_free trace| grep $target_func | wc -l`
misscnt=`grep kmem_cache_free trace| grep -v $target_func | wc -l`
if [ $hitcnt -eq 0 ]; then
exit_fail
fi
if [ $misscnt -gt 0 ]; then
exit_fail
fi
# Check strings too
if [ -f events/syscalls/sys_enter_openat/filter ]; then
DIRNAME=`basename $TMPDIR`
echo "filename.ustring ~ \"*$DIRNAME*\"" > events/syscalls/sys_enter_openat/filter
echo 1 > events/syscalls/sys_enter_openat/enable
echo 1 > tracing_on
ls /bin/sh
nocnt=`grep openat trace | wc -l`
ls $TMPDIR
echo 0 > tracing_on
hitcnt=`grep openat trace | wc -l`;
echo 0 > events/syscalls/sys_enter_openat/enable
if [ $nocnt -gt 0 ]; then
exit_fail
fi
if [ $hitcnt -eq 0 ]; then
exit_fail
fi
fi
reset_events_filter
exit 0
@@ -0,0 +1,73 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function graph filters with stack tracer
# requires: stack_trace set_ftrace_filter function_graph:tracer
# Make sure that function graph filtering works, and is not
# affected by other tracers enabled (like stack tracer)
do_reset() {
if [ -e /proc/sys/kernel/stack_tracer_enabled ]; then
echo 0 > /proc/sys/kernel/stack_tracer_enabled
fi
}
fail() { # msg
do_reset
echo $1
exit_fail
}
disable_tracing
clear_trace;
# filter something, schedule is always good
if ! echo "schedule" > set_ftrace_filter; then
# test for powerpc 64
if ! echo ".schedule" > set_ftrace_filter; then
fail "can not enable schedule filter"
fi
fi
echo function_graph > current_tracer
echo "Now testing with stack tracer"
echo 1 > /proc/sys/kernel/stack_tracer_enabled
disable_tracing
clear_trace
enable_tracing
sleep 1
count=`cat trace | grep '()' | grep -v schedule | wc -l`
if [ $count -ne 0 ]; then
fail "Graph filtering not working with stack tracer?"
fi
# Make sure we did find something
count=`cat trace | grep 'schedule()' | wc -l`
if [ $count -eq 0 ]; then
fail "No schedule traces found?"
fi
echo 0 > /proc/sys/kernel/stack_tracer_enabled
clear_trace
sleep 1
count=`cat trace | grep '()' | grep -v schedule | wc -l`
if [ $count -ne 0 ]; then
fail "Graph filtering not working after stack tracer disabled?"
fi
count=`cat trace | grep 'schedule()' | wc -l`
if [ $count -eq 0 ]; then
fail "No schedule traces found?"
fi
do_reset
exit 0
@@ -0,0 +1,40 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function graph filters
# requires: set_ftrace_filter function_graph:tracer
# Make sure that function graph filtering works
fail() { # msg
echo $1
exit_fail
}
disable_tracing
clear_trace
# filter something, schedule is always good
if ! echo "schedule" > set_ftrace_filter; then
# test for powerpc 64
if ! echo ".schedule" > set_ftrace_filter; then
fail "can not enable schedule filter"
fi
fi
echo function_graph > current_tracer
enable_tracing
sleep 1
# search for functions (has "()" on the line), and make sure
# that only the schedule function was found
count=`cat trace | grep '()' | grep -v schedule | wc -l`
if [ $count -ne 0 ]; then
fail "Graph filtering not working by itself?"
fi
# Make sure we did find something
count=`cat trace | grep 'schedule()' | wc -l`
if [ $count -eq 0 ]; then
fail "No schedule traces found?"
fi
exit 0
@@ -0,0 +1,177 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function graph filters
# requires: set_ftrace_filter function_graph:tracer
# Make sure that function graph filtering works
INSTANCE1="instances/test1_$$"
INSTANCE2="instances/test2_$$"
WD=`pwd`
do_reset() {
cd $WD
if [ -d $INSTANCE1 ]; then
echo nop > $INSTANCE1/current_tracer
rmdir $INSTANCE1
fi
if [ -d $INSTANCE2 ]; then
echo nop > $INSTANCE2/current_tracer
rmdir $INSTANCE2
fi
}
mkdir $INSTANCE1
if ! grep -q function_graph $INSTANCE1/available_tracers; then
echo "function_graph not allowed with instances"
rmdir $INSTANCE1
exit_unsupported
fi
mkdir $INSTANCE2
fail() { # msg
do_reset
echo $1
exit_fail
}
disable_tracing
clear_trace
function_count() {
search=$1
vsearch=$2
if [ -z "$search" ]; then
cat enabled_functions | wc -l
elif [ -z "$vsearch" ]; then
grep $search enabled_functions | wc -l
else
grep $search enabled_functions | grep $vsearch| wc -l
fi
}
set_fgraph() {
instance=$1
filter="$2"
notrace="$3"
echo "$filter" > $instance/set_ftrace_filter
echo "$notrace" > $instance/set_ftrace_notrace
echo function_graph > $instance/current_tracer
}
check_functions() {
orig_cnt=$1
test=$2
cnt=`function_count $test`
if [ $cnt -gt $orig_cnt ]; then
fail
fi
}
check_cnt() {
orig_cnt=$1
search=$2
vsearch=$3
cnt=`function_count $search $vsearch`
if [ $cnt -gt $orig_cnt ]; then
fail
fi
}
reset_graph() {
instance=$1
echo nop > $instance/current_tracer
}
# get any functions that were enabled before the test
total_cnt=`function_count`
sched_cnt=`function_count sched`
lock_cnt=`function_count lock`
time_cnt=`function_count time`
clock_cnt=`function_count clock`
locks_clock_cnt=`function_count locks clock`
clock_locks_cnt=`function_count clock locks`
# Trace functions with "sched" but not "time"
set_fgraph $INSTANCE1 '*sched*' '*time*'
# Make sure "time" isn't listed
check_functions $time_cnt 'time'
instance1_cnt=`function_count`
# Trace functions with "lock" but not "clock"
set_fgraph $INSTANCE2 '*lock*' '*clock*'
instance1_2_cnt=`function_count`
# Turn off the first instance
reset_graph $INSTANCE1
# The second instance doesn't trace "clock" functions
check_functions $clock_cnt 'clock'
instance2_cnt=`function_count`
# Start from a clean slate
reset_graph $INSTANCE2
check_functions $total_cnt
# Trace functions with "lock" but not "clock"
set_fgraph $INSTANCE2 '*lock*' '*clock*'
# This should match the last time instance 2 was by itself
cnt=`function_count`
if [ $instance2_cnt -ne $cnt ]; then
fail
fi
# And it should not be tracing "clock" functions
check_functions $clock_cnt 'clock'
# Trace functions with "sched" but not "time"
set_fgraph $INSTANCE1 '*sched*' '*time*'
# This should match the last time both instances were enabled
cnt=`function_count`
if [ $instance1_2_cnt -ne $cnt ]; then
fail
fi
# Turn off the second instance
reset_graph $INSTANCE2
# This should match the last time instance 1 was by itself
cnt=`function_count`
if [ $instance1_cnt -ne $cnt ]; then
fail
fi
# And it should not be tracing "time" functions
check_functions $time_cnt 'time'
# Start from a clean slate
reset_graph $INSTANCE1
check_functions $total_cnt
# Enable all functions but those that have "locks"
set_fgraph $INSTANCE1 '' '*locks*'
# Enable all functions but those that have "clock"
set_fgraph $INSTANCE2 '' '*clock*'
# If a function has "locks" it should not have "clock"
check_cnt $locks_clock_cnt locks clock
# If a function has "clock" it should not have "locks"
check_cnt $clock_locks_cnt clock locks
reset_graph $INSTANCE1
reset_graph $INSTANCE2
do_reset
exit 0
@@ -0,0 +1,103 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function graph filters
# requires: set_ftrace_filter function_graph:tracer
# Make sure that function graph filtering works
INSTANCE1="instances/test1_$$"
INSTANCE2="instances/test2_$$"
INSTANCE3="instances/test3_$$"
WD=`pwd`
do_reset() {
cd $WD
if [ -d $INSTANCE1 ]; then
echo nop > $INSTANCE1/current_tracer
rmdir $INSTANCE1
fi
if [ -d $INSTANCE2 ]; then
echo nop > $INSTANCE2/current_tracer
rmdir $INSTANCE2
fi
if [ -d $INSTANCE3 ]; then
echo nop > $INSTANCE3/current_tracer
rmdir $INSTANCE3
fi
}
mkdir $INSTANCE1
if ! grep -q function_graph $INSTANCE1/available_tracers; then
echo "function_graph not allowed with instances"
rmdir $INSTANCE1
exit_unsupported
fi
mkdir $INSTANCE2
mkdir $INSTANCE3
fail() { # msg
do_reset
echo $1
exit_fail
}
disable_tracing
clear_trace
do_test() {
REGEX=$1
TEST=$2
# filter something, schedule is always good
if ! echo "$REGEX" > set_ftrace_filter; then
fail "can not enable filter $REGEX"
fi
echo > trace
echo function_graph > current_tracer
enable_tracing
sleep 1
# search for functions (has "{" or ";" on the line)
echo 0 > tracing_on
count=`cat trace | grep -v '^#' | grep -e '{' -e ';' | grep -v "$TEST" | wc -l`
echo 1 > tracing_on
if [ $count -ne 0 ]; then
fail "Graph filtering not working by itself against $TEST?"
fi
# Make sure we did find something
echo 0 > tracing_on
count=`cat trace | grep -v '^#' | grep -e '{' -e ';' | grep "$TEST" | wc -l`
echo 1 > tracing_on
if [ $count -eq 0 ]; then
fail "No traces found with $TEST?"
fi
}
do_test '*sched*' 'sched'
cd $INSTANCE1
do_test '*lock*' 'lock'
cd $WD
cd $INSTANCE2
do_test '*rcu*' 'rcu'
cd $WD
cd $INSTANCE3
echo function_graph > current_tracer
sleep 1
count=`cat trace | grep -v '^#' | grep -e '{' -e ';' | grep "$TEST" | wc -l`
if [ $count -eq 0 ]; then
fail "No traces found with all tracing?"
fi
cd $WD
echo nop > current_tracer
echo nop > $INSTANCE1/current_tracer
echo nop > $INSTANCE2/current_tracer
echo nop > $INSTANCE3/current_tracer
do_reset
exit 0
@@ -0,0 +1,31 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function profiler with function graph tracing
# requires: function_profile_enabled set_ftrace_filter function_graph:tracer
# The function graph tracer can now be run along side of the function
# profiler. But there was a bug that caused the combination of the two
# to crash. It also required the function graph tracer to be started
# first.
#
# This test triggers that bug
#
# We need both function_graph and profiling to run this test
fail() { # mesg
echo $1
exit_fail
}
echo "Enabling function graph tracer:"
echo function_graph > current_tracer
echo "enable profiler"
# Older kernels do not allow function_profile to be enabled with
# function graph tracer. If the below fails, mark it as unsupported
echo 1 > function_profile_enabled || exit_unsupported
# Let it run for a bit to make sure nothing explodes
sleep 1
exit 0
@@ -0,0 +1,44 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function graph print function return value
# requires: options/funcgraph-retval options/funcgraph-retval-hex function_graph:tracer
# Make sure that funcgraph-retval works
fail() { # msg
echo $1
exit_fail
}
disable_tracing
clear_trace
# get self PID, can not use $$, because it is PPID
read PID _ < /proc/self/stat
[ -f set_ftrace_filter ] && echo proc_reg_write > set_ftrace_filter
[ -f set_ftrace_pid ] && echo ${PID} > set_ftrace_pid
echo function_graph > current_tracer
echo 1 > options/funcgraph-retval
set +e
enable_tracing
echo > /proc/interrupts
disable_tracing
set -e
: "Test printing the error code in signed decimal format"
echo 0 > options/funcgraph-retval-hex
count=`cat trace | grep 'proc_reg_write' | grep -e '=-5 ' -e '= -5 ' | wc -l`
if [ $count -eq 0 ]; then
fail "Return value can not be printed in signed decimal format"
fi
: "Test printing the error code in hexadecimal format"
echo 1 > options/funcgraph-retval-hex
count=`cat trace | grep 'proc_reg_write' | grep 'fffffffb' | wc -l`
if [ $count -eq 0 ]; then
fail "Return value can not be printed in hexadecimal format"
fi
exit 0
@@ -0,0 +1,58 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function glob filters
# requires: set_ftrace_filter function:tracer
# Make sure that function glob matching filter works.
disable_tracing
clear_trace
ftrace_filter_check() { # glob grep
echo "$1" > set_ftrace_filter
cut -f1 -d" " set_ftrace_filter > $TMPDIR/actual
cut -f1 -d" " available_filter_functions | grep "$2" > $TMPDIR/expected
DIFF=`diff $TMPDIR/actual $TMPDIR/expected`
test -z "$DIFF"
}
# filter by *, front match
ftrace_filter_check '*schedule' '^.*schedule$'
# filter by *, middle match
ftrace_filter_check '*schedule*' '^.*schedule.*$'
# filter by *, end match
ftrace_filter_check 'schedule*' '^schedule.*$'
# filter by *mid*end
ftrace_filter_check '*pin*lock' '.*pin.*lock$'
# filter by start*mid*
ftrace_filter_check 'mutex*unl*' '^mutex.*unl.*'
# Advanced full-glob matching feature is recently supported.
# Skip the tests if we are sure the kernel does not support it.
if grep -q 'accepts: .* glob-matching-pattern' README ; then
# filter by *, both side match
ftrace_filter_check 'sch*ule' '^sch.*ule$'
# filter by char class.
ftrace_filter_check '[Ss]y[Ss]_*' '^[Ss]y[Ss]_.*$'
# filter by ?, schedule is always good
if ! echo "sch?dule" > set_ftrace_filter; then
# test for powerpc 64
if ! echo ".sch?dule" > set_ftrace_filter; then
fail "can not enable schedule filter"
fi
cat set_ftrace_filter | grep '^.schedule$'
else
cat set_ftrace_filter | grep '^schedule$'
fi
fi
echo > set_ftrace_filter
enable_tracing
@@ -0,0 +1,94 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function pid notrace filters
# requires: set_ftrace_notrace_pid set_ftrace_filter function:tracer
# flags: instance
# Make sure that function pid matching filter with notrace works.
do_function_fork=1
if [ ! -f options/function-fork ]; then
do_function_fork=0
echo "no option for function-fork found. Option will not be tested."
fi
read PID _ < /proc/self/stat
if [ $do_function_fork -eq 1 ]; then
# default value of function-fork option
orig_value=`grep function-fork trace_options`
fi
do_reset() {
if [ $do_function_fork -eq 0 ]; then
return
fi
echo > set_ftrace_notrace_pid
echo $orig_value > trace_options
}
fail() { # msg
do_reset
echo $1
exit_fail
}
do_test() {
disable_tracing
echo do_execve* > set_ftrace_filter
echo $FUNCTION_FORK >> set_ftrace_filter
echo $PID > set_ftrace_notrace_pid
echo function > current_tracer
if [ $do_function_fork -eq 1 ]; then
# don't allow children to be traced
echo nofunction-fork > trace_options
fi
enable_tracing
yield
count_pid=`cat trace | grep -v ^# | grep $PID | wc -l`
count_other=`cat trace | grep -v ^# | grep -v $PID | wc -l`
# count_pid should be 0
if [ $count_pid -ne 0 -o $count_other -eq 0 ]; then
fail "PID filtering not working? traced task = $count_pid; other tasks = $count_other "
fi
disable_tracing
clear_trace
if [ $do_function_fork -eq 0 ]; then
return
fi
# allow children to be traced
echo function-fork > trace_options
# With pid in both set_ftrace_pid and set_ftrace_notrace_pid
# there should not be any tasks traced.
echo $PID > set_ftrace_pid
enable_tracing
yield
count_pid=`cat trace | grep -v ^# | grep $PID | wc -l`
count_other=`cat trace | grep -v ^# | grep -v $PID | wc -l`
# both should be zero
if [ $count_pid -ne 0 -o $count_other -ne 0 ]; then
fail "PID filtering not following fork? traced task = $count_pid; other tasks = $count_other "
fi
}
do_test
do_reset
exit 0
@@ -0,0 +1,107 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function pid filters
# requires: set_ftrace_pid set_ftrace_filter function:tracer
# flags: instance
# Make sure that function pid matching filter works.
# Also test it on an instance directory
do_function_fork=1
do_funcgraph_proc=1
if [ ! -f options/function-fork ]; then
do_function_fork=0
echo "no option for function-fork found. Option will not be tested."
fi
if [ ! -f options/funcgraph-proc ]; then
do_funcgraph_proc=0
echo "no option for function-fork found. Option will not be tested."
fi
read PID _ < /proc/self/stat
if [ $do_function_fork -eq 1 ]; then
# default value of function-fork option
orig_value=`grep function-fork trace_options`
fi
if [ $do_funcgraph_proc -eq 1 ]; then
orig_value2=`cat options/funcgraph-proc`
echo 1 > options/funcgraph-proc
fi
do_reset() {
if [ $do_function_fork -eq 1 ]; then
echo $orig_value > trace_options
fi
if [ $do_funcgraph_proc -eq 1 ]; then
echo $orig_value2 > options/funcgraph-proc
fi
}
fail() { # msg
do_reset
echo $1
exit_fail
}
do_test() {
TRACER=$1
disable_tracing
echo do_execve* > set_ftrace_filter
echo $FUNCTION_FORK >> set_ftrace_filter
echo $PID > set_ftrace_pid
echo $TRACER > current_tracer
if [ $do_function_fork -eq 1 ]; then
# don't allow children to be traced
echo nofunction-fork > trace_options
fi
enable_tracing
yield
count_pid=`cat trace | grep -v ^# | grep $PID | wc -l`
count_other=`cat trace | grep -v ^# | grep -v $PID | wc -l`
# count_other should be 0
if [ $count_pid -eq 0 -o $count_other -ne 0 ]; then
fail "PID filtering not working?"
fi
disable_tracing
clear_trace
if [ $do_function_fork -eq 0 ]; then
return
fi
# allow children to be traced
echo function-fork > trace_options
enable_tracing
yield
count_pid=`cat trace | grep -v ^# | grep $PID | wc -l`
count_other=`cat trace | grep -v ^# | grep -v $PID | wc -l`
# count_other should NOT be 0
if [ $count_pid -eq 0 -o $count_other -eq 0 ]; then
fail "PID filtering not following fork?"
fi
}
do_test function
if grep -s function_graph available_tracers; then
do_test function_graph
fi
do_reset
exit 0
@@ -0,0 +1,13 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - stacktrace filter command
# requires: set_ftrace_filter
# flags: instance
echo $FUNCTION_FORK:stacktrace >> set_ftrace_filter
grep -q "$FUNCTION_FORK:stacktrace:unlimited" set_ftrace_filter
(echo "forked"; sleep 1)
grep -q "<stack trace>" trace
@@ -0,0 +1,43 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function trace with cpumask
# requires: function:tracer
if ! which nproc ; then
nproc() {
ls -d /sys/devices/system/cpu/cpu[0-9]* | wc -l
}
fi
NP=`nproc`
if [ $NP -eq 1 ] ;then
echo "We can not test cpumask on UP environment"
exit_unresolved
fi
ORIG_CPUMASK=`cat tracing_cpumask`
do_reset() {
echo $ORIG_CPUMASK > tracing_cpumask
}
echo 0 > tracing_on
echo > trace
: "Bitmask only record on CPU1"
echo 2 > tracing_cpumask
MASK=0x`cat tracing_cpumask`
test `printf "%d" $MASK` -eq 2 || do_reset
echo function > current_tracer
echo 1 > tracing_on
(echo "forked")
echo 0 > tracing_on
: "Check CPU1 events are recorded"
grep -q -e "\[001\]" trace || do_reset
: "There should be No other cpu events"
! grep -qv -e "\[001\]" -e "^#" trace || do_reset
do_reset
@@ -0,0 +1,123 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - test for function event triggers
# flags: instance
#
# The triggers are set within the set_ftrace_filter file
# requires: set_ftrace_filter
#
# Ftrace allows to add triggers to functions, such as enabling or disabling
# tracing, enabling or disabling trace events, or recording a stack trace
# within the ring buffer.
#
# This test is designed to test event triggers
do_reset() {
reset_ftrace_filter
reset_tracer
disable_events
clear_trace
enable_tracing
}
fail() { # mesg
echo $1
exit_fail
}
SLEEP_TIME=".1"
echo "Testing function probes with events:"
EVENT="sched:sched_switch"
EVENT_ENABLE="events/sched/sched_switch/enable"
cnt_trace() {
grep -v '^#' trace | wc -l
}
test_event_enabled() {
val=$1
check_times=10 # wait for 10 * SLEEP_TIME at most
while [ $check_times -ne 0 ]; do
e=`cat $EVENT_ENABLE`
if [ "$e" = $val ]; then
return 0
fi
sleep $SLEEP_TIME
check_times=$((check_times - 1))
done
fail "Expected $val but found $e"
}
run_enable_disable() {
enable=$1 # enable
Enable=$2 # Enable
check_disable=$3 # 0
check_enable_star=$4 # 1*
check_disable_star=$5 # 0*
cnt=`cnt_trace`
if [ $cnt -ne 0 ]; then
fail "Found junk in trace file"
fi
echo "$Enable event all the time"
echo $check_disable > $EVENT_ENABLE
sleep $SLEEP_TIME
test_event_enabled $check_disable
echo "schedule:${enable}_event:$EVENT" > set_ftrace_filter
if [ -d ../../instances ]; then # Check instances
cur=`cat set_ftrace_filter`
top=`cat ../../set_ftrace_filter`
if [ "$cur" = "$top" ]; then
echo "This kernel is too old to support per instance filter"
reset_ftrace_filter
exit_unsupported
fi
fi
echo " make sure it works 5 times"
for i in `seq 5`; do
sleep $SLEEP_TIME
echo " test $i"
test_event_enabled $check_enable_star
echo $check_disable > $EVENT_ENABLE
done
sleep $SLEEP_TIME
echo " make sure it still works"
test_event_enabled $check_enable_star
reset_ftrace_filter
echo " make sure it only works 3 times"
echo $check_disable > $EVENT_ENABLE
sleep $SLEEP_TIME
echo "schedule:${enable}_event:$EVENT:3" > set_ftrace_filter
for i in `seq 3`; do
sleep $SLEEP_TIME
echo " test $i"
test_event_enabled $check_enable_star
echo $check_disable > $EVENT_ENABLE
done
sleep $SLEEP_TIME
echo " make sure it stop working"
test_event_enabled $check_disable_star
do_reset
}
run_enable_disable enable Enable 0 "1*" "0*"
run_enable_disable disable Disable 1 "0*" "1*"
@@ -0,0 +1,42 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later
# description: ftrace - function trace across cpu hotplug
# requires: function:tracer
if ! which nproc ; then
nproc() {
ls -d /sys/devices/system/cpu/cpu[0-9]* | wc -l
}
fi
NP=`nproc`
if [ $NP -eq 1 ] ;then
echo "We cannot test cpu hotplug in UP environment"
exit_unresolved
fi
# Find online cpu
for i in /sys/devices/system/cpu/cpu[1-9]*; do
if [ -f $i/online ] && [ "$(cat $i/online)" = "1" ]; then
cpu=$i
break
fi
done
if [ -z "$cpu" ]; then
echo "We cannot test cpu hotplug with a single cpu online"
exit_unresolved
fi
echo 0 > tracing_on
echo > trace
: "Set $(basename $cpu) offline/online with function tracer enabled"
echo function > current_tracer
echo 1 > tracing_on
(echo 0 > $cpu/online)
(echo "forked"; sleep 1)
(echo 1 > $cpu/online)
echo 0 > tracing_on
echo nop > current_tracer
@@ -0,0 +1,23 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function trace on module
# requires: set_ftrace_filter
: "mod: allows to filter a non exist function"
echo 'non_exist_func:mod:non_exist_module' > set_ftrace_filter
grep -q "non_exist_func" set_ftrace_filter
: "mod: on exist module"
echo '*:mod:trace_printk' > set_ftrace_filter
if ! modprobe trace-printk ; then
echo "No trace-printk sample module - please make CONFIG_SAMPLE_TRACE_PRINTK=
m"
exit_unresolved;
fi
: "Wildcard should be resolved after loading module"
grep -q "trace_printk_irq_work" set_ftrace_filter
: "After removing the filter becomes empty"
rmmod trace_printk
test `cat set_ftrace_filter | wc -l` -eq 0
@@ -0,0 +1,21 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function profiling
# requires: function_profile_enabled
: "Enable function profile"
echo 1 > function_profile_enabled
: "Profile must be updated"
cp trace_stat/function0 $TMPDIR/
( echo "forked"; sleep 1 )
: "diff returns 0 if there is no difference"
! diff trace_stat/function0 $TMPDIR/function0
echo 0 > function_profile_enabled
: "Profile must NOT be updated"
cp trace_stat/function0 $TMPDIR/
( echo "forked"; sleep 1 )
: "diff returns 0 if there is no difference"
diff trace_stat/function0 $TMPDIR/function0
@@ -0,0 +1,64 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function profiler with function tracing
# requires: function_profile_enabled set_ftrace_filter function_graph:tracer
# There was a bug after a rewrite of the ftrace infrastructure that
# caused the function_profiler not to be able to run with the function
# tracer, because the function_profiler used the function_graph tracer
# and it was assumed the two could not run simultaneously.
#
# There was another related bug where the solution to the first bug
# broke the way filtering of the function tracer worked.
#
# This test triggers those bugs on those kernels.
#
# We need function_graph and profiling to to run this test
fail() { # mesg
echo $1
exit_fail
}
echo "Testing function tracer with profiler:"
echo "enable function tracer"
echo function > current_tracer
echo "enable profiler"
echo 1 > function_profile_enabled
sleep 1
echo "Now filter on just schedule"
echo '*schedule' > set_ftrace_filter
clear_trace
echo "Now disable function profiler"
echo 0 > function_profile_enabled
sleep 1
# make sure only schedule functions exist
echo "testing if only schedule is being traced"
if grep -v -e '^#' -e 'schedule' trace; then
fail "more than schedule was found"
fi
echo "Make sure schedule was traced"
if ! grep -e 'schedule' trace > /dev/null; then
cat trace
fail "can not find schedule in trace"
fi
echo > set_ftrace_filter
clear_trace
sleep 1
echo "make sure something other than scheduler is being traced"
if ! grep -v -e '^#' -e 'schedule' trace > /dev/null; then
cat trace
fail "no other functions besides schedule was found"
fi
exit 0
@@ -0,0 +1,161 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - test reading of set_ftrace_filter
#
# The triggers are set within the set_ftrace_filter file
# requires: set_ftrace_filter
#
# The set_ftrace_filter file of ftrace is used to list functions as well as
# triggers (probes) attached to functions. The code to read this file is not
# straight forward and has had various bugs in the past. This test is designed
# to add functions and triggers to that file in various ways and read that
# file in various ways (cat vs dd).
#
fail() { # mesg
echo $1
exit_fail
}
FILTER=set_ftrace_filter
FUNC1="schedule"
if grep '^sched_tick\b' available_filter_functions; then
FUNC2="sched_tick"
elif grep '^scheduler_tick\b' available_filter_functions; then
FUNC2="scheduler_tick"
else
exit_unresolved
fi
ALL_FUNCS="#### all functions enabled ####"
test_func() {
if ! echo "$1" | grep -q "^$2\$"; then
return 0
fi
echo "$1" | grep -v "^$2\$"
return 1
}
check_set_ftrace_filter() {
cat=`cat $FILTER`
dd1=`dd if=$FILTER bs=1 | grep -v -e 'records in' -e 'records out' -e 'bytes copied'`
dd100=`dd if=$FILTER bs=100 | grep -v -e 'records in' -e 'records out' -e 'bytes copied'`
echo "Testing '$@'"
while [ $# -gt 0 ]; do
echo "test $1"
if cat=`test_func "$cat" "$1"`; then
return 0
fi
if dd1=`test_func "$dd1" "$1"`; then
return 0
fi
if dd100=`test_func "$dd100" "$1"`; then
return 0
fi
shift
done
if [ -n "$cat" ]; then
return 0
fi
if [ -n "$dd1" ]; then
return 0
fi
if [ -n "$dd100" ]; then
return 0
fi
return 1;
}
if check_set_ftrace_filter "$ALL_FUNCS"; then
fail "Expected only $ALL_FUNCS"
fi
echo "$FUNC1:traceoff" > set_ftrace_filter
if check_set_ftrace_filter "$ALL_FUNCS" "$FUNC1:traceoff:unlimited"; then
fail "Expected $ALL_FUNCS and $FUNC1:traceoff:unlimited"
fi
echo "$FUNC1" > set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" "$FUNC1:traceoff:unlimited"; then
fail "Expected $FUNC1 and $FUNC1:traceoff:unlimited"
fi
echo "$FUNC2" >> set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" "$FUNC2" "$FUNC1:traceoff:unlimited"; then
fail "Expected $FUNC1 $FUNC2 and $FUNC1:traceoff:unlimited"
fi
echo "$FUNC2:traceoff" >> set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" "$FUNC2" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
fail "Expected $FUNC1 $FUNC2 $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
fi
echo "$FUNC1" > set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
fail "Expected $FUNC1 $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
fi
echo > set_ftrace_filter
if check_set_ftrace_filter "$ALL_FUNCS" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
fail "Expected $ALL_FUNCS $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
fi
reset_ftrace_filter
if check_set_ftrace_filter "$ALL_FUNCS"; then
fail "Expected $ALL_FUNCS"
fi
echo "$FUNC1" > set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" ; then
fail "Expected $FUNC1"
fi
echo "$FUNC2" >> set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" "$FUNC2" ; then
fail "Expected $FUNC1 and $FUNC2"
fi
test_actual() { # Compares $TMPDIR/expected with set_ftrace_filter
cat set_ftrace_filter | grep -v '#' | cut -d' ' -f1 | cut -d':' -f1 | sort -u > $TMPDIR/actual
DIFF=`diff $TMPDIR/actual $TMPDIR/expected`
test -z "$DIFF"
}
# Set traceoff trigger for all fuctions with "lock" in their name
cat available_filter_functions | cut -d' ' -f1 | grep 'lock' | sort -u > $TMPDIR/expected
echo '*lock*:traceoff' > set_ftrace_filter
test_actual
# now remove all with 'try' in it, and end with lock
grep -v 'try.*lock$' $TMPDIR/expected > $TMPDIR/expected2
mv $TMPDIR/expected2 $TMPDIR/expected
echo '!*try*lock:traceoff' >> set_ftrace_filter
test_actual
# remove all that start with "m" and end with "lock"
grep -v '^m.*lock$' $TMPDIR/expected > $TMPDIR/expected2
mv $TMPDIR/expected2 $TMPDIR/expected
echo '!m*lock:traceoff' >> set_ftrace_filter
test_actual
# remove all that start with "c" and have "unlock"
grep -v '^c.*unlock' $TMPDIR/expected > $TMPDIR/expected2
mv $TMPDIR/expected2 $TMPDIR/expected
echo '!c*unlock*:traceoff' >> set_ftrace_filter
test_actual
# clear all the rest
> $TMPDIR/expected
echo '!*:traceoff' >> set_ftrace_filter
test_actual
rm $TMPDIR/expected
rm $TMPDIR/actual
exit 0
@@ -0,0 +1,35 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - Max stack tracer
# requires: stack_trace stack_trace_filter
# Test the basic function of max-stack usage tracing
echo > stack_trace_filter
echo 0 > stack_max_size
echo 1 > /proc/sys/kernel/stack_tracer_enabled
: "Fork and wait for the first entry become !lock"
timeout=10
while [ $timeout -ne 0 ]; do
( echo "forked" )
FL=`grep " 0)" stack_trace`
echo $FL | grep -q "lock" || break;
timeout=$((timeout - 1))
done
echo 0 > /proc/sys/kernel/stack_tracer_enabled
echo '*lock*' > stack_trace_filter
test `cat stack_trace_filter | wc -l` -eq `grep lock stack_trace_filter | wc -l`
echo 0 > stack_max_size
echo 1 > /proc/sys/kernel/stack_tracer_enabled
: "Fork and always the first entry including lock"
timeout=10
while [ $timeout -ne 0 ]; do
( echo "forked" )
FL=`grep " 0)" stack_trace`
echo $FL | grep -q "lock"
timeout=$((timeout - 1))
done
echo 0 > /proc/sys/kernel/stack_tracer_enabled
@@ -0,0 +1,173 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - test for function traceon/off triggers
# flags: instance
#
# The triggers are set within the set_ftrace_filter file
# requires: set_ftrace_filter
#
# Ftrace allows to add triggers to functions, such as enabling or disabling
# tracing, enabling or disabling trace events, or recording a stack trace
# within the ring buffer.
#
# This test is designed to test enabling and disabling tracing triggers
#
fail() { # mesg
echo $1
exit_fail
}
SLEEP_TIME=".1"
echo "Testing function probes with enabling disabling tracing:"
cnt_trace() {
grep -v '^#' trace | wc -l
}
echo '** DISABLE TRACING'
disable_tracing
clear_trace
cnt=`cnt_trace`
if [ $cnt -ne 0 ]; then
fail "Found junk in trace"
fi
echo '** ENABLE EVENTS'
echo 1 > events/sched/enable
echo '** ENABLE TRACING'
enable_tracing
cnt=`cnt_trace`
if [ $cnt -eq 0 ]; then
fail "Nothing found in trace"
fi
# powerpc uses .schedule
func="schedule"
available_file=available_filter_functions
if [ -d ../../instances -a -f ../../available_filter_functions ]; then
available_file=../../available_filter_functions
fi
x=`grep '^\.schedule$' available_filter_functions | wc -l`
if [ "$x" -eq 1 ]; then
func=".schedule"
fi
echo '** SET TRACEOFF'
echo "$func:traceoff" > set_ftrace_filter
if [ -d ../../instances ]; then # Check instances
cur=`cat set_ftrace_filter`
top=`cat ../../set_ftrace_filter`
if [ "$cur" = "$top" ]; then
echo "This kernel is too old to support per instance filter"
reset_ftrace_filter
exit_unsupported
fi
fi
cnt=`grep schedule set_ftrace_filter | wc -l`
if [ $cnt -ne 1 ]; then
fail "Did not find traceoff trigger"
fi
cnt=`cnt_trace`
sleep $SLEEP_TIME
cnt2=`cnt_trace`
if [ $cnt -ne $cnt2 ]; then
fail "Tracing is not stopped"
fi
on=`cat tracing_on`
if [ $on != "0" ]; then
fail "Tracing is not off"
fi
# Cannot rely on names being around as they are only cached, strip them
csum1=`cat trace | sed -e 's/^ *[^ ]*\(-[0-9][0-9]*\)/\1/' | md5sum`
sleep $SLEEP_TIME
csum2=`cat trace | sed -e 's/^ *[^ ]*\(-[0-9][0-9]*\)/\1/' | md5sum`
if [ "$csum1" != "$csum2" ]; then
fail "Tracing file is still changing"
fi
clear_trace
cnt=`cnt_trace`
if [ $cnt -ne 0 ]; then
fail "Tracing is still happeing"
fi
echo "!$func:traceoff" >> set_ftrace_filter
cnt=`grep schedule set_ftrace_filter | wc -l`
if [ $cnt -ne 0 ]; then
fail "traceoff trigger still exists"
fi
on=`cat tracing_on`
if [ $on != "0" ]; then
fail "Tracing is started again"
fi
echo "$func:traceon" > set_ftrace_filter
cnt=`grep schedule set_ftrace_filter | wc -l`
if [ $cnt -ne 1 ]; then
fail "traceon trigger not found"
fi
cnt=`cnt_trace`
if [ $cnt -eq 0 ]; then
fail "Tracing did not start"
fi
on=`cat tracing_on`
if [ $on != "1" ]; then
fail "Tracing was not enabled"
fi
echo "!$func:traceon" >> set_ftrace_filter
cnt=`grep schedule set_ftrace_filter | wc -l`
if [ $cnt -ne 0 ]; then
fail "traceon trigger still exists"
fi
check_sleep() {
val=$1
sleep $SLEEP_TIME
cat set_ftrace_filter
on=`cat tracing_on`
if [ $on != "$val" ]; then
fail "Expected tracing_on to be $val, but it was $on"
fi
}
echo "$func:traceoff:3" > set_ftrace_filter
check_sleep "0"
echo 1 > tracing_on
check_sleep "0"
echo 1 > tracing_on
check_sleep "0"
echo 1 > tracing_on
check_sleep "1"
echo "!$func:traceoff:0" > set_ftrace_filter
if grep -e traceon -e traceoff set_ftrace_filter; then
fail "Tracing on and off triggers still exist"
fi
disable_events
exit 0
@@ -0,0 +1,15 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - test tracing error log support
# event tracing is currently the only ftrace tracer that uses the
# tracing error_log, hence this check
# requires: set_event error_log
fail() { #msg
echo $1
exit_fail
}
ftrace_errlog_check 'event filter parse error' '((sig >= 10 && sig < 15) || dsig ^== 17) && comm != bash' 'events/signal/signal_generate/filter'
exit 0
@@ -0,0 +1,230 @@
clear_trace() { # reset trace output
echo > trace
}
disable_tracing() { # stop trace recording
echo 0 > tracing_on
}
enable_tracing() { # start trace recording
echo 1 > tracing_on
}
reset_tracer() { # reset the current tracer
echo nop > current_tracer
}
reset_trigger_file() {
# remove action triggers first
grep -H ':on[^:]*(' $@ |
while read line; do
cmd=`echo $line | cut -f2- -d: | cut -f1 -d"["`
file=`echo $line | cut -f1 -d:`
echo "!$cmd" >> $file
done
grep -Hv ^# $@ |
while read line; do
cmd=`echo $line | cut -f2- -d: | cut -f1 -d"["`
file=`echo $line | cut -f1 -d:`
echo "!$cmd" > $file
done
}
reset_trigger() { # reset all current setting triggers
if [ -d events/synthetic ]; then
reset_trigger_file events/synthetic/*/trigger
fi
reset_trigger_file events/*/*/trigger
}
reset_events_filter() { # reset all current setting filters
grep -v ^none events/*/*/filter |
while read line; do
echo 0 > `echo $line | cut -f1 -d:`
done
}
reset_ftrace_filter() { # reset all triggers in set_ftrace_filter
if [ ! -f set_ftrace_filter ]; then
return 0
fi
echo > set_ftrace_filter
grep -v '^#' set_ftrace_filter | while read t; do
tr=`echo $t | cut -d: -f2`
if [ "$tr" = "" ]; then
continue
fi
if ! grep -q "$t" set_ftrace_filter; then
continue;
fi
name=`echo $t | cut -d: -f1 | cut -d' ' -f1`
if [ $tr = "enable_event" -o $tr = "disable_event" ]; then
tr=`echo $t | cut -d: -f2-4`
limit=`echo $t | cut -d: -f5`
else
tr=`echo $t | cut -d: -f2`
limit=`echo $t | cut -d: -f3`
fi
if [ "$limit" != "unlimited" ]; then
tr="$tr:$limit"
fi
echo "!$name:$tr" > set_ftrace_filter
done
}
disable_events() {
echo 0 > events/enable
}
clear_synthetic_events() { # reset all current synthetic events
grep -v ^# synthetic_events |
while read line; do
echo "!$line" >> synthetic_events
done
}
clear_dynamic_events() { # reset all current dynamic events
again=1
stop=1
# loop mulitple times as some events require other to be removed first
while [ $again -eq 1 ]; do
stop=$((stop+1))
# Prevent infinite loops
if [ $stop -gt 10 ]; then
break;
fi
again=2
grep -v '^#' dynamic_events|
while read line; do
del=`echo $line | sed -e 's/^.\([^ ]*\).*/-\1/'`
if ! echo "$del" >> dynamic_events; then
again=1
fi
done
done
}
initialize_system() { # Reset ftrace to initial-state
# As the initial state, ftrace will be set to nop tracer,
# no events, no triggers, no filters, no function filters,
# no probes, and tracing on.
disable_tracing
reset_tracer
reset_trigger
reset_events_filter
reset_ftrace_filter
disable_events
clear_dynamic_events
[ -f set_event_pid ] && echo > set_event_pid
[ -f set_ftrace_pid ] && echo > set_ftrace_pid
[ -f set_ftrace_notrace ] && echo > set_ftrace_notrace
[ -f set_graph_function ] && echo | tee set_graph_*
[ -f stack_trace_filter ] && echo > stack_trace_filter
[ -f kprobe_events ] && echo > kprobe_events
[ -f uprobe_events ] && echo > uprobe_events
[ -f synthetic_events ] && echo > synthetic_events
[ -f snapshot ] && echo 0 > snapshot
# Stop tracing while reading the trace file by default, to prevent
# the test results while checking it and to avoid taking a long time
# to check the result.
[ -f options/pause-on-trace ] && echo 1 > options/pause-on-trace
clear_trace
enable_tracing
}
finish_system() {
initialize_system
# And recover it to default.
[ -f options/pause-on-trace ] && echo 0 > options/pause-on-trace
}
check_requires() { # Check required files and tracers
for i in "$@" ; do
p=${i%:program}
r=${i%:README}
t=${i%:tracer}
if [ "$p" != "$i" ]; then
if ! which "$p" ; then
echo "Required program $p is not found."
exit_unresolved
fi
elif [ "$t" != "$i" ]; then
if ! grep -wq "$t" available_tracers ; then
echo "Required tracer $t is not configured."
exit_unsupported
fi
elif [ "$r" != "$i" ]; then
# If this is an instance, check the top directory
if echo $TRACING_DIR | grep -q "/instances/"; then
test="$TRACING_DIR/../.."
else
test=$TRACING_DIR
fi
if ! grep -Fq "$r" "$test"/README ; then
echo "Required feature pattern \"$r\" is not in README."
exit_unsupported
fi
elif [ ! -e "$i" ]; then
echo "Required feature interface $i doesn't exist."
exit_unsupported
fi
done
}
check_awk_strtonum() { # strtonum is GNU awk extension
awk 'BEGIN{strtonum("0x1")}'
}
LOCALHOST=127.0.0.1
yield() {
ping $LOCALHOST -c 1 || sleep .001 || usleep 1 || sleep 1
}
# The fork function in the kernel was renamed from "_do_fork" to
# "kernel_fork". As older tests should still work with older kernels
# as well as newer kernels, check which version of fork is used on this
# kernel so that the tests can use the fork function for the running kernel.
FUNCTION_FORK=`(if grep '\bkernel_clone\b' /proc/kallsyms > /dev/null; then
echo kernel_clone; else echo '_do_fork'; fi)`
# Since probe event command may include backslash, explicitly use printf "%s"
# to NOT interpret it.
ftrace_errlog_check() { # err-prefix command-with-error-pos-by-^ command-file
pos=$(printf "%s" "${2%^*}" | wc -c) # error position
command=$(printf "%s" "$2" | tr -d ^)
echo "Test command: $command"
echo > error_log
(! printf "%s" "$command" >> "$3" ) 2> /dev/null
grep "$1: error:" -A 3 error_log
N=$(tail -n 1 error_log | wc -c)
# " Command: " and "^\n" => 13
test $(expr 13 + $pos) -eq $N
}
# Helper to get the tracefs mount point
get_mount_point() {
local mount_point=`stat -c '%m' .`
# If stat -c '%m' does not work (e.g. busybox) or failed, try to use the
# current working directory (which should be a tracefs) as the mount point.
if [ ! -d "$mount_point" ]; then
if mount | grep -qw "$PWD"; then
mount_point=$PWD
else
# If PWD doesn't work, that is an environmental problem.
exit_unresolved
fi
fi
echo "$mount_point"
}
# Helper function to retrieve mount options for a given mount point
get_mnt_options() {
local mnt_point="$1"
local opts=$(mount | grep -m1 "$mnt_point" | sed -e 's/.*(\(.*\)).*/\1/')
echo "$opts"
}
@@ -0,0 +1,142 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Test creation and deletion of trace instances while setting an event
# requires: instances
fail() { # mesg
rmdir foo 2>/dev/null
echo $1
set -e
exit_fail
}
cd instances
# we don't want to fail on error
set +e
mkdir x
rmdir x
result=$?
if [ $result -ne 0 ]; then
echo "instance rmdir not supported"
exit_unsupported
fi
instance_slam() {
while :; do
mkdir foo 2> /dev/null
rmdir foo 2> /dev/null
done
}
instance_read() {
while :; do
cat foo/trace 1> /dev/null 2>&1
done
}
instance_set() {
while :; do
echo 1 > foo/events/sched/sched_switch/enable
done 2> /dev/null
}
instance_slam &
p1=$!
echo $p1
instance_set &
p2=$!
echo $p2
instance_read &
p3=$!
echo $p3
sleep 1
kill -1 $p3
kill -1 $p2
kill -1 $p1
echo "Wait for processes to finish"
wait $p1 $p2 $p3
echo "all processes finished, wait for cleanup"
sleep 1
mkdir foo
ls foo > /dev/null
rmdir foo
if [ -d foo ]; then
fail "foo still exists"
fi
mkdir foo
echo "schedule:enable_event:sched:sched_switch" > foo/set_ftrace_filter
rmdir foo
if [ -d foo ]; then
fail "foo still exists"
fi
if grep -q "schedule:enable_event:sched:sched_switch" ../set_ftrace_filter; then
echo "Older kernel detected. Cleanup filter"
echo '!schedule:enable_event:sched:sched_switch' > ../set_ftrace_filter
fi
instance_slam() {
while :; do
mkdir x
mkdir y
mkdir z
rmdir x
rmdir y
rmdir z
done 2>/dev/null
}
instance_slam &
p1=$!
echo $p1
instance_slam &
p2=$!
echo $p2
instance_slam &
p3=$!
echo $p3
instance_slam &
p4=$!
echo $p4
instance_slam &
p5=$!
echo $p5
ls -lR >/dev/null
sleep 1
kill -1 $p1
kill -1 $p2
kill -1 $p3
kill -1 $p4
kill -1 $p5
echo "Wait for processes to finish"
wait $p1 $p2 $p3 $p4 $p5
echo "all processes finished, wait for cleanup"
mkdir x y z
ls x y z
rmdir x y z
for d in x y z; do
if [ -d $d ]; then
fail "instance $d still exists"
fi
done
set -e
exit 0
@@ -0,0 +1,82 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Test creation and deletion of trace instances
# requires: instances
fail() { # mesg
rmdir x y z 2>/dev/null
echo $1
set -e
exit_fail
}
cd instances
# we don't want to fail on error
set +e
mkdir x
rmdir x
result=$?
if [ $result -ne 0 ]; then
echo "instance rmdir not supported"
exit_unsupported
fi
instance_slam() {
while :; do
mkdir x
mkdir y
mkdir z
rmdir x
rmdir y
rmdir z
done 2>/dev/null
}
instance_slam &
p1=$!
echo $p1
instance_slam &
p2=$!
echo $p2
instance_slam &
p3=$!
echo $p3
instance_slam &
p4=$!
echo $p4
instance_slam &
p5=$!
echo $p5
ls -lR >/dev/null
sleep 1
kill -1 $p1
kill -1 $p2
kill -1 $p3
kill -1 $p4
kill -1 $p5
echo "Wait for processes to finish"
wait $p1 $p2 $p3 $p4 $p5
echo "all processes finished, wait for cleanup"
mkdir x y z
ls x y z
rmdir x y z
for d in x y z; do
if [ -d $d ]; then
fail "instance $d still exists"
fi
done
set -e
exit 0
@@ -0,0 +1,9 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe dynamic event - adding and removing
# requires: kprobe_events
echo p:myevent $FUNCTION_FORK > kprobe_events
grep myevent kprobe_events
test -d events/kprobes/myevent
echo > kprobe_events
@@ -0,0 +1,11 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe dynamic event - busy event check
# requires: kprobe_events
echo p:myevent $FUNCTION_FORK > kprobe_events
test -d events/kprobes/myevent
echo 1 > events/kprobes/myevent/enable
echo > kprobe_events && exit_fail # this must fail
echo 0 > events/kprobes/myevent/enable
echo > kprobe_events # this must succeed
@@ -0,0 +1,19 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe dynamic event with arguments
# requires: kprobe_events
echo "p:testprobe $FUNCTION_FORK \$stack \$stack0 +0(\$stack)" > kprobe_events
grep testprobe kprobe_events | grep -q 'arg1=\$stack arg2=\$stack0 arg3=+0(\$stack)'
test -d events/kprobes/testprobe
echo 1 > events/kprobes/testprobe/enable
( echo "forked")
grep testprobe trace | grep "$FUNCTION_FORK" | \
grep -q 'arg1=0x[[:xdigit:]]* arg2=0x[[:xdigit:]]* arg3=0x[[:xdigit:]]*$'
echo 0 > events/kprobes/testprobe/enable
echo "-:testprobe" >> kprobe_events
clear_trace
test -d events/kprobes/testprobe && exit_fail || exit_pass
@@ -0,0 +1,60 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event char type argument
# requires: kprobe_events available_filter_functions
case `uname -m` in
x86_64)
ARG1=%di
;;
i[3456]86)
ARG1=%ax
;;
aarch64)
ARG1=%x0
;;
arm*)
ARG1=%r0
;;
ppc64*)
ARG1=%r3
;;
ppc*)
ARG1=%r3
;;
s390*)
ARG1=%r2
;;
mips*)
ARG1=%r4
;;
loongarch*)
ARG1=%r4
;;
riscv*)
ARG1=%a0
;;
*)
echo "Please implement other architecture here"
exit_untested
esac
: "Test get argument (1)"
if grep -q eventfs_create_dir available_filter_functions; then
DIR_NAME="eventfs_create_dir"
elif grep -q eventfs_add_dir available_filter_functions; then
DIR_NAME="eventfs_add_dir"
else
DIR_NAME="tracefs_create_dir"
fi
echo "p:testprobe ${DIR_NAME} arg1=+0(${ARG1}):char" > kprobe_events
echo 1 > events/kprobes/testprobe/enable
echo "p:test $FUNCTION_FORK" >> kprobe_events
grep -qe "testprobe.* arg1='t'" trace
echo 0 > events/kprobes/testprobe/enable
: "Test get argument (2)"
echo "p:testprobe ${DIR_NAME} arg1=+0(${ARG1}):char arg2=+0(${ARG1}):char[4]" > kprobe_events
echo 1 > events/kprobes/testprobe/enable
echo "p:test $FUNCTION_FORK" >> kprobe_events
grep -qe "testprobe.* arg1='t' arg2={'t','e','s','t'}" trace
@@ -0,0 +1,16 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event with comm arguments
# requires: kprobe_events
grep -A1 "fetcharg:" README | grep -q "\$comm" || exit_unsupported # this is too old
echo "p:testprobe $FUNCTION_FORK comm=\$comm " > kprobe_events
grep testprobe kprobe_events | grep -q 'comm=$comm'
test -d events/kprobes/testprobe
echo 1 > events/kprobes/testprobe/enable
( echo "forked")
grep testprobe trace | grep -q 'comm=".*"'
exit 0
@@ -0,0 +1,61 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event string type argument
# requires: kprobe_events available_filter_functions
case `uname -m` in
x86_64)
ARG1=%di
;;
i[3456]86)
ARG1=%ax
;;
aarch64)
ARG1=%x0
;;
arm*)
ARG1=%r0
;;
ppc64*)
ARG1=%r3
;;
ppc*)
ARG1=%r3
;;
s390*)
ARG1=%r2
;;
mips*)
ARG1=%r4
;;
loongarch*)
ARG1=%r4
;;
riscv*)
ARG1=%a0
;;
*)
echo "Please implement other architecture here"
exit_untested
esac
: "Test get argument (1)"
if grep -q eventfs_create_dir available_filter_functions; then
DIR_NAME="eventfs_create_dir"
elif grep -q eventfs_add_dir available_filter_functions; then
DIR_NAME="eventfs_add_dir"
else
DIR_NAME="tracefs_create_dir"
fi
echo "p:testprobe ${DIR_NAME} arg1=+0(${ARG1}):string" > kprobe_events
echo 1 > events/kprobes/testprobe/enable
echo "p:test $FUNCTION_FORK" >> kprobe_events
grep -qe "testprobe.* arg1=\"test\"" trace
echo 0 > events/kprobes/testprobe/enable
: "Test get argument (2)"
echo "p:testprobe ${DIR_NAME} arg1=+0(${ARG1}):string arg2=+0(${ARG1}):string" > kprobe_events
echo 1 > events/kprobes/testprobe/enable
echo "p:test $FUNCTION_FORK" >> kprobe_events
grep -qe "testprobe.* arg1=\"test\" arg2=\"test\"" trace
@@ -0,0 +1,38 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event symbol argument
# requires: kprobe_events
SYMBOL="linux_proc_banner"
if [ ! -f /proc/kallsyms ]; then
echo "Can not check the target symbol - please enable CONFIG_KALLSYMS"
exit_unresolved
elif ! grep "$SYMBOL\$" /proc/kallsyms; then
echo "Linux banner is not exported - please enable CONFIG_KALLSYMS_ALL"
exit_unresolved
fi
: "Test get basic types symbol argument"
echo "p:testprobe_u $FUNCTION_FORK arg1=@linux_proc_banner:u64 arg2=@linux_proc_banner:u32 arg3=@linux_proc_banner:u16 arg4=@linux_proc_banner:u8" > kprobe_events
echo "p:testprobe_s $FUNCTION_FORK arg1=@linux_proc_banner:s64 arg2=@linux_proc_banner:s32 arg3=@linux_proc_banner:s16 arg4=@linux_proc_banner:s8" >> kprobe_events
if grep -q "x8/16/32/64" README; then
echo "p:testprobe_x $FUNCTION_FORK arg1=@linux_proc_banner:x64 arg2=@linux_proc_banner:x32 arg3=@linux_proc_banner:x16 arg4=@linux_proc_banner:x8" >> kprobe_events
fi
echo "p:testprobe_bf $FUNCTION_FORK arg1=@linux_proc_banner:b8@4/32" >> kprobe_events
echo 1 > events/kprobes/enable
(echo "forked")
echo 0 > events/kprobes/enable
grep "testprobe_[usx]:.* arg1=.* arg2=.* arg3=.* arg4=.*" trace
grep "testprobe_bf:.* arg1=.*" trace
: "Test get string symbol argument"
echo "p:testprobe_str $FUNCTION_FORK arg1=@linux_proc_banner:string" > kprobe_events
echo 1 > events/kprobes/enable
(echo "forked")
echo 0 > events/kprobes/enable
RESULT=`grep "testprobe_str" trace | sed -e 's/.* arg1=\(.*\)/\1/'`
RESULT=`echo $RESULT | sed -e 's/.* \((.*)\) \((.*)\) .*/\1 \2/'`
ORIG=`cat /proc/version | sed -e 's/.* \((.*)\) \((.*)\) .*/\1 \2/'`
test "$RESULT" = "$ORIG"
@@ -0,0 +1,115 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event argument syntax
# requires: kprobe_events "x8/16/32/64":README
PROBEFUNC="vfs_read"
GOODREG=
BADREG=
GOODSYM="_sdata"
if ! grep -qw ${GOODSYM} /proc/kallsyms ; then
GOODSYM=$PROBEFUNC
fi
BADSYM="deaqswdefr"
SYMADDR=0x`grep -w ${GOODSYM} /proc/kallsyms | cut -f 1 -d " "`
GOODTYPE="x16"
BADTYPE="y16"
case `uname -m` in
x86_64|i[3456]86)
GOODREG=%ax
BADREG=%ex
;;
aarch64)
GOODREG=%x0
BADREG=%ax
;;
arm*)
GOODREG=%r0
BADREG=%ax
;;
ppc*)
GOODREG=%r3
BADREG=%msr
;;
s390*)
GOODREG=%r2
BADREG=%s2
;;
mips*)
GOODREG=%r4
BADREG=%r12
;;
loongarch*)
GOODREG=%r4
BADREG=%r12
;;
riscv*)
GOODREG=%a0
BADREG=%a8
;;
*)
echo "Please implement other architecture here"
exit_untested
esac
test_goodarg() # Good-args
{
while [ "$1" ]; do
echo "p ${PROBEFUNC} $1" > kprobe_events
shift 1
done;
}
test_badarg() # Bad-args
{
while [ "$1" ]; do
! echo "p ${PROBEFUNC} $1" > kprobe_events
shift 1
done;
}
echo > kprobe_events
: "Register access"
test_goodarg ${GOODREG}
test_badarg ${BADREG}
: "Symbol access"
test_goodarg "@${GOODSYM}" "@${SYMADDR}" "@${GOODSYM}+10" "@${GOODSYM}-10"
test_badarg "@" "@${BADSYM}" "@${GOODSYM}*10" "@${GOODSYM}/10" \
"@${GOODSYM}%10" "@${GOODSYM}&10" "@${GOODSYM}|10"
: "Stack access"
test_goodarg "\$stack" "\$stack0" "\$stack1"
test_badarg "\$stackp" "\$stack0+10" "\$stack1-10"
: "Retval access"
echo "r ${PROBEFUNC} \$retval" > kprobe_events
! echo "p ${PROBEFUNC} \$retval" > kprobe_events
# $comm was introduced in 4.8, older kernels reject it.
if grep -A1 "fetcharg:" README | grep -q '\$comm' ; then
: "Comm access"
test_goodarg "\$comm"
fi
: "Indirect memory access"
test_goodarg "+0(${GOODREG})" "-0(${GOODREG})" "+10(\$stack)" \
"+0(\$stack1)" "+10(@${GOODSYM}-10)" "+0(+10(+20(\$stack)))"
test_badarg "+(${GOODREG})" "(${GOODREG}+10)" "-(${GOODREG})" "(${GOODREG})" \
"+10(\$comm)" "+0(${GOODREG})+10"
: "Name assignment"
test_goodarg "varname=${GOODREG}"
test_badarg "varname=varname2=${GOODREG}"
: "Type syntax"
test_goodarg "${GOODREG}:${GOODTYPE}"
test_badarg "${GOODREG}::${GOODTYPE}" "${GOODREG}:${BADTYPE}" \
"${GOODTYPE}:${GOODREG}"
: "Combination check"
test_goodarg "\$comm:string" "+0(\$stack):string"
test_badarg "\$comm:x64" "\$stack:string" "${GOODREG}:string"
@@ -0,0 +1,47 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobes event arguments with types
# requires: kprobe_events "x8/16/32/64":README
gen_event() { # Bitsize
echo "p:testprobe $FUNCTION_FORK \$stack0:s$1 \$stack0:u$1 \$stack0:x$1 \$stack0:b4@4/$1"
}
check_types() { # s-type u-type x-type bf-type width
test $# -eq 5
CW=$5
CW=$((CW / 4))
X1=`printf "%x" $1 | tail -c ${CW}`
X2=`printf "%x" $2`
X3=`printf "%x" $3`
test $X1 = $X2
test $X2 = $X3
test 0x$X3 = $3
B4=`printf "%1x" $4`
B3=`printf "%03x" 0x$X3 | tail -c 2 | head -c 1`
test $B3 = $B4
}
for width in 64 32 16 8; do
: "Add new event with basic types"
gen_event $width > kprobe_events
grep testprobe kprobe_events
test -d events/kprobes/testprobe
: "Trace the event"
echo 1 > events/kprobes/testprobe/enable
( echo "forked")
echo 0 > events/kprobes/testprobe/enable
: "Confirm the arguments is recorded in given types correctly"
ARGS=`grep "testprobe" trace | head -n 1 | sed -e 's/.* arg1=\(.*\) arg2=\(.*\) arg3=\(.*\) arg4=\(.*\)/\1 \2 \3 \4/'`
check_types $ARGS $width
: "Clear event for next loop"
echo "-:testprobe" >> kprobe_events
clear_trace
done
exit_pass
@@ -0,0 +1,34 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event user-memory access
# requires: kprobe_events '$arg<N>':README
grep -A10 "fetcharg:" README | grep -q 'ustring' || exit_unsupported
grep -A10 "fetcharg:" README | grep -q '\[u\]<offset>' || exit_unsupported
:;: "user-memory access syntax and ustring working on user memory";:
echo 'p:myevent do_sys_open path=+0($arg2):ustring path2=+u0($arg2):string' \
> kprobe_events
echo 'p:myevent2 do_sys_openat2 path=+0($arg2):ustring path2=+u0($arg2):string' \
>> kprobe_events
grep myevent kprobe_events | \
grep -q 'path=+0($arg2):ustring path2=+u0($arg2):string'
echo 1 > events/kprobes/myevent/enable
echo 1 > events/kprobes/myevent2/enable
echo > /dev/null
echo 0 > events/kprobes/myevent/enable
echo 0 > events/kprobes/myevent2/enable
grep myevent trace | grep -q 'path="/dev/null" path2="/dev/null"'
:;: "user-memory access syntax and ustring not working with kernel memory";:
echo 'p:myevent vfs_symlink path=+0($arg3):ustring path2=+u0($arg3):string' \
> kprobe_events
echo 1 > events/kprobes/myevent/enable
ln -s foo $TMPDIR/bar
echo 0 > events/kprobes/myevent/enable
grep myevent trace | grep -q 'path=(fault) path2=(fault)'
exit 0
@@ -0,0 +1,40 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event VFS type argument
# requires: kprobe_events "%pd/%pD":README
: "Test argument %pd with name"
echo 'p:testprobe dput name=$arg1:%pd' > kprobe_events
echo 1 > events/kprobes/testprobe/enable
grep -q "1" events/kprobes/testprobe/enable
echo 0 > events/kprobes/testprobe/enable
grep "dput" trace | grep -q "enable"
echo "" > kprobe_events
echo "" > trace
: "Test argument %pd without name"
echo 'p:testprobe dput $arg1:%pd' > kprobe_events
echo 1 > events/kprobes/testprobe/enable
grep -q "1" events/kprobes/testprobe/enable
echo 0 > events/kprobes/testprobe/enable
grep "dput" trace | grep -q "enable"
echo "" > kprobe_events
echo "" > trace
: "Test argument %pD with name"
echo 'p:testprobe vfs_read name=$arg1:%pD' > kprobe_events
echo 1 > events/kprobes/testprobe/enable
grep -q "1" events/kprobes/testprobe/enable
echo 0 > events/kprobes/testprobe/enable
grep "vfs_read" trace | grep -q "enable"
echo "" > kprobe_events
echo "" > trace
: "Test argument %pD without name"
echo 'p:testprobe vfs_read $arg1:%pD' > kprobe_events
echo 1 > events/kprobes/testprobe/enable
grep -q "1" events/kprobes/testprobe/enable
echo 0 > events/kprobes/testprobe/enable
grep "vfs_read" trace | grep -q "enable"
echo "" > kprobe_events
echo "" > trace
@@ -0,0 +1,46 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event auto/manual naming
# requires: kprobe_events
:;: "Add an event on function without name" ;:
FUNC=`grep " [tT] .*vfs_read$" /proc/kallsyms | tail -n 1 | cut -f 3 -d " "`
[ "x" != "x$FUNC" ] || exit_unresolved
echo "p $FUNC" > kprobe_events
PROBE_NAME=`echo $FUNC | tr ".:" "_"`
test -d events/kprobes/p_${PROBE_NAME}_0 || exit_failure
:;: "Add an event on function with new name" ;:
echo "p:event1 $FUNC" > kprobe_events
test -d events/kprobes/event1 || exit_failure
:;: "Add an event on function with new name and group" ;:
echo "p:kprobes2/event2 $FUNC" > kprobe_events
test -d events/kprobes2/event2 || exit_failure
:;: "Add an event on dot function without name" ;:
find_dot_func() {
if [ ! -f available_filter_functions ]; then
grep -m 10 " [tT] .*\.isra\..*$" /proc/kallsyms | tail -n 1 | cut -f 3 -d " "
return;
fi
grep " [tT] .*\.isra\..*" /proc/kallsyms | cut -f 3 -d " " | while read f; do
cnt=`grep -s $f available_filter_functions | wc -l`;
if [ $cnt -eq 1 ]; then
echo $f
break
fi
done
}
FUNC=`find_dot_func | tail -n 1`
[ "x" != "x$FUNC" ] || exit_unresolved
echo "p $FUNC" > kprobe_events
EVENT=`grep $FUNC kprobe_events | cut -f 1 -d " " | cut -f 2 -d:`
[ "x" != "x$EVENT" ] || exit_failure
test -d events/$EVENT || exit_failure
@@ -0,0 +1,45 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe dynamic event with function tracer
# requires: kprobe_events stack_trace_filter function:tracer
# prepare
echo nop > current_tracer
echo $FUNCTION_FORK > set_ftrace_filter
echo "p:testprobe $FUNCTION_FORK" > kprobe_events
# kprobe on / ftrace off
echo 1 > events/kprobes/testprobe/enable
echo > trace
( echo "forked")
grep testprobe trace
! grep "$FUNCTION_FORK <-" trace
# kprobe on / ftrace on
echo function > current_tracer
echo > trace
( echo "forked")
grep testprobe trace
grep "$FUNCTION_FORK <-" trace
# kprobe off / ftrace on
echo 0 > events/kprobes/testprobe/enable
echo > trace
( echo "forked")
! grep testprobe trace
grep "$FUNCTION_FORK <-" trace
# kprobe on / ftrace on
echo 1 > events/kprobes/testprobe/enable
echo function > current_tracer
echo > trace
( echo "forked")
grep testprobe trace
grep "$FUNCTION_FORK <-" trace
# kprobe on / ftrace off
echo nop > current_tracer
echo > trace
( echo "forked")
grep testprobe trace
! grep "$FUNCTION_FORK <-" trace
@@ -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"
@@ -0,0 +1,52 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe dynamic event - probing module
# requires: kprobe_events
rmmod trace-printk ||:
if ! modprobe trace-printk ; then
echo "No trace-printk sample module - please make CONFIG_SAMPLE_TRACE_PRINTK=
m"
exit_unresolved;
fi
MOD=trace_printk
FUNC=trace_printk_irq_work
:;: "Add an event on a module function without specifying event name" ;:
echo "p $MOD:$FUNC" > kprobe_events
PROBE_NAME=`echo $MOD:$FUNC | tr ".:" "_"`
test -d events/kprobes/p_${PROBE_NAME}_0 || exit_failure
:;: "Add an event on a module function with new event name" ;:
echo "p:event1 $MOD:$FUNC" > kprobe_events
test -d events/kprobes/event1 || exit_failure
:;: "Add an event on a module function with new event and group name" ;:
echo "p:kprobes1/event1 $MOD:$FUNC" > kprobe_events
test -d events/kprobes1/event1 || exit_failure
:;: "Remove target module, but event still be there" ;:
if ! rmmod trace-printk ; then
echo "Failed to unload module - please enable CONFIG_MODULE_UNLOAD"
exit_unresolved;
fi
test -d events/kprobes1/event1
:;: "Check posibility to defining events on unloaded module";:
echo "p:event2 $MOD:$FUNC" >> kprobe_events
:;: "Target is gone, but we can prepare for next time";:
echo 1 > events/kprobes1/event1/enable
:;: "Load module again, which means the event1 should be recorded";:
modprobe trace-printk
grep "event1:" trace
:;: "Remove the module again and check the event is not locked"
rmmod trace-printk
echo 0 > events/kprobes1/event1/enable
echo "-:kprobes1/event1" >> kprobe_events
@@ -0,0 +1,32 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Create/delete multiprobe on kprobe event
# requires: kprobe_events "Create/append/":README
# Choose 2 symbols for target
SYM1=$FUNCTION_FORK
SYM2=do_exit
EVENT_NAME=kprobes/testevent
DEF1="p:$EVENT_NAME $SYM1"
DEF2="p:$EVENT_NAME $SYM2"
:;: "Define an event which has 2 probes" ;:
echo $DEF1 >> kprobe_events
echo $DEF2 >> kprobe_events
cat kprobe_events | grep "$DEF1"
cat kprobe_events | grep "$DEF2"
:;: "Remove the event by name (should remove both)" ;:
echo "-:$EVENT_NAME" >> kprobe_events
test `cat kprobe_events | wc -l` -eq 0
:;: "Remove just 1 event" ;:
echo $DEF1 >> kprobe_events
echo $DEF2 >> kprobe_events
echo "-:$EVENT_NAME $SYM1" >> kprobe_events
! cat kprobe_events | grep "$DEF1"
cat kprobe_events | grep "$DEF2"
:;: "Appending different type must fail" ;:
! echo "$DEF1 \$stack" >> kprobe_events
@@ -0,0 +1,13 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Test failure of registering kprobe on non unique symbol
# requires: kprobe_events
SYMBOL='name_show'
# We skip this test on kernel where SYMBOL is unique or does not exist.
if [ "$(grep -c -E "[[:alnum:]]+ t ${SYMBOL}" /proc/kallsyms)" -le '1' ]; then
exit_unsupported
fi
! echo "p:test_non_unique ${SYMBOL}" > kprobe_events
@@ -0,0 +1,34 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2023 Akanksha J N, IBM corporation
# description: Register/unregister optimized probe
# requires: kprobe_events
case `uname -m` in
x86_64)
;;
arm*)
;;
ppc*)
;;
*)
echo "Please implement other architecture here"
exit_unsupported
esac
DEFAULT=$(cat /proc/sys/debug/kprobes-optimization)
echo 1 > /proc/sys/debug/kprobes-optimization
for i in `seq 0 255`; do
echo "p:testprobe $FUNCTION_FORK+${i}" > kprobe_events || continue
echo 1 > events/kprobes/enable || continue
(echo "forked")
PROBE=$(grep $FUNCTION_FORK /sys/kernel/debug/kprobes/list)
echo 0 > events/kprobes/enable
echo > kprobe_events
if echo $PROBE | grep -q OPTIMIZED; then
echo "$DEFAULT" > /proc/sys/debug/kprobes-optimization
exit_pass
fi
done
echo "$DEFAULT" > /proc/sys/debug/kprobes-optimization
exit_unresolved
@@ -0,0 +1,122 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event parser error log check
# requires: kprobe_events error_log
check_error() { # command-with-error-pos-by-^
ftrace_errlog_check 'trace_kprobe' "$1" 'kprobe_events'
}
if grep -q 'r\[maxactive\]' README; then
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
check_error 'p ^non_exist_func' # BAD_PROBE_ADDR (enoent)
check_error 'p ^hoge-fuga' # BAD_PROBE_ADDR (bad syntax)
check_error 'p ^hoge+1000-1000' # BAD_PROBE_ADDR (bad syntax)
check_error 'r ^vfs_read+10' # BAD_RETPROBE
check_error 'p:^/bar vfs_read' # NO_GROUP_NAME
check_error 'p:^12345678901234567890123456789012345678901234567890123456789012345/bar vfs_read' # GROUP_TOO_LONG
check_error 'p:^foo.1/bar vfs_read' # BAD_GROUP_NAME
check_error 'p:^ vfs_read' # NO_EVENT_NAME
check_error 'p:foo/^12345678901234567890123456789012345678901234567890123456789012345 vfs_read' # EVENT_TOO_LONG
check_error 'p:foo/^bar.1 vfs_read' # BAD_EVENT_NAME
check_error 'p vfs_read ^$retval' # RETVAL_ON_PROBE
check_error 'p vfs_read ^$stack10000' # BAD_STACK_NUM
if grep -q '$arg<N>' README; then
check_error 'p vfs_read ^$arg10000' # BAD_ARG_NUM
fi
check_error 'p vfs_read ^$none_var' # BAD_VAR
check_error 'p vfs_read ^%none_reg' # BAD_REG_NAME
check_error 'p vfs_read ^@12345678abcde' # BAD_MEM_ADDR
check_error 'p vfs_read ^@+10' # FILE_ON_KPROBE
grep -q "imm-value" README && \
check_error 'p vfs_read arg1=\^x' # BAD_IMM
grep -q "imm-string" README && \
check_error 'p vfs_read arg1=\"abcd^' # IMMSTR_NO_CLOSE
check_error 'p vfs_read ^+0@0)' # DEREF_NEED_BRACE
check_error 'p vfs_read ^+0ab1(@0)' # BAD_DEREF_OFFS
check_error 'p vfs_read +0(+0(@0^)' # DEREF_OPEN_BRACE
if grep -A1 "fetcharg:" README | grep -q '\$comm' ; then
check_error 'p vfs_read +0(^$comm)' # COMM_CANT_DEREF
fi
check_error 'p vfs_read ^&1' # BAD_FETCH_ARG
# We've introduced this limitation with array support
if grep -q ' <type>\\\[<array-size>\\\]' README; then
check_error 'p vfs_read +0(^+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(@0))))))))))))))' # TOO_MANY_OPS?
check_error 'p vfs_read +0(@11):u8[10^' # ARRAY_NO_CLOSE
check_error 'p vfs_read +0(@11):u8[10]^a' # BAD_ARRAY_SUFFIX
check_error 'p vfs_read +0(@11):u8[^10a]' # BAD_ARRAY_NUM
check_error 'p vfs_read +0(@11):u8[^256]' # ARRAY_TOO_BIG
fi
check_error 'p vfs_read @11:^unknown_type' # BAD_TYPE
check_error 'p vfs_read $stack0:^string' # BAD_STRING
check_error 'p vfs_read @11:^b10@a/16' # BAD_BITFIELD
check_error 'p vfs_read ^arg123456789012345678901234567890=@11' # ARG_NAME_TOO_LOG
check_error 'p vfs_read ^=@11' # NO_ARG_NAME
check_error 'p vfs_read ^var.1=@11' # BAD_ARG_NAME
check_error 'p vfs_read var1=@11 ^var1=@12' # USED_ARG_NAME
check_error 'p vfs_read ^+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(@1234))))))' # ARG_TOO_LONG
check_error 'p vfs_read arg1=^' # NO_ARG_BODY
# instruction boundary check is valid on x86 (at this moment)
case $(uname -m) in
x86_64|i[3456]86)
echo 'p vfs_read' > kprobe_events
if grep -q FTRACE ../kprobes/list ; then
check_error 'p ^vfs_read+3' # BAD_INSN_BNDRY (only if function-tracer is enabled)
fi
;;
esac
# multiprobe errors
if grep -q "Create/append/" README && grep -q "imm-value" README; then
echo "p:kprobes/testevent $FUNCTION_FORK" > kprobe_events
check_error '^r:kprobes/testevent do_exit' # DIFF_PROBE_TYPE
# Explicitly use printf "%s" to not interpret \1
printf "%s" "p:kprobes/testevent $FUNCTION_FORK abcd=\\1" > kprobe_events
check_error "p:kprobes/testevent $FUNCTION_FORK ^bcd=\\1" # DIFF_ARG_TYPE
check_error "p:kprobes/testevent $FUNCTION_FORK ^abcd=\\1:u8" # DIFF_ARG_TYPE
check_error "p:kprobes/testevent $FUNCTION_FORK ^abcd=\\\"foo\"" # DIFF_ARG_TYPE
check_error "^p:kprobes/testevent $FUNCTION_FORK abcd=\\1" # SAME_PROBE
fi
# %return suffix errors
if grep -q "place (kretprobe): .*%return.*" README; then
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
if !grep -q 'kernel return probes support:' README; then
check_error 'r vfs_read ^$arg*' # NOFENTRY_ARGS
fi
check_error 'p vfs_read+20 ^$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

Some files were not shown because too many files have changed in this diff Show More