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