C++程序  |  64行  |  1.88 KB

// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// kcovtrace is like strace but show kernel coverage collected with KCOV.
// It is very simplistic at this point and does not support multithreaded processes, etc.
// It can be used to understand, for example, exact location where kernel bails out
// with an error for a particular syscall.

#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.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 (16 << 20)

int main(int argc, char** argv, char** envp)
{
	int fd, pid, status;
	unsigned long *cover, n, i;

	if (argc == 1)
		fprintf(stderr, "usage: kcovtrace program [args...]\n"), exit(1);
	fd = open("/sys/kernel/debug/kcov", O_RDWR);
	if (fd == -1)
		perror("open"), exit(1);
	if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
		perror("ioctl"), exit(1);
	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);
	pid = fork();
	if (pid < 0)
		perror("fork"), exit(1);
	if (pid == 0) {
		if (ioctl(fd, KCOV_ENABLE, 0))
			perror("ioctl"), exit(1);
		__atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
		execve(argv[1], argv + 1, envp);
		perror("execve");
		exit(1);
	}
	while (waitpid(-1, &status, __WALL) != pid) {
	}
	n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
	for (i = 0; i < n; i++)
		printf("0x%lx\n", cover[i + 1]);
	if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
		perror("munmap"), exit(1);
	if (close(fd))
		perror("close"), exit(1);
	return 0;
}