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();
|
|
}
|