162306a36Sopenharmony_ci#!/usr/bin/env bash
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci# Linux kernel coccicheck
462306a36Sopenharmony_ci#
562306a36Sopenharmony_ci# Read Documentation/dev-tools/coccinelle.rst
662306a36Sopenharmony_ci#
762306a36Sopenharmony_ci# This script requires at least spatch
862306a36Sopenharmony_ci# version 1.0.0-rc11.
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ciDIR="$(dirname $(readlink -f $0))/.."
1162306a36Sopenharmony_ciSPATCH="`which ${SPATCH:=spatch}`"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ciif [ ! -x "$SPATCH" ]; then
1462306a36Sopenharmony_ci    echo 'spatch is part of the Coccinelle project and is available at http://coccinelle.lip6.fr/'
1562306a36Sopenharmony_ci    exit 1
1662306a36Sopenharmony_cifi
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciSPATCH_VERSION=$($SPATCH --version | head -1 | awk '{print $3}')
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ciUSE_JOBS="no"
2162306a36Sopenharmony_ci$SPATCH --help | grep -e "--jobs" > /dev/null && USE_JOBS="yes"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci# The verbosity may be set by the environmental parameter V=
2462306a36Sopenharmony_ci# as for example with 'make V=1 coccicheck'
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciif [ -n "$V" -a "$V" != "0" ]; then
2762306a36Sopenharmony_ci	VERBOSE="$V"
2862306a36Sopenharmony_cielse
2962306a36Sopenharmony_ci	VERBOSE=0
3062306a36Sopenharmony_cifi
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ciFLAGS="--very-quiet"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci# You can use SPFLAGS to append extra arguments to coccicheck or override any
3562306a36Sopenharmony_ci# heuristics done in this file as Coccinelle accepts the last options when
3662306a36Sopenharmony_ci# options conflict.
3762306a36Sopenharmony_ci#
3862306a36Sopenharmony_ci# A good example for use of SPFLAGS is if you want to debug your cocci script,
3962306a36Sopenharmony_ci# you can for instance use the following:
4062306a36Sopenharmony_ci#
4162306a36Sopenharmony_ci# $ export COCCI=scripts/coccinelle/misc/irqf_oneshot.cocci
4262306a36Sopenharmony_ci# $ make coccicheck MODE=report DEBUG_FILE="all.err" SPFLAGS="--profile --show-trying" M=./drivers/mfd/arizona-irq.c
4362306a36Sopenharmony_ci#
4462306a36Sopenharmony_ci# "--show-trying" should show you what rule is being processed as it goes to
4562306a36Sopenharmony_ci# stdout, you do not need a debug file for that. The profile output will be
4662306a36Sopenharmony_ci# be sent to stdout, if you provide a DEBUG_FILE the profiling data can be
4762306a36Sopenharmony_ci# inspected there.
4862306a36Sopenharmony_ci#
4962306a36Sopenharmony_ci# --profile will not output if --very-quiet is used, so avoid it.
5062306a36Sopenharmony_ciecho $SPFLAGS | grep -E -e "--profile|--show-trying" 2>&1 > /dev/null
5162306a36Sopenharmony_ciif [ $? -eq 0 ]; then
5262306a36Sopenharmony_ci	FLAGS="--quiet"
5362306a36Sopenharmony_cifi
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci# spatch only allows include directories with the syntax "-I include"
5662306a36Sopenharmony_ci# while gcc also allows "-Iinclude" and "-include include"
5762306a36Sopenharmony_ciCOCCIINCLUDE=${LINUXINCLUDE//-I/-I }
5862306a36Sopenharmony_ciCOCCIINCLUDE=${COCCIINCLUDE// -include/ --include}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ciif [ "$C" = "1" -o "$C" = "2" ]; then
6162306a36Sopenharmony_ci    ONLINE=1
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci    if [[ $# -le 0 ]]; then
6462306a36Sopenharmony_ci	    echo ''
6562306a36Sopenharmony_ci	    echo 'Specifying both the variable "C" and rule "coccicheck" in the make
6662306a36Sopenharmony_cicommand results in a shift count error.'
6762306a36Sopenharmony_ci	    echo ''
6862306a36Sopenharmony_ci	    echo 'Try specifying "scripts/coccicheck" as a value for the CHECK variable instead.'
6962306a36Sopenharmony_ci	    echo ''
7062306a36Sopenharmony_ci	    echo 'Example:	make C=2 CHECK=scripts/coccicheck drivers/net/ethernet/ethoc.o'
7162306a36Sopenharmony_ci	    echo ''
7262306a36Sopenharmony_ci	    exit 1
7362306a36Sopenharmony_ci    fi
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci    # Take only the last argument, which is the C file to test
7662306a36Sopenharmony_ci    shift $(( $# - 1 ))
7762306a36Sopenharmony_ci    OPTIONS="$COCCIINCLUDE $1"
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci    # No need to parallelize Coccinelle since this mode takes one input file.
8062306a36Sopenharmony_ci    NPROC=1
8162306a36Sopenharmony_cielse
8262306a36Sopenharmony_ci    ONLINE=0
8362306a36Sopenharmony_ci    if [ "$KBUILD_EXTMOD" = "" ] ; then
8462306a36Sopenharmony_ci        OPTIONS="--dir $srctree $COCCIINCLUDE"
8562306a36Sopenharmony_ci    else
8662306a36Sopenharmony_ci        OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE"
8762306a36Sopenharmony_ci    fi
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci    # Use only one thread per core by default if hyperthreading is enabled
9062306a36Sopenharmony_ci    THREADS_PER_CORE=$(LANG=C lscpu | grep "Thread(s) per core: " | tr -cd "[:digit:]")
9162306a36Sopenharmony_ci    if [ -z "$J" ]; then
9262306a36Sopenharmony_ci        NPROC=$(getconf _NPROCESSORS_ONLN)
9362306a36Sopenharmony_ci	if [ $THREADS_PER_CORE -gt 1 -a $NPROC -gt 4 ] ; then
9462306a36Sopenharmony_ci		NPROC=$((NPROC/2))
9562306a36Sopenharmony_ci	fi
9662306a36Sopenharmony_ci    else
9762306a36Sopenharmony_ci        NPROC="$J"
9862306a36Sopenharmony_ci    fi
9962306a36Sopenharmony_cifi
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciif [ "$KBUILD_EXTMOD" != "" ] ; then
10262306a36Sopenharmony_ci    OPTIONS="--patch $srctree $OPTIONS"
10362306a36Sopenharmony_cifi
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci# You can override by using SPFLAGS
10662306a36Sopenharmony_ciif [ "$USE_JOBS" = "no" ]; then
10762306a36Sopenharmony_ci	trap kill_running SIGTERM SIGINT
10862306a36Sopenharmony_ci	declare -a SPATCH_PID
10962306a36Sopenharmony_cielif [ "$NPROC" != "1" ]; then
11062306a36Sopenharmony_ci	# Using 0 should work as well, refer to _SC_NPROCESSORS_ONLN use on
11162306a36Sopenharmony_ci	# https://github.com/rdicosmo/parmap/blob/master/setcore_stubs.c
11262306a36Sopenharmony_ci	OPTIONS="$OPTIONS --jobs $NPROC --chunksize 1"
11362306a36Sopenharmony_cifi
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciif [ "$MODE" = "" ] ; then
11662306a36Sopenharmony_ci    if [ "$ONLINE" = "0" ] ; then
11762306a36Sopenharmony_ci	echo 'You have not explicitly specified the mode to use. Using default "report" mode.'
11862306a36Sopenharmony_ci	echo 'Available modes are the following: patch, report, context, org, chain'
11962306a36Sopenharmony_ci	echo 'You can specify the mode with "make coccicheck MODE=<mode>"'
12062306a36Sopenharmony_ci	echo 'Note however that some modes are not implemented by some semantic patches.'
12162306a36Sopenharmony_ci    fi
12262306a36Sopenharmony_ci    MODE="report"
12362306a36Sopenharmony_cifi
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ciif [ "$MODE" = "chain" ] ; then
12662306a36Sopenharmony_ci    if [ "$ONLINE" = "0" ] ; then
12762306a36Sopenharmony_ci	echo 'You have selected the "chain" mode.'
12862306a36Sopenharmony_ci	echo 'All available modes will be tried (in that order): patch, report, context, org'
12962306a36Sopenharmony_ci    fi
13062306a36Sopenharmony_cielif [ "$MODE" = "report" -o "$MODE" = "org" ] ; then
13162306a36Sopenharmony_ci    FLAGS="--no-show-diff $FLAGS"
13262306a36Sopenharmony_cifi
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ciif [ "$ONLINE" = "0" ] ; then
13562306a36Sopenharmony_ci    echo ''
13662306a36Sopenharmony_ci    echo 'Please check for false positives in the output before submitting a patch.'
13762306a36Sopenharmony_ci    echo 'When using "patch" mode, carefully review the patch before submitting it.'
13862306a36Sopenharmony_ci    echo ''
13962306a36Sopenharmony_cifi
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cirun_cmd_parmap() {
14262306a36Sopenharmony_ci	if [ $VERBOSE -ne 0 ] ; then
14362306a36Sopenharmony_ci		echo "Running ($NPROC in parallel): $@"
14462306a36Sopenharmony_ci	fi
14562306a36Sopenharmony_ci	if [ "$DEBUG_FILE" != "/dev/null" -a "$DEBUG_FILE" != "" ]; then
14662306a36Sopenharmony_ci                echo $@>>$DEBUG_FILE
14762306a36Sopenharmony_ci                $@ 2>>$DEBUG_FILE
14862306a36Sopenharmony_ci        else
14962306a36Sopenharmony_ci                echo $@
15062306a36Sopenharmony_ci                $@ 2>&1
15162306a36Sopenharmony_ci	fi
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	err=$?
15462306a36Sopenharmony_ci	if [[ $err -ne 0 ]]; then
15562306a36Sopenharmony_ci		echo "coccicheck failed"
15662306a36Sopenharmony_ci		exit $err
15762306a36Sopenharmony_ci	fi
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cirun_cmd_old() {
16162306a36Sopenharmony_ci	local i
16262306a36Sopenharmony_ci	if [ $VERBOSE -ne 0 ] ; then
16362306a36Sopenharmony_ci		echo "Running ($NPROC in parallel): $@"
16462306a36Sopenharmony_ci	fi
16562306a36Sopenharmony_ci	for i in $(seq 0 $(( NPROC - 1)) ); do
16662306a36Sopenharmony_ci		eval "$@ --max $NPROC --index $i &"
16762306a36Sopenharmony_ci		SPATCH_PID[$i]=$!
16862306a36Sopenharmony_ci		if [ $VERBOSE -eq 2 ] ; then
16962306a36Sopenharmony_ci			echo "${SPATCH_PID[$i]} running"
17062306a36Sopenharmony_ci		fi
17162306a36Sopenharmony_ci	done
17262306a36Sopenharmony_ci	wait
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cirun_cmd() {
17662306a36Sopenharmony_ci	if [ "$USE_JOBS" = "yes" ]; then
17762306a36Sopenharmony_ci		run_cmd_parmap $@
17862306a36Sopenharmony_ci	else
17962306a36Sopenharmony_ci		run_cmd_old $@
18062306a36Sopenharmony_ci	fi
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cikill_running() {
18462306a36Sopenharmony_ci	for i in $(seq 0 $(( NPROC - 1 )) ); do
18562306a36Sopenharmony_ci		if [ $VERBOSE -eq 2 ] ; then
18662306a36Sopenharmony_ci			echo "Killing ${SPATCH_PID[$i]}"
18762306a36Sopenharmony_ci		fi
18862306a36Sopenharmony_ci		kill ${SPATCH_PID[$i]} 2>/dev/null
18962306a36Sopenharmony_ci	done
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci# You can override heuristics with SPFLAGS, these must always go last
19362306a36Sopenharmony_ciOPTIONS="$OPTIONS $SPFLAGS"
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cicoccinelle () {
19662306a36Sopenharmony_ci    COCCI="$1"
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci    OPT=`grep "Options:" $COCCI | cut -d':' -f2`
19962306a36Sopenharmony_ci    REQ=`grep "Requires:" $COCCI | cut -d':' -f2 | sed "s| ||"`
20062306a36Sopenharmony_ci    if [ -n "$REQ" ] && ! { echo "$REQ"; echo "$SPATCH_VERSION"; } | sort -CV ; then
20162306a36Sopenharmony_ci	    echo "Skipping coccinelle SmPL patch: $COCCI"
20262306a36Sopenharmony_ci	    echo "You have coccinelle:           $SPATCH_VERSION"
20362306a36Sopenharmony_ci	    echo "This SmPL patch requires:      $REQ"
20462306a36Sopenharmony_ci	    return
20562306a36Sopenharmony_ci    fi
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci#   The option '--parse-cocci' can be used to syntactically check the SmPL files.
20862306a36Sopenharmony_ci#
20962306a36Sopenharmony_ci#    $SPATCH -D $MODE $FLAGS -parse_cocci $COCCI $OPT > /dev/null
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci    if [ $VERBOSE -ne 0 -a $ONLINE -eq 0 ] ; then
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	FILE=${COCCI#$srctree/}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	echo "Processing `basename $COCCI`"
21662306a36Sopenharmony_ci	echo "with option(s) \"$OPT\""
21762306a36Sopenharmony_ci	echo ''
21862306a36Sopenharmony_ci	echo 'Message example to submit a patch:'
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	sed -ne 's|^///||p' $COCCI
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if [ "$MODE" = "patch" ] ; then
22362306a36Sopenharmony_ci	    echo ' The semantic patch that makes this change is available'
22462306a36Sopenharmony_ci	elif [ "$MODE" = "report" ] ; then
22562306a36Sopenharmony_ci	    echo ' The semantic patch that makes this report is available'
22662306a36Sopenharmony_ci	elif [ "$MODE" = "context" ] ; then
22762306a36Sopenharmony_ci	    echo ' The semantic patch that spots this code is available'
22862306a36Sopenharmony_ci	elif [ "$MODE" = "org" ] ; then
22962306a36Sopenharmony_ci	    echo ' The semantic patch that makes this Org report is available'
23062306a36Sopenharmony_ci	else
23162306a36Sopenharmony_ci	    echo ' The semantic patch that makes this output is available'
23262306a36Sopenharmony_ci	fi
23362306a36Sopenharmony_ci	echo " in $FILE."
23462306a36Sopenharmony_ci	echo ''
23562306a36Sopenharmony_ci	echo ' More information about semantic patching is available at'
23662306a36Sopenharmony_ci	echo ' http://coccinelle.lip6.fr/'
23762306a36Sopenharmony_ci	echo ''
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if [ "`sed -ne 's|^//#||p' $COCCI`" ] ; then
24062306a36Sopenharmony_ci	    echo 'Semantic patch information:'
24162306a36Sopenharmony_ci	    sed -ne 's|^//#||p' $COCCI
24262306a36Sopenharmony_ci	    echo ''
24362306a36Sopenharmony_ci	fi
24462306a36Sopenharmony_ci    fi
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci    if [ "$MODE" = "chain" ] ; then
24762306a36Sopenharmony_ci	run_cmd $SPATCH -D patch   \
24862306a36Sopenharmony_ci		$FLAGS --cocci-file $COCCI $OPT $OPTIONS               || \
24962306a36Sopenharmony_ci	run_cmd $SPATCH -D report  \
25062306a36Sopenharmony_ci		$FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff || \
25162306a36Sopenharmony_ci	run_cmd $SPATCH -D context \
25262306a36Sopenharmony_ci		$FLAGS --cocci-file $COCCI $OPT $OPTIONS               || \
25362306a36Sopenharmony_ci	run_cmd $SPATCH -D org     \
25462306a36Sopenharmony_ci		$FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff || exit 1
25562306a36Sopenharmony_ci    elif [ "$MODE" = "rep+ctxt" ] ; then
25662306a36Sopenharmony_ci	run_cmd $SPATCH -D report  \
25762306a36Sopenharmony_ci		$FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff && \
25862306a36Sopenharmony_ci	run_cmd $SPATCH -D context \
25962306a36Sopenharmony_ci		$FLAGS --cocci-file $COCCI $OPT $OPTIONS || exit 1
26062306a36Sopenharmony_ci    else
26162306a36Sopenharmony_ci	run_cmd $SPATCH -D $MODE   $FLAGS --cocci-file $COCCI $OPT $OPTIONS || exit 1
26262306a36Sopenharmony_ci    fi
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ciif [ "$DEBUG_FILE" != "/dev/null" -a "$DEBUG_FILE" != "" ]; then
26762306a36Sopenharmony_ci	if [ -f $DEBUG_FILE ]; then
26862306a36Sopenharmony_ci		echo "Debug file $DEBUG_FILE exists, bailing"
26962306a36Sopenharmony_ci		exit
27062306a36Sopenharmony_ci	fi
27162306a36Sopenharmony_cielse
27262306a36Sopenharmony_ci	DEBUG_FILE="/dev/null"
27362306a36Sopenharmony_cifi
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ciif [ "$COCCI" = "" ] ; then
27662306a36Sopenharmony_ci    for f in `find $srctree/scripts/coccinelle/ -name '*.cocci' -type f | sort`; do
27762306a36Sopenharmony_ci	coccinelle $f
27862306a36Sopenharmony_ci    done
27962306a36Sopenharmony_cielse
28062306a36Sopenharmony_ci    coccinelle $COCCI
28162306a36Sopenharmony_cifi
282