[ "$(uname -m)" = "aarch64" ];
}
+has_kaslr_bug() {
+ [ "$(uname -m)" != "aarch64" ];
+}
+
check_branches() {
if ! tr -s ' ' '\n' < "$TMPDIR/perf.script" | grep -E -m1 -q "$1"; then
- echo "Branches missing $1"
+ echo "ERROR: Branches missing $1"
err=1
fi
}
test_user_branches() {
echo "Testing user branch stack sampling"
+ start_err=$err
+ err=0
perf record -o "$TMPDIR/perf.data" --branch-filter any,save_type,u -- ${TESTPROG} > "$TMPDIR/record.txt" 2>&1
perf script -i "$TMPDIR/perf.data" --fields brstacksym > "$TMPDIR/perf.script"
perf script -i "$TMPDIR/perf.data" --fields brstack | \
tr ' ' '\n' > "$TMPDIR/perf.script"
- # There should be no kernel addresses with the u option, in either
- # source or target addresses.
- if grep -E -m1 "0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then
- echo "ERROR: Kernel address found in user mode"
+ # There should be no kernel addresses in the target with the u option.
+ local regex="0x[89a-f][0-9a-f]{15}"
+ if has_kaslr_bug; then
+ # If the system has a kaslr bug that may leak kernel addresses
+ # in the source of something like an ERET/SYSRET. Make the regex
+ # more specific and just check the target address is in user
+ # code.
+ regex="^0x[0-9a-f]{0,16}/0x[89a-f][0-9a-f]{15}/"
+ fi
+ if grep -q -E -m1 "$regex" $TMPDIR/perf.script; then
+ echo "Testing user branch stack sampling [Failed kernel address found in user mode]"
err=1
fi
# some branch types are still not being tested:
# IND COND_CALL COND_RET SYSRET SERROR NO_TX
+ if [ $err -eq 0 ]; then
+ echo "Testing user branch stack sampling [Passed]"
+ err=$start_err
+ else
+ echo "Testing user branch stack sampling [Failed]"
+ fi
}
test_trap_eret_branches() {
echo "Testing trap & eret branches"
+
if ! is_arm64; then
- echo "skip: not arm64"
+ echo "Testing trap & eret branches [Skipped not arm64]"
+ return
+ fi
+ start_err=$err
+ err=0
+ perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \
+ perf test -w traploop 1000 > "$TMPDIR/record.txt" 2>&1
+ perf script -i $TMPDIR/perf.data --fields brstacksym | \
+ tr ' ' '\n' > $TMPDIR/perf.script
+
+ # BRBINF<n>.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver
+ check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/"
+ check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/"
+ if [ $err -eq 0 ]; then
+ echo "Testing trap & eret branches [Passed]"
+ err=$start_err
else
- perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \
- perf test -w traploop 1000
- perf script -i $TMPDIR/perf.data --fields brstacksym | \
- tr ' ' '\n' > $TMPDIR/perf.script
-
- # BRBINF<n>.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver
- check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/"
- check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/"
+ echo "Testing trap & eret branches [Failed]"
fi
}
test_kernel_branches() {
- echo "Testing that k option only includes kernel source addresses"
+ echo "Testing kernel branch sampling"
- if ! perf record --branch-filter any,k -o- -- true > /dev/null; then
- echo "skip: not enough privileges"
+ if ! perf record --branch-filter any,k -o- -- true > "$TMPDIR/record.txt" 2>&1; then
+ echo "Testing that k option [Skipped not enough privileges]"
+ return
+ fi
+ start_err=$err
+ err=0
+ perf record -o $TMPDIR/perf.data --branch-filter any,k -- \
+ perf bench syscall basic --loop 1000 > "$TMPDIR/record.txt" 2>&1
+ perf script -i $TMPDIR/perf.data --fields brstack | \
+ tr ' ' '\n' > $TMPDIR/perf.script
+
+ # Example of branch entries:
+ # "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..."
+ # Source addresses come first in user or kernel code. Next is the target
+ # address that must be in the kernel.
+
+ # Look for source addresses with top bit set
+ if ! grep -q -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then
+ echo "Testing kernel branch sampling [Failed kernel branches missing]"
+ err=1
+ fi
+ # Look for no target addresses without top bit set
+ if grep -q -E -m1 "^0x[0-9a-f]{0,16}/0x[0-7][0-9a-f]{1,15}/" $TMPDIR/perf.script; then
+ echo "Testing kernel branch sampling [Failed user branches found]"
+ err=1
+ fi
+ if [ $err -eq 0 ]; then
+ echo "Testing kernel branch sampling [Passed]"
+ err=$start_err
else
- perf record -o $TMPDIR/perf.data --branch-filter any,k -- \
- perf bench syscall basic --loop 1000
- perf script -i $TMPDIR/perf.data --fields brstack | \
- tr ' ' '\n' > $TMPDIR/perf.script
-
- # Example of branch entries:
- # "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..."
- # Source addresses come first and target address can be either
- # userspace or kernel even with k option, as long as the source
- # is in kernel.
-
- #Look for source addresses with top bit set
- if ! grep -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then
- echo "ERROR: Kernel branches missing"
- err=1
- fi
- # Look for no source addresses without top bit set
- if grep -E -m1 "^0x[0-7][0-9a-f]{0,15}" $TMPDIR/perf.script; then
- echo "ERROR: User branches found with kernel filter"
- err=1
- fi
+ echo "Testing kernel branch sampling [Failed]"
fi
}
test_filter_expect=$2
echo "Testing branch stack filtering permutation ($test_filter_filter,$test_filter_expect)"
- perf record -o "$TMPDIR/perf.data" --branch-filter "$test_filter_filter,save_type,u" -- ${TESTPROG} > "$TMPDIR/record.txt" 2>&1
+ perf record -o "$TMPDIR/perf.data" --branch-filter "$test_filter_filter,save_type,u" -- \
+ ${TESTPROG} > "$TMPDIR/record.txt" 2>&1
perf script -i "$TMPDIR/perf.data" --fields brstack > "$TMPDIR/perf.script"
# fail if we find any branch type that doesn't match any of the expected ones
# also consider UNKNOWN branch types (-)
if [ ! -s "$TMPDIR/perf.script" ]
then
- echo "Empty script output"
+ echo "Testing branch stack filtering [Failed empty script output]"
err=1
return
fi
> "$TMPDIR/perf.script-filtered" || true
if [ -s "$TMPDIR/perf.script-filtered" ]
then
- echo "Unexpected branch filter in script output"
+ echo "Testing branch stack filtering [Failed unexpected branch filter]"
cat "$TMPDIR/perf.script"
err=1
return
fi
+ echo "Testing branch stack filtering [Passed]"
}
test_syscall() {
echo "Testing syscalls"
# skip if perf doesn't have enough privileges
- if ! perf record --branch-filter any,k -o- -- true > /dev/null; then
- echo "skip: not enough privileges"
+ if ! perf record --branch-filter any,k -o- -- true > "$TMPDIR/record.txt" 2>&1; then
+ echo "Testing syscalls [Skipped: not enough privileges]"
+ return
+ fi
+ start_err=$err
+ err=0
+ perf record -o $TMPDIR/perf.data --branch-filter \
+ any_call,save_type,u,k -c 10007 -- \
+ perf bench syscall basic --loop 8000 > "$TMPDIR/record.txt" 2>&1
+ perf script -i $TMPDIR/perf.data --fields brstacksym | \
+ tr ' ' '\n' > $TMPDIR/perf.script
+
+ check_branches "getppid[^ ]*/SYSCALL/"
+
+ if [ $err -eq 0 ]; then
+ echo "Testing syscalls [Passed]"
+ err=$start_err
else
- perf record -o $TMPDIR/perf.data --branch-filter \
- any_call,save_type,u,k -c 10000 -- \
- perf bench syscall basic --loop 1000
- perf script -i $TMPDIR/perf.data --fields brstacksym | \
- tr ' ' '\n' > $TMPDIR/perf.script
-
- check_branches "getppid[^ ]*/SYSCALL/"
+ echo "Testing syscalls [Failed]"
fi
}
set -e