13e52c092SNavid Emamdoost // Tests -fsanitize-coverage=control-flow.
23e52c092SNavid Emamdoost
33e52c092SNavid Emamdoost // REQUIRES: has_sancovcc,stable-runtime
43e52c092SNavid Emamdoost // UNSUPPORTED: i386-darwin, x86_64-darwin
53e52c092SNavid Emamdoost
63e52c092SNavid Emamdoost // RUN: %clangxx -O0 -std=c++11 -fsanitize-coverage=control-flow %s -o %t
73e52c092SNavid Emamdoost // RUN: %run %t 2>&1 | FileCheck %s
83e52c092SNavid Emamdoost
93e52c092SNavid Emamdoost #include <cstdint>
103e52c092SNavid Emamdoost #include <cstdio>
11*c6e83ddbSBlue Gaston #if __has_feature(ptrauth_calls)
12*c6e83ddbSBlue Gaston #include <ptrauth.h>
13*c6e83ddbSBlue Gaston #else
14*c6e83ddbSBlue Gaston #define ptrauth_strip(__value, __key) (__value)
15*c6e83ddbSBlue Gaston #endif
163e52c092SNavid Emamdoost
173e52c092SNavid Emamdoost uintptr_t *CFS_BEG, *CFS_END;
183e52c092SNavid Emamdoost
__sanitizer_cov_cfs_init(const uintptr_t * cfs_beg,const uintptr_t * cfs_end)193e52c092SNavid Emamdoost extern "C" void __sanitizer_cov_cfs_init(const uintptr_t *cfs_beg,
203e52c092SNavid Emamdoost const uintptr_t *cfs_end) {
213e52c092SNavid Emamdoost CFS_BEG = (uintptr_t *)cfs_beg;
223e52c092SNavid Emamdoost CFS_END = (uintptr_t *)cfs_end;
233e52c092SNavid Emamdoost }
243e52c092SNavid Emamdoost
foo(int x)253e52c092SNavid Emamdoost __attribute__((noinline)) void foo(int x) { /* empty body */
263e52c092SNavid Emamdoost }
273e52c092SNavid Emamdoost
check_cfs_section(uintptr_t main_ptr,uintptr_t foo_ptr)283e52c092SNavid Emamdoost void check_cfs_section(uintptr_t main_ptr, uintptr_t foo_ptr) {
293e52c092SNavid Emamdoost printf("Control Flow section boundaries: [%p %p)\n", CFS_BEG, CFS_END);
303e52c092SNavid Emamdoost uintptr_t *pt = CFS_BEG;
313e52c092SNavid Emamdoost uintptr_t currBB;
323e52c092SNavid Emamdoost
333e52c092SNavid Emamdoost while (pt < CFS_END) {
343e52c092SNavid Emamdoost currBB = *pt;
353e52c092SNavid Emamdoost pt++;
363e52c092SNavid Emamdoost
373e52c092SNavid Emamdoost if (currBB == main_ptr)
383e52c092SNavid Emamdoost printf("Saw the main().\n");
393e52c092SNavid Emamdoost else if (currBB == foo_ptr)
403e52c092SNavid Emamdoost printf("Saw the foo().\n");
413e52c092SNavid Emamdoost
423e52c092SNavid Emamdoost // Iterate over successors.
433e52c092SNavid Emamdoost while (*pt) {
443e52c092SNavid Emamdoost pt++;
453e52c092SNavid Emamdoost }
463e52c092SNavid Emamdoost pt++;
473e52c092SNavid Emamdoost // Iterate over callees.
483e52c092SNavid Emamdoost while (*pt) {
493e52c092SNavid Emamdoost if (*pt == foo_ptr && currBB != main_ptr)
503e52c092SNavid Emamdoost printf("Direct call matched.\n");
513e52c092SNavid Emamdoost if (*pt == -1 && currBB != main_ptr)
523e52c092SNavid Emamdoost printf("Indirect call matched.\n");
533e52c092SNavid Emamdoost pt++;
543e52c092SNavid Emamdoost }
553e52c092SNavid Emamdoost pt++;
563e52c092SNavid Emamdoost }
573e52c092SNavid Emamdoost }
583e52c092SNavid Emamdoost
main()593e52c092SNavid Emamdoost int main() {
60*c6e83ddbSBlue Gaston auto main_ptr = ptrauth_strip(&main, ptrauth_key_function_pointer);
61*c6e83ddbSBlue Gaston auto foo_ptr = ptrauth_strip(&foo, ptrauth_key_function_pointer);
623e52c092SNavid Emamdoost int x = 10;
633e52c092SNavid Emamdoost
643e52c092SNavid Emamdoost if (x > 0)
653e52c092SNavid Emamdoost foo(x);
663e52c092SNavid Emamdoost else
673e52c092SNavid Emamdoost (*foo_ptr)(x);
683e52c092SNavid Emamdoost
693e52c092SNavid Emamdoost check_cfs_section((uintptr_t)(*main_ptr), (uintptr_t)(*foo_ptr));
703e52c092SNavid Emamdoost
713e52c092SNavid Emamdoost printf("Finished!\n");
723e52c092SNavid Emamdoost return 0;
733e52c092SNavid Emamdoost }
743e52c092SNavid Emamdoost
753e52c092SNavid Emamdoost // CHECK: Control Flow section boundaries
763e52c092SNavid Emamdoost // CHECK-DAG: Saw the foo().
773e52c092SNavid Emamdoost // CHECK-DAG: Saw the main().
783e52c092SNavid Emamdoost // CHECK-DAG: Direct call matched.
793e52c092SNavid Emamdoost // CHECK-DAG: Indirect call matched.
803e52c092SNavid Emamdoost // CHECK: Finished!
81