Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/bash
0002 # SPDX-License-Identifier: GPL-2.0
0003 # Linux kernel coccicheck
0004 #
0005 # Read Documentation/dev-tools/coccinelle.rst
0006 #
0007 # This script requires at least spatch
0008 # version 1.0.0-rc11.
0009 
0010 DIR="$(dirname $(readlink -f $0))/.."
0011 SPATCH="`which ${SPATCH:=spatch}`"
0012 
0013 if [ ! -x "$SPATCH" ]; then
0014     echo 'spatch is part of the Coccinelle project and is available at http://coccinelle.lip6.fr/'
0015     exit 1
0016 fi
0017 
0018 SPATCH_VERSION=$($SPATCH --version | head -1 | awk '{print $3}')
0019 
0020 USE_JOBS="no"
0021 $SPATCH --help | grep "\-\-jobs" > /dev/null && USE_JOBS="yes"
0022 
0023 # The verbosity may be set by the environmental parameter V=
0024 # as for example with 'make V=1 coccicheck'
0025 
0026 if [ -n "$V" -a "$V" != "0" ]; then
0027         VERBOSE="$V"
0028 else
0029         VERBOSE=0
0030 fi
0031 
0032 FLAGS="--very-quiet"
0033 
0034 # You can use SPFLAGS to append extra arguments to coccicheck or override any
0035 # heuristics done in this file as Coccinelle accepts the last options when
0036 # options conflict.
0037 #
0038 # A good example for use of SPFLAGS is if you want to debug your cocci script,
0039 # you can for instance use the following:
0040 #
0041 # $ export COCCI=scripts/coccinelle/misc/irqf_oneshot.cocci
0042 # $ make coccicheck MODE=report DEBUG_FILE="all.err" SPFLAGS="--profile --show-trying" M=./drivers/mfd/arizona-irq.c
0043 #
0044 # "--show-trying" should show you what rule is being processed as it goes to
0045 # stdout, you do not need a debug file for that. The profile output will be
0046 # be sent to stdout, if you provide a DEBUG_FILE the profiling data can be
0047 # inspected there.
0048 #
0049 # --profile will not output if --very-quiet is used, so avoid it.
0050 echo $SPFLAGS | egrep -e "--profile|--show-trying" 2>&1 > /dev/null
0051 if [ $? -eq 0 ]; then
0052         FLAGS="--quiet"
0053 fi
0054 
0055 # spatch only allows include directories with the syntax "-I include"
0056 # while gcc also allows "-Iinclude" and "-include include"
0057 COCCIINCLUDE=${LINUXINCLUDE//-I/-I }
0058 COCCIINCLUDE=${COCCIINCLUDE// -include/ --include}
0059 
0060 if [ "$C" = "1" -o "$C" = "2" ]; then
0061     ONLINE=1
0062 
0063     if [[ $# -le 0 ]]; then
0064             echo ''
0065             echo 'Specifying both the variable "C" and rule "coccicheck" in the make
0066 command results in a shift count error.'
0067             echo ''
0068             echo 'Try specifying "scripts/coccicheck" as a value for the CHECK variable instead.'
0069             echo ''
0070             echo 'Example:      make C=2 CHECK=scripts/coccicheck drivers/net/ethernet/ethoc.o'
0071             echo ''
0072             exit 1
0073     fi
0074 
0075     # Take only the last argument, which is the C file to test
0076     shift $(( $# - 1 ))
0077     OPTIONS="$COCCIINCLUDE $1"
0078 
0079     # No need to parallelize Coccinelle since this mode takes one input file.
0080     NPROC=1
0081 else
0082     ONLINE=0
0083     if [ "$KBUILD_EXTMOD" = "" ] ; then
0084         OPTIONS="--dir $srctree $COCCIINCLUDE"
0085     else
0086         OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE"
0087     fi
0088 
0089     # Use only one thread per core by default if hyperthreading is enabled
0090     THREADS_PER_CORE=$(LANG=C lscpu | grep "Thread(s) per core: " | tr -cd "[:digit:]")
0091     if [ -z "$J" ]; then
0092         NPROC=$(getconf _NPROCESSORS_ONLN)
0093         if [ $THREADS_PER_CORE -gt 1 -a $NPROC -gt 4 ] ; then
0094                 NPROC=$((NPROC/2))
0095         fi
0096     else
0097         NPROC="$J"
0098     fi
0099 fi
0100 
0101 if [ "$KBUILD_EXTMOD" != "" ] ; then
0102     OPTIONS="--patch $srctree $OPTIONS"
0103 fi
0104 
0105 # You can override by using SPFLAGS
0106 if [ "$USE_JOBS" = "no" ]; then
0107         trap kill_running SIGTERM SIGINT
0108         declare -a SPATCH_PID
0109 elif [ "$NPROC" != "1" ]; then
0110         # Using 0 should work as well, refer to _SC_NPROCESSORS_ONLN use on
0111         # https://github.com/rdicosmo/parmap/blob/master/setcore_stubs.c
0112         OPTIONS="$OPTIONS --jobs $NPROC --chunksize 1"
0113 fi
0114 
0115 if [ "$MODE" = "" ] ; then
0116     if [ "$ONLINE" = "0" ] ; then
0117         echo 'You have not explicitly specified the mode to use. Using default "report" mode.'
0118         echo 'Available modes are the following: patch, report, context, org, chain'
0119         echo 'You can specify the mode with "make coccicheck MODE=<mode>"'
0120         echo 'Note however that some modes are not implemented by some semantic patches.'
0121     fi
0122     MODE="report"
0123 fi
0124 
0125 if [ "$MODE" = "chain" ] ; then
0126     if [ "$ONLINE" = "0" ] ; then
0127         echo 'You have selected the "chain" mode.'
0128         echo 'All available modes will be tried (in that order): patch, report, context, org'
0129     fi
0130 elif [ "$MODE" = "report" -o "$MODE" = "org" ] ; then
0131     FLAGS="--no-show-diff $FLAGS"
0132 fi
0133 
0134 if [ "$ONLINE" = "0" ] ; then
0135     echo ''
0136     echo 'Please check for false positives in the output before submitting a patch.'
0137     echo 'When using "patch" mode, carefully review the patch before submitting it.'
0138     echo ''
0139 fi
0140 
0141 run_cmd_parmap() {
0142         if [ $VERBOSE -ne 0 ] ; then
0143                 echo "Running ($NPROC in parallel): $@"
0144         fi
0145         if [ "$DEBUG_FILE" != "/dev/null" -a "$DEBUG_FILE" != "" ]; then
0146                 echo $@>>$DEBUG_FILE
0147                 $@ 2>>$DEBUG_FILE
0148         else
0149                 echo $@
0150                 $@ 2>&1
0151         fi
0152 
0153         err=$?
0154         if [[ $err -ne 0 ]]; then
0155                 echo "coccicheck failed"
0156                 exit $err
0157         fi
0158 }
0159 
0160 run_cmd_old() {
0161         local i
0162         if [ $VERBOSE -ne 0 ] ; then
0163                 echo "Running ($NPROC in parallel): $@"
0164         fi
0165         for i in $(seq 0 $(( NPROC - 1)) ); do
0166                 eval "$@ --max $NPROC --index $i &"
0167                 SPATCH_PID[$i]=$!
0168                 if [ $VERBOSE -eq 2 ] ; then
0169                         echo "${SPATCH_PID[$i]} running"
0170                 fi
0171         done
0172         wait
0173 }
0174 
0175 run_cmd() {
0176         if [ "$USE_JOBS" = "yes" ]; then
0177                 run_cmd_parmap $@
0178         else
0179                 run_cmd_old $@
0180         fi
0181 }
0182 
0183 kill_running() {
0184         for i in $(seq 0 $(( NPROC - 1 )) ); do
0185                 if [ $VERBOSE -eq 2 ] ; then
0186                         echo "Killing ${SPATCH_PID[$i]}"
0187                 fi
0188                 kill ${SPATCH_PID[$i]} 2>/dev/null
0189         done
0190 }
0191 
0192 # You can override heuristics with SPFLAGS, these must always go last
0193 OPTIONS="$OPTIONS $SPFLAGS"
0194 
0195 coccinelle () {
0196     COCCI="$1"
0197 
0198     OPT=`grep "Options:" $COCCI | cut -d':' -f2`
0199     REQ=`grep "Requires:" $COCCI | cut -d':' -f2 | sed "s| ||"`
0200     if [ -n "$REQ" ] && ! { echo "$REQ"; echo "$SPATCH_VERSION"; } | sort -CV ; then
0201             echo "Skipping coccinelle SmPL patch: $COCCI"
0202             echo "You have coccinelle:           $SPATCH_VERSION"
0203             echo "This SmPL patch requires:      $REQ"
0204             return
0205     fi
0206 
0207 #   The option '--parse-cocci' can be used to syntactically check the SmPL files.
0208 #
0209 #    $SPATCH -D $MODE $FLAGS -parse_cocci $COCCI $OPT > /dev/null
0210 
0211     if [ $VERBOSE -ne 0 -a $ONLINE -eq 0 ] ; then
0212 
0213         FILE=${COCCI#$srctree/}
0214 
0215         echo "Processing `basename $COCCI`"
0216         echo "with option(s) \"$OPT\""
0217         echo ''
0218         echo 'Message example to submit a patch:'
0219 
0220         sed -ne 's|^///||p' $COCCI
0221 
0222         if [ "$MODE" = "patch" ] ; then
0223             echo ' The semantic patch that makes this change is available'
0224         elif [ "$MODE" = "report" ] ; then
0225             echo ' The semantic patch that makes this report is available'
0226         elif [ "$MODE" = "context" ] ; then
0227             echo ' The semantic patch that spots this code is available'
0228         elif [ "$MODE" = "org" ] ; then
0229             echo ' The semantic patch that makes this Org report is available'
0230         else
0231             echo ' The semantic patch that makes this output is available'
0232         fi
0233         echo " in $FILE."
0234         echo ''
0235         echo ' More information about semantic patching is available at'
0236         echo ' http://coccinelle.lip6.fr/'
0237         echo ''
0238 
0239         if [ "`sed -ne 's|^//#||p' $COCCI`" ] ; then
0240             echo 'Semantic patch information:'
0241             sed -ne 's|^//#||p' $COCCI
0242             echo ''
0243         fi
0244     fi
0245 
0246     if [ "$MODE" = "chain" ] ; then
0247         run_cmd $SPATCH -D patch   \
0248                 $FLAGS --cocci-file $COCCI $OPT $OPTIONS               || \
0249         run_cmd $SPATCH -D report  \
0250                 $FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff || \
0251         run_cmd $SPATCH -D context \
0252                 $FLAGS --cocci-file $COCCI $OPT $OPTIONS               || \
0253         run_cmd $SPATCH -D org     \
0254                 $FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff || exit 1
0255     elif [ "$MODE" = "rep+ctxt" ] ; then
0256         run_cmd $SPATCH -D report  \
0257                 $FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff && \
0258         run_cmd $SPATCH -D context \
0259                 $FLAGS --cocci-file $COCCI $OPT $OPTIONS || exit 1
0260     else
0261         run_cmd $SPATCH -D $MODE   $FLAGS --cocci-file $COCCI $OPT $OPTIONS || exit 1
0262     fi
0263 
0264 }
0265 
0266 if [ "$DEBUG_FILE" != "/dev/null" -a "$DEBUG_FILE" != "" ]; then
0267         if [ -f $DEBUG_FILE ]; then
0268                 echo "Debug file $DEBUG_FILE exists, bailing"
0269                 exit
0270         fi
0271 else
0272         DEBUG_FILE="/dev/null"
0273 fi
0274 
0275 if [ "$COCCI" = "" ] ; then
0276     for f in `find $srctree/scripts/coccinelle/ -name '*.cocci' -type f | sort`; do
0277         coccinelle $f
0278     done
0279 else
0280     coccinelle $COCCI
0281 fi