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 | |
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(x: fid); |
24 | __xray_unpatch_function(FuncId: fid); |
25 | patching = false; |
26 | } |
27 | |
28 | [[clang::xray_always_instrument]] void baz() { |
29 | // do nothing! |
30 | } |
31 | |
32 | [[clang::xray_always_instrument]] void bar() { |
33 | baz(); |
34 | } |
35 | |
36 | [[clang::xray_always_instrument]] void foo() { |
37 | bar(); |
38 | } |
39 | |
40 | [[clang::xray_always_instrument]] int main(int argc, char *argv[]) { |
41 | __xray_set_handler(entry: 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(format: "first pass.\n" ); |
48 | for (const auto id : function_ids) |
49 | printf(format: "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(format: "second pass.\n" ); |
72 | for (const auto id : function_ids) |
73 | printf(format: "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(format: "missing 1.\n" ); |
89 | for (const auto id : function_ids) |
90 | printf(format: "patched: %d\n" , id); |
91 | // CHECK-LABEL: missing 1. |
92 | // CHECK-NOT: patched: 1 |
93 | } |
94 | |