blob: 64df056d24bbb39c3d05a7e7a3eb4076cb860967 [file] [log] [blame]
#
# SPDX-License-Identifier: BSD-3-Clause
# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
#
include(FetchContent)
include("${SOURCE_DIR}/tools/cbmc/SummaryHelpers.cmake")
find_program(RMM_CBMC_PATH "cbmc"
DOC "Path to cbmc.")
find_program(RMM_GOTO_CC_PATH "goto-cc"
DOC "Path to goto-cc.")
find_program(RMM_CBMC_VIEWER_PATH "cbmc-viewer"
DOC "Path to cbmc-viewer.")
find_program(RMM_GCC_PATH "gcc"
DOC "Path to gcc.")
find_package(Python3 REQUIRED)
find_program(CHECK_CBMC_SUMMARY_EXECUTABLE "compare_summary.py"
PATHS ${CMAKE_SOURCE_DIR}
PATH_SUFFIXES tools/cbmc
DOC "Path to compare_summary.py"
)
#
# Configure and execute CBMC
#
if(NOT (EXISTS "${RMM_CBMC_PATH}"))
message(FATAL_ERROR "cbmc executable not found. (${RMM_CBMC_PATH})")
endif()
string(TOLOWER "${RMM_CBMC_CONFIGURATION}" CBMC_RESULT_FILE_SUFFIX)
if(RMM_CBMC_VIEWER_OUTPUT)
set(CBMC_OUT_FILE_ENDING "xml")
set(CBMC_UI_OPTION "--xml-ui")
else()
set(CBMC_OUT_FILE_ENDING "output")
set(CBMC_UI_OPTION "")
endif()
if(${RMM_CBMC_CONFIGURATION} STREQUAL "GCC")
set(COMPILED_FILE_PREFIX "gcc")
set(RMM_CBMC_COMPILER_PATH "${RMM_GCC_PATH}")
list(APPEND RMM_IMP_SRCS "${TESTBENCH_DIR}/../gcc/gcc_defs.c")
else()
set(COMPILED_FILE_PREFIX "goto_cc")
set(RMM_CBMC_COMPILER_PATH "${RMM_GOTO_CC_PATH}")
endif()
set(RMM_TESTBENCH_RESULT_DIR "${BINARY_DIR}/cbmc_${CBMC_RESULT_FILE_SUFFIX}_results")
set(SUMMARY_FILE "SUMMARY.${CBMC_RESULT_FILE_SUFFIX}")
set(RMM_CBMC_SUMMARY_FIELD_WIDTH 38)
# Configurations for the initial state.
set(GRANULE_SHIFT "9")
set(MAX_NUM_OF_GRANULE "4")
math(EXPR HOST_MEM_SIZE "(1 << ${GRANULE_SHIFT}) * ${MAX_NUM_OF_GRANULE}")
set(HOST_MEM_SIZE "${HOST_MEM_SIZE}UL")
set(MAX_RTT_UNWIND "6")
set(MAX_AUX_REC "2")
set(MAX_ROOT_RTT "3")
set(MAX_UNWIND_FLAGS "")
#
# Set up cbmc command line
#
set(cbmc_unwinds_list
"--unwindset;find_lock_granules.3:${MAX_ROOT_RTT}"
"--unwindset;find_lock_rd_granules.0:${MAX_RTT_UNWIND}"
"--unwindset;find_lock_rd_granules.1:${MAX_RTT_UNWIND}"
"--unwindset;free_rec_aux_granules.0:${MAX_AUX_REC}"
"--unwindset;free_sl_rtts.0:${MAX_RTT_UNWIND}"
"--unwindset;init_realm_descriptor_page.0:${MAX_ROOT_RTT}"
"--unwindset;init_realm_descriptor_page.1:${MAX_ROOT_RTT}"
"--unwindset;init_rec.0:${MAX_AUX_REC}"
"--unwindset;init_rtt_root_page.0:${MAX_ROOT_RTT}"
"--unwindset;init_walk_path.0:${MAX_RTT_UNWIND}"
"--unwindset;lock_order_invariable.0:21"
"--unwindset;lock_order_invariable.1:11"
"--unwindset;lock_order_invariable.2:"
"--unwindset;RealmIsLive.0:${MAX_ROOT_RTT}"
"--unwindset;RealmIsLive.2:${MAX_ROOT_RTT}"
"--unwindset;rtt_walk_lock_unlock.0:${MAX_RTT_UNWIND}"
"--unwindset;RttWalk.0:${MAX_RTT_UNWIND}"
"--unwindset;smc_realm_create.0:${MAX_RTT_UNWIND}"
"--unwindset;smc_rec_create.0:${MAX_AUX_REC}"
"--unwindset;total_root_rtt_refcount.0:${MAX_RTT_UNWIND}"
)
set(cbmc_defines_list
"-DCBMC"
"-DGRANULE_SHIFT=${GRANULE_SHIFT}"
"-DXLAT_GRANULARITY_SIZE_SHIFT=${GRANULE_SHIFT}"
"-DRMM_MAX_GRANULES=${MAX_NUM_OF_GRANULE}"
"-DMAX_CPUS=1"
"-DMAX_RTT_LEVEL=${MAX_RTT_UNWIND}"
"-DHOST_MEM_SIZE=${HOST_MEM_SIZE}"
"-DNAME=\"RMM\""
"-DVERSION=\"CBMC\""
"-DCOMMIT_INFO=\"CBMC\""
"-DRMM_NUM_PAGES_PER_STACK=1"
)
# CBMC flags for memory safety analysis and undefined behaviour analysis.
set(cbmc_analysis_flags_list
"--bounds-check"
"--pointer-check"
"--div-by-zero-check"
"--signed-overflow-check"
"--unsigned-overflow-check"
"--pointer-overflow-check"
"--conversion-check"
"--undefined-shift-check"
"--float-overflow-check"
"--nan-check"
"--enum-range-check"
"--pointer-primitive-check"
"--memory-leak-check")
set(cbmc_flags_list
"--timestamp;wall"
"--verbosity;9"
# Optimisation flags:
"--drop-unused-functions"
"--reachability-slice"
)
if("${RMM_CBMC_CONFIGURATION}" STREQUAL "COVERAGE")
list(APPEND cbmc_flags_list
"--cover;cover"
"--no-assertions")
elseif("${RMM_CBMC_CONFIGURATION}" STREQUAL "ASSERT")
list(APPEND cbmc_flags_list
"--unwinding-assertions"
"--trace"
"--trace-show-function-calls")
elseif("${RMM_CBMC_CONFIGURATION}" STREQUAL "ANALYSIS")
list(APPEND cbmc_flags_list
"--unwinding-assertions"
"${cbmc_analysis_flags_list}")
elseif("${RMM_CBMC_CONFIGURATION}" STREQUAL "GCC")
list(APPEND cbmc_compiler_options
"-Wall"
"-Werror"
"-Wno-unused-function"
"-Wno-main" # Do not warning on the non-standard signature of main
"-Wno-error=unused-variable" # Some of the testbenches contain unused variables
"-include;${TESTBENCH_DIR}/../gcc/gcc_defs.h")
else()
message(FATAL_ERROR "Invalid RMM_CBMC_CONFIGURATION '${RMM_CBMC_CONFIGURATION}'")
endif()
# Convert the space separated strings to a CMake list
string(REPLACE " " ";" TESTBENCH_FILES "${TESTBENCH_FILES}")
#
# Create semi-colon separated list from white-space seperated ones.
#
separate_arguments(RMM_IMP_SRCS)
separate_arguments(RMM_IMP_INCS)
#
# Execute CBMC on the testbench files
#
rmm_cbmc_write_summary_header(${RMM_CBMC_SUMMARY_FIELD_WIDTH}
${RMM_TESTBENCH_RESULT_DIR} ${SUMMARY_FILE} ${RMM_CBMC_CONFIGURATION})
function(rmm_cbmc_gen_file_names
testbench_file_path
filename_prefix
out_file_ending
cmd_file_var_name
out_file_var_name
err_file_var_name)
get_filename_component(testbench_file_name "${testbench_file_path}" NAME)
get_filename_component(parent "${testbench_file_path}" DIRECTORY)
set("${cmd_file_var_name}" "${parent}/${filename_prefix}_${testbench_file_name}.cmd" PARENT_SCOPE)
set("${out_file_var_name}" "${parent}/${filename_prefix}_${testbench_file_name}.${out_file_ending}" PARENT_SCOPE)
set("${err_file_var_name}" "${parent}/${filename_prefix}_${testbench_file_name}.error" PARENT_SCOPE)
endfunction()
function(normalise_cmd cmd_str out_var_name)
# replace the ; with space
string (REPLACE ";" " " cmd_str "${cmd_str}")
set("${out_var_name}" "${cmd_str}" PARENT_SCOPE)
endfunction()
foreach(testbench_file ${TESTBENCH_FILES})
string(REPLACE ${TESTBENCH_DIR}/ "" testbench_filename ${testbench_file})
string(REGEX REPLACE "\\.[^\\.]*$" "" entry_point "${testbench_filename}")
set(RMM_GOTO_PROG_NAME "${RMM_TESTBENCH_RESULT_DIR}/rmm_${entry_point}.goto")
# Set the names of output files
string(REPLACE ${TESTBENCH_DIR} ${RMM_TESTBENCH_RESULT_DIR} OUT_FILE_NAME_PREFIX "${testbench_file}")
rmm_cbmc_gen_file_names(${OUT_FILE_NAME_PREFIX} "cbmc" "${CBMC_OUT_FILE_ENDING}"
cbmc_cmd_file cbmc_output_file cbmc_error_file)
rmm_cbmc_gen_file_names(${OUT_FILE_NAME_PREFIX} "cbmc_prop" "xml"
cbmc_prop_cmd_file cbmc_prop_output_file cbmc_prop_error_file)
rmm_cbmc_gen_file_names(${OUT_FILE_NAME_PREFIX} "${COMPILED_FILE_PREFIX}" "output"
compile_cmd_file compile_output_file compile_error_file)
rmm_cbmc_gen_file_names(${OUT_FILE_NAME_PREFIX} "cbmc_viewer" "output"
cbmc_viewer_cmd_file cbmc_viewer_output_file cbmc_viewer_error_file)
set(CBMC_VIEWER_REPORT_DIR "${RMM_TESTBENCH_RESULT_DIR}/report_${entry_point}")
if(${RMM_CBMC_CONFIGURATION} STREQUAL "GCC")
set(CBMC_ENTRY_POINT "-D${entry_point}=main")
else()
set(CBMC_ENTRY_POINT "--function;${entry_point}")
endif()
set(compile_cmd
${RMM_CBMC_COMPILER_PATH}
${cbmc_compiler_options}
${cbmc_defines_list}
${CBMC_ENTRY_POINT}
"-o;${RMM_GOTO_PROG_NAME}"
${RMM_IMP_INCS}
${RMM_IMP_SRCS}
${testbench_file}
)
set(cbmc_cmd
${RMM_CBMC_PATH}
${CBMC_UI_OPTION}
${cbmc_flags_list}
${cbmc_unwinds_list}
${RMM_GOTO_PROG_NAME})
set(cbmc_prop_cmd
${RMM_CBMC_PATH}
${cbmc_flags_list}
"--xml-ui"
"--show-properties"
${RMM_GOTO_PROG_NAME})
set(cbmc_viewer_cmd
"${RMM_CBMC_VIEWER_PATH}"
"--goto;${RMM_GOTO_PROG_NAME}"
"--result;${cbmc_output_file}"
"--property;${cbmc_prop_output_file}"
"--srcdir;${CMAKE_SOURCE_DIR}"
"--reportdir;${CBMC_VIEWER_REPORT_DIR}")
# remove the absolute path making it relative (shorten the command line)
string (REPLACE "${SOURCE_DIR}/" "" compile_cmd "${compile_cmd}")
normalise_cmd("${compile_cmd}" COMPILE_CMD_STR)
normalise_cmd("${cbmc_cmd}" CBMC_CMD_STR)
file(WRITE ${compile_cmd_file} "${COMPILE_CMD_STR}")
file(WRITE ${cbmc_cmd_file} "${CBMC_CMD_STR}")
execute_process(COMMAND ${CMAKE_COMMAND} -E echo_append "CBMC: ${testbench_file}... ")
execute_process(
COMMAND ${compile_cmd}
RESULT_VARIABLE res_var
OUTPUT_FILE ${compile_output_file}
ERROR_FILE ${compile_error_file})
if (NOT ${res_var} EQUAL "0")
message(FATAL_ERROR "Compiling testbench with ${RMM_CBMC_COMPILER_PATH} failed. For details see: ${compile_error_file}")
endif()
# Only run CBMC if not using compiler-only mode:
if(NOT ${RMM_CBMC_CONFIGURATION} STREQUAL "GCC")
execute_process(
COMMAND ${cbmc_cmd}
RESULT_VARIABLE res_var
OUTPUT_FILE ${cbmc_output_file}
ERROR_FILE ${cbmc_error_file})
if(RMM_CBMC_VIEWER_OUTPUT)
normalise_cmd("${cbmc_prop_cmd}" CBMC_PROP_CMD_STR)
file(WRITE ${cbmc_prop_cmd_file} "${CBMC_PROP_CMD_STR}")
execute_process(
COMMAND ${cbmc_prop_cmd}
RESULT_VARIABLE res_var
OUTPUT_FILE ${cbmc_prop_output_file}
ERROR_FILE ${cbmc_prop_error_file})
normalise_cmd("${cbmc_viewer_cmd}" CBMC_VIEWER_CMD_STR)
file(WRITE ${cbmc_viewer_cmd_file} "${CBMC_VIEWER_CMD_STR}")
execute_process(
COMMAND ${cbmc_viewer_cmd}
RESULT_VARIABLE res_var
OUTPUT_FILE ${cbmc_viewer_output_file}
ERROR_FILE ${cbmc_viewer_error_file})
if (NOT ${res_var} EQUAL "0")
message(FATAL_ERROR "Failed to run cbmc-viewer. For details see: ${cbmc_viewer_error_file}")
endif()
endif()
rmm_cbmc_append_summary("${testbench_filename}" "${cbmc_output_file}"
"${CBMC_RESULT_FILE_SUFFIX}-${CBMC_OUT_FILE_ENDING}"
${RMM_CBMC_SUMMARY_FIELD_WIDTH} ${RMM_TESTBENCH_RESULT_DIR} ${SUMMARY_FILE})
endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E echo "DONE")
endforeach()
message(STATUS "Result in ${RMM_TESTBENCH_RESULT_DIR}")
# Only run CBMC if not using compiler-only mode:
if(NOT ${RMM_CBMC_CONFIGURATION} STREQUAL "GCC")
list(TRANSFORM TESTBENCH_FILES REPLACE "${TESTBENCH_DIR}/" "" OUTPUT_VARIABLE TESTBENCH_FILENAMES)
execute_process(
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${CHECK_CBMC_SUMMARY_EXECUTABLE}
${CMAKE_SOURCE_DIR}/tools/cbmc/testbenches_results/BASELINE.${CBMC_RESULT_FILE_SUFFIX}
--testbench-files "${TESTBENCH_FILENAMES}"
${RMM_TESTBENCH_RESULT_DIR}/${SUMMARY_FILE}
OUTPUT_VARIABLE CHECK_SUMMARY_OUTPUT
ERROR_VARIABLE CHECK_SUMMARY_ERROR
RESULT_VARIABLE CHECK_SUMMARY_RC
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT ${CHECK_SUMMARY_RC} EQUAL "0")
message(WARNING
"cbmc-${CBMC_RESULT_FILE_SUFFIX}: FAILED\n${CHECK_SUMMARY_ERROR}")
else()
message(STATUS "cbmc-${CBMC_RESULT_FILE_SUFFIX}: PASSED")
endif()
endif()