| 1 | // Check that indirect call hash tables properly register multiple calls, |
| 2 | // and that calls from different processes don't get mixed up when using |
| 3 | // --instrumentation-file-append-pid. |
| 4 | |
| 5 | #include <stdio.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <unistd.h> |
| 8 | |
| 9 | __attribute__((noinline)) void funcA(int pid) { printf(format: "funcA %d\n" , pid); } |
| 10 | __attribute__((noinline)) void funcB(int pid) { printf(format: "funcB %d\n" , pid); } |
| 11 | __attribute__((noinline)) void funcC(int pid) { printf(format: "funcC %d\n" , pid); } |
| 12 | __attribute__((noinline)) void funcD(int pid) { printf(format: "funcD %d\n" , pid); } |
| 13 | __attribute__((noinline)) void funcE(int pid) { printf(format: "funcE %d\n" , pid); } |
| 14 | __attribute__((noinline)) void funcF(int pid) { printf(format: "funcF %d\n" , pid); } |
| 15 | __attribute__((noinline)) void funcG(int pid) { printf(format: "funcG %d\n" , pid); } |
| 16 | __attribute__((noinline)) void funcH(int pid) { printf(format: "funcH %d\n" , pid); } |
| 17 | __attribute__((noinline)) void funcI(int pid) { printf(format: "funcI %d\n" , pid); } |
| 18 | __attribute__((noinline)) void funcJ(int pid) { printf(format: "funcJ %d\n" , pid); } |
| 19 | __attribute__((noinline)) void funcK(int pid) { printf(format: "funcK %d\n" , pid); } |
| 20 | __attribute__((noinline)) void funcL(int pid) { printf(format: "funcL %d\n" , pid); } |
| 21 | __attribute__((noinline)) void funcM(int pid) { printf(format: "funcM %d\n" , pid); } |
| 22 | __attribute__((noinline)) void funcN(int pid) { printf(format: "funcN %d\n" , pid); } |
| 23 | __attribute__((noinline)) void funcO(int pid) { printf(format: "funcO %d\n" , pid); } |
| 24 | __attribute__((noinline)) void funcP(int pid) { printf(format: "funcP %d\n" , pid); } |
| 25 | |
| 26 | int main() { |
| 27 | |
| 28 | void (*funcs[])(int) = {funcA, funcB, funcC, funcD, funcE, funcF, |
| 29 | funcG, funcH, funcI, funcJ, funcK, funcL, |
| 30 | funcM, funcN, funcO, funcP}; |
| 31 | int i; |
| 32 | |
| 33 | switch (fork()) { |
| 34 | case -1: |
| 35 | printf(format: "Failed to fork!\n" ); |
| 36 | exit(status: -1); |
| 37 | break; |
| 38 | case 0: |
| 39 | i = 0; |
| 40 | break; |
| 41 | default: |
| 42 | i = 1; |
| 43 | break; |
| 44 | } |
| 45 | int pid = getpid(); |
| 46 | for (; i < sizeof(funcs) / sizeof(void *); i += 2) { |
| 47 | funcs[i](pid); |
| 48 | } |
| 49 | |
| 50 | return 0; |
| 51 | } |
| 52 | /* |
| 53 | REQUIRES: system-linux,shell,fuser |
| 54 | |
| 55 | RUN: %clang %cflags %s -o %t.exe -Wl,-q -pie -fpie |
| 56 | |
| 57 | RUN: llvm-bolt %t.exe --instrument --instrumentation-file=%t.fdata \ |
| 58 | RUN: --conservative-instrumentation -o %t.instrumented_conservative \ |
| 59 | RUN: --instrumentation-sleep-time=1 --instrumentation-no-counters-clear \ |
| 60 | RUN: --instrumentation-wait-forks |
| 61 | |
| 62 | # Instrumented program needs to finish returning zero |
| 63 | # Both output and profile must contain all 16 functions |
| 64 | RUN: %t.instrumented_conservative > %t.output |
| 65 | # Wait for profile and output to be fully written |
| 66 | RUN: bash %S/wait_file.sh %t.output |
| 67 | RUN: bash %S/wait_file.sh %t.fdata |
| 68 | RUN: cat %t.output | FileCheck %s --check-prefix=CHECK-OUTPUT |
| 69 | RUN: cat %t.fdata | FileCheck %s --check-prefix=CHECK-COMMON-PROF |
| 70 | |
| 71 | CHECK-OUTPUT-DAG: funcA |
| 72 | CHECK-OUTPUT-DAG: funcB |
| 73 | CHECK-OUTPUT-DAG: funcC |
| 74 | CHECK-OUTPUT-DAG: funcD |
| 75 | CHECK-OUTPUT-DAG: funcE |
| 76 | CHECK-OUTPUT-DAG: funcF |
| 77 | CHECK-OUTPUT-DAG: funcG |
| 78 | CHECK-OUTPUT-DAG: funcH |
| 79 | CHECK-OUTPUT-DAG: funcI |
| 80 | CHECK-OUTPUT-DAG: funcJ |
| 81 | CHECK-OUTPUT-DAG: funcK |
| 82 | CHECK-OUTPUT-DAG: funcL |
| 83 | CHECK-OUTPUT-DAG: funcM |
| 84 | CHECK-OUTPUT-DAG: funcN |
| 85 | CHECK-OUTPUT-DAG: funcO |
| 86 | CHECK-OUTPUT-DAG: funcP |
| 87 | |
| 88 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcA 0 0 1 |
| 89 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcB 0 0 1 |
| 90 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcC 0 0 1 |
| 91 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcD 0 0 1 |
| 92 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcE 0 0 1 |
| 93 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcF 0 0 1 |
| 94 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcG 0 0 1 |
| 95 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcH 0 0 1 |
| 96 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcI 0 0 1 |
| 97 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcJ 0 0 1 |
| 98 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcK 0 0 1 |
| 99 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcL 0 0 1 |
| 100 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcM 0 0 1 |
| 101 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcN 0 0 1 |
| 102 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcO 0 0 1 |
| 103 | CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcP 0 0 1 |
| 104 | |
| 105 | RUN: llvm-bolt %t.exe --instrument --instrumentation-file=%t \ |
| 106 | RUN: --instrumentation-file-append-pid \ |
| 107 | RUN: -o %t.instrumented |
| 108 | |
| 109 | RUN: %t.instrumented > %t.output |
| 110 | # Wait till output is fully written in case child outlives parent |
| 111 | RUN: bash %S/wait_file.sh %t.output |
| 112 | # Make sure all functions were called |
| 113 | RUN: cat %t.output | FileCheck %s --check-prefix=CHECK-OUTPUT |
| 114 | |
| 115 | RUN: child_pid=$(cat %t.output | grep funcA | awk '{print $2;}') |
| 116 | RUN: par_pid=$(cat %t.output | grep funcB | awk '{print $2;}') |
| 117 | |
| 118 | RUN: bash %S/wait_file.sh %t.$child_pid.fdata |
| 119 | RUN: bash %S/wait_file.sh %t.$par_pid.fdata |
| 120 | |
| 121 | RUN: mv %t.$child_pid.fdata %t.child.fdata |
| 122 | RUN: mv %t.$par_pid.fdata %t.parent.fdata |
| 123 | |
| 124 | # Instrumented binary must produce two profiles with only local calls |
| 125 | # recorded. Functions called only in child should not appear in parent's |
| 126 | # process and vice versa. |
| 127 | RUN: cat %t.child.fdata | FileCheck %s --check-prefix=CHECK-CHILD |
| 128 | RUN: cat %t.child.fdata | FileCheck %s --check-prefix=CHECK-NOCHILD |
| 129 | RUN: cat %t.parent.fdata | FileCheck %s --check-prefix=CHECK-PARENT |
| 130 | RUN: cat %t.parent.fdata | FileCheck %s --check-prefix=CHECK-NOPARENT |
| 131 | |
| 132 | CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcA 0 0 1 |
| 133 | CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcC 0 0 1 |
| 134 | CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcE 0 0 1 |
| 135 | CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcG 0 0 1 |
| 136 | CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcI 0 0 1 |
| 137 | CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcK 0 0 1 |
| 138 | CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcM 0 0 1 |
| 139 | CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcO 0 0 1 |
| 140 | |
| 141 | CHECK-NOCHILD-NOT: funcB |
| 142 | CHECK-NOCHILD-NOT: funcD |
| 143 | CHECK-NOCHILD-NOT: funcF |
| 144 | CHECK-NOCHILD-NOT: funcH |
| 145 | CHECK-NOCHILD-NOT: funcJ |
| 146 | CHECK-NOCHILD-NOT: funcL |
| 147 | CHECK-NOCHILD-NOT: funcN |
| 148 | CHECK-NOCHILD-NOT: funcP |
| 149 | |
| 150 | CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcB 0 0 1 |
| 151 | CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcD 0 0 1 |
| 152 | CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcF 0 0 1 |
| 153 | CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcH 0 0 1 |
| 154 | CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcJ 0 0 1 |
| 155 | CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcL 0 0 1 |
| 156 | CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcN 0 0 1 |
| 157 | CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcP 0 0 1 |
| 158 | |
| 159 | CHECK-NOPARENT-NOT: funcA |
| 160 | CHECK-NOPARENT-NOT: funcC |
| 161 | CHECK-NOPARENT-NOT: funcE |
| 162 | CHECK-NOPARENT-NOT: funcG |
| 163 | CHECK-NOPARENT-NOT: funcI |
| 164 | CHECK-NOPARENT-NOT: funcK |
| 165 | CHECK-NOPARENT-NOT: funcM |
| 166 | CHECK-NOPARENT-NOT: funcO |
| 167 | |
| 168 | */ |
| 169 | |