18c2ecf20Sopenharmony_ci#!/bin/bash
28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
38c2ecf20Sopenharmony_ci#
48c2ecf20Sopenharmony_ci# Here's how to use this:
58c2ecf20Sopenharmony_ci#
68c2ecf20Sopenharmony_ci# This script is used to help find functions that are being traced by function
78c2ecf20Sopenharmony_ci# tracer or function graph tracing that causes the machine to reboot, hang, or
88c2ecf20Sopenharmony_ci# crash. Here's the steps to take.
98c2ecf20Sopenharmony_ci#
108c2ecf20Sopenharmony_ci# First, determine if function tracing is working with a single function:
118c2ecf20Sopenharmony_ci#
128c2ecf20Sopenharmony_ci#   (note, if this is a problem with function_graph tracing, then simply
138c2ecf20Sopenharmony_ci#    replace "function" with "function_graph" in the following steps).
148c2ecf20Sopenharmony_ci#
158c2ecf20Sopenharmony_ci#  # cd /sys/kernel/tracing
168c2ecf20Sopenharmony_ci#  # echo schedule > set_ftrace_filter
178c2ecf20Sopenharmony_ci#  # echo function > current_tracer
188c2ecf20Sopenharmony_ci#
198c2ecf20Sopenharmony_ci# If this works, then we know that something is being traced that shouldn't be.
208c2ecf20Sopenharmony_ci#
218c2ecf20Sopenharmony_ci#  # echo nop > current_tracer
228c2ecf20Sopenharmony_ci#
238c2ecf20Sopenharmony_ci# Starting with v5.1 this can be done with numbers, making it much faster:
248c2ecf20Sopenharmony_ci#
258c2ecf20Sopenharmony_ci# The old (slow) way, for kernels before v5.1.
268c2ecf20Sopenharmony_ci#
278c2ecf20Sopenharmony_ci# [old-way] # cat available_filter_functions > ~/full-file
288c2ecf20Sopenharmony_ci#
298c2ecf20Sopenharmony_ci# [old-way] *** Note ***  this process will take several minutes to update the
308c2ecf20Sopenharmony_ci# [old-way] filters. Setting multiple functions is an O(n^2) operation, and we
318c2ecf20Sopenharmony_ci# [old-way] are dealing with thousands of functions. So go have coffee, talk
328c2ecf20Sopenharmony_ci# [old-way] with your coworkers, read facebook. And eventually, this operation
338c2ecf20Sopenharmony_ci# [old-way] will end.
348c2ecf20Sopenharmony_ci#
358c2ecf20Sopenharmony_ci# The new way (using numbers) is an O(n) operation, and usually takes less than a second.
368c2ecf20Sopenharmony_ci#
378c2ecf20Sopenharmony_ci# seq `wc -l available_filter_functions | cut -d' ' -f1` > ~/full-file
388c2ecf20Sopenharmony_ci#
398c2ecf20Sopenharmony_ci# This will create a sequence of numbers that match the functions in
408c2ecf20Sopenharmony_ci# available_filter_functions, and when echoing in a number into the
418c2ecf20Sopenharmony_ci# set_ftrace_filter file, it will enable the corresponding function in
428c2ecf20Sopenharmony_ci# O(1) time. Making enabling all functions O(n) where n is the number of
438c2ecf20Sopenharmony_ci# functions to enable.
448c2ecf20Sopenharmony_ci#
458c2ecf20Sopenharmony_ci# For either the new or old way, the rest of the operations remain the same.
468c2ecf20Sopenharmony_ci#
478c2ecf20Sopenharmony_ci#  # ftrace-bisect ~/full-file ~/test-file ~/non-test-file
488c2ecf20Sopenharmony_ci#  # cat ~/test-file > set_ftrace_filter
498c2ecf20Sopenharmony_ci#
508c2ecf20Sopenharmony_ci#  # echo function > current_tracer
518c2ecf20Sopenharmony_ci#
528c2ecf20Sopenharmony_ci# If it crashes, we know that ~/test-file has a bad function.
538c2ecf20Sopenharmony_ci#
548c2ecf20Sopenharmony_ci#   Reboot back to test kernel.
558c2ecf20Sopenharmony_ci#
568c2ecf20Sopenharmony_ci#     # cd /sys/kernel/tracing
578c2ecf20Sopenharmony_ci#     # mv ~/test-file ~/full-file
588c2ecf20Sopenharmony_ci#
598c2ecf20Sopenharmony_ci# If it didn't crash.
608c2ecf20Sopenharmony_ci#
618c2ecf20Sopenharmony_ci#     # echo nop > current_tracer
628c2ecf20Sopenharmony_ci#     # mv ~/non-test-file ~/full-file
638c2ecf20Sopenharmony_ci#
648c2ecf20Sopenharmony_ci# Get rid of the other test file from previous run (or save them off somewhere).
658c2ecf20Sopenharmony_ci#  # rm -f ~/test-file ~/non-test-file
668c2ecf20Sopenharmony_ci#
678c2ecf20Sopenharmony_ci# And start again:
688c2ecf20Sopenharmony_ci#
698c2ecf20Sopenharmony_ci#  # ftrace-bisect ~/full-file ~/test-file ~/non-test-file
708c2ecf20Sopenharmony_ci#
718c2ecf20Sopenharmony_ci# The good thing is, because this cuts the number of functions in ~/test-file
728c2ecf20Sopenharmony_ci# by half, the cat of it into set_ftrace_filter takes half as long each
738c2ecf20Sopenharmony_ci# iteration, so don't talk so much at the water cooler the second time.
748c2ecf20Sopenharmony_ci#
758c2ecf20Sopenharmony_ci# Eventually, if you did this correctly, you will get down to the problem
768c2ecf20Sopenharmony_ci# function, and all we need to do is to notrace it.
778c2ecf20Sopenharmony_ci#
788c2ecf20Sopenharmony_ci# The way to figure out if the problem function is bad, just do:
798c2ecf20Sopenharmony_ci#
808c2ecf20Sopenharmony_ci#  # echo <problem-function> > set_ftrace_notrace
818c2ecf20Sopenharmony_ci#  # echo > set_ftrace_filter
828c2ecf20Sopenharmony_ci#  # echo function > current_tracer
838c2ecf20Sopenharmony_ci#
848c2ecf20Sopenharmony_ci# And if it doesn't crash, we are done.
858c2ecf20Sopenharmony_ci#
868c2ecf20Sopenharmony_ci# If it does crash, do this again (there's more than one problem function)
878c2ecf20Sopenharmony_ci# but you need to echo the problem function(s) into set_ftrace_notrace before
888c2ecf20Sopenharmony_ci# enabling function tracing in the above steps. Or if you can compile the
898c2ecf20Sopenharmony_ci# kernel, annotate the problem functions with "notrace" and start again.
908c2ecf20Sopenharmony_ci#
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ciif [ $# -ne 3 ]; then
948c2ecf20Sopenharmony_ci  echo 'usage: ftrace-bisect full-file test-file  non-test-file'
958c2ecf20Sopenharmony_ci  exit
968c2ecf20Sopenharmony_cifi
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cifull=$1
998c2ecf20Sopenharmony_citest=$2
1008c2ecf20Sopenharmony_cinontest=$3
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cix=`cat $full | wc -l`
1038c2ecf20Sopenharmony_ciif [ $x -eq 1 ]; then
1048c2ecf20Sopenharmony_ci	echo "There's only one function left, must be the bad one"
1058c2ecf20Sopenharmony_ci	cat $full
1068c2ecf20Sopenharmony_ci	exit 0
1078c2ecf20Sopenharmony_cifi
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cilet x=$x/2
1108c2ecf20Sopenharmony_cilet y=$x+1
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ciif [ ! -f $full ]; then
1138c2ecf20Sopenharmony_ci	echo "$full does not exist"
1148c2ecf20Sopenharmony_ci	exit 1
1158c2ecf20Sopenharmony_cifi
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ciif [ -f $test ]; then
1188c2ecf20Sopenharmony_ci	echo -n "$test exists, delete it? [y/N]"
1198c2ecf20Sopenharmony_ci	read a
1208c2ecf20Sopenharmony_ci	if [ "$a" != "y" -a "$a" != "Y" ]; then
1218c2ecf20Sopenharmony_ci		exit 1
1228c2ecf20Sopenharmony_ci	fi
1238c2ecf20Sopenharmony_cifi
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ciif [ -f $nontest ]; then
1268c2ecf20Sopenharmony_ci	echo -n "$nontest exists, delete it? [y/N]"
1278c2ecf20Sopenharmony_ci	read a
1288c2ecf20Sopenharmony_ci	if [ "$a" != "y" -a "$a" != "Y" ]; then
1298c2ecf20Sopenharmony_ci		exit 1
1308c2ecf20Sopenharmony_ci	fi
1318c2ecf20Sopenharmony_cifi
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cised -ne "1,${x}p" $full > $test
1348c2ecf20Sopenharmony_cised -ne "$y,\$p" $full > $nontest
135