1 // Copyright 2021 Code Intelligence GmbH
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "sanitizer_hooks_with_pc.h"
16
17 #include <algorithm>
18 #include <cmath>
19 #include <cstdint>
20 #include <iostream>
21
22 #include "gtest/gtest.h"
23
24 static std::vector<uint16_t> gCoverageMap(512);
25
RecordCoverage()26 inline void __attribute__((always_inline)) RecordCoverage() {
27 auto return_address =
28 reinterpret_cast<uintptr_t>(__builtin_return_address(0));
29 auto idx = return_address & (gCoverageMap.size() - 1);
30 gCoverageMap[idx]++;
31 }
32
33 extern "C" {
__sanitizer_cov_trace_cmp4(uint32_t arg1,uint32_t arg2)34 void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) {
35 RecordCoverage();
36 }
37
__sanitizer_cov_trace_cmp8(uint64_t arg1,uint64_t arg2)38 void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) {
39 RecordCoverage();
40 }
41
__sanitizer_cov_trace_switch(uint64_t val,uint64_t * cases)42 void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
43 RecordCoverage();
44 }
45
__sanitizer_cov_trace_div4(uint32_t val)46 void __sanitizer_cov_trace_div4(uint32_t val) { RecordCoverage(); }
47
__sanitizer_cov_trace_div8(uint64_t val)48 void __sanitizer_cov_trace_div8(uint64_t val) { RecordCoverage(); }
49
__sanitizer_cov_trace_gep(uintptr_t idx)50 void __sanitizer_cov_trace_gep(uintptr_t idx) { RecordCoverage(); }
51
__sanitizer_cov_trace_pc_indir(uintptr_t callee)52 void __sanitizer_cov_trace_pc_indir(uintptr_t callee) { RecordCoverage(); }
53 }
54
ClearCoverage()55 void ClearCoverage() { std::fill(gCoverageMap.begin(), gCoverageMap.end(), 0); }
56
HasAllPcsCovered()57 bool HasAllPcsCovered() {
58 return 0 == std::count(gCoverageMap.cbegin(), gCoverageMap.cend(), 0);
59 }
60
HasSingleCoveredPc()61 bool HasSingleCoveredPc() {
62 return gCoverageMap.size() - 1 ==
63 std::count(gCoverageMap.cbegin(), gCoverageMap.cend(), 0);
64 }
65
PrettyPrintCoverage()66 std::string PrettyPrintCoverage() {
67 std::ostringstream out;
68 std::size_t break_after = 16;
69 out << "Coverage:" << std::endl;
70 for (uintptr_t i = 0; i < gCoverageMap.size(); i++) {
71 out << (gCoverageMap[i] ? "X" : "_");
72 if (i % break_after == break_after - 1) out << std::endl;
73 }
74 return out.str();
75 }
76
77 class TestFakePcTrampoline : public ::testing::Test {
78 protected:
TestFakePcTrampoline()79 TestFakePcTrampoline() {
80 ClearCoverage();
81 CalibrateTrampoline();
82 }
83 };
84
TEST_F(TestFakePcTrampoline,TraceCmp4Direct)85 TEST_F(TestFakePcTrampoline, TraceCmp4Direct) {
86 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
87 __sanitizer_cov_trace_cmp4(i, i);
88 }
89 EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
90 }
91
TEST_F(TestFakePcTrampoline,TraceCmp8Direct)92 TEST_F(TestFakePcTrampoline, TraceCmp8Direct) {
93 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
94 __sanitizer_cov_trace_cmp8(i, i);
95 }
96 EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
97 }
98
TEST_F(TestFakePcTrampoline,TraceSwitchDirect)99 TEST_F(TestFakePcTrampoline, TraceSwitchDirect) {
100 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
101 __sanitizer_cov_trace_switch(i, nullptr);
102 }
103 EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
104 }
105
TEST_F(TestFakePcTrampoline,TraceDiv4Direct)106 TEST_F(TestFakePcTrampoline, TraceDiv4Direct) {
107 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
108 __sanitizer_cov_trace_div4(i);
109 }
110 EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
111 }
112
TEST_F(TestFakePcTrampoline,TraceDiv8Direct)113 TEST_F(TestFakePcTrampoline, TraceDiv8Direct) {
114 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
115 __sanitizer_cov_trace_div8(i);
116 }
117 EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
118 }
119
TEST_F(TestFakePcTrampoline,TraceGepDirect)120 TEST_F(TestFakePcTrampoline, TraceGepDirect) {
121 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
122 __sanitizer_cov_trace_gep(i);
123 }
124 EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
125 }
126
TEST_F(TestFakePcTrampoline,TracePcIndirDirect)127 TEST_F(TestFakePcTrampoline, TracePcIndirDirect) {
128 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
129 __sanitizer_cov_trace_pc_indir(i);
130 }
131 EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
132 }
133
TEST_F(TestFakePcTrampoline,TraceCmp4Trampoline)134 TEST_F(TestFakePcTrampoline, TraceCmp4Trampoline) {
135 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
136 __sanitizer_cov_trace_cmp4_with_pc(reinterpret_cast<void *>(i), i, i);
137 EXPECT_EQ(1, gCoverageMap[i]);
138 }
139 EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
140 }
141
TEST_F(TestFakePcTrampoline,TraceCmp8Trampoline)142 TEST_F(TestFakePcTrampoline, TraceCmp8Trampoline) {
143 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
144 __sanitizer_cov_trace_cmp8_with_pc(reinterpret_cast<void *>(i), i, i);
145 EXPECT_EQ(1, gCoverageMap[i]);
146 }
147 EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
148 }
149
TEST_F(TestFakePcTrampoline,TraceSwitchTrampoline)150 TEST_F(TestFakePcTrampoline, TraceSwitchTrampoline) {
151 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
152 __sanitizer_cov_trace_switch_with_pc(reinterpret_cast<void *>(i), i,
153 nullptr);
154 EXPECT_EQ(1, gCoverageMap[i]);
155 }
156 EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
157 }
158
TEST_F(TestFakePcTrampoline,TraceDiv4Trampoline)159 TEST_F(TestFakePcTrampoline, TraceDiv4Trampoline) {
160 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
161 __sanitizer_cov_trace_div4_with_pc(reinterpret_cast<void *>(i), i);
162 EXPECT_EQ(1, gCoverageMap[i]);
163 }
164 EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
165 }
166
TEST_F(TestFakePcTrampoline,TraceDiv8Trampoline)167 TEST_F(TestFakePcTrampoline, TraceDiv8Trampoline) {
168 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
169 __sanitizer_cov_trace_div8_with_pc(reinterpret_cast<void *>(i), i);
170 EXPECT_EQ(1, gCoverageMap[i]);
171 }
172 EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
173 }
174
TEST_F(TestFakePcTrampoline,TraceGepTrampoline)175 TEST_F(TestFakePcTrampoline, TraceGepTrampoline) {
176 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
177 __sanitizer_cov_trace_gep_with_pc(reinterpret_cast<void *>(i), i);
178 EXPECT_EQ(1, gCoverageMap[i]);
179 }
180 EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
181 }
182
TEST_F(TestFakePcTrampoline,TracePcIndirTrampoline)183 TEST_F(TestFakePcTrampoline, TracePcIndirTrampoline) {
184 for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
185 __sanitizer_cov_trace_pc_indir_with_pc(reinterpret_cast<void *>(i), i);
186 }
187 EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
188 }
189