Back to home page

LXR

 
 

    


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