1 // Check that we can patch and unpatch specific function ids.
2 //
3 // RUN: %clangxx_xray -std=c++11 %s -o %t
4 // RUN: XRAY_OPTIONS="patch_premain=false" %run %t | FileCheck %s
5 // RUN: %clangxx_xray -fno-xray-function-index -std=c++11 %s -o %t
6 // RUN: XRAY_OPTIONS="patch_premain=false" %run %t | FileCheck %s
7 
8 // UNSUPPORTED: target-is-mips64,target-is-mips64el
9 
10 #include "xray/xray_interface.h"
11 
12 #include <set>
13 #include <cstdio>
14 #include <cassert>
15 
16 std::set<int32_t> function_ids;
17 
coverage_handler(int32_t fid,XRayEntryType)18 [[clang::xray_never_instrument]] void coverage_handler(int32_t fid,
19                                                        XRayEntryType) {
20   thread_local bool patching = false;
21   if (patching) return;
22   patching = true;
23   function_ids.insert(fid);
24   __xray_unpatch_function(fid);
25   patching = false;
26 }
27 
baz()28 [[clang::xray_always_instrument]] void baz() {
29   // do nothing!
30 }
31 
bar()32 [[clang::xray_always_instrument]] void bar() {
33   baz();
34 }
35 
foo()36 [[clang::xray_always_instrument]] void foo() {
37   bar();
38 }
39 
main(int argc,char * argv[])40 [[clang::xray_always_instrument]] int main(int argc, char *argv[]) {
41   __xray_set_handler(coverage_handler);
42   assert(__xray_patch() == XRayPatchingStatus::SUCCESS);
43   foo();
44   assert(__xray_unpatch() == XRayPatchingStatus::SUCCESS);
45 
46   // print out the function_ids.
47   printf("first pass.\n");
48   for (const auto id : function_ids)
49     printf("patched: %d\n", id);
50 
51   // CHECK-LABEL: first pass.
52   // CHECK-DAG: patched: [[F1:.*]]
53   // CHECK-DAG: patched: [[F2:.*]]
54   // CHECK-DAG: patched: [[F3:.*]]
55 
56   // make a copy of the function_ids, then patch them later.
57   auto called_fns = function_ids;
58 
59   // clear the function_ids.
60   function_ids.clear();
61 
62   // patch the functions we've called before.
63   for (const auto id : called_fns)
64     assert(__xray_patch_function(id) == XRayPatchingStatus::SUCCESS);
65 
66   // then call them again.
67   foo();
68   assert(__xray_unpatch() == XRayPatchingStatus::SUCCESS);
69 
70   // confirm that we've seen the same functions again.
71   printf("second pass.\n");
72   for (const auto id : function_ids)
73     printf("patched: %d\n", id);
74   // CHECK-LABEL: second pass.
75   // CHECK-DAG: patched: [[F1]]
76   // CHECK-DAG: patched: [[F2]]
77   // CHECK-DAG: patched: [[F3]]
78 
79   // Now we want to make sure that if we unpatch one, that we're only going to
80   // see two calls of the coverage_handler.
81   function_ids.clear();
82   assert(__xray_patch() == XRayPatchingStatus::SUCCESS);
83   assert(__xray_unpatch_function(1) == XRayPatchingStatus::SUCCESS);
84   foo();
85   assert(__xray_unpatch() == XRayPatchingStatus::SUCCESS);
86 
87   // confirm that we don't see function id one called anymore.
88   printf("missing 1.\n");
89   for (const auto id : function_ids)
90     printf("patched: %d\n", id);
91   // CHECK-LABEL: missing 1.
92   // CHECK-NOT: patched: 1
93 }
94