189 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
| // Copyright 2021 Code Intelligence GmbH
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //      http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| #include "sanitizer_hooks_with_pc.h"
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <cmath>
 | |
| #include <cstdint>
 | |
| #include <iostream>
 | |
| 
 | |
| #include "gtest/gtest.h"
 | |
| 
 | |
| static std::vector<uint16_t> gCoverageMap(512);
 | |
| 
 | |
| inline void __attribute__((always_inline)) RecordCoverage() {
 | |
|   auto return_address =
 | |
|       reinterpret_cast<uintptr_t>(__builtin_return_address(0));
 | |
|   auto idx = return_address & (gCoverageMap.size() - 1);
 | |
|   gCoverageMap[idx]++;
 | |
| }
 | |
| 
 | |
| extern "C" {
 | |
| void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) {
 | |
|   RecordCoverage();
 | |
| }
 | |
| 
 | |
| void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) {
 | |
|   RecordCoverage();
 | |
| }
 | |
| 
 | |
| void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
 | |
|   RecordCoverage();
 | |
| }
 | |
| 
 | |
| void __sanitizer_cov_trace_div4(uint32_t val) { RecordCoverage(); }
 | |
| 
 | |
| void __sanitizer_cov_trace_div8(uint64_t val) { RecordCoverage(); }
 | |
| 
 | |
| void __sanitizer_cov_trace_gep(uintptr_t idx) { RecordCoverage(); }
 | |
| 
 | |
| void __sanitizer_cov_trace_pc_indir(uintptr_t callee) { RecordCoverage(); }
 | |
| }
 | |
| 
 | |
| void ClearCoverage() { std::fill(gCoverageMap.begin(), gCoverageMap.end(), 0); }
 | |
| 
 | |
| bool HasAllPcsCovered() {
 | |
|   return 0 == std::count(gCoverageMap.cbegin(), gCoverageMap.cend(), 0);
 | |
| }
 | |
| 
 | |
| bool HasSingleCoveredPc() {
 | |
|   return gCoverageMap.size() - 1 ==
 | |
|          std::count(gCoverageMap.cbegin(), gCoverageMap.cend(), 0);
 | |
| }
 | |
| 
 | |
| std::string PrettyPrintCoverage() {
 | |
|   std::ostringstream out;
 | |
|   std::size_t break_after = 16;
 | |
|   out << "Coverage:" << std::endl;
 | |
|   for (uintptr_t i = 0; i < gCoverageMap.size(); i++) {
 | |
|     out << (gCoverageMap[i] ? "X" : "_");
 | |
|     if (i % break_after == break_after - 1) out << std::endl;
 | |
|   }
 | |
|   return out.str();
 | |
| }
 | |
| 
 | |
| class TestFakePcTrampoline : public ::testing::Test {
 | |
|  protected:
 | |
|   TestFakePcTrampoline() {
 | |
|     ClearCoverage();
 | |
|     CalibrateTrampoline();
 | |
|   }
 | |
| };
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceCmp4Direct) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_cmp4(i, i);
 | |
|   }
 | |
|   EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceCmp8Direct) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_cmp8(i, i);
 | |
|   }
 | |
|   EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceSwitchDirect) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_switch(i, nullptr);
 | |
|   }
 | |
|   EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceDiv4Direct) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_div4(i);
 | |
|   }
 | |
|   EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceDiv8Direct) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_div8(i);
 | |
|   }
 | |
|   EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceGepDirect) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_gep(i);
 | |
|   }
 | |
|   EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TracePcIndirDirect) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_pc_indir(i);
 | |
|   }
 | |
|   EXPECT_TRUE(HasSingleCoveredPc()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceCmp4Trampoline) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_cmp4_with_pc(reinterpret_cast<void *>(i), i, i);
 | |
|     EXPECT_EQ(1, gCoverageMap[i]);
 | |
|   }
 | |
|   EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceCmp8Trampoline) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_cmp8_with_pc(reinterpret_cast<void *>(i), i, i);
 | |
|     EXPECT_EQ(1, gCoverageMap[i]);
 | |
|   }
 | |
|   EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceSwitchTrampoline) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_switch_with_pc(reinterpret_cast<void *>(i), i,
 | |
|                                          nullptr);
 | |
|     EXPECT_EQ(1, gCoverageMap[i]);
 | |
|   }
 | |
|   EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceDiv4Trampoline) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_div4_with_pc(reinterpret_cast<void *>(i), i);
 | |
|     EXPECT_EQ(1, gCoverageMap[i]);
 | |
|   }
 | |
|   EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceDiv8Trampoline) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_div8_with_pc(reinterpret_cast<void *>(i), i);
 | |
|     EXPECT_EQ(1, gCoverageMap[i]);
 | |
|   }
 | |
|   EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TraceGepTrampoline) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_gep_with_pc(reinterpret_cast<void *>(i), i);
 | |
|     EXPECT_EQ(1, gCoverageMap[i]);
 | |
|   }
 | |
|   EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
 | |
| }
 | |
| 
 | |
| TEST_F(TestFakePcTrampoline, TracePcIndirTrampoline) {
 | |
|   for (uint32_t i = 0; i < gCoverageMap.size(); ++i) {
 | |
|     __sanitizer_cov_trace_pc_indir_with_pc(reinterpret_cast<void *>(i), i);
 | |
|   }
 | |
|   EXPECT_TRUE(HasAllPcsCovered()) << PrettyPrintCoverage();
 | |
| }
 |