Loading Documentation/kcov.txtdeleted 100644 → 0 +0 −111 Original line number Diff line number Diff line kcov: code coverage for fuzzing =============================== kcov exposes kernel code coverage information in a form suitable for coverage- guided fuzzing (randomized testing). Coverage data of a running kernel is exported via the "kcov" debugfs file. Coverage collection is enabled on a task basis, and thus it can capture precise coverage of a single system call. Note that kcov does not aim to collect as much coverage as possible. It aims to collect more or less stable coverage that is function of syscall inputs. To achieve this goal it does not collect coverage in soft/hard interrupts and instrumentation of some inherently non-deterministic parts of kernel is disbled (e.g. scheduler, locking). Usage: ====== Configure kernel with: CONFIG_KCOV=y CONFIG_KCOV requires gcc built on revision 231296 or later. Profiling data will only become accessible once debugfs has been mounted: mount -t debugfs none /sys/kernel/debug The following program demonstrates kcov usage from within a test program: #include <stdio.h> #include <stddef.h> #include <stdint.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <unistd.h> #include <fcntl.h> #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) #define KCOV_ENABLE _IO('c', 100) #define KCOV_DISABLE _IO('c', 101) #define COVER_SIZE (64<<10) int main(int argc, char **argv) { int fd; unsigned long *cover, n, i; /* A single fd descriptor allows coverage collection on a single * thread. */ fd = open("/sys/kernel/debug/kcov", O_RDWR); if (fd == -1) perror("open"), exit(1); /* Setup trace mode and trace size. */ if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) perror("ioctl"), exit(1); /* Mmap buffer shared between kernel- and user-space. */ cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if ((void*)cover == MAP_FAILED) perror("mmap"), exit(1); /* Enable coverage collection on the current thread. */ if (ioctl(fd, KCOV_ENABLE, 0)) perror("ioctl"), exit(1); /* Reset coverage from the tail of the ioctl() call. */ __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); /* That's the target syscal call. */ read(-1, NULL, 0); /* Read number of PCs collected. */ n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); for (i = 0; i < n; i++) printf("0x%lx\n", cover[i + 1]); /* Disable coverage collection for the current thread. After this call * coverage can be enabled for a different thread. */ if (ioctl(fd, KCOV_DISABLE, 0)) perror("ioctl"), exit(1); /* Free resources. */ if (munmap(cover, COVER_SIZE * sizeof(unsigned long))) perror("munmap"), exit(1); if (close(fd)) perror("close"), exit(1); return 0; } After piping through addr2line output of the program looks as follows: SyS_read fs/read_write.c:562 __fdget_pos fs/file.c:774 __fget_light fs/file.c:746 __fget_light fs/file.c:750 __fget_light fs/file.c:760 __fdget_pos fs/file.c:784 SyS_read fs/read_write.c:562 If a program needs to collect coverage from several threads (independently), it needs to open /sys/kernel/debug/kcov in each thread separately. The interface is fine-grained to allow efficient forking of test processes. That is, a parent process opens /sys/kernel/debug/kcov, enables trace mode, mmaps coverage buffer and then forks child processes in a loop. Child processes only need to enable coverage (disable happens automatically on thread end). Makefile +2 −12 Original line number Diff line number Diff line VERSION = 3 PATCHLEVEL = 18 SUBLEVEL = 122 SUBLEVEL = 123 EXTRAVERSION = NAME = Diseased Newt Loading Loading @@ -380,8 +380,6 @@ LDFLAGS_MODULE = CFLAGS_KERNEL = AFLAGS_KERNEL = CFLAGS_GCOV = -fprofile-arcs -ftest-coverage -fno-tree-loop-im CFLAGS_KCOV = -fsanitize-coverage=trace-pc # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE := \ Loading Loading @@ -426,7 +424,7 @@ export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KCOV CFLAGS_KASAN CFLAGS_UBSAN export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL Loading Loading @@ -682,14 +680,6 @@ endif endif KBUILD_CFLAGS += $(stackp-flag) ifdef CONFIG_KCOV ifeq ($(call cc-option, $(CFLAGS_KCOV)),) $(warning Cannot use CONFIG_KCOV: \ -fsanitize-coverage=trace-pc is not supported by compiler) CFLAGS_KCOV = endif endif ifeq ($(COMPILER),clang) KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,) KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,) Loading arch/arm/kernel/entry-common.S +7 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ #include <asm/unistd.h> #include <asm/ftrace.h> #include <asm/unwind.h> #include <asm/memory.h> #ifdef CONFIG_NEED_RET_TO_USER #include <mach/entry-macro.S> Loading @@ -33,6 +34,9 @@ ret_fast_syscall: UNWIND(.fnstart ) UNWIND(.cantunwind ) disable_irq @ disable interrupts ldr r2, [tsk, #TI_ADDR_LIMIT] cmp r2, #TASK_SIZE blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing tst r1, #_TIF_SYSCALL_WORK bne __sys_trace_return Loading Loading @@ -69,6 +73,9 @@ ENTRY(ret_to_user) ret_slow_syscall: disable_irq @ disable interrupts ENTRY(ret_to_user_from_irq) ldr r2, [tsk, #TI_ADDR_LIMIT] cmp r2, #TASK_SIZE blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK bne work_pending Loading arch/arm/kernel/signal.c +7 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #include <linux/uaccess.h> #include <linux/tracehook.h> #include <linux/uprobes.h> #include <linux/syscalls.h> #include <asm/elf.h> #include <asm/cacheflush.h> Loading Loading @@ -639,3 +640,9 @@ struct page *get_signal_page(void) return page; } /* Defer to generic check */ asmlinkage void addr_limit_check_failed(void) { addr_limit_user_check(); } arch/arm/mach-hisi/hotplug.c +22 −11 Original line number Diff line number Diff line Loading @@ -145,14 +145,21 @@ static int hi3xxx_hotplug_init(void) struct device_node *node; node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); if (node) { if (!node) { id = ERROR_CTRL; return -ENOENT; } ctrl_base = of_iomap(node, 0); of_node_put(node); if (!ctrl_base) { id = ERROR_CTRL; return -ENOMEM; } id = HI3620_CTRL; return 0; } id = ERROR_CTRL; return -ENOENT; } void hi3xxx_set_cpu(int cpu, bool enable) { Loading @@ -170,11 +177,15 @@ static bool hix5hd2_hotplug_init(void) struct device_node *np; np = of_find_compatible_node(NULL, NULL, "hisilicon,cpuctrl"); if (np) { if (!np) return false; ctrl_base = of_iomap(np, 0); return true; } of_node_put(np); if (!ctrl_base) return false; return true; } void hix5hd2_set_cpu(int cpu, bool enable) Loading Loading
Documentation/kcov.txtdeleted 100644 → 0 +0 −111 Original line number Diff line number Diff line kcov: code coverage for fuzzing =============================== kcov exposes kernel code coverage information in a form suitable for coverage- guided fuzzing (randomized testing). Coverage data of a running kernel is exported via the "kcov" debugfs file. Coverage collection is enabled on a task basis, and thus it can capture precise coverage of a single system call. Note that kcov does not aim to collect as much coverage as possible. It aims to collect more or less stable coverage that is function of syscall inputs. To achieve this goal it does not collect coverage in soft/hard interrupts and instrumentation of some inherently non-deterministic parts of kernel is disbled (e.g. scheduler, locking). Usage: ====== Configure kernel with: CONFIG_KCOV=y CONFIG_KCOV requires gcc built on revision 231296 or later. Profiling data will only become accessible once debugfs has been mounted: mount -t debugfs none /sys/kernel/debug The following program demonstrates kcov usage from within a test program: #include <stdio.h> #include <stddef.h> #include <stdint.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <unistd.h> #include <fcntl.h> #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) #define KCOV_ENABLE _IO('c', 100) #define KCOV_DISABLE _IO('c', 101) #define COVER_SIZE (64<<10) int main(int argc, char **argv) { int fd; unsigned long *cover, n, i; /* A single fd descriptor allows coverage collection on a single * thread. */ fd = open("/sys/kernel/debug/kcov", O_RDWR); if (fd == -1) perror("open"), exit(1); /* Setup trace mode and trace size. */ if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) perror("ioctl"), exit(1); /* Mmap buffer shared between kernel- and user-space. */ cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if ((void*)cover == MAP_FAILED) perror("mmap"), exit(1); /* Enable coverage collection on the current thread. */ if (ioctl(fd, KCOV_ENABLE, 0)) perror("ioctl"), exit(1); /* Reset coverage from the tail of the ioctl() call. */ __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); /* That's the target syscal call. */ read(-1, NULL, 0); /* Read number of PCs collected. */ n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); for (i = 0; i < n; i++) printf("0x%lx\n", cover[i + 1]); /* Disable coverage collection for the current thread. After this call * coverage can be enabled for a different thread. */ if (ioctl(fd, KCOV_DISABLE, 0)) perror("ioctl"), exit(1); /* Free resources. */ if (munmap(cover, COVER_SIZE * sizeof(unsigned long))) perror("munmap"), exit(1); if (close(fd)) perror("close"), exit(1); return 0; } After piping through addr2line output of the program looks as follows: SyS_read fs/read_write.c:562 __fdget_pos fs/file.c:774 __fget_light fs/file.c:746 __fget_light fs/file.c:750 __fget_light fs/file.c:760 __fdget_pos fs/file.c:784 SyS_read fs/read_write.c:562 If a program needs to collect coverage from several threads (independently), it needs to open /sys/kernel/debug/kcov in each thread separately. The interface is fine-grained to allow efficient forking of test processes. That is, a parent process opens /sys/kernel/debug/kcov, enables trace mode, mmaps coverage buffer and then forks child processes in a loop. Child processes only need to enable coverage (disable happens automatically on thread end).
Makefile +2 −12 Original line number Diff line number Diff line VERSION = 3 PATCHLEVEL = 18 SUBLEVEL = 122 SUBLEVEL = 123 EXTRAVERSION = NAME = Diseased Newt Loading Loading @@ -380,8 +380,6 @@ LDFLAGS_MODULE = CFLAGS_KERNEL = AFLAGS_KERNEL = CFLAGS_GCOV = -fprofile-arcs -ftest-coverage -fno-tree-loop-im CFLAGS_KCOV = -fsanitize-coverage=trace-pc # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE := \ Loading Loading @@ -426,7 +424,7 @@ export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KCOV CFLAGS_KASAN CFLAGS_UBSAN export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL Loading Loading @@ -682,14 +680,6 @@ endif endif KBUILD_CFLAGS += $(stackp-flag) ifdef CONFIG_KCOV ifeq ($(call cc-option, $(CFLAGS_KCOV)),) $(warning Cannot use CONFIG_KCOV: \ -fsanitize-coverage=trace-pc is not supported by compiler) CFLAGS_KCOV = endif endif ifeq ($(COMPILER),clang) KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,) KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,) Loading
arch/arm/kernel/entry-common.S +7 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ #include <asm/unistd.h> #include <asm/ftrace.h> #include <asm/unwind.h> #include <asm/memory.h> #ifdef CONFIG_NEED_RET_TO_USER #include <mach/entry-macro.S> Loading @@ -33,6 +34,9 @@ ret_fast_syscall: UNWIND(.fnstart ) UNWIND(.cantunwind ) disable_irq @ disable interrupts ldr r2, [tsk, #TI_ADDR_LIMIT] cmp r2, #TASK_SIZE blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing tst r1, #_TIF_SYSCALL_WORK bne __sys_trace_return Loading Loading @@ -69,6 +73,9 @@ ENTRY(ret_to_user) ret_slow_syscall: disable_irq @ disable interrupts ENTRY(ret_to_user_from_irq) ldr r2, [tsk, #TI_ADDR_LIMIT] cmp r2, #TASK_SIZE blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK bne work_pending Loading
arch/arm/kernel/signal.c +7 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #include <linux/uaccess.h> #include <linux/tracehook.h> #include <linux/uprobes.h> #include <linux/syscalls.h> #include <asm/elf.h> #include <asm/cacheflush.h> Loading Loading @@ -639,3 +640,9 @@ struct page *get_signal_page(void) return page; } /* Defer to generic check */ asmlinkage void addr_limit_check_failed(void) { addr_limit_user_check(); }
arch/arm/mach-hisi/hotplug.c +22 −11 Original line number Diff line number Diff line Loading @@ -145,14 +145,21 @@ static int hi3xxx_hotplug_init(void) struct device_node *node; node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); if (node) { if (!node) { id = ERROR_CTRL; return -ENOENT; } ctrl_base = of_iomap(node, 0); of_node_put(node); if (!ctrl_base) { id = ERROR_CTRL; return -ENOMEM; } id = HI3620_CTRL; return 0; } id = ERROR_CTRL; return -ENOENT; } void hi3xxx_set_cpu(int cpu, bool enable) { Loading @@ -170,11 +177,15 @@ static bool hix5hd2_hotplug_init(void) struct device_node *np; np = of_find_compatible_node(NULL, NULL, "hisilicon,cpuctrl"); if (np) { if (!np) return false; ctrl_base = of_iomap(np, 0); return true; } of_node_put(np); if (!ctrl_base) return false; return true; } void hix5hd2_set_cpu(int cpu, bool enable) Loading