Kernel: Exclude individual functions from coverage instrumentation

Sticking this to the function source has multiple benefits:
- We instrument more code, by not excluding entire files.
- NO_SANITIZE_COVERAGE can be used in Header files.
- Keeping the info with the source code, means if a function or
  file is moved around, the NO_SANITIZE_COVERAGE moves with it.
This commit is contained in:
Space Meyer 2024-04-08 02:52:13 +02:00 committed by Andrew Kaster
parent ca89116a46
commit fdc0328ce3
9 changed files with 32 additions and 22 deletions

View file

@ -186,6 +186,15 @@
#endif
#define RETURNS_NONNULL __attribute__((returns_nonnull))
#ifdef NO_SANITIZE_COVERAGE
# undef NO_SANITIZE_COVERAGE
#endif
#if defined(AK_COMPILER_CLANG)
# define NO_SANITIZE_COVERAGE __attribute__((no_sanitize("coverage")))
#else
# define NO_SANITIZE_COVERAGE __attribute__((no_sanitize_coverage))
#endif
#ifdef NO_SANITIZE_ADDRESS
# undef NO_SANITIZE_ADDRESS
#endif

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Platform.h>
#include <AK/Types.h>
#include <Kernel/Arch/CPU.h>
#include <Kernel/Arch/InterruptManagement.h>
@ -165,7 +166,7 @@ Atomic<Graphics::Console*> g_boot_console;
READONLY_AFTER_INIT static u8 s_command_line_buffer[512];
#endif
extern "C" [[noreturn]] UNMAP_AFTER_INIT void init([[maybe_unused]] BootInfo const& boot_info)
extern "C" [[noreturn]] UNMAP_AFTER_INIT NO_SANITIZE_COVERAGE void init([[maybe_unused]] BootInfo const& boot_info)
{
g_in_early_boot = true;

View file

@ -23,7 +23,7 @@ ALWAYS_INLINE void sti()
asm volatile("sti" ::
: "memory");
}
ALWAYS_INLINE FlatPtr cpu_flags()
ALWAYS_INLINE NO_SANITIZE_COVERAGE FlatPtr cpu_flags()
{
FlatPtr flags;
asm volatile(
@ -52,7 +52,7 @@ ALWAYS_INLINE void write_gs_value(FlatPtr offset, T val)
: "memory");
}
ALWAYS_INLINE FlatPtr read_gs_ptr(FlatPtr offset)
ALWAYS_INLINE NO_SANITIZE_COVERAGE FlatPtr read_gs_ptr(FlatPtr offset)
{
FlatPtr val;
asm volatile(
@ -69,7 +69,7 @@ ALWAYS_INLINE void write_gs_ptr(u32 offset, FlatPtr val)
: "memory");
}
ALWAYS_INLINE bool are_interrupts_enabled()
ALWAYS_INLINE NO_SANITIZE_COVERAGE bool are_interrupts_enabled()
{
return (cpu_flags() & 0x200) != 0;
}

View file

@ -5,13 +5,14 @@
*/
#include <AK/Assertions.h>
#include <AK/Platform.h>
#include <Kernel/Arch/CPU.h>
#include <Kernel/Library/Panic.h>
#include <Kernel/Tasks/Process.h>
using namespace Kernel;
void __assertion_failed(char const* msg, char const* file, unsigned line, char const* func)
NO_SANITIZE_COVERAGE void __assertion_failed(char const* msg, char const* file, unsigned line, char const* func)
{
asm volatile("cli");
critical_dmesgln("ASSERTION FAILED: {}", msg);

View file

@ -1409,7 +1409,7 @@ extern "C" void enter_thread_context(Thread* from_thread, Thread* to_thread)
asm volatile("frstor %0" ::"m"(to_thread->fpu_state()));
}
extern "C" FlatPtr do_init_context(Thread* thread, u32 flags)
extern "C" NO_SANITIZE_COVERAGE FlatPtr do_init_context(Thread* thread, u32 flags)
{
VERIFY_INTERRUPTS_DISABLED();
thread->regs().set_flags(flags);
@ -1461,7 +1461,7 @@ NAKED void thread_context_first_enter(void)
" jmp common_trap_exit \n");
}
NAKED void do_assume_context(Thread*, u32)
NAKED NO_SANITIZE_COVERAGE void do_assume_context(Thread*, u32)
{
// clang-format off
// FIXME: I hope (Thread* thread, u32 flags) aren't compiled away

View file

@ -156,7 +156,7 @@ public:
};
template<typename T>
ALWAYS_INLINE Thread* ProcessorBase<T>::current_thread()
ALWAYS_INLINE NO_SANITIZE_COVERAGE Thread* ProcessorBase<T>::current_thread()
{
// If we were to use ProcessorBase::current here, we'd have to
// disable interrupts to prevent a race where we may get pre-empted
@ -224,7 +224,7 @@ ALWAYS_INLINE void ProcessorBase<T>::enter_critical()
}
template<typename T>
ALWAYS_INLINE bool ProcessorBase<T>::are_interrupts_enabled()
ALWAYS_INLINE NO_SANITIZE_COVERAGE bool ProcessorBase<T>::are_interrupts_enabled()
{
return Kernel::are_interrupts_enabled();
}
@ -297,7 +297,7 @@ ALWAYS_INLINE void ProcessorBase<T>::wait_check()
}
template<typename T>
ALWAYS_INLINE FlatPtr ProcessorBase<T>::current_in_irq()
ALWAYS_INLINE NO_SANITIZE_COVERAGE FlatPtr ProcessorBase<T>::current_in_irq()
{
return read_gs_ptr(__builtin_offsetof(Processor, m_in_irq));
}

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Platform.h>
#include <Kernel/API/Syscall.h>
#include <Kernel/Arch/Processor.h>
#include <Kernel/Arch/TrapFrame.h>
@ -18,7 +19,7 @@
using namespace Kernel;
extern "C" void syscall_entry();
extern "C" [[gnu::naked]] void syscall_entry()
extern "C" NO_SANITIZE_COVERAGE [[gnu::naked]] void syscall_entry()
{
// clang-format off
asm(

View file

@ -716,18 +716,15 @@ if (ENABLE_KERNEL_COVERAGE_COLLECTION)
)
add_compile_options(-fsanitize-coverage=trace-pc)
# To avoid __sanitizer_cov_trace_pc from causing an infinite recursion,
# don't instrument any even transitively used code. You can either skip
# individual function via the NO_SANITIZE_COVERAGE macro or by excluding
# the whole file by adding it to KCOV_EXCLUDED_SOURCES.
# Note that you can only add .cpp and not .h files to KCOV_EXCLUDED_SOURCES.
set(KCOV_EXCLUDED_SOURCES
# Make sure we don't instrument any code called from __sanitizer_cov_trace_pc
# otherwise we'll end up with recursive calls to that function.
../AK/Error.cpp
../AK/Format.cpp
../AK/StringBuilder.cpp
../Kernel/Arch/x86_64/Processor.cpp
# Skip core KCOV code.
../Kernel/Devices/KCOVDevice.cpp
../Kernel/Devices/KCOVInstance.cpp
../Kernel/FileSystem/File.cpp
../Kernel/FileSystem/OpenFileDescription.cpp
../Kernel/init.cpp
../Kernel/SanCov.cpp
# GCC assumes that the caller saves registers for functions according
# to the System V ABI and happily inserts coverage calls into the

View file

@ -13,6 +13,7 @@
#include <AK/IntrusiveList.h>
#include <AK/Optional.h>
#include <AK/OwnPtr.h>
#include <AK/Platform.h>
#include <AK/Time.h>
#include <AK/Variant.h>
#include <AK/Vector.h>
@ -94,8 +95,8 @@ public:
return m_is_joinable;
}
Process& process() { return m_process; }
Process const& process() const { return m_process; }
NO_SANITIZE_COVERAGE Process& process() { return m_process; }
NO_SANITIZE_COVERAGE Process const& process() const { return m_process; }
using Name = FixedStringBuffer<64>;
SpinlockProtected<Name, LockRank::None> const& name() const