Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -159,6 +159,7 @@ set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64}) set(ALL_ESAN_SUPPORTED_ARCH ${X86_64}) set(ALL_SCUDO_SUPPORTED_ARCH ${X86_64}) +set(ALL_CSI_SUPPORTED_ARCH ${X86_64}) if(APPLE) include(CompilerRTDarwinUtils) @@ -348,6 +349,9 @@ list_intersect(SCUDO_SUPPORTED_ARCH ALL_SCUDO_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) + list_intersect(CSI_SUPPORTED_ARCH + ALL_CSI_SUPPORTED_ARCH + SANITIZER_COMMON_SUPPORTED_ARCH) else() # Architectures supported by compiler-rt libraries. filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH @@ -371,6 +375,7 @@ filter_available_targets(ESAN_SUPPORTED_ARCH ${ALL_ESAN_SUPPORTED_ARCH}) filter_available_targets(SCUDO_SUPPORTED_ARCH ${ALL_SCUDO_SUPPORTED_ARCH}) + filter_available_targets(CSI_SUPPORTED_ARCH ${ALL_CSI_SUPPORTED_ARCH}) endif() if (MSVC) @@ -491,3 +496,9 @@ set(COMPILER_RT_HAS_SCUDO FALSE) endif() +if (COMPILER_RT_HAS_SANITIZER_COMMON AND CSI_SUPPORTED_ARCH AND + OS_NAME MATCHES "Linux") + set(COMPILER_RT_HAS_CSI TRUE) +else() + set(COMPILER_RT_HAS_CSI FALSE) +endif() Index: lib/CMakeLists.txt =================================================================== --- lib/CMakeLists.txt +++ lib/CMakeLists.txt @@ -56,4 +56,8 @@ if(COMPILER_RT_HAS_SCUDO) add_subdirectory(scudo) endif() + + if(COMPILER_RT_HAS_CSI) + add_subdirectory(csi) + endif() endif() Index: lib/csi/CMakeLists.txt =================================================================== --- /dev/null +++ lib/csi/CMakeLists.txt @@ -0,0 +1,26 @@ +# Build for the ComprehensiveStaticInstrumentation runtime support library. + +add_custom_target(csi) + +set(CSI_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS} -std=c11) +append_rtti_flag(OFF CSI_RTL_CFLAGS) + +include_directories(..) + +set(CSI_SOURCES csirt.c) + +foreach (arch ${CSI_SUPPORTED_ARCH}) + add_compiler_rt_runtime(clang_rt.csi + STATIC + ARCHS ${arch} + SOURCES ${CSI_SOURCES} + CFLAGS ${CSI_RTL_CFLAGS}) + add_dependencies(csi + clang_rt.csi-${arch}) +endforeach() + +add_dependencies(compiler-rt csi) + +if (COMPILER_RT_INCLUDE_TESTS) + # TODO(bruening): add tests via add_subdirectory(tests) +endif() Index: lib/csi/csi.h =================================================================== --- /dev/null +++ lib/csi/csi.h @@ -0,0 +1,100 @@ +#ifndef __CSI_H__ +#define __CSI_H__ + +#include + +#ifdef __cplusplus +#define EXTERN_C extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C +#define EXTERN_C_END +#include // for C99 bool type +#endif + +#define WEAK __attribute__((weak)) + +// API function signatures +EXTERN_C + +/** + * Unless a type requires bitwise operations (e.g., property lists), we use + * signed integers. We don't need the extra bit of data, and using unsigned + * integers can lead to subtle bugs. See + * http://www.soundsoftware.ac.uk/c-pitfall-unsigned + */ + +typedef int64_t csi_id_t; + +#define UNKNOWN_CSI_ID ((csi_id_t)-1) + +typedef struct { + csi_id_t num_bb; + csi_id_t num_callsite; + csi_id_t num_func; + csi_id_t num_func_exit; + csi_id_t num_load; + csi_id_t num_store; +} instrumentation_counts_t; + +WEAK void __csi_init(); + +WEAK void __csi_unit_init(const char * const file_name, + const instrumentation_counts_t counts); + +WEAK void __csi_func_entry(const csi_id_t func_id); + +WEAK void __csi_func_exit(const csi_id_t func_exit_id, + const csi_id_t func_id); + +WEAK void __csi_bb_entry(const csi_id_t bb_id); + +WEAK void __csi_bb_exit(const csi_id_t bb_id); + +WEAK void __csi_before_call(const csi_id_t call_id, const csi_id_t func_id); + +WEAK void __csi_after_call(const csi_id_t call_id, const csi_id_t func_id); + +WEAK void __csi_before_load(const csi_id_t load_id, + const void *addr, + const int32_t num_bytes, + const uint64_t prop); + +WEAK void __csi_after_load(const csi_id_t load_id, + const void *addr, + const int32_t num_bytes, + const uint64_t prop); + +WEAK void __csi_before_store(const csi_id_t store_id, + const void *addr, + const int32_t num_bytes, + const uint64_t prop); + +WEAK void __csi_after_store(const csi_id_t store_id, + const void *addr, + const int32_t num_bytes, + const uint64_t prop); + +typedef struct { + // TODO(ddoucet): Why is this 32 bits? + int32_t line_number; + char *filename; +} source_loc_t; + +// Front-end data (FED) table accessors. +source_loc_t const * __csi_get_func_source_loc(const csi_id_t func_id); +source_loc_t const * __csi_get_func_exit_source_loc(const csi_id_t func_exit_id); +source_loc_t const * __csi_get_bb_source_loc(const csi_id_t bb_id); +source_loc_t const * __csi_get_callsite_source_loc(const csi_id_t call_id); +source_loc_t const * __csi_get_load_source_loc(const csi_id_t load_id); +source_loc_t const * __csi_get_store_source_loc(const csi_id_t store_id); + +// Property bitmasks. + +// Load property: the load is a read-before-write on the address in +// the same basic block. +#define CSI_PROP_LOAD_READ_BEFORE_WRITE_IN_BB 0x1 + +EXTERN_C_END + +#endif Index: lib/csi/csirt.c =================================================================== --- /dev/null +++ lib/csi/csirt.c @@ -0,0 +1,189 @@ +#include +#include +#include + +#include "csi.h" + +#define CSIRT_API __attribute__((visibility("default"))) + +// ------------------------------------------------------------------------ +// Front end data (FED) table structures. +// ------------------------------------------------------------------------ + +// A FED table is a flat list of FED entries, indexed by a CSI +// ID. Each FED table has its own private ID space. +typedef struct { + int64_t num_entries; + source_loc_t *entries; +} fed_table_t; + +// Types of FED tables that we maintain across all units. +typedef enum { + FED_TYPE_BASICBLOCK, + FED_TYPE_FUNCTIONS, + FED_TYPE_FUNCTION_EXIT, + FED_TYPE_CALLSITE, + FED_TYPE_LOAD, + FED_TYPE_STORE, + NUM_FED_TYPES // Must be last +} fed_type_t; + +// ------------------------------------------------------------------------ +// Globals +// ------------------------------------------------------------------------ + +// The list of FED tables. This is indexed by a value of +// 'fed_type_t'. +static fed_table_t *fed_tables = NULL; + +// Initially false, set to true once the first unit is initialized, +// which results in the FED list being initialized. +static bool fed_tables_initialized = false; + +// Initially false, set to true once the first unit is initialized, +// which results in the __csi_init() function being called. +static bool csi_init_called = false; + +// ------------------------------------------------------------------------ +// Private function definitions +// ------------------------------------------------------------------------ + +// Initialize the FED tables list, indexed by a value of type +// fed_type_t. This is called once, by the first unit to load. +static void initialize_fed_tables() { + fed_tables = (fed_table_t *)malloc(NUM_FED_TYPES * sizeof(fed_table_t)); + assert(fed_tables != NULL); + for (unsigned i = 0; i < NUM_FED_TYPES; i++) { + fed_table_t table; + table.num_entries = 0; + table.entries = NULL; + fed_tables[i] = table; + } + fed_tables_initialized = true; +} + +// Ensure that the FED table of the given type has enough memory +// allocated to add a new unit's entries. +static void ensure_fed_table_capacity(fed_type_t fed_type, int64_t num_new_entries) { + if (!fed_tables_initialized) { + initialize_fed_tables(); + } + fed_table_t *table = &fed_tables[fed_type]; + int64_t total_num_entries = table->num_entries + num_new_entries; + if (total_num_entries > 0) { + table->entries = (source_loc_t *)realloc(table->entries, + total_num_entries * sizeof(source_loc_t)); + table->num_entries = total_num_entries; + assert(table->entries != NULL); + } +} + +// Add a new FED table of the given type. +static inline void add_fed_table(fed_type_t fed_type, int64_t num_entries, source_loc_t const * fed_entries) { + ensure_fed_table_capacity(fed_type, num_entries); + fed_table_t *table = &fed_tables[fed_type]; + csi_id_t base = table->num_entries - num_entries; + for (csi_id_t i = 0; i < num_entries; i++) { + table->entries[base + i] = fed_entries[i]; + } +} + +// The unit-local counter pointed to by 'fed_id_base' keeps track of +// that unit's "base" ID value of the given type (recall that there is +// a private ID space per FED type). The "base" ID value is the global +// ID that corresponds to the unit's local ID 0. This function stores +// the correct value into a unit's base ID. +static inline void update_ids(fed_type_t fed_type, int64_t num_entries, csi_id_t *fed_id_base) { + fed_table_t *table = &fed_tables[fed_type]; + // The base ID is the current number of FED entries before adding + // the new FED table. + *fed_id_base = table->num_entries - num_entries; +} + +// Return the FED entry of the given type, corresponding to the given +// CSI ID. +static inline source_loc_t const * get_fed_entry(fed_type_t fed_type, const csi_id_t csi_id) { + // TODO(ddoucet): threadsafety + fed_table_t *table = &fed_tables[fed_type]; + if (csi_id < table->num_entries) { + assert(table->entries != NULL); + return &table->entries[csi_id]; + } else { + return NULL; + } +} + +// ------------------------------------------------------------------------ +// External function definitions, including CSIRT API functions. +// ------------------------------------------------------------------------ + +EXTERN_C + +typedef struct { + int64_t num_entries; + csi_id_t *id_base; + source_loc_t const * entries; +} unit_fed_table_t; + +// Function signature for the function (generated by the CSI compiler +// pass) that updates the callsite to function ID mappings. +typedef void (*__csi_init_callsite_to_functions)(); + +static inline instrumentation_counts_t compute_inst_counts(unit_fed_table_t *unit_fed_tables) { + instrumentation_counts_t counts; + int64_t *base = (int64_t *)&counts; + for (unsigned i = 0; i < NUM_FED_TYPES; i++) + *(base + i) = unit_fed_tables[i].num_entries; + return counts; +} + +// A call to this is inserted by the CSI compiler pass, and occurs +// before main(). +CSIRT_API void __csirt_unit_init(const char * const name, + unit_fed_table_t *unit_fed_tables, + __csi_init_callsite_to_functions callsite_to_func_init) { + // TODO(ddoucet): threadsafety + if (!csi_init_called) { + __csi_init(); + csi_init_called = true; + } + + // Add all FED tables from the new unit + for (unsigned i = 0; i < NUM_FED_TYPES; i++) { + add_fed_table(i, unit_fed_tables[i].num_entries, unit_fed_tables[i].entries); + update_ids(i, unit_fed_tables[i].num_entries, unit_fed_tables[i].id_base); + } + + // Initialize the callsite -> function mappings. This must happen + // after the base IDs have been updated. + callsite_to_func_init(); + + // Call into the tool implementation. + __csi_unit_init(name, compute_inst_counts(unit_fed_tables)); +} + +CSIRT_API source_loc_t const * __csi_get_func_source_loc(const csi_id_t func_id) { + return get_fed_entry(FED_TYPE_FUNCTIONS, func_id); +} + +CSIRT_API source_loc_t const * __csi_get_func_exit_source_loc(const csi_id_t func_exit_id) { + return get_fed_entry(FED_TYPE_FUNCTION_EXIT, func_exit_id); +} + +CSIRT_API source_loc_t const * __csi_get_bb_source_loc(const csi_id_t bb_id) { + return get_fed_entry(FED_TYPE_BASICBLOCK, bb_id); +} + +CSIRT_API source_loc_t const * __csi_get_callsite_source_loc(const csi_id_t callsite_id) { + return get_fed_entry(FED_TYPE_CALLSITE, callsite_id); +} + +CSIRT_API source_loc_t const * __csi_get_load_source_loc(const csi_id_t load_id) { + return get_fed_entry(FED_TYPE_LOAD, load_id); +} + +CSIRT_API source_loc_t const * __csi_get_store_source_loc(const csi_id_t store_id) { + return get_fed_entry(FED_TYPE_STORE, store_id); +} + +EXTERN_C_END Index: test/CMakeLists.txt =================================================================== --- test/CMakeLists.txt +++ test/CMakeLists.txt @@ -76,6 +76,9 @@ if(COMPILER_RT_HAS_SCUDO) add_subdirectory(scudo) endif() + if(COMPILER_RT_HAS_CSI) + add_subdirectory(csi) + endif() endif() if(COMPILER_RT_STANDALONE_BUILD) Index: test/csi/CMakeLists.txt =================================================================== --- /dev/null +++ test/csi/CMakeLists.txt @@ -0,0 +1,36 @@ +set(CSI_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) + +if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND CSI_TEST_DEPS csi) +endif() + +# Add a dependency on the LTO plugin. +if(LLVM_BINUTILS_INCDIR) + list(APPEND CSI_TEST_DEPS LLVMgold) +endif() + +set(CSI_TESTSUITES) + +set(CSI_TEST_ARCH ${CSI_SUPPORTED_ARCH}) + +set(CSI_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +foreach(arch ${CSI_TEST_ARCH}) + set(CSI_TEST_TARGET_ARCH ${arch}) + string(TOLOWER "-${arch}" CSI_TEST_CONFIG_SUFFIX) + get_target_flags_for_arch(${arch} CSI_TEST_TARGET_CFLAGS) + string(REPLACE ";" " " CSI_TEST_TARGET_CFLAGS "${CSI_TEST_TARGET_CFLAGS}") + + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}Config) + + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg) + list(APPEND CSI_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) +endforeach() + +add_lit_testsuite(check-csi "Running ComprehensiveStaticInstrumentation tests" + ${CSI_TESTSUITES} + DEPENDS ${CSI_TEST_DEPS}) +set_target_properties(check-csi PROPERTIES FOLDER "Csi tests") Index: test/csi/fed-test.c =================================================================== --- /dev/null +++ test/csi/fed-test.c @@ -0,0 +1,20 @@ +// RUN: %clang_csi_toolc %tooldir/null-tool.c -o %t-null-tool.o +// RUN: %clang_csi_toolc %tooldir/fed-test-tool.c -o %t-tool.o +// RUN: %link_csi %t-tool.o %t-null-tool.o -o %t-tool.o +// RUN: %clang_csi_c %s -o %t.o +// RUN: %clang_csi %t.o %t-tool.o %csirtlib -o %t +// RUN: %run %t | FileCheck %s + +#include + +static void foo() { + printf("In foo.\n"); +} + +int main(int argc, char **argv) { + printf("In main.\n"); + foo(); + // CHECK: Enter function 0 [{{.*}}fed-test.c:14] + // CHECK: Enter function 1 [{{.*}}fed-test.c:10] + return 0; +} Index: test/csi/function-call-count.c =================================================================== --- /dev/null +++ test/csi/function-call-count.c @@ -0,0 +1,15 @@ +// RUN: %clang_csi_toolc %tooldir/null-tool.c -o %t-null-tool.o +// RUN: %clang_csi_toolc %tooldir/function-call-count-tool.c -o %t-tool.o +// RUN: %link_csi %t-tool.o %t-null-tool.o -o %t-tool.o +// RUN: %clang_csi_c %s -o %t.o +// RUN: %clang_csi %t.o %t-tool.o %csirtlib -o %t +// RUN: %run %t | FileCheck %s + +#include + +int main(int argc, char **argv) { + printf("One call.\n"); + printf("Two calls.\n"); + // CHECK: num_function_calls = 2 + return 0; +} Index: test/csi/lit.cfg =================================================================== --- /dev/null +++ test/csi/lit.cfg @@ -0,0 +1,51 @@ +# -*- Python -*- + +import glob +import os + +# Setup config name. +config.name = 'ComprehensiveStaticInstrumentation' + config.name_suffix + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +# Setup default compiler flags used with -fcsi option. +base_cflags = ([config.target_cflags] + config.debug_info_flags) +base_cxxflags = config.cxx_mode_flags + base_cflags + +llvm_link = os.path.join(config.llvm_tools_dir, "llvm-link") + +csi_libdir = os.path.join(config.test_source_root, "..", "..", "lib", "csi") +csi_rt_lib = os.path.join(config.compiler_rt_libdir, "libclang_rt.csi-%s.a" % config.target_arch) +csi_testtoolsdir = os.path.join(config.test_source_root, "tools") +csi_testsupportdir = os.path.join(config.test_source_root, "support") + +csi_tool_cflags = (["-g", "-O0", "-c", "-emit-llvm", "-I" + csi_libdir] + base_cflags) +csi_compile_cflags = (["-g", "-O0", "-c", "-fcsi", "-emit-llvm", "-I" + csi_libdir] + base_cflags) +csi_cflags = (["-g", "-O0", "-flto", "-fuse-ld=gold"] + base_cflags) + +def build_invocation(compile_flags): + return " " + " ".join([config.clang] + compile_flags) + " " + +config.substitutions.append(("%clang_csi ", + build_invocation(csi_cflags))) +config.substitutions.append(("%link_csi ", + llvm_link + " ")) +config.substitutions.append(("%clang_csi_c ", + build_invocation(csi_compile_cflags))) +config.substitutions.append(("%clang_csi_toolc ", + build_invocation(csi_tool_cflags))) +config.substitutions.append(("%tooldir", csi_testtoolsdir)) +config.substitutions.append(("%supportdir", csi_testsupportdir)) +config.substitutions.append(("%csirtlib", csi_rt_lib)) + +# Default test suffixes. +config.suffixes = ['.c', '.cpp'] + +# Ignore 'tools- and 'support' +config.excludes.update(map(os.path.basename, glob.glob(os.path.join(csi_testtoolsdir, "*")))) +config.excludes.update(map(os.path.basename, glob.glob(os.path.join(csi_testsupportdir, "*")))) + +# CSI tests are currently supported on Linux x86-64 only. +if config.host_os not in ['Linux'] or config.target_arch != 'x86_64': + config.unsupported = True Index: test/csi/lit.site.cfg.in =================================================================== --- /dev/null +++ test/csi/lit.site.cfg.in @@ -0,0 +1,14 @@ +## Autogenerated by LLVM/Clang configuration. +# Do not edit! + +# Tool-specific config options. +config.name_suffix = "@CSI_TEST_CONFIG_SUFFIX@" +config.csi_lit_source_dir = "@CSI_LIT_SOURCE_DIR@" +config.target_cflags = "@CSI_TEST_TARGET_CFLAGS@" +config.target_arch = "@CSI_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@CSI_LIT_SOURCE_DIR@/lit.cfg") Index: test/csi/load-property-test.c =================================================================== --- /dev/null +++ test/csi/load-property-test.c @@ -0,0 +1,22 @@ +// RUN: %clang_csi_toolc %tooldir/null-tool.c -o %t-null-tool.o +// RUN: %clang_csi_toolc %tooldir/load-property-test-tool.c -o %t-tool.o +// RUN: %link_csi %t-tool.o %t-null-tool.o -o %t-tool.o +// RUN: %clang_csi_c %s -o %t.o +// RUN: %clang_csi %t.o %t-tool.o %csirtlib -o %t +// RUN: %run %t | FileCheck %s + +#include + +static int global = 0; + +int main(int argc, char **argv) { + int x = global + 1; // Read-before-write on global + printf("x is %d\n", x); // Read-before-write on x + global = 1; // Write on global + x = global + 1; // Read on global; write on x + printf("x is %d\n", x); // Read on x + printf("global is %d\n", global); // Read on global + // CHECK: num_loads = 5 + // CHECK: num_read_before_writes = 2 + return 0; +} Index: test/csi/multiple-units-function-call-count.c =================================================================== --- /dev/null +++ test/csi/multiple-units-function-call-count.c @@ -0,0 +1,21 @@ +// RUN: %clang_csi_toolc %tooldir/null-tool.c -o %t-null-tool.o +// RUN: %clang_csi_toolc %tooldir/function-call-count-tool.c -o %t-tool.o +// RUN: %link_csi %t-tool.o %t-null-tool.o -o %t-tool.o +// RUN: %clang_csi_c %s -o %t.o +// RUN: %clang_csi_c %supportdir/a.c -o %t.a.o +// RUN: %clang_csi_c %supportdir/b.c -o %t.b.o +// RUN: %clang_csi %t.o %t.a.o %t.b.o %t-tool.o %csirtlib -o %t +// RUN: %run %t | FileCheck %s + +#include + +#include "support/a.h" + +int main(int argc, char **argv) { + printf("One call.\n"); + printf("Two calls.\n"); + a(); + // Calls are: main + a + b + one printf each. + // CHECK: num_function_calls = 6 + return 0; +} Index: test/csi/shobj-function-call-count.c =================================================================== --- /dev/null +++ test/csi/shobj-function-call-count.c @@ -0,0 +1,19 @@ +// RUN: %clang_csi_toolc %tooldir/null-tool.c -o %t-null-tool.o +// RUN: %clang_csi_toolc %tooldir/function-call-count-tool.c -o %t-tool.o +// RUN: %link_csi %t-tool.o %t-null-tool.o -o %t-tool.o +// RUN: %clang_csi_c -fPIC %supportdir/libtest.c -o %t-libtest.o +// RUN: %clang_csi -Wl,-soname,libtest.so -shared %t-libtest.o %t-tool.o -o %t-libtest.so +// RUN: %clang_csi_c %s -o %t.o +// RUN: %clang_csi -Wl,-rpath,%T -L %T %t.o %t-tool.o -ltest %csirtlib -o %t +// RUN: %run %t | FileCheck %s + +#include +#include "support/libtest.h" + +int main(int argc, char **argv) { + printf("One call.\n"); + printf("Two calls.\n"); + libtest(); + // CHECK: num_function_calls = 4 + return 0; +} Index: test/csi/support/a.h =================================================================== --- /dev/null +++ test/csi/support/a.h @@ -0,0 +1 @@ +void a(); Index: test/csi/support/a.c =================================================================== --- /dev/null +++ test/csi/support/a.c @@ -0,0 +1,7 @@ +#include +#include "b.h" + +void a() { + printf("In a.\n"); + b(); +} Index: test/csi/support/b.h =================================================================== --- /dev/null +++ test/csi/support/b.h @@ -0,0 +1 @@ +void b(); Index: test/csi/support/b.c =================================================================== --- /dev/null +++ test/csi/support/b.c @@ -0,0 +1,5 @@ +#include + +void b() { + printf("In b.\n"); +} Index: test/csi/support/libtest.h =================================================================== --- /dev/null +++ test/csi/support/libtest.h @@ -0,0 +1 @@ +void libtest(); Index: test/csi/support/libtest.c =================================================================== --- /dev/null +++ test/csi/support/libtest.c @@ -0,0 +1,5 @@ +#include + +void libtest() { + printf("In libtest.\n"); +} Index: test/csi/tools/fed-test-tool.c =================================================================== --- /dev/null +++ test/csi/tools/fed-test-tool.c @@ -0,0 +1,9 @@ +#include +#include +#include "csi.h" + +void __csi_func_entry(const csi_id_t func_id) { + printf("Enter function %ld [%s:%d]\n", func_id, + __csi_get_func_source_loc(func_id)->filename, + __csi_get_func_source_loc(func_id)->line_number); +} Index: test/csi/tools/function-call-count-tool.c =================================================================== --- /dev/null +++ test/csi/tools/function-call-count-tool.c @@ -0,0 +1,18 @@ +#include +#include +#include "csi.h" + +static int num_function_calls = 0; + +void report() { + printf("num_function_calls = %d\n", num_function_calls); +} + +void __csi_init() { + num_function_calls = 0; + atexit(report); +} + +void __csi_before_call(const csi_id_t call_id, const csi_id_t func_id) { + num_function_calls++; +} Index: test/csi/tools/load-property-test-tool.c =================================================================== --- /dev/null +++ test/csi/tools/load-property-test-tool.c @@ -0,0 +1,21 @@ +#include +#include +#include "csi.h" + +static int num_loads = 0, num_read_before_writes = 0; + +void report() { + printf("num_loads = %d\n", num_loads); + printf("num_read_before_writes = %d\n", num_read_before_writes); +} + +void __csi_init() { + num_loads = num_read_before_writes = 0; + atexit(report); +} + +void __csi_before_load(const csi_id_t load_id, const void *addr, + const int32_t num_bytes, const uint64_t prop) { + num_loads++; + if (prop & CSI_PROP_LOAD_READ_BEFORE_WRITE_IN_BB) num_read_before_writes++; +} Index: test/csi/tools/null-tool.c =================================================================== --- /dev/null +++ test/csi/tools/null-tool.c @@ -0,0 +1,39 @@ +#include "csi.h" + +WEAK void __csi_init() {} + +WEAK void __csi_unit_init(const char * const file_name, + const instrumentation_counts_t counts) {} + +WEAK void __csi_before_load(const csi_id_t load_id, + const void *addr, + const int32_t num_bytes, + const uint64_t prop) {} + +WEAK void __csi_after_load(const csi_id_t load_id, + const void *addr, + const int32_t num_bytes, + const uint64_t prop) {} + +WEAK void __csi_before_store(const csi_id_t store_id, + const void *addr, + const int32_t num_bytes, + const uint64_t prop) {} + +WEAK void __csi_after_store(const csi_id_t store_id, + const void *addr, + const int32_t num_bytes, + const uint64_t prop) {} + +WEAK void __csi_func_entry(const csi_id_t func_id) {} + +WEAK void __csi_func_exit(const csi_id_t func_exit_id, + const csi_id_t func_id) {} + +WEAK void __csi_bb_entry(const csi_id_t bb_id) {} + +WEAK void __csi_bb_exit(const csi_id_t bb_id) {} + +WEAK void __csi_before_call(csi_id_t callsite_id, csi_id_t func_id) {} + +WEAK void __csi_after_call(csi_id_t callsite_id, csi_id_t func_id) {} Index: test/csi/tools/unknown-function-call-count-tool.c =================================================================== --- /dev/null +++ test/csi/tools/unknown-function-call-count-tool.c @@ -0,0 +1,20 @@ +#include +#include +#include "csi.h" + +static int num_function_calls = 0, num_unknown_function_calls = 0; + +void report() { + printf("num_function_calls = %d\n", num_function_calls); + printf("num_unknown_function_calls = %d\n", num_unknown_function_calls); +} + +void __csi_init() { + num_function_calls = num_unknown_function_calls = 0; + atexit(report); +} + +void __csi_before_call(const csi_id_t call_id, const csi_id_t func_id) { + num_function_calls++; + if (func_id == UNKNOWN_CSI_ID) num_unknown_function_calls++; +} Index: test/csi/unknown-function-call-count.c =================================================================== --- /dev/null +++ test/csi/unknown-function-call-count.c @@ -0,0 +1,21 @@ +// RUN: %clang_csi_toolc %tooldir/null-tool.c -o %t-null-tool.o +// RUN: %clang_csi_toolc %tooldir/unknown-function-call-count-tool.c -o %t-tool.o +// RUN: %link_csi %t-tool.o %t-null-tool.o -o %t-tool.o +// RUN: %clang_csi_c %s -o %t.o +// RUN: %clang_csi %t.o %t-tool.o %csirtlib -o %t +// RUN: %run %t | FileCheck %s + +#include + +static void foo() { + printf("In foo.\n"); +} + +int main(int argc, char **argv) { + printf("One call.\n"); + printf("Two calls.\n"); + foo(); + // CHECK: num_function_calls = 4 + // CHECK: num_unknown_function_calls = 3 + return 0; +}