Index: lib/Fuzzer/FuzzerTracePC.h =================================================================== --- lib/Fuzzer/FuzzerTracePC.h +++ lib/Fuzzer/FuzzerTracePC.h @@ -50,7 +50,7 @@ void HandleInit(uint32_t *start, uint32_t *stop); void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); void HandleValueProfile(size_t Value) { ValueProfileMap.AddValue(Value); } - template void HandleCmp(void *PC, T Arg1, T Arg2); + template void HandleCmp(uintptr_t PC, T Arg1, T Arg2); size_t GetTotalPCCoverage(); void SetUseCounters(bool UC) { UseCounters = UC; } void SetUseValueProfile(bool VP) { UseValueProfile = VP; } Index: lib/Fuzzer/FuzzerTracePC.cpp =================================================================== --- lib/Fuzzer/FuzzerTracePC.cpp +++ lib/Fuzzer/FuzzerTracePC.cpp @@ -26,6 +26,12 @@ namespace fuzzer { +#ifdef __clang__ +# define ALWAYS_INLINE __attribute__((always_inline)) +#else +# define ALWAYS_INLINE +#endif // __clang__ + TracePC TPC; void TracePC::HandleTrace(uint32_t *Guard, uintptr_t PC) { @@ -247,15 +253,11 @@ } template -ATTRIBUTE_TARGET_POPCNT -#ifdef __clang__ // g++ can't handle this __attribute__ here :( -__attribute__((always_inline)) -#endif // __clang__ -void TracePC::HandleCmp(void *PC, T Arg1, T Arg2) { - uintptr_t PCuint = reinterpret_cast(PC); +ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE +void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { uint64_t ArgXor = Arg1 ^ Arg2; uint64_t ArgDistance = __builtin_popcountl(ArgXor) + 1; // [1,65] - uintptr_t Idx = ((PCuint & 4095) + 1) * ArgDistance; + uintptr_t Idx = ((PC & 4095) + 1) * ArgDistance; if (sizeof(T) == 4) TORC4.Insert(ArgXor, Arg1, Arg2); else if (sizeof(T) == 8) @@ -263,12 +265,18 @@ HandleValueProfile(Idx); } +inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(void* pc) { + // TODO: this implementation is x86 only. + // see sanitizer_common GetPreviousInstructionPc for full implementation. + return reinterpret_cast(pc) - 1; +} + } // namespace fuzzer extern "C" { __attribute__((visibility("default"))) void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) { - uintptr_t PC = (uintptr_t)__builtin_return_address(0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); fuzzer::TPC.HandleTrace(Guard, PC); } @@ -279,25 +287,29 @@ __attribute__((visibility("default"))) void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) { - uintptr_t PC = (uintptr_t)__builtin_return_address(0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); fuzzer::TPC.HandleCallerCallee(PC, Callee); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } __attribute__((visibility("default"))) @@ -308,7 +320,7 @@ // Skip the most common and the most boring case. if (Vals[N - 1] < 256 && Val < 256) return; - char *PC = (char*)__builtin_return_address(0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); size_t i; uint64_t Token = 0; for (i = 0; i < N; i++) { @@ -327,15 +339,18 @@ __attribute__((visibility("default"))) void __sanitizer_cov_trace_div4(uint32_t Val) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint32_t)0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_div8(uint64_t Val) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint64_t)0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_gep(uintptr_t Idx) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Idx, (uintptr_t)0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0); } } // extern "C" Index: lib/Fuzzer/test/CMakeLists.txt =================================================================== --- lib/Fuzzer/test/CMakeLists.txt +++ lib/Fuzzer/test/CMakeLists.txt @@ -126,7 +126,6 @@ add_libfuzzer_test(${Test} SOURCES ${Test}.cpp) endforeach() - ############################################################################### # Unit tests ############################################################################### @@ -213,5 +212,5 @@ add_lit_testsuite(check-fuzzer "Running Fuzzer tests" ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${TestBinaries} FileCheck not + DEPENDS ${TestBinaries} FileCheck sancov not ) Index: lib/Fuzzer/test/dump_coverage.test =================================================================== --- lib/Fuzzer/test/dump_coverage.test +++ lib/Fuzzer/test/dump_coverage.test @@ -2,12 +2,14 @@ RUN: BUILD_DIR=$(pwd) RUN: rm -rf $DIR && mkdir -p $DIR && cd $DIR RUN: not $BUILD_DIR/LLVMFuzzer-NullDerefTest -dump_coverage=1 2>&1 | FileCheck %s +RUN: sancov -covered-functions *.sancov $BUILD_DIR/LLVMFuzzer-NullDerefTest | FileCheck %s --check-prefix=SANCOV RUN: $BUILD_DIR/LLVMFuzzer-DSOTest -dump_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO RUN: not $BUILD_DIR/LLVMFuzzer-NullDerefTest -dump_coverage=0 2>&1 | FileCheck %s --check-prefix=NOCOV RUN: rm -rf $DIR CHECK: SanitizerCoverage: ./LLVMFuzzer-NullDerefTest.{{.*}}.sancov {{.*}} PCs written +SANCOV: LLVMFuzzerTestOneInput DSO: SanitizerCoverage: ./LLVMFuzzer-DSOTest.{{.*}}.sancov {{.*}} PCs written DSO-DAG: SanitizerCoverage: ./libLLVMFuzzer-DSO1.{{.*}}.sancov {{.*}} PCs written