451 lines
15 KiB
Plaintext
451 lines
15 KiB
Plaintext
# common definitions used by other sanity check scripts
|
|
|
|
# Copyright (c) 2015 Wind River Systems, Inc.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are met:
|
|
#
|
|
# 1) Redistributions of source code must retain the above copyright notice,
|
|
# this list of conditions and the following disclaimer.
|
|
#
|
|
# 2) Redistributions in binary form must reproduce the above copyright notice,
|
|
# this list of conditions and the following disclaimer in the documentation
|
|
# and/or other materials provided with the distribution.
|
|
#
|
|
# 3) Neither the name of Wind River Systems nor the names of its contributors
|
|
# may be used to endorse or promote products derived from this software without
|
|
# specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
|
|
# shell commands used in scripts
|
|
AWK="/usr/bin/awk"
|
|
BASENAME="/usr/bin/basename"
|
|
CD="cd"
|
|
DATE="/bin/date"
|
|
DIRNAME="/usr/bin/dirname"
|
|
ECHO="/bin/echo"
|
|
GREP="/bin/grep"
|
|
KILL="/bin/kill"
|
|
LS="/bin/ls"
|
|
MAKE="make-ll"
|
|
# MAKE="/usr/bin/make"
|
|
MV="/bin/mv"
|
|
PS="/bin/ps"
|
|
RM="/bin/rm"
|
|
SED="/bin/sed"
|
|
CP="/bin/cp"
|
|
MKDIR="/bin/mkdir"
|
|
SLEEP="/bin/sleep"
|
|
ABS_PATH="/bin/readlink -m"
|
|
|
|
# record how script was invoked
|
|
SCRIPT_NAME=`${BASENAME} $0`
|
|
|
|
# assume log files are not to be kept
|
|
KEEP_LOGS=0
|
|
|
|
# log filename where QEMU console output is redirected to
|
|
SANITY_CHK_LOG="sanity_chk.log"
|
|
|
|
# directory containing code coverage results
|
|
CC_DIR=${TIMO_BASE}/codecoverage/`${BASENAME} $0`/
|
|
HTML_CC_DIR=${TIMO_BASE}/codecoverage_html/`${BASENAME} $0`/
|
|
|
|
# temporary files used when selecting projects to be sanitized
|
|
TEMP_AWK_PROG="${TIMO_BASE}/.tempawkprog"
|
|
TEMP_PRJ_LIST="${TIMO_BASE}/.tempprojlist"
|
|
|
|
# maximum time (in seconds) to allow QEMU to execute a project
|
|
QEMU_TIME_LIMIT=300
|
|
|
|
# console output that indicates termination of a project that is being run,
|
|
# and what indicates successful termination
|
|
# (note: output string is allowed to contain spaces!)
|
|
RUN_UNTIL="PROJECT EXECUTION"
|
|
RUN_PASSED="PROJECT EXECUTION SUCCESSFUL"
|
|
RUN_FAILED="PROJECT EXECUTION FAILED"
|
|
|
|
# architecture BSP lists
|
|
arm_BSP_LIST="fsl_frdm_k64f ti_lm3s6965"
|
|
x86_BSP_LIST="pentium4 minuteia atom quark"
|
|
_BSP_LIST="${arc_BSP_LIST} ${arm_BSP_LIST} ${x86_BSP_LIST}"
|
|
|
|
# header used to identify script output during execution
|
|
#
|
|
print_header() {
|
|
${ECHO} "*-=*-=*-=*-=*-=*-=*-=*-=*-=*-=*-=*-=*-=*-="
|
|
}
|
|
|
|
# routine that prints error message and exits with error code
|
|
#
|
|
# PARAMETERS: $1 is exit value
|
|
# $2 is function name to print
|
|
# $3 is line number where script failed
|
|
# $4 is optional error msg
|
|
#
|
|
fail_exit() {
|
|
if [ -z "$4" ] ; then
|
|
msg=""
|
|
else
|
|
msg="$4"
|
|
fi
|
|
|
|
# print full script pathname to help in case of issues with $PATH
|
|
${ECHO} "$0 line $3 $2 failed: ($1) ${msg}"
|
|
|
|
exit $1
|
|
}
|
|
|
|
# restore a project to its pristine state
|
|
#
|
|
# PARAMETERS: $1 is project directory name
|
|
#
|
|
# ON ENTRY: ${PRJ_PATH} is path to master project directory
|
|
#
|
|
clean_project() {
|
|
${ECHO} "* Cleaning project $1"
|
|
|
|
${CD} ${PRJ_PATH}/$1
|
|
[ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO
|
|
|
|
${MAKE} distclean
|
|
[ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO
|
|
}
|
|
|
|
# restore all projects to their pristine state
|
|
#
|
|
# ON ENTRY: ${PRJ_LIST} is pseudo-file of project information
|
|
#
|
|
# Note that routine will clean a project multiple times if it appears multiple
|
|
# times in ${PRJ_LIST}. It's not worth optimizing to prevent this ...
|
|
#
|
|
clean_all_projects() {
|
|
project_dirs=`${ECHO} -e ${PRJ_LIST} | ${AWK} '!/#/ {print $1}'`
|
|
for project in ${project_dirs}
|
|
do
|
|
clean_project ${project}
|
|
done
|
|
}
|
|
|
|
# set up environment info used to build projects
|
|
#
|
|
# ON ENTRY: ${BSP_NAME} is BSP to use (empty => use per-project default)
|
|
#
|
|
# ON EXIT: ${BUILD_INFO} specifies build options
|
|
#
|
|
build_info_set() {
|
|
# ensure BSP name isn't a script option that was entered by mistake
|
|
if [ x${BSP_NAME:0:1} = "x-" ] ; then
|
|
${ECHO} "invalid BSP '${BSP_NAME}' specified"
|
|
exit 1
|
|
fi
|
|
|
|
# set up toolchain-specific build environment stuff
|
|
BUILD_INFO="EXTRA_CFLAGS=-Werror EXTRA_ASMFLAGS=-Wa,--fatal-warnings EXTRA_LFLAGS=--fatal-warnings"
|
|
}
|
|
|
|
# set up project info used to build projects
|
|
#
|
|
# ON ENTRY: ${PRJ_PATH} is path to master project directory
|
|
# ${PRJ_LIST} is pseudo-file of project information
|
|
# ${BSP_NAME} is BSP to use (empty => use per-project default)
|
|
# ${ARCH_NAME} is architecture to use (empty => no arch restrictions)
|
|
#
|
|
# ON EXIT: ${PRJ_NAME} array specifies project directory name
|
|
# ${PRJ_ARGS} array specifies any additional project build arguments
|
|
# ${PRJ_TYPE} array specifies project type ("nanokernel" or "microkernel")
|
|
# ${PRJ_FLAG} array specifies project flags ('u' or 'n'; optional 'q')
|
|
# ${BSP_INFO} array specifies project BSP and BSP_VARIANT
|
|
# ${BSP_FLAG} array specifies optional BSP flag ('!' or empty)
|
|
# ${NUM_PROJ} specifies number of projects described in arrays
|
|
#
|
|
proj_info_set() {
|
|
# clean up any stale temporary files from an earlier run
|
|
${RM} -f ${TEMP_AWK_PROG} ${TEMP_PRJ_LIST}
|
|
|
|
# create list of projects to sanitize
|
|
# - specified BSP: choose only projects that support that BSP,
|
|
# then filter out info about all other BSPs for those projects
|
|
# - no specified BSP: choose all projects, then filter out info
|
|
# about all BSPs except the first one listed
|
|
# note: ignores any comment lines in the project information file
|
|
# (i.e. any lines containing a '#' character)
|
|
dollar='$'
|
|
if [ x${BSP_NAME} != x ] ; then
|
|
awk_string="!/#/ && /${BSP_NAME}/ {match(${dollar}0,/.+[>]/); \
|
|
prjpart = substr(${dollar}0,RSTART,RLENGTH); \
|
|
bsppart = substr(${dollar}0,RLENGTH+1);
|
|
match(bsppart,/${BSP_NAME}!?/); \
|
|
bsp = substr(bsppart,RSTART,RLENGTH); \
|
|
if(length(bsp) > 0) \
|
|
print prjpart \" \" bsp}"
|
|
else
|
|
awk_string="!/#/ {match(${dollar}0,/.+[>]/); \
|
|
prjpart = substr(${dollar}0,RSTART,RLENGTH); \
|
|
bsppart = substr(${dollar}0,RLENGTH+1);
|
|
match(bsppart,/[-a-zA-Z0-9_]+!?/); \
|
|
bsp = substr(bsppart,RSTART,RLENGTH); \
|
|
print prjpart \" \" bsp}"
|
|
fi
|
|
|
|
${ECHO} "${awk_string}" > ${TEMP_AWK_PROG}
|
|
${ECHO} -e ${PRJ_LIST} | ${AWK} -f ${TEMP_AWK_PROG} > ${TEMP_PRJ_LIST}
|
|
|
|
# deconstruct the filtered project list file
|
|
# into a set of arrays containing project info
|
|
let NUM_PROJ=0
|
|
while read line ; do
|
|
let NUM_PROJ++
|
|
|
|
PRJ_NAME[${NUM_PROJ}]=`${AWK} '{match($0,/[^ ]+[ <]/); \
|
|
print substr($0,RSTART,RLENGTH-1)}' <<< ${line}`
|
|
|
|
PRJ_ARGS[${NUM_PROJ}]=`${AWK} '{match($0,/ .*[<]/); \
|
|
print substr($0,RSTART+1,RLENGTH-2)}' <<< ${line}`
|
|
|
|
PRJ_FLAG[${NUM_PROJ}]=`${AWK} '{match($0,/<.*>/); \
|
|
print substr($0,RSTART+1,RLENGTH-2)}' <<< ${line}`
|
|
if [ ${PRJ_FLAG[${NUM_PROJ}]:0:1} = "u" ] ; then
|
|
PRJ_TYPE[${NUM_PROJ}]="microkernel"
|
|
elif [ ${PRJ_FLAG[${NUM_PROJ}]:0:1} = "n" ] ; then
|
|
PRJ_TYPE[${NUM_PROJ}]="nanokernel"
|
|
else
|
|
${ECHO} "unrecognized project type"
|
|
exit 1
|
|
fi
|
|
|
|
bsp2use_tmp=`${AWK} '{match($0,/[>] [-a-zA-Z0-9_]+/); \
|
|
print substr($0,RSTART+1,RLENGTH-1)}' <<< ${line}`
|
|
bsp2use="$(${ECHO} -e "${bsp2use_tmp}" | ${SED} -e 's/^[[:space:]]*//')"
|
|
|
|
${ECHO} ${_BSP_LIST} | ${GREP} -q -w ${bsp2use}
|
|
if [ $? -ne 0 ]; then
|
|
${ECHO} "Unrecognized BSP or BSP variant"
|
|
exit 1
|
|
fi
|
|
|
|
if [ x${ARCH_NAME} != x ] ; then
|
|
# An architecture has been specified.
|
|
bsp_list=${ARCH_NAME}_BSP_LIST
|
|
${ECHO} ${!bsp_list} | ${GREP} -q -w ${bsp2use}
|
|
if [ $? -ne 0 ] ; then
|
|
# The specified architecture does not support the
|
|
# BSP or BSP variant ${bsp2use}
|
|
let NUM_PROJ--
|
|
continue
|
|
fi
|
|
fi
|
|
|
|
if [ ${bsp2use} = "pentium4" ] ; then
|
|
BSP_INFO[${NUM_PROJ}]="BSP=generic_pc BSP_VARIANT=pentium4"
|
|
BSP[${NUM_PROJ}]=generic_pc
|
|
elif [ ${bsp2use} = "minuteia" ] ; then
|
|
BSP_INFO[${NUM_PROJ}]="BSP=generic_pc BSP_VARIANT=minuteia"
|
|
BSP[${NUM_PROJ}]=generic_pc
|
|
elif [ ${bsp2use} = "atom" ] ; then
|
|
BSP_INFO[${NUM_PROJ}]="BSP=generic_pc BSP_VARIANT=atom_n28xx"
|
|
BSP[${NUM_PROJ}]=generic_pc
|
|
elif [ ${bsp2use} = "quark" ] ; then
|
|
BSP_INFO[${NUM_PROJ}]="BSP=quark"
|
|
BSP[${NUM_PROJ}]=quark
|
|
else
|
|
BSP_INFO[${NUM_PROJ}]="BSP=${bsp2use}"
|
|
BSP[${NUM_PROJ}]=${bsp2use}
|
|
fi
|
|
|
|
BSP_FLAG[${NUM_PROJ}]=`${AWK} '/!/ {print "!"}' <<< ${line}`
|
|
done < ${TEMP_PRJ_LIST}
|
|
|
|
# clean up temporary files
|
|
${RM} -f ${TEMP_AWK_PROG} ${TEMP_PRJ_LIST}
|
|
}
|
|
|
|
# skip building of a standard project
|
|
#
|
|
# PARAMETERS: $1 is project array entry to use
|
|
#
|
|
# ON ENTRY: ${PRJ_PATH} is path to master project directory
|
|
# ${PRJ_NAME} array specifies project directory name
|
|
# ${PRJ_ARGS} array specifies any additional project build arguments
|
|
# ${PRJ_TYPE} array specifies project type ("nanokernel" or "microkernel")
|
|
# ${PRJ_FLAG} array specifies project flags ('u' or 'n'; optional 'q')
|
|
# ${BSP_INFO} array specifies project BSP and BSP_VARIANT
|
|
# ${BUILD_INFO} specifies build options
|
|
# ${NUM_PROJ} specifies # of projects described in arrays
|
|
# ${PRJ_CLASS} specifies type of projects being sanitized
|
|
#
|
|
skip_project() {
|
|
proj_name=`${BASENAME} ${PRJ_NAME[$1]}`
|
|
|
|
${ECHO} "Skipping ${proj_name} [${PRJ_CLASS} project $1 of ${NUM_PROJ}]"
|
|
${ECHO}
|
|
}
|
|
|
|
# build a standard project
|
|
#
|
|
# PARAMETERS: $1 is project array entry to use
|
|
# $2 if set, tells the routine not to check for an elf file
|
|
#
|
|
# ON ENTRY: ${PRJ_PATH} is path to master project directory
|
|
# ${PRJ_NAME} array specifies project directory name
|
|
# ${PRJ_ARGS} array specifies any additional project build arguments
|
|
# ${PRJ_TYPE} array specifies project type ("nanokernel" or "microkernel")
|
|
# ${PRJ_FLAG} array specifies project flags ('u' or 'n'; optional 'q')
|
|
# ${BSP_INFO} array specifies project BSP and BSP_VARIANT
|
|
# ${BUILD_INFO} specifies build options
|
|
# ${NUM_PROJ} specifies # of projects described in arrays
|
|
# ${PRJ_CLASS} specifies type of projects being sanitized
|
|
#
|
|
build_project() {
|
|
proj_name=`${BASENAME} ${PRJ_NAME[$1]}`
|
|
|
|
${ECHO} "Building ${proj_name} [${PRJ_CLASS} project $1 of ${NUM_PROJ}]"
|
|
${ECHO}
|
|
${ECHO} "target: ${BSP_INFO[$1]}"
|
|
${ECHO} "arguments: ${PRJ_ARGS[$1]}"
|
|
${ECHO}
|
|
|
|
${CD} ${PRJ_PATH}/${PRJ_NAME[$1]}
|
|
[ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO
|
|
|
|
# build project from scratch
|
|
${MAKE} distclean
|
|
[ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO
|
|
|
|
if [[ $arm_BSP_LIST == *"${BSP[$1]}"* ]]; then
|
|
arch=arm
|
|
else
|
|
arch=x86
|
|
fi
|
|
if [ ! -z ${ARCH_NAME} ]; then
|
|
arch=${ARCH_NAME}
|
|
fi
|
|
|
|
${MAKE} ARCH=${arch} ${BUILD_INFO} ${PRJ_ARGS[$1]} ${BSP_INFO[$1]}
|
|
[ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO
|
|
|
|
if [ x$2 == x ] ; then
|
|
elf_name=`${LS} outdir/${PRJ_TYPE[$1]}.elf`
|
|
[ x${elf_name} != "x" ] || \
|
|
fail_exit $? $FUNCNAME $LINENO "couldn't build ${proj_name}"
|
|
fi
|
|
}
|
|
|
|
# use QEMU to run a standard project that is already built
|
|
#
|
|
# PARAMETERS: $1 is project array entry to use
|
|
#
|
|
# ON ENTRY: ${PRJ_PATH} is path to master project directory
|
|
# ${PRJ_NAME} array specifies project directory name
|
|
# ${PRJ_ARGS} array specifies any additional project build arguments
|
|
# ${PRJ_TYPE} array specifies project type ("nanokernel" or "microkernel")
|
|
# ${PRJ_FLAG} array specifies project flags ('u' or 'n'; optional 'q')
|
|
# ${BSP_INFO} array specifies project BSP and BSP_VARIANT
|
|
# ${BUILD_INFO} specifies build options
|
|
# ${NUM_PROJ} specifies # of projects described in arrays
|
|
# ${PRJ_CLASS} specifies type of projects being sanitized
|
|
#
|
|
qemu_project() {
|
|
proj_name=`${BASENAME} ${PRJ_NAME[$1]}`
|
|
|
|
${ECHO}
|
|
${ECHO} "Running ${proj_name} using QEMU [${PRJ_CLASS} project $1 of ${NUM_PROJ}]"
|
|
${ECHO}
|
|
${ECHO} "target: ${BSP_INFO[$1]}"
|
|
${ECHO} "arguments: ${PRJ_ARGS[$1]}"
|
|
${ECHO}
|
|
|
|
${CD} ${PRJ_PATH}/${PRJ_NAME[$1]}
|
|
[ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO $1
|
|
|
|
# create empty log now so the grep loop below can access the file
|
|
# right away for the case where QEMU did had a chance to run and
|
|
# create the file by the time the grep loop starts
|
|
${RM} -f ${SANITY_CHK_LOG}
|
|
:> ${SANITY_CHK_LOG}
|
|
if [[ $arm_BSP_LIST == *"${BSP[$1]}"* ]]; then
|
|
arch=arm
|
|
else
|
|
arch=x86
|
|
fi
|
|
if [ ! -z ${ARCH_NAME} ]; then
|
|
arch=${ARCH_NAME}
|
|
fi
|
|
# launch a separate process to run ELF file in QEMU,
|
|
# and append the logs into the empty log file created above
|
|
# (supply all build-related arguments to allow final linking
|
|
# to be done using the same arguments as the original build)
|
|
( ${MAKE} ARCH=${arch} qemu ${PRJ_ARGS[$1]} ${BSP_INFO[$1]} \
|
|
${BUILD_INFO} | tee ${SANITY_CHK_LOG} )&
|
|
|
|
# get QEMU's pid
|
|
# (wait for QEMU process to be spawned by examining list of tasks
|
|
# associated with this script's terminal, then grab the pid)
|
|
while ! [ -f outdir/qemu.pid ]
|
|
do
|
|
${SLEEP} 1
|
|
done
|
|
|
|
qemu_pid=$(<outdir/qemu.pid)
|
|
|
|
# assume execution will fail
|
|
let RESULT=1
|
|
|
|
# wait up for project to complete (or time limit to be reached)
|
|
let loop_cnt=0
|
|
while [ "${loop_cnt}" -le "${QEMU_TIME_LIMIT}" ]
|
|
do
|
|
${GREP} -q -E "${RUN_PASSED}" ${SANITY_CHK_LOG}
|
|
if [ $? -eq 0 ] ; then
|
|
let RESULT=0
|
|
break
|
|
fi
|
|
${GREP} -q -E "${RUN_FAILED}" ${SANITY_CHK_LOG}
|
|
if [ $? -eq 0 ] ; then
|
|
break
|
|
fi
|
|
let loop_cnt++
|
|
${SLEEP} 1
|
|
done
|
|
|
|
# kill QEMU, otherwise it continues running forever
|
|
# (tee will SIGPIPE when qemu is killed,
|
|
# and the subshell will exit when both its children exit)
|
|
${KILL} ${qemu_pid}
|
|
|
|
# keep log if requested or when there is an error
|
|
if [ ${KEEP_LOGS} = 1 -o ${RESULT} -ne 0 ] ; then
|
|
# append info identifying how log file was generated
|
|
$ECHO >> ${SANITY_CHK_LOG}
|
|
$ECHO "Project name: ${PRJ_NAME[$1]}" >> ${SANITY_CHK_LOG}
|
|
$ECHO "Project arguments: ${PRJ_ARGS[$1]}" >> ${SANITY_CHK_LOG}
|
|
$ECHO "BSP info: ${BSP_INFO[$1]}" >> ${SANITY_CHK_LOG}
|
|
$ECHO "Build info: ${BUILD_INFO}" >> ${SANITY_CHK_LOG}
|
|
|
|
# ensure log file name is unique to avoid overwriting
|
|
# a previously generated log file
|
|
# (note: assumes identical test isn't re-run within 60 seconds)
|
|
new_name=${SANITY_CHK_LOG}_project$1_`${DATE} +%F_%R`
|
|
${ECHO}
|
|
${ECHO} "saving log file ${PRJ_PATH}/${PRJ_NAME[$1]}/${new_name}"
|
|
${MV} -f ${SANITY_CHK_LOG} ${new_name}
|
|
else
|
|
${RM} -f ${SANITY_CHK_LOG}
|
|
fi
|
|
|
|
[ ${RESULT} -eq 0 ] || fail_exit 1 $FUNCNAME $LINENO \
|
|
"error running ${proj_name}"
|
|
}
|