Files
Astral/kernel-src/sys/kcov_gcc.c
T
Matheus e4a4896b4b kcov: initial implementation
Implement a device (/dev/kcov) that exposes coverage info for the
kernel. This will be especially useful for coverage-based fuzzing (e.g.
syzkaller).

Exclude a lot of functions which would crash/otherwise interfere in the
coverage, including only processing coverage callbacks when not handling
an irq.
2026-10-06 11:51:02 -03:00

102 lines
2.9 KiB
C

#include <kernel/kcov.h>
#include <arch/cpu.h>
#ifdef KCOV_ENABLED
KCOV_DISABLED void __sanitizer_cov_trace_pc(void) {
if (current_thread() == NULL || current_thread()->kcov == NULL ||
current_thread()->kcov->mode != KCOV_MODE_PC)
return;
if (current_irq_depth() > 0)
return;
uint64_t pc = (uint64_t)__builtin_return_address(0);
kcov_publish_pc(pc);
}
KCOV_DISABLED static void publish_cmp(uint64_t pc, uint64_t v1, uint64_t v2, uint64_t flags) {
if (current_thread() == NULL || current_thread()->kcov == NULL ||
current_thread()->kcov->mode != KCOV_MODE_CMP)
return;
if (current_irq_depth() > 0)
return;
kcov_publish_cmp(pc, v1, v2, flags);
}
KCOV_DISABLED void __sanitizer_cov_trace_const_cmp1(uint8_t a1, uint8_t a2) {
uint64_t pc = (uint64_t)__builtin_return_address(0);
publish_cmp(pc, a1, a2, KCOV_CMP_FLAGS_CONST | KCOV_CMP_FLAGS_8BIT);
}
KCOV_DISABLED void __sanitizer_cov_trace_const_cmp2(uint16_t a1, uint16_t a2) {
uint64_t pc = (uint64_t)__builtin_return_address(0);
publish_cmp(pc, a1, a2, KCOV_CMP_FLAGS_CONST | KCOV_CMP_FLAGS_16BIT);
}
KCOV_DISABLED void __sanitizer_cov_trace_const_cmp4(uint32_t a1, uint32_t a2) {
uint64_t pc = (uint64_t)__builtin_return_address(0);
publish_cmp(pc, a1, a2, KCOV_CMP_FLAGS_CONST | KCOV_CMP_FLAGS_32BIT);
}
KCOV_DISABLED void __sanitizer_cov_trace_const_cmp8(uint64_t a1, uint64_t a2) {
uint64_t pc = (uint64_t)__builtin_return_address(0);
publish_cmp(pc, a1, a2, KCOV_CMP_FLAGS_CONST | KCOV_CMP_FLAGS_64BIT);
}
KCOV_DISABLED void __sanitizer_cov_trace_cmp1(uint8_t a1, uint8_t a2) {
uint64_t pc = (uint64_t)__builtin_return_address(0);
publish_cmp(pc, a1, a2, KCOV_CMP_FLAGS_8BIT);
}
KCOV_DISABLED void __sanitizer_cov_trace_cmp2(uint16_t a1, uint16_t a2) {
uint64_t pc = (uint64_t)__builtin_return_address(0);
publish_cmp(pc, a1, a2, KCOV_CMP_FLAGS_16BIT);
}
KCOV_DISABLED void __sanitizer_cov_trace_cmp4(uint32_t a1, uint32_t a2) {
uint64_t pc = (uint64_t)__builtin_return_address(0);
publish_cmp(pc, a1, a2, KCOV_CMP_FLAGS_32BIT);
}
KCOV_DISABLED void __sanitizer_cov_trace_cmp8(uint64_t a1, uint64_t a2) {
uint64_t pc = (uint64_t)__builtin_return_address(0);
publish_cmp(pc, a1, a2, KCOV_CMP_FLAGS_64BIT);
}
KCOV_DISABLED void __sanitizer_cov_trace_switch(uint64_t v, uint64_t *cases) {
if (current_thread() == NULL || current_thread()->kcov == NULL ||
current_thread()->kcov->mode != KCOV_MODE_CMP)
return;
if (current_irq_depth() > 0)
return;
uint64_t pc = (uint64_t)__builtin_return_address(0);
uint64_t flags = KCOV_CMP_FLAGS_CONST;
switch (cases[1]) {
case 8:
flags |= KCOV_CMP_FLAGS_8BIT;
break;
case 16:
flags |= KCOV_CMP_FLAGS_16BIT;
break;
case 32:
flags |= KCOV_CMP_FLAGS_32BIT;
break;
case 64:
flags |= KCOV_CMP_FLAGS_64BIT;
break;
default:
return;
}
for (int i = 0; i < cases[0]; ++i)
kcov_publish_cmp(pc, cases[2 + i], v, flags);
}
#endif