code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#myinsmod */

#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

#define init_module(module_image, len, param_values) syscall(__NR_init_module, module_image, len, param_values)
#define finit_module(fd, param_values, flags) syscall(__NR_finit_module, fd, param_values, flags)

int main(int argc, char **argv) {
	const char *params;
	int fd, use_finit;
	size_t image_size;
	struct stat st;
	void *image;

	/* CLI handling. */
	if (argc < 2) {
		puts("Usage ./prog mymodule.ko [args="" [use_finit=0]");
		return EXIT_FAILURE;
	}
	if (argc < 3) {
		params = "";
	} else {
		params = argv[2];
	}
	if (argc < 4) {
		use_finit = 0;
	} else {
		use_finit = (argv[3][0] != '0');
	}

	/* Action. */
	fd = open(argv[1], O_RDONLY);
	if (use_finit) {
		puts("finit");
		if (finit_module(fd, params, 0) != 0) {
			perror("finit_module");
			return EXIT_FAILURE;
		}
		close(fd);
	} else {
		puts("init");
		fstat(fd, &st);
		image_size = st.st_size;
		image = malloc(image_size);
		read(fd, image, image_size);
		close(fd);
		if (init_module(image, image_size, params) != 0) {
			perror("init_module");
			return EXIT_FAILURE;
		}
		free(image);
	}
	return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#myinsmod */

#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

#define delete_module(name, flags) syscall(__NR_delete_module, name, flags)

int main(int argc, char **argv) {
	if (argc != 2) {
		puts("Usage ./prog mymodule");
		return EXIT_FAILURE;
	}
	if (delete_module(argv[1], O_NONBLOCK) != 0) {
		perror("delete_module");
		return EXIT_FAILURE;
	}
	return EXIT_SUCCESS;
}

repo_name: liberatehongkong/linux

license: mit


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#netlink-sockets */

#include <linux/netlink.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#include "../netlink.h"

#define MAX_PAYLOAD 1024

/* Some of these structs fields must be zeroed.
 * We could brute force memset them, but
 * TODO determine exactly which, and move into main. */
int sock_fd;
struct iovec iov;
struct msghdr msg;
struct nlmsghdr *nlh;
struct sockaddr_nl src_addr, dest_addr;

int main()
{
	sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
	if (sock_fd < 0) {
		perror("socket");
		return EXIT_FAILURE;
	}
	src_addr.nl_family = AF_NETLINK;
	src_addr.nl_pid = getpid();
	bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
	dest_addr.nl_family = AF_NETLINK;
	nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
	memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
	nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
	nlh->nlmsg_pid = getpid();
	nlh->nlmsg_flags = 0;
	strcpy(NLMSG_DATA(nlh), "user request");
	iov.iov_base = (void *)nlh;
	iov.iov_len = nlh->nlmsg_len;
	msg.msg_name = (void *)&dest_addr;
	msg.msg_namelen = sizeof(dest_addr);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	fprintf(stderr, "before sendmsg\n");
	sendmsg(sock_fd, &msg, 0);
	fprintf(stderr, "after sendmsg\n");
	recvmsg(sock_fd, &msg, 0);
	printf("%s\n", (char *)NLMSG_DATA(nlh));
	close(sock_fd);
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#blas
 * Adapted from: https://github.com/xianyi/OpenBLAS/wiki/User-Manual/59b62f98e7400270fb03ad1d85fba5b64ebbff2b#call-cblas-interface */

#include "common.h"

#include <assert.h>
#include <cblas.h>

int main()
{
	double A[6] = {1.0, 2.0, 1.0, -3.0, 4.0, -1.0};
	double B[6] = {1.0, 2.0, 1.0, -3.0, 4.0, -1.0};
	double C[9] = {0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5};
	cblas_dgemm(CblasColMajor, CblasNoTrans, CblasTrans, 3, 3, 2, 1, A, 3, B, 3, 2, C, 3);
	assert(common_vector_equal(9, C, (double[]){11.0, -9.0, 5.0, -9.0, 21.0, -1.0, 5.0, -1.0, 3.0}, 1e-6));
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#openmp */

#include <omp.h>
#include <stdio.h>
#include <stdlib.h>

int main () {
	int nthreads, tid;
#pragma omp parallel private(nthreads, tid)
	{
		tid = omp_get_thread_num();
		printf("Hello World from thread = %d\n", tid);
		if (tid == 0) {
			nthreads = omp_get_num_threads();
			printf("Number of threads = %d\n", nthreads);
		}
	}
	return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#pagemap_dump-out */

#define _XOPEN_SOURCE 700
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

#include "common.h" /* pagemap_get_entry */

int main(int argc, char **argv)
{
	char buffer[BUFSIZ];
	char maps_file[BUFSIZ];
	char pagemap_file[BUFSIZ];
	int maps_fd;
	int offset = 0;
	int pagemap_fd;
	pid_t pid;

	if (argc < 2) {
		printf("Usage: %s pid\n", argv[0]);
		return EXIT_FAILURE;
	}
	pid = strtoull(argv[1], NULL, 0);
	snprintf(maps_file, sizeof(maps_file), "/proc/%ju/maps", (uintmax_t)pid);
	snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid);
	maps_fd = open(maps_file, O_RDONLY);
	if (maps_fd < 0) {
		perror("open maps");
		return EXIT_FAILURE;
	}
	pagemap_fd = open(pagemap_file, O_RDONLY);
	if (pagemap_fd < 0) {
		perror("open pagemap");
		return EXIT_FAILURE;
	}
	printf("vaddr pfn soft-dirty file/shared swapped present library\n");
	for (;;) {
		ssize_t length = read(maps_fd, buffer + offset, sizeof buffer - offset);
		if (length <= 0) break;
		length += offset;
		for (size_t i = offset; i < (size_t)length; i++) {
			uintptr_t low = 0, high = 0;
			if (buffer[i] == '\n' && i) {
				const char *lib_name;
				size_t y;
				/* Parse a line from maps. Each line contains a range that contains many pages. */
				{
					size_t x = i - 1;
					while (x && buffer[x] != '\n') x--;
					if (buffer[x] == '\n') x++;
					while (buffer[x] != '-' && x < sizeof buffer) {
						char c = buffer[x++];
						low *= 16;
						if (c >= '0' && c <= '9') {
							low += c - '0';
						} else if (c >= 'a' && c <= 'f') {
							low += c - 'a' + 10;
						} else {
						    break;
						}
					}
					while (buffer[x] != '-' && x < sizeof buffer) x++;
					if (buffer[x] == '-') x++;
					while (buffer[x] != ' ' && x < sizeof buffer) {
						char c = buffer[x++];
						high *= 16;
						if (c >= '0' && c <= '9') {
							high += c - '0';
						} else if (c >= 'a' && c <= 'f') {
							high += c - 'a' + 10;
						} else {
							break;
						}
					}
					lib_name = 0;
					for (int field = 0; field < 4; field++) {
						x++;
						while(buffer[x] != ' ' && x < sizeof buffer) x++;
					}
					while (buffer[x] == ' ' && x < sizeof buffer) x++;
					y = x;
					while (buffer[y] != '\n' && y < sizeof buffer) y++;
					buffer[y] = 0;
					lib_name = buffer + x;
				}
				/* Get info about all pages in this page range with pagemap. */
				{
					PagemapEntry entry;
					for (uintptr_t vaddr = low; vaddr < high; vaddr += sysconf(_SC_PAGE_SIZE)) {
						/* TODO always fails for the last page (vsyscall), why? pread returns 0. */
						if (!pagemap_get_entry(&entry, pagemap_fd, vaddr)) {
							printf("%jx %jx %u %u %u %u %s\n",
								(uintmax_t)vaddr,
								(uintmax_t)entry.pfn,
								entry.soft_dirty,
								entry.file_page,
								entry.swapped,
								entry.present,
								lib_name
							);
						}
					}
				}
				buffer[y] = '\n';
			}
		}
	}
	close(maps_fd);
	close(pagemap_fd);
	return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#poll */

#define _XOPEN_SOURCE 700
#include <assert.h>
#include <fcntl.h> /* creat, O_CREAT */
#include <poll.h> /* poll */
#include <stdio.h> /* printf, puts, snprintf */
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
#include <unistd.h> /* read */

int main(int argc, char **argv) {
	char buf[1024];
	int fd, i, n;
	short revents;
	struct pollfd pfd;

	if (argc < 2) {
		fprintf(stderr, "usage: %s <poll-device>\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	fd = open(argv[1], O_RDONLY | O_NONBLOCK);
	if (fd == -1) {
		perror("open");
		exit(EXIT_FAILURE);
	}
	pfd.fd = fd;
	pfd.events = POLLIN;
	while (1) {
		puts("loop");
		i = poll(&pfd, 1, -1);
		if (i == -1) {
			perror("poll");
			assert(0);
		}
		revents = pfd.revents;
		if (revents & POLLIN) {
			n = read(pfd.fd, buf, sizeof(buf));
			printf("POLLIN n=%d buf=%.*s\n", n, n, buf);
		}
	}
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#poweroff-out */

#define _XOPEN_SOURCE 700
#include <sys/reboot.h>
#include <unistd.h>

int main(void) {
	reboot(RB_POWER_OFF);
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#config_proc_events
 *
 * Adapted from: https://stackoverflow.com/questions/6075013/detect-launching-of-programs-on-linux-platform/8255487#8255487
 */

#if defined(__aarch64__)

int main() {}

#else

#define _XOPEN_SOURCE 700
#include <errno.h>
#include <linux/cn_proc.h>
#include <linux/connector.h>
#include <linux/netlink.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

static volatile bool need_exit = false;

static int nl_connect()
{
	int rc;
	int nl_sock;
	struct sockaddr_nl sa_nl;

	nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
	if (nl_sock == -1) {
		perror("socket");
		return -1;
	}
	sa_nl.nl_family = AF_NETLINK;
	sa_nl.nl_groups = CN_IDX_PROC;
	sa_nl.nl_pid = getpid();
	rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
	if (rc == -1) {
		perror("bind");
		close(nl_sock);
		return -1;
	}
	return nl_sock;
}

static int set_proc_ev_listen(int nl_sock, bool enable)
{
	int rc;
	struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
		struct nlmsghdr nl_hdr;
		struct __attribute__ ((__packed__)) {
			struct cn_msg cn_msg;
			enum proc_cn_mcast_op cn_mcast;
		};
	} nlcn_msg;

	memset(&nlcn_msg, 0, sizeof(nlcn_msg));
	nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg);
	nlcn_msg.nl_hdr.nlmsg_pid = getpid();
	nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE;

	nlcn_msg.cn_msg.id.idx = CN_IDX_PROC;
	nlcn_msg.cn_msg.id.val = CN_VAL_PROC;
	nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);

	nlcn_msg.cn_mcast = enable ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE;

	rc = send(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
	if (rc == -1) {
		perror("netlink send");
		return -1;
	}

	return 0;
}

static int handle_proc_ev(int nl_sock)
{
	int rc;
	struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
		struct nlmsghdr nl_hdr;
		struct __attribute__ ((__packed__)) {
			struct cn_msg cn_msg;
			struct proc_event proc_ev;
		};
	} nlcn_msg;
	while (!need_exit) {
		rc = recv(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
		if (rc == 0) {
			return 0;
		} else if (rc == -1) {
			if (errno == EINTR) continue;
			perror("netlink recv");
			return -1;
		}
		switch (nlcn_msg.proc_ev.what) {
			case PROC_EVENT_NONE:
				printf("set mcast listen ok\n");
				break;
			case PROC_EVENT_FORK:
				printf("fork: parent tid=%d pid=%d -> child tid=%d pid=%d\n",
						nlcn_msg.proc_ev.event_data.fork.parent_pid,
						nlcn_msg.proc_ev.event_data.fork.parent_tgid,
						nlcn_msg.proc_ev.event_data.fork.child_pid,
						nlcn_msg.proc_ev.event_data.fork.child_tgid);
				break;
			case PROC_EVENT_EXEC:
				printf("exec: tid=%d pid=%d\n",
						nlcn_msg.proc_ev.event_data.exec.process_pid,
						nlcn_msg.proc_ev.event_data.exec.process_tgid);
				break;
			case PROC_EVENT_UID:
				printf("uid change: tid=%d pid=%d from %d to %d\n",
						nlcn_msg.proc_ev.event_data.id.process_pid,
						nlcn_msg.proc_ev.event_data.id.process_tgid,
						nlcn_msg.proc_ev.event_data.id.r.ruid,
						nlcn_msg.proc_ev.event_data.id.e.euid);
				break;
			case PROC_EVENT_GID:
				printf("gid change: tid=%d pid=%d from %d to %d\n",
						nlcn_msg.proc_ev.event_data.id.process_pid,
						nlcn_msg.proc_ev.event_data.id.process_tgid,
						nlcn_msg.proc_ev.event_data.id.r.rgid,
						nlcn_msg.proc_ev.event_data.id.e.egid);
				break;
			case PROC_EVENT_EXIT:
				printf("exit: tid=%d pid=%d exit_code=%d\n",
						nlcn_msg.proc_ev.event_data.exit.process_pid,
						nlcn_msg.proc_ev.event_data.exit.process_tgid,
						nlcn_msg.proc_ev.event_data.exit.exit_code);
				break;
			default:
				printf("unhandled proc event\n");
				break;
		}
	}

	return 0;
}

static void on_sigint(__attribute__ ((unused)) int unused)
{
	need_exit = true;
}

int main()
{
	int nl_sock;
	int rc = EXIT_SUCCESS;

	signal(SIGINT, &on_sigint);
	siginterrupt(SIGINT, true);
	nl_sock = nl_connect();
	if (nl_sock == -1)
		exit(EXIT_FAILURE);
	rc = set_proc_ev_listen(nl_sock, true);
	if (rc == -1) {
		rc = EXIT_FAILURE;
		goto out;
	}
	rc = handle_proc_ev(nl_sock);
	if (rc == -1) {
		rc = EXIT_FAILURE;
		goto out;
	}
	set_proc_ev_listen(nl_sock, false);
out:
	close(nl_sock);
	exit(rc);
}

#endif


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#rand_check-out */

#include <inttypes.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

int bss = 0;
int data = 1;

int main(__attribute__((unused)) int argc, char **argv) {
	int i, *ip;
	uint64_t uint64;
	FILE *fp;

	/* Loaded addresses. */
	printf("&i         = %p\n", (void *)&i);
	printf("&argv[0]   = %p\n", (void *)&argv[0]);
	printf("&main      = %p\n", (void *)(intptr_t)main);
	printf("&bss       = %p\n", (void *)&bss);
	printf("&data      = %p\n", (void *)&data);

	/* Misc syscalls. */
	printf("time(NULL) = %ju\n", (uintmax_t)time(NULL));
	printf("pid = %ju\n", (uintmax_t)getpid());

	/* malloc */
	ip = malloc(sizeof(*ip));
	printf("&malloc    = %p\n", (void *)ip);
	free(ip);

	/* /dev/urandom */
	fp = fopen("/dev/urandom", "rb");
	fread(&uint64, sizeof(uint64), 1, fp);
	printf("/dev/urandom = %" PRIx64 "\n", uint64);
	fclose(fp);
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#rdtsc */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#if defined(__i386__) || defined(__x86_64__)
#include <x86intrin.h>
#endif

int main(void) {
	uintmax_t val;
#if defined(__i386__) || defined(__x86_64__)
	val = __rdtsc();
#else
	val = 0;
#endif
	printf("%ju\n", val);
	return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#ring0 */

#include <stdio.h>
#include <stdlib.h>

#include "../ring0.h"

int main(void) {
#if defined(__x86_64__) || defined(__i386__)
	Ring0Regs ring0_regs;
	ring0_get_control_regs(&ring0_regs);
#endif
	return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-step-debug-multicore */

#define _GNU_SOURCE
#include <assert.h>
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void print_affinity() {
    cpu_set_t mask;
    long nproc, i;

    if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
        perror("sched_getaffinity");
        assert(false);
    } else {
        nproc = sysconf(_SC_NPROCESSORS_ONLN);
        printf("sched_getaffinity = ");
        for (i = 0; i < nproc; i++) {
            printf("%d ", CPU_ISSET(i, &mask));
        }
        printf("\n");
    }
}

int main(void) {
    cpu_set_t mask;

    print_affinity();
    printf("sched_getcpu = %d\n", sched_getcpu());
    CPU_ZERO(&mask);
    CPU_SET(0, &mask);
    if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
        perror("sched_setaffinity");
        assert(false);
    }
    print_affinity();
    printf("sched_getcpu = %d\n", sched_getcpu());
    return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-step-debug-multicore */

#define _GNU_SOURCE
#include <assert.h>
#include <pthread.h>
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void* main_thread_0(void *arg) {
	int i;
    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(*((int*)arg), &mask);
    sched_setaffinity(0, sizeof(cpu_set_t), &mask);
    i = 0;
    while (true) {
    	printf("0 %d\n", i);
    	sleep(1);
    	i++;
    }
    return NULL;
}

void* main_thread_1(void *arg) {
	int i;
    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(*((int*)arg), &mask);
    sched_setaffinity(1, sizeof(cpu_set_t), &mask);
    i = 0;
    while (true) {
    	printf("1 %d\n", i);
    	sleep(1);
    	i++;
    }
    return NULL;
}

int main(void) {
    enum NUM_THREADS {NUM_THREADS = 2};
    pthread_t threads[NUM_THREADS];
    int thread_args[NUM_THREADS];
	pthread_create(&threads[0], NULL, main_thread_0, (void*)&thread_args[0]);
	pthread_create(&threads[1], NULL, main_thread_1, (void*)&thread_args[1]);
    pthread_join(threads[0], NULL);
    pthread_join(threads[1], NULL);
    return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#sleep_forever-out */

#include <stdio.h>
#include <unistd.h>

int main(void) {
	puts(__FILE__);
	while (1)
		sleep(0xFFFFFFFF);
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#time_boot-out */

#include <stdio.h>
#include <unistd.h>

int main(void) {
    FILE *fp;
    fp = fopen("/dev/kmsg", "w");
	fputs(__FILE__ "\n", fp);
	fclose(fp);
	while (1)
		sleep(0xFFFFFFFF);
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#uio */

#if 1

/* Adapted from: https://yurovsky.github.io/2014/10/10/linux-uio-gpio-interrupt */

#define _XOPEN_SOURCE 700
#include <fcntl.h> /* open */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h> /* write */

#include <assert.h>
#include <sys/mman.h>

int main(int argc, char **argv)
{
    char *dev = "/dev/uio0";
    if (argc > 1) {
        dev = argv[1];
        exit(EXIT_FAILURE);
    }
    int fd = open(dev, O_RDWR);
    if (fd < 0) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    /* TODO not supported by this kernel module? */
	/*int *addr = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);*/
	/*if (addr == MAP_FAILED) {*/
		/*perror("mmap");*/
		/*assert(0);*/
	/*}*/
	/**addr = 0x12345678;*/

    while (1) {
        uint32_t info = 1;
        size_t nb = write(fd, &info, sizeof(info));
        if (nb < sizeof(info)) {
            perror("write");
            close(fd);
            exit(EXIT_FAILURE);
        }
        nb = read(fd, &info, sizeof(info));
        if (nb == sizeof(info)) {
            printf(__FILE__ " read = %u\n", info);
        }
    }
}

#else

/* Ripped from the kernel docs. */

#define _XOPEN_SOURCE 700
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <unistd.h>

int main()
{
    int uiofd;
    int configfd;
    int err;
    int i;
    unsigned icount;
    unsigned char command_high;

    uiofd = open("/dev/uio0", O_RDONLY);
    if (uiofd < 0) {
        perror("uio open:");
        return errno;
    }
    configfd = open("/sys/class/uio/uio0/device/config", O_RDWR);
    if (configfd < 0) {
        perror("config open:");
        return errno;
    }
    err = pread(configfd, &command_high, 1, 5);
    if (err != 1) {
        perror("command config read:");
        return errno;
    }
    command_high &= ~0x4;
    for(i = 0;; ++i) {
        fprintf(stderr, "Interrupts: %d\n", icount);
        err = pwrite(configfd, &command_high, 1, 5);
        if (err != 1) {
            perror("config write:");
            break;
        }
        err = read(uiofd, &icount, 4);
        if (err != 4) {
            perror("uio read:");
            break;
        }

    }
    return errno;
}

#endif


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-physical-address-experiments */

#define _XOPEN_SOURCE 700
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

enum { I0 = 0x12345678 };

static volatile uint32_t i = I0;

int main(void) {
	printf("vaddr %p\n", (void *)&i);
	printf("pid %ju\n", (uintmax_t)getpid());
	while (i == I0) {
		sleep(1);
	}
	printf("i %jx\n", (uintmax_t)i);
	return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-physical-address-experiments */

#define _XOPEN_SOURCE 700
#include <stdio.h> /* printf */
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE, strtoull */

#include "common.h" /* virt_to_phys_user */

int main(int argc, char **argv)
{
	pid_t pid;
	uintptr_t vaddr, paddr = 0;

	if (argc < 3) {
		printf("Usage: %s pid vaddr\n", argv[0]);
		return EXIT_FAILURE;
	}
	pid = strtoull(argv[1], NULL, 0);
	vaddr = strtoull(argv[2], NULL, 0);
	if (virt_to_phys_user(&paddr, pid, vaddr)) {
		fprintf(stderr, "error: virt_to_phys_user\n");
		return EXIT_FAILURE;
	};
	printf("0x%jx\n", (uintmax_t)paddr);
	return EXIT_SUCCESS;
}


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#vermagic */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/vermagic.h>

static int myinit(void)
{
	pr_info("VERMAGIC_STRING = " VERMAGIC_STRING "\n");
	/* Nice try, but it is not a member. */
	/*pr_info("THIS_MODULE->vermagic = %s\n", THIS_MODULE->vermagic);*/
	return 0;
}

static void myexit(void) {}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#vermagic */

#include <linux/module.h>
#include <linux/kernel.h>

static int myinit(void)
{
	pr_info("vermagic_fail\n");
	return 0;
}

static void myexit(void) {}

module_init(myinit)
module_exit(myexit)
MODULE_INFO(vermagic, "asdfqwer");
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#virt_to_phys */

#include <asm/io.h> /* virt_to_phys */
#include <linux/debugfs.h>
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/seq_file.h> /* single_open, single_release */
#include <linux/slab.h> /* kmalloc, kfree */

static volatile u32 *kmalloc_ptr;
static volatile u32 static_var;

static struct dentry *debugfs_file;

static int show(struct seq_file *m, void *v)
{
	seq_printf(m,
		"*kmalloc_ptr = 0x%llx\n"
		"kmalloc_ptr = %px\n"
		"virt_to_phys(kmalloc_ptr) = 0x%llx\n"
		"static_var = 0x%llx\n"
		"&static_var = %px\n"
		"virt_to_phys(&static_var) = 0x%llx\n",
		(unsigned long long)*kmalloc_ptr,
		kmalloc_ptr,
		(unsigned long long)virt_to_phys((void *)kmalloc_ptr),
		(unsigned long long)static_var,
		&static_var,
		(unsigned long long)virt_to_phys((void *)&static_var)
	);
	return 0;
}

static int open(struct inode *inode, struct  file *file)
{
	return single_open(file, show, NULL);
}

static const struct file_operations fops = {
	.llseek = seq_lseek,
	.open = open,
	.owner = THIS_MODULE,
	.read = seq_read,
	.release = single_release,
};

static int myinit(void)
{
	kmalloc_ptr = kmalloc(sizeof(kmalloc_ptr), GFP_KERNEL);
	*kmalloc_ptr = 0x12345678;
	static_var = 0x12345678;
	debugfs_file = debugfs_create_file("lkmc_virt_to_phys", S_IRUSR, NULL, NULL, &fops);
	return 0;
}

static void myexit(void)
{
	debugfs_remove(debugfs_file);
	kfree((void *)kmalloc_ptr);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#wait-queues */

#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/wait.h> /* wait_queue_head_t, wait_event_interruptible, wake_up_interruptible  */

static struct task_struct *kthread_wake;
static struct task_struct *kthread_sleep1;
static struct task_struct *kthread_sleep2;
static wait_queue_head_t queue;
static atomic_t awake1 = ATOMIC_INIT(0);
static atomic_t awake2 = ATOMIC_INIT(0);

static int kthread_wake_func(void *data)
{
	unsigned int i = 0;
	while (!kthread_should_stop()) {
		pr_info("0 %u\n", i);
		usleep_range(1000000, 1000001);
		atomic_set(&awake1, 1);
		atomic_set(&awake2, 1);
		wake_up(&queue);
		i++;
	}
	return 0;
}

static int kthread_sleep_func_1(void *data)
{
	unsigned int i = 0;
	while (!kthread_should_stop()) {
		pr_info("1 %u\n", i);
		i++;
		wait_event(queue, atomic_read(&awake1));
		atomic_set(&awake1, 0);
		schedule();
	}
	return 0;
}

static int kthread_sleep_func_2(void *data)
{
	unsigned int i = 0;
	while (!kthread_should_stop()) {
		pr_info("2 %u\n", i);
		i++;
		wait_event(queue, atomic_read(&awake2));
		atomic_set(&awake2, 0);
		schedule();
	}
	return 0;
}

int init_module(void)
{
	init_waitqueue_head(&queue);
	kthread_wake = kthread_create(kthread_wake_func, NULL, "wake");
	kthread_sleep1 = kthread_create(kthread_sleep_func_1, NULL, "sleep1");
	kthread_sleep2 = kthread_create(kthread_sleep_func_2, NULL, "sleep2");
	wake_up_process(kthread_wake);
	wake_up_process(kthread_sleep1);
	wake_up_process(kthread_sleep2);
	return 0;
}

void cleanup_module(void)
{
	kthread_stop(kthread_sleep2);
	kthread_stop(kthread_sleep1);
	kthread_stop(kthread_wake);
}
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#warn_on */

#include <linux/module.h>
#include <linux/kernel.h>

static int myinit(void)
{
	pr_info("warn_on init\n");
	WARN_ON("warn_on do it");
	pr_info("warn_on after\n");
	return 0;
}

static void myexit(void)
{
	pr_info("warn_on cleanup\n");
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#workqueue-from-workqueue */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>

static int i;
static struct workqueue_struct *queue;

static void work_func(struct work_struct *work);

DECLARE_DELAYED_WORK(next_work, work_func);
DECLARE_WORK(work, work_func);

static void work_func(struct work_struct *work)
{
	pr_info("%d\n", i);
	i++;
	if (i == 10)
		i = 0;
	queue_delayed_work(queue, &next_work, HZ);
}

static int myinit(void)
{
	queue = create_workqueue("myworkqueue");
	queue_work(queue, &work);
	return 0;
}

static void myexit(void)
{
	cancel_delayed_work(&next_work);
	flush_workqueue(queue);
	destroy_workqueue(queue);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#workqueues */

#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h> /* atomic_t */
#include <linux/workqueue.h>

static struct workqueue_struct *queue;
static atomic_t run = ATOMIC_INIT(1);

static void work_func(struct work_struct *work)
{
	int i = 0;
	while (atomic_read(&run)) {
		pr_info("%d\n", i);
		usleep_range(1000000, 1000001);
		i++;
		if (i == 10)
			i = 0;
	}
}

DECLARE_WORK(work, work_func);

static int myinit(void)
{
	queue = create_workqueue("myworkqueue");
	queue_work(queue, &work);
	return 0;
}

static void myexit(void)
{
	atomic_set(&run, 0);
	destroy_workqueue(queue);
}

module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");


code:
config BR2_PACKAGE_LKMC_MANY_FILES
	bool "lkmc_many_files"
	help
		Create a bunch of files in target/ to benchmark Buildroot.


code:
.PHONY: all clean

CFLAGS_EXTRA ?= -fopenmp -std=c99 -Wall -Werror -Wextra
IN_EXT ?= .c
LIBS :=
OUT_EXT ?= .out

OUTS := $(addsuffix $(OUT_EXT), $(basename $(wildcard *$(IN_EXT))))

all: $(OUTS)

%$(OUT_EXT): %$(IN_EXT)
	$(CC) $(CFLAGS) $(CFLAGS_EXTRA) -o '$@' '$<' $(LIBS)

clean:
	rm -f *'$(OUT_EXT)'


code: name: LKMC_MANY_FILES


code:
################################################################################
#
# lkmc_many_files
#
################################################################################

LKMC_MANY_FILES_VERSION = 1.0
LKMC_MANY_FILES_SITE = $(BR2_EXTERNAL_LKMC_MANY_FILES_PATH)
LKMC_MANY_FILES_SITE_METHOD = local

define LKMC_MANY_FILES_BUILD_CMDS
	# D contains the source code of this package.
	# TARGET_CONFIGURE_OPTS contains several common options such as CFLAGS and LDFLAGS.
	$(MAKE) -C '$(@D)' $(TARGET_CONFIGURE_OPTS)
endef

define LKMC_MANY_FILES_INSTALL_TARGET_CMDS
  # Anything put inside TARGET_DIR will end up on the guest relative to the root directory.
  i=0; \
  while [ $$i -le 128 ]; do \
    j=0; \
    while [ $$j -le 128 ]; do \
      $(INSTALL) -D -m 0755 $(@D)/lkmc_many_files.out $(TARGET_DIR)/lkmc_many_files/$${i}_$${j}.out; \
      j=$$(($$j+1)); \
    done; \
    i=$$(($$i+1)); \
  done
endef

$(eval $(generic-package))


code:
#include <stdio.h>
#include <stdlib.h>

int main(void) {
	puts("hello lkmc_many_files");
	return EXIT_SUCCESS;
}


code:
config BR2_PACKAGE_PARSEC_BENCHMARK
	bool "PARSEC_BENCHMARK"
	help
	  Parsec system benchmark.

	  http://parsec.cs.princeton.edu/

if BR2_PACKAGE_PARSEC_BENCHMARK

config BR2_PACKAGE_PARSEC_BENCHMARK_BUILD_LIST
	string "build_list"
	default splash2x
	help
	  Space separated list of parsec packages to build.

config BR2_PACKAGE_PARSEC_BENCHMARK_PARSECMGMT
	bool "parsecmgmt"
	select BR2_PACKAGE_BUSYBOX_SHOW_OTHERS
	select BR2_PACKAGE_BASH
	help
	  Enable the parsecmgmt script.
	  Too slow for gem5, but doable in QEMU.

	  This installs bash because Parsec shell scripts use a hardcoded /bin/bash

	  One option would be to try and use /bin/sh.
	  But symlinking fails because of BusyBox' symlink mechanism.
	  The other option would be to patch Parsec to use /bin/sh and be POSIX compliant.
	  But let's take the path of smallest resistance for now.

if !BR2_PACKAGE_PARSEC_BENCHMARK_PARSECMGMT

config BR2_PACKAGE_PARSEC_BENCHMARK_INPUT_SIZE
	string "input_size"
	default test
	help
	  Which input size to generate on the host for the guest.

endif

endif


code: name: PARSEC_BENCHMARK


code:
################################################################################
#
# PARSEC_BENCHMARK
#
################################################################################

# If we ever upstream to Buildroot.
# PARSEC_BENCHMARK_VERSION = 75d55ac446a43c47efb1044844a108c6c330184c
# PARSEC_BENCHMARK_SITE = git@github.com:cirosantilli/parsec-benchmark.git
# PARSEC_BENCHMARK_SITE_METHOD = git

PARSEC_BENCHMARK_VERSION = 1.0
PARSEC_BENCHMARK_SITE = $(LKMC_PARSEC_BENCHMARK_SRCDIR)
PARSEC_BENCHMARK_SITE_METHOD = local

define PARSEC_BENCHMARK_BUILD_CMDS
  # TODO make this nicer, only untar when extract step is done.
  # EXTRACT_CMDS and EXTRA_DOWNLOADS would be good candidates,
  # but they don't run with OVERRIDE_SRCDIR.
  '$(@D)/get-inputs' $(if $(filter $(V),1),-v,) '$(DL_DIR)' '$(@D)/'
  # We run the benchmarks with the wrong arch here to generate the inputs on the host.
  # This is because on gem5 this takes too long to do.
  export GNU_TARGET_NAME='$(GNU_TARGET_NAME)' && \
  export GNU_HOST_NAME='$(GNU_HOST_NAME)' && \
  export HOSTCC='$(HOSTCC)' && \
  export M4='$(HOST_DIR)/usr/bin/m4' && \
  export MAKE='$(MAKE)' && \
  export OSTYPE=linux && \
  export TARGET_CROSS='$(TARGET_CROSS)' && \
  export CC="$(TARGET_CC)" && \
  export CPP="$(TARGET_CPP)" && \
  export CXX="$(TARGET_CXX)" && \
  export HOSTTYPE=$(BR2_ARCH) && \
  cd $(@D) && \
  . env.sh && \
  for pkg in $(BR2_PACKAGE_PARSEC_BENCHMARK_BUILD_LIST); do \
    parsecmgmt -a build -p $$pkg && \
    if [ ! '$(BR2_PACKAGE_PARSEC_BENCHMARK_PARSECMGMT)' = y ]; then \
      parsecmgmt -a run -p $$pkg -i $(BR2_PACKAGE_PARSEC_BENCHMARK_INPUT_SIZE); \
    fi \
  done
endef

define PARSEC_BENCHMARK_INSTALL_TARGET_CMDS
  mkdir -p '$(TARGET_DIR)/parsec/'
  $(INSTALL) -D -m 0755 '$(@D)/test.sh' '$(TARGET_DIR)/parsec/'
  if [ '$(BR2_PACKAGE_PARSEC_BENCHMARK_PARSECMGMT)' = y ]; then \
    rsync -am $(if $(filter $(V),1),-v,) \
      --exclude '**/obj/' \
      --exclude '**/run/' \
      --exclude '**/src/' \
      '$(@D)/' '$(TARGET_DIR)/parsec/' \
    ; \
  else \
    rsync -am $(if $(filter $(V),1),-v,) --include '*/' \
      --include 'inst/***' \
      --include 'run/***' \
      --exclude '*' '$(@D)/' '$(TARGET_DIR)/parsec/' \
    ; \
  fi
  # rsync finished.
endef

$(eval $(generic-package))


code:
config BR2_PACKAGE_SAMPLE_PACKAGE
	bool "sample_package"
	help
		Sample Buildroot package.


code: name: SAMPLE_PACKAGE


code:
################################################################################
#
# sample_package
#
################################################################################

SAMPLE_PACKAGE_VERSION = 1.0
SAMPLE_PACKAGE_SITE = $(BR2_EXTERNAL_SAMPLE_PACKAGE_PATH)
SAMPLE_PACKAGE_SITE_METHOD = local

define SAMPLE_PACKAGE_BUILD_CMDS
	# D contains the source code of this package.
	# TARGET_CONFIGURE_OPTS contains several common options such as CFLAGS and LDFLAGS.
	$(MAKE) -C '$(@D)' $(TARGET_CONFIGURE_OPTS)
endef

define SAMPLE_PACKAGE_INSTALL_TARGET_CMDS
  # Anything put inside TARGET_DIR will end up on the guest relative to the root directory.
  $(INSTALL) -D -m 0755 $(@D)/*.out '$(TARGET_DIR)'
endef

$(eval $(generic-package))


code:
#include <stdio.h>
#include <stdlib.h>

int main(void) {
	puts("hello sample_package");
	return EXIT_SUCCESS;
}


code:
diff --git a/configs/example/arm/fs_bigLITTLE.py b/configs/example/arm/fs_bigLITTLE.py
index 7d66c03a6..d71e714fe 100644
--- a/configs/example/arm/fs_bigLITTLE.py
+++ b/configs/example/arm/fs_bigLITTLE.py
@@ -194,7 +194,7 @@ def build(options):
         "norandmaps",
         "loglevel=8",
         "mem=%s" % default_mem_size,
-        "root=/dev/vda1",
+        "root=/dev/vda",
         "rw",
         "init=%s" % options.kernel_init,
         "vmalloc=768MB",


code:
diff --git a/configs/example/fs.py b/configs/example/fs.py
index 4031fd05e..0f502a34a 100644
--- a/configs/example/fs.py
+++ b/configs/example/fs.py
@@ -395,5 +395,6 @@ if buildEnv['TARGET_ISA'] == "arm" and options.generate_dtb:
             sys = getattr(root, sysname)
             sys.dtb_filename = create_dtb_for_system(sys, '%s.dtb' % sysname)

+test_sys.panic_on_panic = True
 Simulation.setWorkCountOptions(test_sys, options)
 Simulation.run(options, root, test_sys, FutureClass)


code:
#!/usr/bin/env python3

import os
import subprocess
import sys

import common

def main():
    cmd = [
        os.path.join(common.qemu_src_dir, 'scripts/simpletrace.py'),
        os.path.join(common.qemu_build_dir, 'trace-events-all'),
        os.path.join(common.qemu_trace_file),
    ]
    return common.run_cmd(
        cmd,
        cmd_file=os.path.join(common.run_dir, 'qemu-trace2txt'),
        out_file=common.qemu_trace_txt_file,
        show_stdout=False,
    )

if __name__ == '__main__':
    parser = common.get_argparse(argparse_args={
        'description': 'Convert a QEMU `-trace exec_tb` to text form.'
    })
    args = common.setup(parser)
    sys.exit(main())


code:
#!/usr/bin/env expect
# Ee have to use expect since QEMU 2.12: just piping commands
# into telnet stopped working at that version.
spawn telnet localhost 45454
set prompt "\n(qemu) "
expect $prompt
if {$argc > 0} {
  send "[concat [join $argv " "]]\r"
  expect $prompt
} else {
  interact
}

# In order to treat input from stdin, we would need to differentiate between input from pipe vs terminal.
# For bash we can do it as:
# https://stackoverflow.com/questions/911168/how-to-detect-if-my-shell-script-is-running-through-a-pipe
# but no one knows for Tcl:
# https://stackoverflow.com/questions/43660612/how-to-check-if-stdin-stdout-are-connected-to-a-terminal-in-tcl
# One option would also be to have a bash wrapper that calls this tcl script.
# Related: https://stackoverflow.com/questions/10237872/expect-redirect-stdin
#while {[gets stdin line] > 0} {
  #expect $prompt
  #send "$line\r"
#}

path: qemumonitor


code:
#!/usr/bin/env bash
set -eu
./run -r "$@"
./run -R "$@"

path: qemurr


code:
#!/usr/bin/env python3
import subprocess
import common
subprocess.check_call(['./build-all'])
subprocess.check_call(['./zip-img'])
tag = 'sha-{}'.format(common.sha)
subprocess.check_call(['git', 'tag' tag])
subprocess.check_call(['git', 'push' '--tags'])
# TODO
# - https://stackoverflow.com/questions/41022470/curl-request-to-add-file-to-github-release
# - https://stackoverflow.com/questions/38627115/upload-files-to-github-directory-using-github-api
# upload_basename = 'images-{}.zip'.format(common.sha)
#curl "https://api.github.com/repos/cirosantilli/linux-kernel-module-cheat/releases/tags/${tag}/assets?access_token=$(cat data/access_token)&tag_name=${upload_basename}" \
#  --header 'Content-Type: application/zip' \
#  --upload-file "${common_out_dir}/${upload_basename}" \
#  -H 'Accept: application/vnd.github.v3+json' \
#  -X POST \
#;
subprocess.check_call(['./bench-all', '-A', '-u'])

path: release


code:
#!/bin/sh
set -e
insmod /anonymous_inode.ko
[ "$(/anonymous_inode.out /sys/kernel/debug/lkmc_anonymous_inode 3)" = "$(printf '1\n10\n100')" ]
rmmod anonymous_inode


code:
#!/bin/sh
set -e
insmod /character_device.ko
/mknoddev.sh lkmc_character_device
[ "$(cat /dev/lkmc_character_device)" = 'abcd' ]
rm /dev/lkmc_character_device
rmmod character_device


code:
#!/bin/sh
set -e
insmod /character_device_create.ko
dev='/dev/lkmc_character_device_create_dev'
[ "$(cat "$dev")" = abcd ]
rmmod character_device_create
[ ! -e "$dev" ]


code:
#!/bin/sh
zcat /proc/config.gz | grep -Ei "${1:-}"


code:
#!/bin/sh
# Generate infinitely many system calls :-)
i=0
while true; do
  echo "$i"
  i=$(($i+1))
  sleep 1
done


code:
#!/bin/sh
set -e
d=/debugfs
mkdir -p "$d"
mount -t debugfs none "$d"
insmod /debugfs.ko
[ "$(cat "${d}/lkmc_debugfs/myfile")" = 42 ]
echo 13 > "${d}/lkmc_debugfs/myfile"
[ "$(cat "${d}/lkmc_debugfs/myfile")" = 13 ]
echo 666 > "${d}/lkmc_debugfs_file"
[ "$(cat "${d}/lkmc_debugfs/myfile")" = 666 ]
rmmod debugfs
umount "$d"


code:
#!/bin/sh
set -e
f=/sys/kernel/debug/lkmc_dep
f2=/sys/kernel/debug/lkmc_dep2

insmod /dep.ko
insmod /dep2.ko

# Initial value.
[ "$(cat "$f")" = 0 ]

# Changhing dep2 also changes dep.
printf 1 > "$f2"
[ "$(cat "$f")" = 1 ]

# Changhing dep also changes dep2.
printf 2 > "$f"
[ "$(cat "$f2")" = 2 ]

# sysfs shows us that the module has dependants.
[ "$(cat /sys/module/dep/refcnt)" = 1 ]
[ "$(ls /sys/module/dep/holders)" = dep2 ]
rmmod /dep2.ko
[ "$(cat /sys/module/dep/refcnt)" = 0 ]
[ -z "$(ls /sys/module/dep/holders)" ]

rmmod /dep.ko


code:
# <file system>	<mount pt>	<type>	<options>	<dump>	<pass>
/dev/root		/		ext2	rw,noauto	0	1
proc			/proc		proc	defaults	0	0
devpts			/dev/pts	devpts	defaults,gid=5,mode=620	0	0
tmpfs			/dev/shm	tmpfs	mode=0777	0	0
tmpfs			/tmp		tmpfs	mode=1777	0	0
tmpfs			/run		tmpfs	mode=0755,nosuid,nodev	0	0
sysfs			/sys		sysfs	defaults	0	0
debugfs			/sys/kernel/debug	debugfs	defaults	0	0
host_scratch	/mnt/9p				9p		trans=virtio,version=9p2000.L	0	0
host_out		/mnt/out			9p		trans=virtio,version=9p2000.L	0	0


code:
#!/bin/sh
echo "hello S98"
if [ -n "$lkmc_eval" ]; then
  eval "$lkmc_eval"
elif [ -n "$lkmc_eval_base64" ]; then
  eval "$(printf "$lkmc_eval_base64" | base64 -d)"
fi
exit 0


code:
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -o remount,rw /
::sysinit:/bin/mkdir -p /dev/pts
::sysinit:/bin/mkdir -p /dev/shm
::sysinit:/bin/mount -a
::sysinit:/bin/hostname -F /etc/hostname
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
# Same as above: console is the default.
#console::respawn:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/etc/init.d/rcK
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r


code: options params i=12 j=34


code:
AuthorizedKeysFile	.ssh/authorized_keys
Subsystem	sftp	/usr/libexec/sftp-server
PermitRootLogin yes
PermitEmptyPasswords yes


code:
#!/bin/sh
echo "$lkmc_eval"
eval "$lkmc_eval"

# Ideally, this script would do just:
#
## Get rid of the '-'.
#shift
#echo "$@"
#
# However, the kernel CLI parsing is crap, and the 4.14 docs lie.
#
# In particular, not all that is passed after "-" goes to an argument to init,
# e.g. stuff with dots like "- /poweroff.out" still gets treated specially and
# does not go to init.
#
# This also likely means that the above solution is also unreliable in some cases,
# and that in the end you just have to add a script to the root filesystem.


code:
#!/bin/sh
eval "$(printf "$lkmc_eval" | base64 -d)"


code:
#!/bin/sh
cat /dev/urandom > "/dev/fb${1:-0}"


code:
#!/bin/sh
set -e

# Setup
f=/sys/kernel/debug/lkmc_fops
insmod /fops.ko

# read
[ "$(cat "$f")" = abcd ]

# write
printf 01 > "$f"
[ "$(cat "$f")" = 01cd ]

# ENOSPC
printf abcd > "$f"
set +e
printf 12345 > "$f"
exit_status="$?"
set -e
[ "$exit_status" -eq 8 ]
[ "$(cat "$f")" = abcd ]

# seek
printf 1234 > "$f"
printf z | dd bs=1 of="$f" seek=2
[ "$(cat "$f")" = 12z4 ]

# Teardown
rmmod fops


code:
#!/bin/sh
/sbin/ifup -a
gdbserver :45455 "$@"


code:
#!/bin/sh
# https://github.com/cirosantilli/linux-kernel-module-cheat#gem5-restore-new-scrip
m5 checkpoint
m5 resetstats
m5 readfile | sh
m5 exit


code:
#!/bin/sh
set -e
cd /sys/class/gpio
echo 480 > export
echo 481 > export
echo 482 > export
echo 488 > export
echo 496 > export
echo out > gpio480/direction
echo out > gpio481/direction
echo out > gpio482/direction
echo out > gpio488/direction
echo out > gpio496/direction
v=1
while true; do
  echo $v > gpio480/value
  echo $v > gpio481/value
  echo $v > gpio482/value
  echo $v > gpio488/value
  echo $v > gpio496/value
  if [ $v -eq 1 ]; then
    v=0
  else
    v=1
  fi
  sleep 1
done


code:
#!/bin/sh
# Failed attempt at debugging /init, because:
#     init must be run as pid 1
# Is this just a random BusyBox sanity check?
# - https://stackoverflow.com/questions/35019995/strace-init-process-pid-1-in-linux
/sbin/init "$@"


code:
#!/bin/sh
set -e
insmod /init_module.ko
rmmod init_module


code:
#!/bin/sh
# Insert and remove a module n times to check for spurious errors / deadlocks.
set -e
mod="$1"
n="${2:-1}"
i=0
while [ $i -lt $n ]; do
  echo "insmod $i"
  insmod "/$mod.ko"
  echo "rmmod $i"
  rmmod "$mod"
  i=$(($i+1))
done


code:
#!/bin/sh
set -e
f=/sys/kernel/debug/lkmc_ioctl
insmod /ioctl.ko
[ "$(/ioctl.out "$f" 0 1)" = 2 ]
[ "$(/ioctl.out "$f" 1 1 1)" = '2 0' ]
rmmod ioctl


code:
#!/bin/sh
insmod /fops.ko
cd /sys/kernel/debug/lkmc_fops
i=0
while true; do
  printf "$i" >f
  i=$(($i+1))
done &
/kgdb.sh


code:
#!/bin/sh
echo g > /proc/sysrq-trigger


code:
#!/bin/sh
set -e
f=/sys/kernel/debug/lkmc_kstrto
insmod /kstrto.ko
printf 123 > "$f"
[ "$(cat "$f")" = 124 ]
echo foobar > "$f" && exit 1
rmmod kstrto


code:
#!/bin/sh
exec /bin/login root


code:
#!/bin/sh
dev="$1"
major="$(awk -F ' ' '$2 == "'"$dev"'" { print $1 }' /proc/devices)"
mknod "/dev/$dev" c "$major" 0


code:
#!/bin/sh
set -e
insmod /mmap.ko
/mmap.out /proc/lkmc_mmap 2>&1 1>/dev/null
rmmod /mmap.ko


code:
#!/bin/sh
set -e
insmod /netlink.ko
[ "$(/netlink.out)" = 0 ]
[ "$(/netlink.out)" = 1 ]
[ "$(/netlink.out)" = 2 ]
rmmod netlink


code:
#!/bin/sh
set -ex
lower="${1:-/}"
mount="$2"
if [ -z "$mount" ]; then
  mount="$lower"
fi
upper="${lower}/upper"
work="${lower}/work"
mkdir -p "$lower" "$upper" "$work" "$mount"
touch "${lower}/asdf" "${upper}/qwer"
mount -t overlay -o lowerdir="$lower",upperdir="$upper",workdir="$work" none "$mount"
ls "$lower" "$upper"
umount "$mount"


code:
#!/bin/sh
set -e
d=/sys/module/params/parameters
i="${d}/i"
j="${d}/j"
f=/sys/kernel/debug/lkmc_params

insmod /params.ko
[ "$(cat "$i")" = 0 ]
[ "$(cat "$j")" = 0 ]
[ "$(cat "$f")" = '0 0' ]
printf 1 > "$i"
[ "$(cat "$f")" = '1 0' ]
printf 2 > "$j"
[ "$(cat "$f")" = '1 2' ]
rmmod params

insmod /params.ko i=3 j=4
[ "$(cat "$f")" = '3 4' ]
rmmod params


code:
#!/bin/sh
echo 1 > /sys/bus/pci/rescan


code:
#!/bin/sh
insmod /pmccntr.ko
cd /sys/kernel/debug
cat lkmc_pmccntr


code:
#!/bin/sh
set -e
insmod /poll.ko
/poll.out /sys/kernel/debug/lkmc_poll
#rmmod poll


code:
#!/bin/sh
echo 8 > /proc/sys/kernel/printk
echo 'file kernel/module.c +p' > /sys/kernel/debug/dynamic_debug/control


code:
#!/bin/sh
set -e
insmod /procfs.ko
[ "$(cat "/proc/lkmc_procfs")" = abcd ]
rmmod procfs


code:
#!/bin/sh
# Show All possible ps fields to get better process visibility.
# TODO for some reason nothing shows after args, so we put it last.
ps -o user,group,comm,pid,ppid,sid,pgid,tty,vsz,rss,stat,args


code:
#!/bin/sh

set -ex

# Our modules does not the PCI device yet.
lspci -k
# => 00:04.0 Class 00ff: 1234:11e8 lkmc_pci

# Interrupt counts before we generate our interrupts.
cat /proc/interrupts

# Setup.
insmod /pci.ko
/mknoddev.sh lkmc_pci

# Shows that this module owns the PCI device.
lspci -k
# => 00:04.0 Class 00ff: 1234:11e8 lkmc_pci

# Identifiction: just returns some fixed magic bytes.
dd bs=4 status=none if=/dev/lkmc_pci count=1 skip=0 | od -An -t x1
# => 010000ed

# Negator. Sanity check that the hardware is getting updated.
dd bs=4 status=none if=/dev/lkmc_pci count=1 skip=1 | od -An -t x1
printf '\xF0\xF0\xF0\xF0' | dd bs=4 status=none of=/dev/lkmc_pci count=1 seek=1
dd bs=4 status=none if=/dev/lkmc_pci count=1 skip=1 | od -An -t x1
# => 0F0F0F0F

# Factorial calculator.
# Request interrupt when the computation is over.
printf '\x80\x00\x00\x00' | dd bs=4 status=none of=/dev/lkmc_pci count=1 seek=8
# factorial(0xC) = 0x1c8cfc00
printf '\x0C\x00\x00\x00' | dd bs=4 status=none of=/dev/lkmc_pci count=1 seek=2
# => irq_handler .*
# Yes, we should use the interrupt to notify poll, but lazy.
sleep 1
dd bs=4 status=none if=/dev/lkmc_pci count=1 skip=2 | od -An -t x1
dd bs=4 status=none if=/dev/lkmc_pci count=1 skip=8 | od -An -t x1
# => 1c8cfc00

# Manual IRQ raising.
printf '\x04\x03\x02\x01' | dd bs=4 status=none of=/dev/lkmc_pci count=1 seek=24
# => irq_handler .*
sleep 1
printf '\x08\x07\x06\x05' | dd bs=4 status=none of=/dev/lkmc_pci count=1 seek=24
# => irq_handler .*
sleep 1

# Teardown.
rm /dev/lkmc_pci
rmmod pci

# Interrupt counts after we generate our interrupts.
# Compare with before.
cat /proc/interrupts


code:
#!/bin/sh
set -ex
/rand_check.out

# Check if network is being replayed.
# https://superuser.com/questions/635020/how-to-know-current-time-from-internet-from-command-line-in-linux
# https://tf.nist.gov/tf-cgi/servers.cgi
#echo | nc 129.6.15.28 13

# busybox's poweroff panics, TODO why. Likely tries to kill shell.
# So just use our super raw command.
/poweroff.out


code:
# https://unix.stackexchange.com/questions/176027/ash-profile-configuration-file
echo "hello $(pwd)/.profile"
# Does not inherit init environment variables.
#env


code:
#!/bin/sh
set -e
f=/sys/kernel/debug/lkmc_seq_file
insmod /seq_file.ko
[ "$(cat "$f")" = "$(printf '0\n1\n2\n')" ]
[ "$(cat "$f")" = "$(printf '0\n1\n2\n')" ]
[ "$(dd if="$f" bs=1 count=2 skip=0 status=none)" = "$(printf '0\n')" ]
[ "$(dd if="$f" bs=1 count=2 skip=2 status=none)" = "$(printf '1\n')" ]
[ "$(dd if="$f" bs=4 count=1 skip=0 status=none)" = "$(printf '0\n1\n')" ]
rmmod seq_file


code:
#!/bin/sh
set -e
f=/sys/kernel/debug/lkmc_seq_file_single_open
insmod /seq_file_single_open.ko
[ "$(cat "$f")" = "$(printf 'ab\ncd\n')" ]
[ "$(dd if="$f" bs=1 count=3 skip=1)" = "$(printf "b\nc\n")" ]
rmmod seq_file_single_open


code:
#!/bin/sh
/sbin/ifup -a
/usr/bin/ssh-keygen -A
/usr/sbin/sshd


code:
#!/bin/sh
set -e
insmod /sysfs.ko
f=/sys/kernel/lkmc_sysfs/foo
# write
printf 12345 > "$f"
# read
[ "$(cat "$f")" = 1234 ]
# seek
[ "$(dd if="$f" bs=1 count=2 skip=1 status=none)" = 23 ]
rmmod sysfs


code:
#!/bin/sh
for test in \
  /anonymous_inode.sh \
  /character_device.sh \
  /character_device_create.sh \
  /debugfs.sh \
  /dep.sh \
  /fops.sh \
  /init_module.sh \
  /ioctl.sh \
  /kstrto.sh \
  /mmap.sh \
  /netlink.sh \
  /params.sh \
  /procfs.sh \
  /seq_file.sh \
  /seq_file_single_open.sh \
  /sysfs.sh \
; do
  if ! "$test"; then
    echo "lkmc_test_fail: ${test}"
    exit 1
  fi
done
echo lkmc_test_pass


code:
#!/bin/sh
# https://github.com/cirosantilli/linux-kernel-module-cheat#uio
set -e
modprobe uio_pci_generic
# pci_min device
echo '1234 11e9' > /sys/bus/pci/drivers/uio_pci_generic/new_id
/uio_read.out &
# Helper to observe interrupts.
insmod /irq.ko
base="$(setpci -d 1234:11e9 BASE_ADDRESS_0)"
# Start generating interrupt.
devmem "0x${base}" w 0x12345678
# Stop generating interrupt.
devmem "0x$(($base + 4))" w 0x12345678
devmem "0x${base}" w 0x12345678
devmem "0x$(($base + 4))" w 0x12345678
modprobe -r uio_pci_generic


code:
#!/bin/sh
set -e
insmod /vermagic.ko
rmmod vermagic


code:
#!/bin/sh
set -ex
insmod /virt_to_phys.ko
cd /sys/kernel/debug
cat lkmc_virt_to_phys
# k = 0x12345678
# i = 0x12345678
addr=$(awk '$1 == "virt_to_phys_k" { print $2 }' lkmc_virt_to_phys)
devmem "$addr"
devmem "$addr" w 0x9ABCDEF0
addr=$(awk '$1 == "virt_to_phys_i" { print $2 }' lkmc_virt_to_phys)
devmem "$addr"
devmem "$addr" w 0x9ABCDEF0
cat lkmc_virt_to_phys
# k = 0x9ABCDEF0
# i = 0x12345678
rmmod virt_to_phys


code:
#!/usr/bin/env bash
# This is run as part of:
#      make target-finalize
# which gets called by the default target.
target_dir="$1"
mkdir -p \
  "${target_dir}/mnt/9p" \
  "${target_dir}/mnt/out" \
;
# Maybe there is a cleaner way to get rid of those files,
# like disabling some Buildroot packages, but no patience.
#
# As of 2d5f95b1839986ca6d7b568296374a2403d2693d
# xorg must be removed or else we get a black screen:
# https://bugs.busybox.net/show_bug.cgi?id=11066
rm -rf \
  "${target_dir}/etc/init.d/S01logging" \
  "${target_dir}/etc/init.d/S20urandom" \
  "${target_dir}/etc/init.d/S40network" \
  "${target_dir}/etc/init.d/S40xorg" \
  "${target_dir}/etc/init.d/S50sshd" \
;


code:
#!/usr/bin/env python3

import os
import shlex
import subprocess
import sys
import re

import common

defaults = {
    'cpus': 1,
    'debug_guest': False,
    'debug_vm': False,
    'eval': None,
    'extra_emulator_args': [],
    'gem5_biglittle': False,
    'gem5_exe_args': '',
    'gem5_readfile': '',
    'gem5_restore': None,
    'graphic': False,
    'initramfs': False,
    'initrd': False,
    'kernel_cli': None,
    'kernel_cli_after_dash': None,
    'eval_busybox': None,
    'kgdb': False,
    'kvm': False,
    'memory': '256M',
    'prebuilt': False,
    'record': False,
    'replay': False,
    'terminal': False,
    'tmux': False,
    'tmux_args': '',
    'trace': None,
    'vnc': False,
}

def main(args, extra_args=None):
    global defaults
    args = common.resolve_args(defaults, args, extra_args)
    # Common qemu / gem5 logic.
    # nokaslr:
    # * https://unix.stackexchange.com/questions/397939/turning-off-kaslr-to-debug-linux-kernel-using-qemu-and-gdb
    # * https://stackoverflow.com/questions/44612822/unable-to-debug-kernel-with-qemu-gdb/49840927#49840927
    #   Turned on by default since v4.12
    kernel_cli = 'console_msg_format=syslog nokaslr norandmaps panic=-1 printk.devkmsg=on printk.time=y'
    if args.kernel_cli is not None:
        kernel_cli += ' {}'.format(args.kernel_cli)
    kernel_cli_after_dash = ''
    extra_emulator_args = args.extra_emulator_args.copy()
    extra_qemu_args = []
    if args.debug_vm:
        debug_vm = ['gdb', '-q', '-ex', 'start', '--args']
    else:
        debug_vm = []
    if args.debug_guest:
        extra_qemu_args.append('-S')
    if args.eval_busybox is not None:
        kernel_cli_after_dash += ' lkmc_eval_base64="{}"'.format(common.base64_encode(args.eval_busybox))
    if args.kernel_cli_after_dash is not None:
        kernel_cli_after_dash += ' {}'.format(args.kernel_cli_after_dash)
    if args.kgdb:
        kernel_cli += ' kgdbwait'
    if args.vnc:
        vnc = ['-vnc', ':0']
    else:
        vnc = []
    if args.initrd or args.initramfs:
        ramfs = True
    else:
        ramfs = False
    if args.eval is not None:
        if ramfs:
            initarg = 'rdinit'
        else:
            initarg = 'init'
        kernel_cli += ' {}=/eval_base64.sh'.format(initarg)
        kernel_cli_after_dash += ' lkmc_eval="{}"'.format(common.base64_encode(args.eval))
    if not args.graphic:
        if args.arch == 'x86_64':
            kernel_cli += ' console=ttyS0'
        extra_qemu_args.append('-nographic')
    if kernel_cli_after_dash:
        kernel_cli += " -{}".format(kernel_cli_after_dash)
    extra_env = {}
    if args.trace is None:
        do_trace = False
        # A dummy value that is already turned on by default and does not produce large output,
        # just to prevent QEMU from emitting a warning that '' is not valid.
        trace_type = 'pr_manager_run'
    else:
        do_trace = True
        trace_type = args.trace

    if args.gem5:
        with open(common.gem5_readfile, 'w') as readfile:
            readfile.write(args.gem5_readfile)
        memory = '{}B'.format(args.memory)
        gem5_exe_args = shlex.split(args.gem5_exe_args)
        if do_trace:
            gem5_exe_args.append('--debug-flags={}'.format(trace_type))
        extra_env['M5_PATH'] = common.gem5_system_dir
        # https://stackoverflow.com/questions/52312070/how-to-modify-a-file-under-src-python-and-run-it-without-rebuilding-in-gem5/52312071#52312071
        extra_env['M5_OVERRIDE_PY_SOURCE'] = 'true'
        cmd = (
            debug_vm +
            [
                common.executable,
                '--debug-file=trace.txt',
            ] +
            gem5_exe_args +
            [
                '-d', common.m5out_dir
            ]
        )
        if args.gem5_biglittle:
            if args.gem5_restore is not None:
                cpt_dir = common.gem_list_checkpoint_dirs()[-args.gem5_restore]
                extra_emulator_args.extend(['--restore-from', os.path.join(common.m5out_dir, cpt_dir)])
            cmd += [
                os.path.join(common.gem5_src_dir, 'configs', 'example', 'arm', 'fs_bigLITTLE.py'),
                '--big-cpus', '2',
                '--cpu-type', 'atomic',
                '--disk', common.ext2_file,
                '--dtb', os.path.join(common.gem5_system_dir, 'arm', 'dt', 'armv8_gem5_v1_big_little_2_2.dtb'),
                '--kernel', common.vmlinux,
                '--little-cpus', '2'
            ]
        else:
            # TODO port
            if args.gem5_restore is not None:
                cpt_dirs = common.gem_list_checkpoint_dirs()
                cpt_dir = cpt_dirs[-args.gem5_restore]
                extra_emulator_args.extend(['-r', str(sorted(cpt_dirs).index(cpt_dir) + 1)])
            cmd += [
                common.gem5_fs_file,
                '--disk-image', common.ext2_file,
                '--kernel', common.vmlinux,
                '--mem-size', memory,
                '--num-cpus', str(args.cpus),
                '--script', common.gem5_readfile,
            ]
            if args.arch == 'x86_64':
                if args.kvm:
                    cmd += ['--cpu-type', 'X86KvmCPU']
                cmd += ['--command-line', 'earlyprintk=ttyS0 console=ttyS0 lpj=7999923 root=/dev/sda {}'.format(kernel_cli)]
            elif args.arch == 'arm' or args.arch == 'aarch64':
                # TODO why is it mandatory to pass mem= here? Not true for QEMU.
                # Anything smaller than physical blows up as expected, but why can't it auto-detect the right value?
                cmd += [
                    '--command-line', 'earlyprintk=pl011,0x1c090000 console=ttyAMA0 lpj=19988480 rw loglevel=8 mem={} root=/dev/sda {}'.format(memory, kernel_cli),
                    '--dtb-file', os.path.join(common.gem5_system_dir, 'arm', 'dt', 'armv{}_gem5_v1_{}cpu.dtb'.format(common.armv, args.cpus)),
                    '--machine-type', 'VExpress_GEM5_V1',
                ]
    else:
        os.makedirs(common.run_dir, exist_ok=True)
        if args.debug_vm:
            serial_monitor = []
        else:
            serial_monitor = ['-serial', 'mon:stdio']
        if args.kvm:
            extra_emulator_args.append('-enable-kvm')
        if args.kgdb:
            extra_qemu_args.extend(['-serial', 'tcp::{},server,nowait'.format(common.gdb_port)])
        if args.prebuilt:
            common.mkdir()
            qemu_executable = "qemu-system-{}".format(args.arch)
        else:
            qemu_executable = common.qemu_executable
        extra_emulator_args = extra_qemu_args + args.extra_emulator_args
        cmd = (
            debug_vm +
            [
                qemu_executable,
                '-device', 'rtl8139,netdev=net0',
                '-gdb', 'tcp::{}'.format(common.gdb_port),
                '-kernel', common.linux_image,
                '-m', args.memory,
                '-monitor', 'telnet::{},server,nowait'.format(common.qemu_monitor_port),
                '-netdev', 'user,hostfwd=tcp::{}-:{},hostfwd=tcp::{}-:22,id=net0'.format(common.qemu_hostfwd_generic_port, common.qemu_hostfwd_generic_port, common.qemu_hostfwd_ssh_port),
                '-no-reboot',
                '-smp', str(args.cpus),
                '-trace', 'enable={},file={}'.format(trace_type, common.qemu_trace_file),
                '-virtfs', 'local,path={},mount_tag=host_scratch,security_model=mapped,id=host_scratch'.format(common.p9_dir),
                '-virtfs', 'local,path={},mount_tag=host_out,security_model=mapped,id=host_out'.format(common.build_dir),
            ] +
            serial_monitor +
            vnc
        )
        if args.initrd:
            extra_emulator_args.extend(['-initrd', os.path.join(common.images_dir, 'rootfs.cpio')])
        rr = args.record or args.replay
        if ramfs:
            # TODO why is this needed, and why any string works.
            root = 'root=/dev/anything'
        else:
            if rr:
                driveif = 'none'
                rrid = ',id=img-direct'
                root = 'root=/dev/sda'
                snapshot = ''
            else:
                driveif = 'virtio'
                root = 'root=/dev/vda'
                rrid = ''
                snapshot = ',snapshot'
            extra_emulator_args.extend([
                '-drive',
                'file={},format=qcow2,if={}{}{}'.format(common.qcow2_file, driveif, snapshot, rrid)
            ])
            if not os.path.exists(common.qcow2_file):
                raise Exception(
                    'Cannot find the qcow2 root filesystem. You must build QEMU\n'
                    'before building the root filesystem? That is needed because the qcow2\n' +
                    'is created with qemu-img. Tried to use: ' + qemu_executable
                )
            if rr:
                extra_emulator_args.extend([
                '-drive', 'driver=blkreplay,if=none,image=img-direct,id=img-blkreplay',
                '-device', 'ide-hd,drive=img-blkreplay'
            ])
        if rr:
            extra_emulator_args.extend([
                '-object', 'filter-replay,id=replay,netdev=net0',
                '-icount', 'shift=7,rr={},rrfile={}'.format('record' if args.record else 'replay', common.qemu_rrfile),
            ])
            virtio_gpu_pci = []
        else:
            virtio_gpu_pci = ['-device', 'virtio-gpu-pci']
        if args.arch == 'x86_64':
            if args.kgdb:
                kernel_cli += ' kgdboc=ttyS0,115200'
            cmd.extend([
                '-M', 'pc',
                '-append', '{} nopat {}'.format(root, kernel_cli),
                '-device', 'edu',
            ])
        elif args.arch == 'arm' or args.arch == 'aarch64':
            if args.kgdb:
                kernel_cli += ' kgdboc=ttyAMA0,115200'
            if args.arch == 'arm':
                cpu = 'cortex-a15'
            else:
                cpu = 'cortex-a57'
            # highmem=off needed since v3.0.0 due to:
            # http://lists.nongnu.org/archive/html/qemu-discuss/2018-08/msg00034.html
            cmd = (
                cmd +
                [
                    '-M', 'virt,highmem=off',
                    '-append', '{} {}'.format(root, kernel_cli),
                    '-cpu', cpu,
                ] +
                virtio_gpu_pci
            )
        if not os.path.exists(qemu_executable):
            raise Exception('QEMU executable does not exist, did you forget to build or install it?\n' +
                            'Tried to use: ' + qemu_executable)
    if args.tmux:
        if args.gem5:
            subprocess.Popen([os.path.join(common.root_dir, 'tmu'),
                'sleep 2;./gem5-shell -n {} {}' \
                .format(args.run_id, args.tmux_args)
            ])
        elif args.debug_guest:
            # TODO find a nicer way to forward all those args automatically.
            # Part of me wants to: https://github.com/jonathanslenders/pymux
            # but it cannot be used as a library properly it seems, and it is
            # slower than tmux.
            subprocess.Popen([os.path.join(common.root_dir, 'tmu'),
                "sleep 2;./rungdb -a '{}' -L '{}' -n '{}' {}" \
                .format(args.arch, args.linux_build_id, args.run_id, args.tmux_args)
            ])
    cmd += extra_emulator_args
    if debug_vm or args.terminal:
        out_file = None
    else:
        out_file = common.termout_file
    returncode = common.run_cmd(cmd, cmd_file=common.run_cmd_file, out_file=out_file, extra_env=extra_env)
    if returncode != 0:
        common.log_error('simulator exited with status != 0')
        return returncode
    # Check if guest panicked.
    if args.gem5:
        # We have to do some parsing here because gem5 exits with status 0 even when panic happens.
        # Grepping for '^panic: ' does not work because some errors don't show that message.
        panic_msg = '--- BEGIN LIBC BACKTRACE ---$'
    else:
        panic_msg = 'Kernel panic - not syncing'
    panic_re = re.compile(panic_msg)
    with open(common.termout_file, 'r') as logfile:
        for line in logfile:
            if panic_re.search(line):
                common.log_error('simulation error detected by parsing logs')
                return 1
    return 0

def get_argparse():
    parser = common.get_argparse(argparse_args={'description':'Run Linux on an emulator'})
    init_group = parser.add_mutually_exclusive_group()
    kvm_group = parser.add_mutually_exclusive_group()
    parser.add_argument(
        '-c', '--cpus', default=defaults['cpus'], type=int,
        help='Number of guest CPUs to emulate. Default: %(default)s'
    )
    parser.add_argument(
        '-D', '--debug-vm', default=defaults['debug_vm'], action='store_true',
        help='Run GDB on the emulator itself.'
    )
    kvm_group.add_argument(
        '-d', '--debug-guest', default=defaults['debug_guest'], action='store_true',
        help='Wait for GDB to connect before starting execution'
    )
    parser.add_argument(
        '-E', '--eval',
        help='''\
Replace the normal init with a minimal init that just evals the given string.
See: https://github.com/cirosantilli/linux-kernel-module-cheat#replace-init
'''
    )
    parser.add_argument(
        '-e', '--kernel-cli',
        help='''\
Pass an extra Linux kernel command line options, and place them before
the dash separator `-`. Only options that come before the `-`, i.e.
"standard" options, should be passed with this option.
Example: `./run -a arm -e 'init=/poweroff.out'`
'''
    )
    parser.add_argument(
        '-F', '--eval-busybox',
        help='''\
Pass a base64 encoded command line parameter that gets evalled by the Busybox init.
See: https://github.com/cirosantilli/linux-kernel-module-cheat#init-busybox
'''
    )
    parser.add_argument(
        '-f', '--kernel-cli-after-dash',
        help='''\
Pass an extra Linux kernel command line options, add a dash `-`
separator, and place the options after the dash. Intended for custom
options understood by our `init` scripts, most of which are prefixed
by `lkmc_`.
Example: `./run -f 'lkmc_eval="wget google.com" lkmc_lala=y'`
Mnenomic: `-f` comes after `-e`.
'''
    )
    parser.add_argument(
        '-G', '--gem5-exe-args', default=defaults['gem5_exe_args'],
        help='''\
Pass extra options to the gem5 executable.
Do not confuse with the arguments passed to config scripts,
like `fs.py`. Example:
./run -G '--debug-flags=Exec --debug' --gem5 -- --cpu-type=HPI --caches
will run:
gem.op5 --debug-flags=Exec fs.py --cpu-type=HPI --caches
'''
    )
    parser.add_argument(
        '--gem5-biglittle', default=defaults['gem5_biglittle'], action='store_true',
        help='Use fs_bigLITTLE.py instead of fs.py'
    )
    parser.add_argument(
        '--gem5-readfile', default=defaults['gem5_readfile'],
        help='Set the contents of m5 readfile to this string.'
    )
    init_group.add_argument(
        '-I', '--initramfs', default=defaults['initramfs'], action='store_true',
        help='Use initramfs instead of a root filesystem'
    )
    init_group.add_argument(
        '-i', '--initrd', default=defaults['initrd'], action='store_true',
        help='Use initrd instead of a root filesystem'
    )
    kvm_group.add_argument(
        '-K', '--kvm', default=defaults['kvm'], action='store_true',
        help='Use KVM. Only works if guest arch == host arch'
    )
    parser.add_argument(
        '-k', '--kgdb', default=defaults['kgdb'], action='store_true'
    )
    parser.add_argument(
        '-l', '--gem5-restore', type=int,
        help='''\
Restore the nth most recently taken gem5 checkpoint according to directory
timestamps.
'''
    )
    parser.add_argument(
        '-m', '--memory', default=defaults['memory'],
        help='''\
Set the memory size of the guest. E.g.: `-m 512M`. We try to keep the default
at the minimal ammount amount that boots all archs. Anything lower could lead
some arch to fail to boot.
Default: %(default)s
'''
    )
    parser.add_argument(
        '-P', '--prebuilt', default=defaults['prebuilt'], action='store_true',
        help='Run the downloaded prebuilt images.'
    )
    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        '-R', '--replay', default=defaults['replay'], action='store_true',
        help='Replay a QEMU run record deterministically'
    )
    group.add_argument(
        '-r', '--record', default=defaults['record'], action='store_true',
        help='Record a QEMU run record for later replay with `-R`'
    )
    parser.add_argument(
        '-T', '--trace',
        help='''\
Set trace events to be enabled. If not given, gem5 tracing is completely
disabled, while QEMU tracing is enabled but uses default traces that are very
rare and don't affect performance, because `./configure
--enable-trace-backends=simple` seems to enable some traces by default, e.g.
`pr_manager_run`, and I don't know how to get rid of them.
'''
    )
    init_group.add_argument(
        '--terminal', default=defaults['terminal'], action='store_true',
        help='''Output to the terminal, don't pipe to tee as the default.
Does not save the output to a file, but allows you to use debuggers.
Set automatically by --debug-vm, but you still need this option to debug
gem5 Python scripts.
'''
    )
    parser.add_argument(
        '-U', '--tmux-args', default=defaults['tmux_args'],
        help='Pass extra parameters to the program running on the `-u` tmux split'
    )
    parser.add_argument(
        '-u', '--tmux', default=defaults['tmux'], action='store_true',
        help='''\
Create a tmUx split the window. You must already be inside of a `tmux` session
to use this option:
* on the main window, run the emulator as usual
* on the split:
** if on QEMU and `-d` is given, GDB
** if on gem5, the gem5 terminal
'''
    )
    parser.add_argument(
        '-x', '--graphic', default=defaults['graphic'], action='store_true',
        help='Run in graphic mode. Mnemonic: X11'
    )
    parser.add_argument(
        '-V', '--vnc', default=defaults['vnc'], action='store_true',
        help='''\
Run QEMU with VNC instead of the default SDL. Connect to it with:
`vinagre localhost:5900`.
'''
    )
    parser.add_argument(
        'extra_emulator_args', nargs='*', default=defaults['extra_emulator_args'],
        help='Extra options to append at the end of the emulator command line'
    )
    return parser

if __name__ == '__main__':
    parser = get_argparse()
    args = common.setup(parser)
    sys.exit(main(args))

path: run


code:
#!/usr/bin/env bash
set -eu
cmd="${1:-start}"
shift
container_name=lkmc
target_dir=/root/linux-kernel-module-cheat
if [ "$cmd" = start ]; then
  sudo docker start -ai "$container_name"
elif [ "$cmd" = sh ]; then
  # https://stackoverflow.com/questions/39794509/how-to-open-multiple-terminals-in-docker
  sudo docker exec -it "$container_name" bash "$@"
elif [ "$cmd" = setup ]; then
  # --privileged for KVM:
  # https://stackoverflow.com/questions/48422001/launching-qemu-kvm-from-inside-docker-container
  sudo docker run --name "$container_name" --net host -i --privileged -t -w "${target_dir}" -v "$(pwd):${target_dir}" ubuntu:16.04 bash
elif [ "$cmd" = DELETE ]; then
  sudo docker rm "$container_name"
else
  echo "error: unknown action: ${cmd}" 1>&2
  exit 2
fi

path: rundocker


code:
#!/usr/bin/env python3

import os
import shlex
import sys
import signal
import subprocess

import common

defaults = {
    'after': '',
    'before': '',
    'no_continue': False,
    'kgdb': False,
    'no_lxsymbols': False,
    'break_at': None,
}

def main(args, extra_args=None):
    '''
    :param args: argparse parse_argument() output. Must contain all the common options,
                 but does not need GDB specific ones.
    :type args: argparse.Namespace

    :param extra_args: extra arguments to be added to args
    :type extra_args: Dict[str,Any]

    :return: GDB exit status
    :rtype: int
    '''
    global defaults
    args = common.resolve_args(defaults, args, extra_args)
    after = shlex.split(args.after)
    before = shlex.split(args.before)
    if args.no_lxsymbols:
        lx_symbols = []
    else:
        lx_symbols = ['-ex', 'lx-symbols ../kernel_modules-1.0/']
    if args.break_at is not None:
        break_at = ['-ex', 'break {}'.format(args.break_at)]
    else:
        break_at = []
    cmd = (
        [
            os.path.join(common.host_bin_dir,
            '{}-linux-gdb'.format(args.arch))
        ] +
        before +
        [
            '-q',
            '-ex', 'add-auto-load-safe-path {}'.format(common.linux_variant_dir),
            '-ex', 'file {}'.format(common.vmlinux),
            '-ex', 'target remote localhost:{}'.format(common.gdb_port),
        ]
    )
    if not args.kgdb:
        cmd.extend(break_at)
    if not args.no_continue:
        # ## lx-symbols
        #
        # ### lx-symbols after continue
        #
        # lx symbols must be run after continue.
        #
        # running it immediately after the connect on the bootloader leads to failure,
        # likely because kernel structure on which it depends are not yet available.
        #
        # With this setup, continue runs, and lx-symbols only runs when a break happens,
        # either by hitting the breakpoint, or by entering Ctrl + C.
        #
        # Sure, if the user sets a break on a raw address of the bootloader,
        # problems will still arise, but let's think about that some other time.
        #
        # ### lx-symbols autoload
        #
        # The lx-symbols commands gets loaded through the file vmlinux-gdb.py
        # which gets put on the kernel build root when python debugging scripts are enabled.
        cmd.extend(['-ex', 'continue'] + lx_symbols)
    cmd.extend(after)
    return common.run_cmd(cmd, cmd_file=os.path.join(common.run_dir, 'rungdb.sh'), cwd=common.linux_variant_dir)

if __name__ == '__main__':
    parser = common.get_argparse(argparse_args={'description': 'Connect with GDB to an emulator to debug Linux itself'})
    parser.add_argument(
        '-A', '--after', default=defaults['after'],
        help='Pass extra arguments to GDB, to be appended after all other arguments'
    )
    parser.add_argument(
        '-b', '--before', default=defaults['before'],
        help='Pass extra arguments to GDB to be prepended before any of the arguments passed by this script'
    )
    parser.add_argument(
        '-C', '--no-continue', default=defaults['no_continue'], action='store_true',
        help="Don't run continue after connecting"
    )
    parser.add_argument(
        '-k', '--kgdb', default=defaults['kgdb'], action='store_true'
    )
    parser.add_argument(
        '-X', '--no-lxsymbols', default=defaults['no_lxsymbols'], action='store_true'
    )
    parser.add_argument(
        'break_at', nargs='?',
        help='Extra options to append at the end of the emulator command line'
    )
    args = common.setup(parser)
    sys.exit(main(args))

path: rungdb


code:
#!/usr/bin/env python3

import imp
import os
import sys

import common
rungdb = imp.load_source('rungdb', os.path.join(common.root_dir, 'rungdb'))

parser = common.get_argparse(argparse_args={
    'description': '''GDB step debug guest userland processes without gdbserver.

More information at: https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-step-debug-userland-processes
'''
})
parser.add_argument(
    'executable',
    help='Path to the executable to be debugged relative to the Buildroot build directory.'
)
parser.add_argument(
    'break',
    default=None,
    help='Break at this point, e.g. main.',
    nargs='?'
)
args = common.setup(parser)
addr = common.get_elf_entry(os.path.join(common.build_dir, args.executable))
extra_args = {}
extra_args['before'] = '-ex \"add-symbol-file {} {}\"'.format(args.executable, hex(addr))
# Or else lx-symbols throws for arm:
# gdb.MemoryError: Cannot access memory at address 0xbf0040cc
# TODO understand better.
# Also, lx-symbols overrides the add-symbol-file commands.
extra_args['no_lxsymbols'] = True
sys.exit(rungdb.main(args, extra_args))

path: rungdb-user


code:
#!/usr/bin/env python3

import glob
import os
import subprocess
import sys

import common

parser = common.get_argparse(argparse_args={
    'description':'Connect to gdbserver running on the guest.'
})
parser.add_argument(
    'executable',
    help='Path to the executable to be debugged relative to the Buildroot build directory.'
)
args = common.setup(parser)
sys.exit(subprocess.Popen([
  common.get_toolchain_tool('gdb'),
  '-q',
  '-ex', 'set sysroot {}'.format(common.staging_dir),
  '-ex', 'target remote localhost:{}'.format(common.qemu_hostfwd_generic_port),
  '-ex', 'tbreak main',
  '-ex', 'continue',
  os.path.join(common.build_dir, args.executable),
]).wait())

path: rungdbserver


code:
#!/usr/bin/env python3

import os
import subprocess
import sys

import common

parser = common.get_argparse(argparse_args={
    'description': '''Run a Buildroot ToolChain tool like readelf or objdump.

For example, to get some information about the arm vmlinux:

....
./%(prog)s readelf -- -e "$(./getvar vmlinux)"
....

Get the list of available tools with:

....
ls "$(./getvar -a arm host_bin_dir)"
....
'''
})
parser.add_argument(
    '--dry',
    help='Just output the tool path to stdout but actually run it',
    action='store_true',
)
parser.add_argument('tool', help='Which tool to run.')
parser.add_argument(
    'extra_args',
    default=[],
    help='Extra arguments for the tool.',
    metavar='extra-args',
    nargs='*'
)
args = common.setup(parser)
if args.dry:
    print(common.get_toolchain_tool(args.tool))
else:
    sys.exit(common.run_cmd(
        [common.get_toolchain_tool(args.tool)] + args.extra_args,
        cmd_file=os.path.join(common.run_dir, 'runtc.sh'),
        cwd=common.linux_variant_dir,
        show_cmd=False,
    ))

path: runtc


code:
#!/usr/bin/env bash
set -eu
./bench-boot -t "${1:-1}"
./run -F '/test_all.sh;/poweroff.out' | grep -q lkmc_test_pass

path: test


code:
#!/usr/bin/env bash
if [ "$(tmux list-panes | wc -l | cut -d' ' -f1)" -ne 1 ]; then
  tmux kill-pane -t 1
fi
# https://unix.stackexchange.com/questions/439031/how-to-split-the-window-that-ran-the-tmux-split-window-command-instead-of-the/439032#439032
tmux split-window -dh -t "$TMUX_PANE" "bash --rcfile <(echo '. ~/.bashrc;$*')"

path: tmu


code:
#!/usr/bin/env python3

import imp
import os
import subprocess
import re

import common
run = imp.load_source('run', os.path.join(common.root_dir, 'run'))
qemu_trace2txt = imp.load_source('qemu_trace2txt', os.path.join(common.root_dir, 'qemu-trace2txt'))

parser = common.get_argparse(argparse_args={
    'description': '''Trace the PIC addresses executed on a Linux kernel boot.

More information at: https://github.com/cirosantilli/linux-kernel-module-cheat#tracing
'''
})
parser.add_argument(
    'extra_emulator_args', nargs='*',
    help='Extra options to append at the end of the emulator command line'
)
args = common.setup(parser)
extra_args = {
    'extra_emulator_args': args.extra_emulator_args,
}
if args.gem5:
    extra_args.update({
        'eval': 'm5 exit',
        'trace': 'Exec,-ExecSymbol,-ExecMicro',
    })
    run.main(args, extra_args)
else:
    extra_args.update({
        'kernel_cli_extra': 'init=/poweroff.out',
        'trace': 'exec_tb',
    })
    run.main(args, extra_args)
    qemu_trace2txt.main()
    # Instruction count.
    # We could put this on a separate script, but it just adds more arch boilerplate to a new script.
    # So let's just leave it here for now since it did not add a significant processing time.
    kernel_entry_addr = hex(common.get_elf_entry(common.vmlinux))
    nlines = 0
    nlines_firmware = 0
    with open(common.qemu_trace_txt_file, 'r') as trace_file:
        in_firmware = True
        for line in trace_file:
            line = line.rstrip()
            nlines += 1
            pc = line.split('=')[-1]
            if pc == kernel_entry_addr:
                in_firmware = False
            if in_firmware:
                nlines_firmware += 1
    print('''\
instructions {}
entry_address {}
instructions_firmware {}\
'''.format(
        nlines,
        kernel_entry_addr,
        nlines_firmware
    ))

path: trace-boot


code:
#!/usr/bin/env python3

'''
TODO port this to Python fully. I started it, but then it was hanging on some
IO blocking annoyance in the pipeline, and I don't have the time to deal with
it, so I'm just going to forward the common options to the old shell script for
now...
'''

import os
import re
import subprocess
import sys

import common

parser = common.get_argparse(argparse_args={
    'description': 'Convert an execution trace containing PC values into the Linux kernel linex executed'
})
args = common.setup(parser)
sys.exit(subprocess.Popen([
    os.path.join(common.root_dir, 'trace2line.sh'),
    'true' if args.gem5 else 'false',
    common.trace_txt_file,
    common.get_toolchain_tool('addr2line'),
    common.vmlinux,
    common.run_dir,
]).wait())

# This was the full conversion attempt.

# if args.gem5:
#     def get_pc(line):
#         # TODO
#         # stdin = sed -r 's/^.* (0x[^. ]*)[. ].*/\1/' "$common_trace_txt_file")
#         pass
# else:
#     def get_pc(line):
#         return line.split('=')[-1]
# with \
#         subprocess.Popen(
#             [
#                 common.get_toolchain_tool('addr2line'),
#                 '-e',
#                 common.vmlinux,
#                 '-f',
#                 '-p',
#             ],
#             stdout=subprocess.PIPE,
#             stdin=subprocess.PIPE,
#         ) as proc, \
#         open(common.trace_txt_file, 'r') as infile, \
#         open(os.path.join(common.run_dir, 'trace-lines.txt'), 'w') as outfile \
#     :
#     for in_line in infile:
#         proc.stdin.write(get_pc(in_line).encode())
#         proc.stdin.flush()
#         stdout = proc.stdout.read()
#         outfile.write(stdout.decode())
#     # TODO
#     # sed -E "s|at ${common.linux_build_dir}/(\./\|)||"
#     # uniq -c


code:
#!/usr/bin/env bash
set -eu
common_gem5="$1"
shift
common_trace_txt_file="$1"
shift
common_addr2line="$1"
shift
common_vmlinux="$1"
shift
common_run_dir="$1"
shift
(
  if "$common_gem5"; then
    sed -r 's/^.* (0x[^. ]*)[. ].*/\1/' "$common_trace_txt_file"
  else
    sed -r 's/.*pc=//' "$common_trace_txt_file"
  fi
) | \
  xargs "${common_addr2line}" -e "${common_vmlinux}" -fp | \
  sed -E "s|at ${common_vmlinux}/(\./\|)||" | \
  uniq -c \
> "${common_run_dir}/trace-lines.txt"


code: user0 -1 user0 -1 =a /home/user0 /bin/sh - user0


code:
#!/usr/bin/env bash
vinagre localhost:5900

path: vnc


code:
#!/usr/bin/env python3

import os
import subprocess
import zipfile

import common

outfile = os.path.join(common.out_dir, 'lkmc-{}.zip'.format(common.sha))
if os.path.exists(outfile):
    os.unlink(outfile)
zipf = zipfile.ZipFile(outfile, 'w', zipfile.ZIP_DEFLATED)
for arch in common.arches:
    common.setup(common.get_argparse(default_args={'arch': arch}))
    zipf.write(common.qcow2_file, arcname=os.path.relpath(common.qcow2_file, common.root_dir))
    zipf.write(common.linux_image, arcname=os.path.relpath(common.linux_image, common.root_dir))
zipf.close()

path: zip-img


code:
.POSIX:

array: array.c

clean:
	rm -f *.o array

repo_name: jkaivo/array

path: Makefile


code:
# array

translate files to C arrays

## Synopsis

`array [-s] [-q qualifier] [file...]`

## Description

The `array` utility translates its input into C arrays (of a qualified type
of `char`) that can then be used (via `#include`) in larger C programs.
This is useful if you need to embed a binary (e.g. an image) or text (e.g.
a template) file and need to ship a program as a single, self-contained
executable.

## Options

The `array` utility conforms to the XBD Utility Syntax Guidelines. It supports
the following options:

`-s`	Include an additional identifier in the output indicating
	the size of the array. See STDOUT below for a detailed
	description.

`-q`	Apply the C type qualifier `qualifier` to the generated array. If
	none is provided, the default is `unsigned`. To remove any qualifiers
	altogether (e.g. to declare an array of `char`), specify the empty
	string (e.g. `-q ''`).

## Operands

The `array` utility supports the following operands:

`file`	A pathname of an input file. If `-` is specified, `array`
	reads from the standard input.

## STDIN

The standard input is used if no `file` operands are provided or if `-` is
specified as an operand.

## Input Files

Input files are treated as raw binary streams, with no requirements on format.

## STDOUT

A definition of a C array of type qualified `char` and unspecified length, with
members initialized to the bytes of the input file. Each array is named with
the name of the input file, except all non alphanumeric characters (as
identified by the function `isalnum()`) are translated to `_`. If the input
file is the standard input, the name of the array is `stdin`.

If the `-s` option is specified, the standard output also includes the
definition of a size identifier. This identifier has the same name as the
array, suffixed with `_size`, and type `size_t`.

## STDERR

The standard error is used for printing diagnostic messages.

## Output Files

None.

## Extended Description

None.

## Exit Status

 0	Successful completion.
 >0	An error occurred.

## Consequence of Errors

If one or more input files cannot be opened, `array` will print a diagnostic
message to standard error and that file will not produe any output to
standard output.


code:
#define _POSIX_C_SOURCE 2
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define CHARS_PER_LINE 8

int make_array(const char *path, const char *qual, int include_size)
{
	FILE *f = stdin;

	if (path && strcmp(path, "-") != 0) {
		f = fopen(path, "rb");
		if (f == NULL) {
			perror(path);
			return 1;
		}
	} else {
		path = "stdin";
	}

	size_t plen = strlen(path);
	char id[plen + 1];
	for (size_t i = 0; i < plen; i++) {
		id[i] = isalnum(path[i]) ? path[i] : '_';
	}
	id[plen] = '\0';

	if (qual && strlen(qual) > 0) {
		printf("%s ", qual);
	}
	printf("char %s[] = {\n", id);

	int c;
	int i = 0;
	while ((c = fgetc(f)) != EOF) {
		if (i == 0) {
			putchar('\t');
		}
		printf("0x%02hhx, ", c);
		if (++i == CHARS_PER_LINE) {
			putchar('\n');
			i = 0;
		}
	}

	if (i != 0) {
		putchar('\n');
	}

	printf("};\n");

	if (include_size) {
		printf("size_t %s_size = sizeof(%s);\n", id, id);
	}

	if (f != stdin) {
		fclose(f);
	}

	return 0;
}

int main(int argc, char *argv[])
{
	char *qual = "unsigned";
	int include_size = 0;
	int c;

	while ((c = getopt(argc, argv, "sq:")) != -1) {
		switch (c) {
		case 's':
			include_size = 1;
			break;

		case 'q':
			qual = optarg;
			break;

		default:
			return 1;
		}
	}

	int ret = 0;
	do {
		ret |= make_array(argv[optind++], qual, include_size);
	} while (optind < argc);

	return ret;
}


code:
/*
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef QBLUETOOTH_H
#define QBLUETOOTH_H

#include <QBtAuxFunctions.h>
#include <QBtGlobal.h>

#include <QBtTypes.h>
#include <QBtDeviceDiscoverer.h>
#include <QBtSingleDeviceSelectorUI.h>
#include <QBtServiceDiscoverer.h>
#include <QBtServiceDiscovererForAll.h>
#include <QBtServiceAdvertiser.h>
#include <QBtSerialPortServer.h>
#include <QBtSerialPortClient.h>
#include <QBtObjectExchangeClient.h>
#include <QBtObjectExchangeServer.h>
#include <QBtLocalDevice.h>

//using namespace QBluetooth;

namespace QBluetooth
{
    static void registerTypes()
    {
        qRegisterMetaType<QBT_PREPEND_NAMESPACE(QBtDevice)>("QBtDevice");
        qRegisterMetaType<QBT_PREPEND_NAMESPACE(QBtService)>("QBtService");
        qRegisterMetaType<QBT_PREPEND_NAMESPACE(QBtAddress)>("QBtAddress");
        qRegisterMetaType<QBT_PREPEND_NAMESPACE(QBtUuid)>("QBtUuid");
        qRegisterMetaType<QBT_PREPEND_NAMESPACE(QBtRemoteFileInfo)>("QBtRemoteFileInfo");
    }

    static void registerQMLTypes()
    {
       /* #if QT_VERSION > 0x040700
        qmlRegisterType<QBT_PREPEND_NAMESPACE(QBtConstants)>(QML_LIBRARY_NAME, 1, 0, "QBtConstants");
        qmlRegisterType<QBT_PREPEND_NAMESPACE(QBtUuid)>(QML_LIBRARY_NAME, 1, 0, "QBtUuid");
        qmlRegisterType<QBT_PREPEND_NAMESPACE(QBtAddress)>(QML_LIBRARY_NAME, 1, 0, "QBtAddress");
        qmlRegisterType<QBT_PREPEND_NAMESPACE(QBtDevice)>(QML_LIBRARY_NAME, 1, 0, "QBtDevice");
        qmlRegisterType<QBT_PREPEND_NAMESPACE(QBtService)>(QML_LIBRARY_NAME, 1, 0, "QBtService");
        qmlRegisterType<QBT_PREPEND_NAMESPACE(QBtDeviceDiscoverer)>(QML_LIBRARY_NAME, 1, 0, "QBtDeviceDiscoverer");
        qmlRegisterType<QBT_PREPEND_NAMESPACE(QBtRemoteFileInfo)>(QML_LIBRARY_NAME, 1, 0, "QBtRemoteFileInfo");
        //qmlRegisterType<QBtServiceDiscoverer>("QBtServiceDiscoverer", 1, 0, "QBtServiceDiscoverer");
        //qmlRegisterType<QBtServiceAdvertiser>("QBtServiceAdvertiser", 1, 0, "QBtServiceAdvertiser");
        //qmlRegisterType<QBtLocalDevice>("QBtLocalDevice", 1, 0, "QBtLocalDevice");
        //qmlRegisterType<QBtSingleDeviceSelectorUI>("QBtSingleDeviceSelectorUI", 1, 0, "QBtSingleDeviceSelectorUI");
        //qmlRegisterType<QBtSerialPortServer>("QBtSerialPortServer", 1, 0, "QBtSerialPortServer");
        //qmlRegisterType<QBtSerialPortClient>("QBtSerialPortClient", 1, 0, "QBtSerialPortClient");
        //qmlRegisterType<QBtObjectExchangeServer>("QBtObjectExchangeServer", 1, 0, "QBtObjectExchangeServer");
        //qmlRegisterType<QBtObjectExchangeClient>("QBtObjectExchangeClient", 1, 0, "QBtObjectExchangeClient");
        #endif*/
    }

}

#endif // QBLUETOOTH_H

repo_name: snapshot/qbluetooth

license: unknown


code:
/*
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef QBTADDRESS_H
#define QBTADDRESS_H

#include <QtCore/QString.h>
#include <QtCore/QByteArray.h>
#include <QBtGlobal.h>

#ifdef Q_OS_SYMBIAN
#include <bttypes.h>
#endif

QBT_NAMESPACE_BEGIN

/**
 * Class that represents the device's bluetooth _address.
 * It is one of the main fields of QBtDevice.
 */
class DLL_EXPORT QBtAddress : public QObject
{
	Q_OBJECT
	Q_PROPERTY(QString _address READ toString)// WRITE setName)

public:

    /**
     * QBtAddress()
     * Default constructor.
     */
    QBtAddress();

    /**
     * QBtAddress()
     * Copy constructor
     */
    QBtAddress (const QBtAddress& other);

    QBtAddress (const QByteArray& byteArray);
    QBtAddress (const QString& addr);

#ifdef Q_OS_SYMBIAN
    QBtAddress (const TBTDevAddr& addr);
#endif
    /**
     * Mainly created because on windows bluesoleil sdk, bluetooth _address
     * byte array is reversed so it is usefull to provide this functionality
     * here
     *
     * @param reversedArray
     */
    static QBtAddress& getAddressFromReversedArray (const QByteArray & reversedArray);

    ~QBtAddress ();

    /**
     * @return true if the _address contained in this instance is
     * a valid bluetooth _address
     */
    bool isValid () const;

    /**
     * Returns a string representation of this bluetooth _address
     */
    QString toString() const;

    /**
     * Returns a 6-byte array representation of the bluetooth _address
     */
    QByteArray toByteArray() const; // Symbian representation

    /**
     * Returns a 6-byte array representation of the bluetooth _address
     * in reversed order. Mainly created for convenience when using
     * windows bluesoleil SDK.
     */
    QByteArray toReversedByteArray() const; // windows representation

    QBtAddress& operator= (const QBtAddress & other );
    bool operator!= (const QBtAddress & other );
    bool operator== (const QBtAddress & other );
    bool operator< (const QBtAddress & other );

#ifdef Q_OS_SYMBIAN
    TBTDevAddr convertToSymbianBtDevAddr() const;
#endif

private:
    QString _address;
    bool _valid;
};

QBT_NAMESPACE_END

Q_DECLARE_METATYPE(QBT_PREPEND_NAMESPACE(QBtAddress))

#endif // QBTADDRESS_H


code:
/*
 * auxFunctions_symbian.h
 *
 *      Author: Ftylitakis Nikolaos, Luis Valente
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef AUXFUNCTIONS_SYMBIAN_H_
#define AUXFUNCTIONS_SYMBIAN_H_

#include <QBtGlobal.h>

QBT_NAMESPACE_BEGIN

template <class T> inline void SafeDelete(T* &ptr)
{
	if(ptr)
	{
		delete ptr;
		ptr = 0;
	}
}

//#ifdef Q_OS_SYMBIAN
#include <QtCore/QString>
#include <QtGui/QMessageBox>
#include <QtCore/QDir>
#include <QtCore/QDebug.h>

inline void _Debug_Msg (const QString & m, const QString & file, int line)
{
    qDebug() << "file: " << file << " line: " << line << " " << m;
}

inline void _Assert_Msg (const QString msg, const QString & file, int line)
{
    // strip directory info
    int index = file.lastIndexOf("/");
    QString f = file.mid (index+1);
    QString m = QString ("file: %1 line: %2\n%3").arg (f).arg(line).arg(msg);

    //
    _Debug_Msg (m, file, line);

    //
    QMessageBox::information(0, "assert failed", m);
    Q_ASSERT (false);
}

inline void _Assert_Msg2 (const QString & msg1, const QString & msg2, const QString & file, int line)
{
   _Assert_Msg (QString("%1 : %2").arg(msg1).arg(msg2), file, line);
}

inline void _Break_Here (const QString & file, int line)
{
    // strip directory info
    int index = file.lastIndexOf("/");
    QString f = file.mid (index+1);
    QString m = QString ("file: %1 line: %2").arg (f).arg (line);

    //
    _Debug_Msg (m, file, line);

    //
    QMessageBox::information(0, "code break", m);
    Q_ASSERT (false);
}

inline void _Break_Here (const QString & file, const QString & line)
{
	// strip directory info
	int index = file.lastIndexOf("/");
	QString f = file.mid (index+1);
	QString m = QString ("file: %1 line: %2").arg (f, line);

	QMessageBox::information(0, "code break", m);
	Q_ASSERT (false);
}

#ifdef QT_DEBUG
    #define BT_DEBUG_MSG(msg) (_Debug_Msg((msg),__FILE__,__LINE__) )
    #define BT_BREAK_HERE() (_Break_Here(__FILE__, QString::number(__LINE__)) )
    #define BT_ASSERT_MSG(test, msg) ((!(test)) ? _Assert_Msg((msg), __FILE__, __LINE__) : qt_noop() )
    #define BT_ASSERT_MSG2(test, msg1, msg2) ((!(test)) ? _Assert_Msg2((msg1), (msg2), __FILE__, __LINE__) : qt_noop() )

#else

    #define BT_DEBUG_MSG(msg) {}
    #define BT_ASSERT_MSG_X(test, where, msg) {}
    #define BT_ASSERT_MSG(test, msg) {}
    #define BT_ASSERT_MSG2(test, msg1, msg2) {}
    #define BT_BREAK_HERE() {}

//#endif

#endif

#ifdef Q_OS_WIN32

#include <windows.h>
#include <conio.h>
#include <QBtAddress.h>

using namespace std;

// used to have the number of the classes that use the Bluesoleil SDK.
// if the number reaches zero the sdk is deinitialized.
static size_t sdkInitializationCounter = 0;

//forward declaration

#ifdef BLUETOOTH_LIB
extern "C"{
#include "./BlueSoleil_SDK_2.0.5/include/Btsdk_ui.h"
}
#else
class BTDEVHDL;
#endif

class DLL_EXPORT QBtAuxFunctions
{
public:
    static bool InitBthSdk();
    static void DeinitBthSdk();
    static BTDEVHDL GetDeviceHandle(const QBtAddress& address);
};

#endif // Q_OS_WIN32

QBT_NAMESPACE_END
#endif /* AUXFUNCTIONS_SYMBIAN_H_ */


code:
/*
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef QBTCONSTANTS_H
#define QBTCONSTANTS_H

#include <QBtGlobal.h>

QBT_NAMESPACE_BEGIN

/**
 * Basic enumerations of bluetooth UUIDs
 */
class DLL_EXPORT QBtConstants : public QObject
{
	Q_OBJECT
	Q_ENUMS(ServiceClass)
	Q_ENUMS(ServiceProtocol)
public:

    /**
     * Short UUIDs for standard services, as unsigned integers.
     */
    enum ServiceClass
    {
            UndefinedClass = 0x0000,
            SerialPort = 0x1101,
            LANAccessUsingPPP,
            DialupNetworking,
            IrMCSync,
            OBEXObjectPush,
            OBEXFileTransfer,
            IrMCSyncCommand,
            Headset,
            CordlessTelephony,
            AudioSource,
            AudioSink,
            RemoteControlTarget,
            AdvancedAudioDistribution,
            AV_RemoteControl,
            VideoConferencing,
            Intercom,
            Fax,
            HeadsetAudioGateway,
            WAP,
            WAP_CLIENT,
            PANU,
            NAP,
            GN,
            DirectPrinting,
            ReferencePrinting,
            Imaging,
            ImagingResponder,
            ImagingAutomaticArchive,
            ImagingReferencedObjects,
            Handsfree,
            HandsfreeAudioGateway,
            DirectPrintingReferenceObjectsService,
            ReflectedUI,
            BasicPrinting,
            PrintingStatus,
            HumanInterfaceDeviceService,
            HardcopyCableReplacement,
            HCR_Print,
            HCR_Scan,
            Common_ISDN_Access,
            VideoConferencingGW,
            UDI_MT,
            UDI_TA,
            Audio_Video,
            SIM_Access,
            PnPInformation,
            GenericNetworking,
            GenericFileTransfer,
            GenericAudio,
            GenericTelephony,
            UPNP_Service,
            UPNP_IP_Service,
            ESDP_UPNP_IP_PAN,
            ESDP_UPNP_IP_LAP,
            ESDP_UPNP_L2CAP,

            MY_CUSTOM = 0x10ff
        };

    /**
     * Short UUIDs for standard protocols.
     */
    enum ServiceProtocol
    {
            UndefinedProtocol 	= 0x0000,
            SDP,
            UDP,
            RFCOMM,
            TCP,
            TCS_BIN,
            TCS_AT,
            OBEX 		= 0x0008,
            IP,
            FTP,
            HTTP		= 0x000C,
            WSP			= 0x000E,
            BNEP,
            UPNP,
            HIDP,
            HardcopyControlChannel,
            HardcopyDataChannel = 0x0014,
            HardcopyNotification = 0x0016,
            AVCTP,
            AVDTP = 0x0019,
            CMPT = 0x001B,
            UDI_C_Plane = 0x001D,
            L2CAP = 0x0100
        };
};

QBT_NAMESPACE_END

Q_DECLARE_METATYPE(QBT_PREPEND_NAMESPACE(QBtConstants::ServiceClass))
Q_DECLARE_METATYPE(QBT_PREPEND_NAMESPACE(QBtConstants::ServiceProtocol))

#endif // QBTCONSTANTS_H