├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── docker └── base │ └── Dockerfile ├── kernel ├── initramfs │ ├── CMakeLists.txt │ ├── common.h │ ├── dart.c │ ├── fuzzer.inc │ ├── init.c │ ├── log.c │ ├── prog-cont │ │ └── main.c │ ├── prog-fuzz │ │ └── main.c │ ├── prog-prep │ │ └── main.c │ ├── prog-test │ │ ├── ltp.h │ │ ├── ltp_common.h │ │ ├── ltp_output.c │ │ ├── ltp_output.h │ │ ├── ltp_safe_op_file.c │ │ ├── ltp_safe_op_file.h │ │ ├── ltp_safe_op_user.c │ │ ├── ltp_safe_op_user.h │ │ └── main.c │ ├── shared.inc │ ├── strace.c │ ├── strace.h │ └── util.c ├── ktsan.patch ├── racer.patch └── spec │ ├── .gitignore │ ├── CMakeLists.txt │ ├── codegen.py │ ├── common.h │ ├── main.cpp │ └── type_int.h ├── pass ├── CMakeCache.txt ├── CMakeFiles │ └── cmake.check_cache ├── CMakeLists.txt ├── codegen.py ├── dart │ ├── .gitignore │ ├── Makefile │ ├── apidef.inc │ ├── dart.h │ ├── dart_common.h │ ├── dart_ctrl.c │ ├── dart_ctrl.h │ ├── dart_hash.h │ ├── dart_kernel.h │ ├── dart_log.c │ ├── dart_log.h │ ├── dart_ptid.h │ ├── dart_wks.c │ ├── dart_wks.h │ ├── rt_async.inc │ ├── rt_cov.inc │ ├── rt_ctxt.inc │ ├── rt_event.inc │ ├── rt_exec.inc │ ├── rt_mark.inc │ ├── rt_mem_access.inc │ ├── rt_mem_heap.inc │ ├── rt_mem_percpu.inc │ ├── rt_mem_stack.inc │ ├── rt_order.inc │ ├── rt_sync.inc │ ├── rt_sys.inc │ ├── runtime.c │ └── vardef.h ├── instrument │ ├── CMakeLists.txt │ ├── Main.cpp │ ├── include │ │ ├── analysis │ │ │ ├── Oracle.h │ │ │ └── Probe.h │ │ ├── base │ │ │ ├── Common.h │ │ │ └── Plugin.h │ │ ├── dart │ │ │ └── API.h │ │ └── util │ │ │ ├── Logger.h │ │ │ └── Lower.h │ └── lib │ │ ├── analysis │ │ ├── Oracle.cpp │ │ └── Probe.cpp │ │ ├── base │ │ └── Plugin.cpp │ │ ├── dart │ │ └── API.cpp │ │ └── util │ │ ├── Logger.cpp │ │ └── Lower.cpp └── profile │ └── linux.json └── script ├── .gitignore ├── admin.py ├── build.mk ├── build.py ├── cmd.py ├── cmd_cc.py ├── config.py ├── config_option.py ├── dart.py ├── dart_app.py ├── dart_viz.py ├── dart_viz_depth.json ├── docker.mk ├── docker.py ├── emu.py ├── exec.mk ├── exec.py ├── fs.py ├── fs_btrfs.py ├── fs_ext4.py ├── fs_xfs.py ├── fuzz.mk ├── fuzz.py ├── fuzz_check.py ├── fuzz_engine.py ├── fuzz_exec.py ├── fuzz_primitive.py ├── fuzz_probe.py ├── fuzz_report.py ├── fuzz_stat.py ├── lint.ini ├── pkg.py ├── pkg_binutils.py ├── pkg_btrfsprogs.py ├── pkg_e2fsprogs.py ├── pkg_gcc.py ├── pkg_initramfs.py ├── pkg_linux.py ├── pkg_llvm.py ├── pkg_musl.py ├── pkg_qemu.py ├── pkg_racer.py ├── pkg_xfsprogs.py ├── racer_parse_compile_data.py ├── racer_query_compile_data.py ├── shortcut.py ├── spec.mk ├── spec.py ├── spec_basis.py ├── spec_const.py ├── spec_extract.py ├── spec_factory.py ├── spec_lego_pointer.py ├── spec_lego_simple.py ├── spec_lego_struct.py ├── spec_lego_vector.py ├── spec_pack.py ├── spec_random.py ├── spec_type_buf.py ├── spec_type_fd.py ├── spec_type_int.py ├── spec_type_len.py ├── spec_type_path.py ├── spec_type_str.py ├── util.py ├── util_bean.py ├── work.mk └── work.py /.gitignore: -------------------------------------------------------------------------------- 1 | # project directories 2 | /studio/ 3 | 4 | # editor 5 | *.swp 6 | *.swo 7 | 8 | # ide 9 | .idea/ 10 | cmake-build-*/ 11 | .clion.* 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tool/binutils"] 2 | path = tool/binutils 3 | url = git://sourceware.org/git/binutils-gdb.git 4 | [submodule "tool/llvm"] 5 | path = tool/llvm 6 | url = https://github.com/llvm/llvm-project.git 7 | [submodule "tool/gcc"] 8 | path = tool/gcc 9 | url = git://gcc.gnu.org/git/gcc.git 10 | [submodule "tool/qemu"] 11 | path = tool/qemu 12 | url = git://git.qemu.org/qemu.git 13 | [submodule "tool/musl"] 14 | path = tool/musl 15 | url = git://git.musl-libc.org/musl 16 | [submodule "kernel/linux"] 17 | path = kernel/linux 18 | url = git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git 19 | ignore = all 20 | [submodule "fs/ext4/e2fsprogs"] 21 | path = fs/ext4/e2fsprogs 22 | url = git://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git 23 | [submodule "fs/btrfs/btrfs-progs"] 24 | path = fs/btrfs/btrfs-progs 25 | url = git://git.kernel.org/pub/scm/linux/kernel/git/kdave/btrfs-progs.git 26 | [submodule "fs/xfs/xfsprogs"] 27 | path = fs/xfs/xfsprogs 28 | url = git://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git 29 | [submodule "misc/json"] 30 | path = misc/json 31 | url = https://github.com/nlohmann/json.git 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Georgia Institute of Technology 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help 2 | help: 3 | @echo "--- help ---" 4 | @echo "F=[ext4, btrfs, xfs]" 5 | @echo "I=[baseline, check-kasan, check-ktsan, dart, dart-dev]" 6 | @echo "" 7 | @echo "`$(MAKE) -s script/docker.mk docker-help`" 8 | @echo "`$(MAKE) -s script/build.mk build-help`" 9 | @echo "`$(MAKE) -s script/spec.mk spec-help`" 10 | @echo "`$(MAKE) -s script/exec.mk exec-help`" 11 | @echo "`$(MAKE) -s script/work.mk work-help`" 12 | @echo "`$(MAKE) -s script/fuzz.mk fuzz-help`" 13 | 14 | include script/docker.mk 15 | 16 | include script/build.mk 17 | 18 | include script/spec.mk 19 | 20 | include script/exec.mk 21 | 22 | include script/work.mk 23 | 24 | include script/fuzz.mk 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # krace : End-to-end fuzzing framework 2 | 3 | krace bring coverage-guided fuzzing to the concurrency dimension with three new constructs: 1) a new coverage tracking metric, alias coverage, specially designed to capture the exploration progress in the concurrency dimension; 2) an evolution algorithm for generating, mutating, and merging multi-threaded syscall sequences as inputs for concurrency fuzzing; and 3) a comprehensive lockset and happens-before modeling for kernel synchronization primitives for precise data race detection. These components are integrated into Krace, an end-to-end fuzzing framework that has discovered 23 data races in ext4, btrfs, and the VFS layer so far, and 9 are confirmed to be harmful. 4 | 5 | This repository is provided under the terms of MIT license. 6 | 7 | ## Reference 8 | https://ieeexplore.ieee.org/abstract/document/9152693 9 | ``` 10 | @INPROCEEDINGS{9152693, 11 | author={Xu, Meng and Kashyap, Sanidhya and Zhao, Hanqing and Kim, Taesoo}, 12 | booktitle={2020 IEEE Symposium on Security and Privacy (SP)}, 13 | title={Krace: Data Race Fuzzing for Kernel File Systems}, 14 | year={2020}, 15 | volume={}, 16 | number={}, 17 | pages={1643-1660}, 18 | doi={10.1109/SP40000.2020.00078}} 19 | ``` 20 | -------------------------------------------------------------------------------- /docker/base/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax = docker/dockerfile:experimental 2 | 3 | FROM ubuntu:18.04 4 | 5 | ENV IN_RACER_DOCKER 1 6 | ENV DEBIAN_FRONTEND noninteractive 7 | 8 | RUN echo "[racer] start" && \ 9 | \ 10 | apt-get update && apt-get install -y apt-utils && apt-get upgrade -y && \ 11 | \ 12 | apt-get install -y \ 13 | build-essential \ 14 | autoconf cmake pkg-config \ 15 | texinfo flex bison bc gettext \ 16 | python3.7 python3.7-dev python3-distutils python3-pip \ 17 | git curl wget doxygen cpio rsync kmod \ 18 | libcap2 libcap-dev libattr1 libattr1-dev \ 19 | libglib2.0-dev libfdt-dev libpixman-1-dev \ 20 | libncurses-dev libelf-dev libssl-dev \ 21 | libblkid-dev libzstd-dev liblzo2-dev \ 22 | libgl1-mesa-glx \ 23 | libtool && \ 24 | \ 25 | update-alternatives --install \ 26 | /usr/bin/python3 python3 /usr/bin/python3.7 1 && \ 27 | \ 28 | pip3 install \ 29 | asciitree termcolor \ 30 | sortedcontainers \ 31 | lark-parser graphviz PySide2 && \ 32 | \ 33 | cd /root && \ 34 | wget https://cmake.org/files/v3.14/cmake-3.14.4.tar.gz && \ 35 | tar xvf cmake-3.14.4.tar.gz && \ 36 | cd cmake-3.14.4 && \ 37 | ./bootstrap -- -DCMAKE_BUILD_TYPE:STRING=Release && \ 38 | make -j$(nproc) && make install && \ 39 | cd /root && \ 40 | rm -rf cmake-* && \ 41 | \ 42 | echo "[racer] ready" 43 | 44 | ENV DEBIAN_FRONTEND teletype 45 | -------------------------------------------------------------------------------- /kernel/initramfs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(initramfs C) 3 | 4 | # studio 5 | if (DEFINED ENV{IN_RACER_DOCKER}) 6 | set(RACER_STUDIO "dock") 7 | else () 8 | set(RACER_STUDIO "host") 9 | endif () 10 | 11 | # paths 12 | get_filename_component(RACER_PATH_KERNEL 13 | ${CMAKE_SOURCE_DIR} DIRECTORY) 14 | 15 | get_filename_component(RACER_PATH_BASE 16 | ${RACER_PATH_KERNEL} DIRECTORY) 17 | 18 | set(LINUX_NAME 19 | ${LINUX_FLAVOR}-${LINUX_INTENT}) 20 | 21 | set(RACER_PATH_LINUX 22 | "${RACER_PATH_BASE}/studio/${RACER_STUDIO}/store/linux-${LINUX_NAME}") 23 | 24 | set(RACER_PATH_DART 25 | "${RACER_PATH_BASE}/pass/dart") 26 | 27 | # global level flags 28 | set(CMAKE_C_STANDARD 11) 29 | set(CMAKE_C_STANDARD_REQUIRED TRUE) 30 | 31 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") 32 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-inline-small-functions") 33 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-caller-saves") 34 | 35 | set(THREADS_PREFER_PTHREAD_FLAG ON) 36 | find_package(Threads REQUIRED) 37 | 38 | include_directories( 39 | ${CMAKE_SOURCE_DIR} 40 | ${RACER_PATH_LINUX}/include 41 | ${RACER_PATH_DART} 42 | ) 43 | 44 | # debug 45 | add_compile_definitions(RACER_DEBUG) 46 | 47 | # misc 48 | set(CMAKE_VERBOSE_MAKEFILE ON) 49 | 50 | # the init program 51 | add_executable(init 52 | # the init program 53 | init.c dart.c log.c util.c strace.c 54 | # ltp 55 | prog-test/main.c 56 | prog-test/ltp_output.c 57 | prog-test/ltp_safe_op_user.c 58 | prog-test/ltp_safe_op_file.c 59 | # fs preparation 60 | prog-prep/main.c 61 | # fs continued execution 62 | prog-cont/main.c 63 | # fs fuzzing 64 | prog-fuzz/main.c) 65 | target_link_libraries(init PUBLIC Threads::Threads) 66 | target_link_libraries(init PUBLIC "-static") 67 | 68 | # install 69 | install(TARGETS init DESTINATION bin) -------------------------------------------------------------------------------- /kernel/initramfs/common.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_INITRAMFS_COMMON_H_ 2 | #define _RACER_INITRAMFS_COMMON_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | // Not all alternative libc implementations support these constants yet. 18 | #ifndef O_CLOEXEC 19 | #define O_CLOEXEC 02000000 20 | #endif 21 | 22 | // structs 23 | struct shmem_hdr { 24 | char command; 25 | char desc[7]; 26 | unsigned long status; 27 | }; 28 | 29 | // constants that may be used by anyone 30 | #define FSSHARE_MNT "/host" 31 | #define FS_DISK_IMG FSSHARE_MNT "/disk.img" 32 | #define FS_DISK_MNT "/work" 33 | 34 | #define _MB(i) ((i) * (1 << 20)) 35 | 36 | #define IVSHMEM_OFFSET_METADATA 0 37 | #define IVSHMEM_OFFSET_BYTECODE IVSHMEM_OFFSET_METADATA + _MB(2) 38 | #define IVSHMEM_OFFSET_STRACE IVSHMEM_OFFSET_BYTECODE + _MB(48) 39 | #define IVSHMEM_SIZE IVSHMEM_OFFSET_STRACE + _MB(12) 40 | 41 | // init.c 42 | extern void *g_shmem; 43 | 44 | // util.c 45 | void set_buf(char *buf, size_t size, ...); 46 | void app_buf(char *buf, size_t size, ...); 47 | 48 | // log.c 49 | void warn(const char *str1, ...); 50 | void panic(int err, ...) __attribute__((noreturn)); 51 | 52 | // dart.c 53 | void dart_launch(void); 54 | void dart_finish(void); 55 | void dart_ctxt_syscall_enter(unsigned long sysno); 56 | void dart_ctxt_syscall_exit(unsigned long sysno); 57 | 58 | // racer functions 59 | void racer_test(void); 60 | void racer_prep(void); 61 | void racer_cont(void); 62 | void racer_fuzz(void); 63 | 64 | // utils 65 | static inline void load_module(const char *path) { 66 | int fd = open(path, O_RDONLY | O_CLOEXEC); 67 | if (fd < 0) { 68 | panic(errno, "No module found.", NULL); 69 | } 70 | 71 | int rv = (int) syscall(SYS_finit_module, fd, "", 0); 72 | if (rv != 0) { 73 | panic(errno, "Failed to load module", NULL); 74 | } 75 | 76 | close(fd); 77 | } 78 | 79 | static inline void unload_module(const char *name) { 80 | int rv = (int) syscall(SYS_delete_module, name); 81 | if (rv != 0) { 82 | panic(errno, "Failed to unload module", NULL); 83 | } 84 | } 85 | 86 | // racer configs 87 | #define RACER_THREAD_MAX 64 88 | 89 | #endif /* _RACER_INITRAMFS_COMMON_H_ */ 90 | -------------------------------------------------------------------------------- /kernel/initramfs/dart.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | // syscall constants 4 | #define SYS_DART 500 5 | 6 | #define CMD_DART_LAUNCH 1 7 | #define CMD_DART_FINISH 2 8 | #define CMD_DART_CTXT_SYSCALL_START 3 9 | #define CMD_DART_CTXT_SYSCALL_EXIT 4 10 | 11 | // wrappers 12 | void dart_launch(void) { 13 | syscall(SYS_DART, CMD_DART_LAUNCH, NULL); 14 | } 15 | 16 | void dart_finish(void) { 17 | syscall(SYS_DART, CMD_DART_FINISH, NULL); 18 | } 19 | 20 | void dart_ctxt_syscall_enter(unsigned long sysno) { 21 | syscall(SYS_DART, CMD_DART_CTXT_SYSCALL_START, sysno); 22 | } 23 | 24 | void dart_ctxt_syscall_exit(unsigned long sysno) { 25 | syscall(SYS_DART, CMD_DART_CTXT_SYSCALL_EXIT, sysno); 26 | } 27 | -------------------------------------------------------------------------------- /kernel/initramfs/init.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // configs 11 | 12 | #define IVSHMEM_KMOD "/mod/drivers/misc/ivshmem.ko" 13 | #define IVSHMEM_PATH "/dev/uio0" 14 | #define FSSHARE_TAG "fsshare" 15 | 16 | // global pointer to the ivshmem 17 | void *g_shmem = NULL; 18 | 19 | // utils 20 | static inline void mount_pseudofs(char *type, char *dest) { 21 | int rv = mount("none", dest, type, 0, NULL); 22 | if (rv < 0) { 23 | panic(errno, "Failed to mount fs", NULL); 24 | } 25 | } 26 | 27 | static inline void *setup_ivshmem(void) { 28 | int rv; 29 | 30 | // map ivshmem 31 | int fd = open(IVSHMEM_PATH, O_RDWR); 32 | if (fd < 0) { 33 | panic(errno, "Failed to open ivshmem device", NULL); 34 | } 35 | 36 | void *ivshmem = mmap( 37 | 0, IVSHMEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 38 | ); 39 | if (ivshmem == (void *) -1) { 40 | panic(errno, "Failed to mmap ivshmem", NULL); 41 | } 42 | 43 | // prevent from getting swapped out 44 | rv = mlockall(MCL_CURRENT | MCL_FUTURE); 45 | if (rv) { 46 | panic(errno, "Failed to mlockall", NULL); 47 | } 48 | 49 | return ivshmem; 50 | } 51 | 52 | static inline void clean_ivshmem(void *ivshmem) { 53 | int rv; 54 | 55 | rv = munlockall(); 56 | if (rv) { 57 | panic(errno, "Failed to munlockall", NULL); 58 | } 59 | 60 | rv = munmap(ivshmem, IVSHMEM_SIZE); 61 | if (rv) { 62 | panic(errno, "Failed to munmap ivshmem", NULL); 63 | } 64 | } 65 | 66 | static inline void setup_fsshare(void) { 67 | int rv; 68 | 69 | // prepare the mount point 70 | rv = mkdir(FSSHARE_MNT, 0777); 71 | if (rv == -1) { 72 | panic(errno, "Failed to create host point", NULL); 73 | } 74 | 75 | // do the actual mount 76 | rv = mount( 77 | FSSHARE_TAG, FSSHARE_MNT, 78 | "9p", 0, 79 | "trans=virtio,version=9p2000.L" 80 | ); 81 | if (rv == -1) { 82 | panic(errno, "Failed to mount fsshare", NULL); 83 | } 84 | } 85 | 86 | static inline void clean_fsshare(void) { 87 | int rv; 88 | 89 | // do force umount 90 | rv = umount2(FSSHARE_MNT, 0); 91 | if (rv) { 92 | panic(errno, "Failed to umount fsshare", NULL); 93 | } 94 | } 95 | 96 | int main(void) { 97 | // warm the system 98 | #ifdef RACER_DEBUG 99 | warn("Starting the guest system", NULL); 100 | #endif 101 | 102 | // modules 103 | load_module(IVSHMEM_KMOD); 104 | 105 | // fs 106 | mount_pseudofs("devtmpfs", "/dev"); 107 | 108 | // set-up 109 | g_shmem = setup_ivshmem(); 110 | setup_fsshare(); 111 | 112 | // prepare variables 113 | struct shmem_hdr *hdr = (struct shmem_hdr *) g_shmem; 114 | 115 | // mark that we have not started executing 116 | hdr->status = 0; 117 | 118 | // fork and wait 119 | pid_t child = fork(); 120 | if (child < 0) { 121 | panic(errno, "Failed to spwan child process", NULL); 122 | } 123 | 124 | if (child) { 125 | // in parent, wait for termination 126 | int status; 127 | if (waitpid(child, &status, WUNTRACED) != child) { 128 | panic(errno, "Failed to wait for child termination", NULL); 129 | } 130 | 131 | if (!(WIFEXITED(status) || WIFSIGNALED(status))) { 132 | panic(errno, "Child stopped for no valid reason", NULL); 133 | } 134 | } else { 135 | // in child, choose action based on command 136 | switch (hdr->command) { 137 | case 't': 138 | racer_test(); 139 | break; 140 | case 'p': 141 | racer_prep(); 142 | break; 143 | case 'c': 144 | racer_cont(); 145 | break; 146 | case 'f': 147 | racer_fuzz(); 148 | break; 149 | default: 150 | warn("Unknown command, exiting...", NULL); 151 | break; 152 | } 153 | } 154 | 155 | // mark that we have done with the execution 156 | hdr->status = 1; 157 | 158 | // tear-down 159 | clean_fsshare(); 160 | clean_ivshmem(g_shmem); 161 | 162 | // halt the system 163 | #ifdef RACER_DEBUG 164 | warn("Stopping the guest system", NULL); 165 | #endif 166 | 167 | reboot(RB_POWER_OFF); 168 | 169 | // should not even reach here 170 | return 1; 171 | } 172 | -------------------------------------------------------------------------------- /kernel/initramfs/log.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | #include 4 | 5 | #define LOG_PREFIX "[racer]: " 6 | 7 | static void showmsgv(va_list ap, 8 | const char *before, 9 | const char *after1, const char *after2) { 10 | 11 | /* Don't use stdio functions, because we link statically 12 | * and they bloat the binary. */ 13 | 14 | const int fd = 2; /* write to stderr */ 15 | const unsigned extra_arg_count = (const unsigned int) ( 16 | (after1 != NULL) + (after2 != NULL) 17 | ); 18 | 19 | int argc = 1; 20 | struct iovec iov[32]; 21 | 22 | const char *arg; 23 | 24 | if (before) { 25 | iov[1].iov_base = (char *) before; 26 | iov[1].iov_len = strlen(before); 27 | argc++; 28 | } 29 | 30 | while ((arg = va_arg(ap, const char *))) { 31 | iov[argc].iov_base = (char *) arg; 32 | iov[argc].iov_len = strlen(arg); 33 | argc++; 34 | 35 | /* We only support a fixed number of arguments. */ 36 | if (argc + 1 + extra_arg_count > 32) 37 | break; 38 | } 39 | 40 | if (after1) { 41 | iov[argc].iov_base = (char *) after1; 42 | iov[argc].iov_len = strlen(after1); 43 | argc++; 44 | } 45 | 46 | if (after2) { 47 | iov[argc].iov_base = (char *) after2; 48 | iov[argc].iov_len = strlen(after2); 49 | argc++; 50 | } 51 | 52 | if (argc == 1) 53 | return; 54 | 55 | iov[argc].iov_base = (char *) "\n"; 56 | iov[argc].iov_len = 1; 57 | 58 | iov[0].iov_base = (char *) LOG_PREFIX; 59 | iov[0].iov_len = sizeof(LOG_PREFIX) - 1; 60 | 61 | writev(fd, iov, argc + 1); 62 | } 63 | 64 | void panic(int err, ...) { 65 | va_list ap; 66 | va_start(ap, err); 67 | 68 | if (err) 69 | showmsgv(ap, NULL, ": ", strerror(err)); 70 | else 71 | showmsgv(ap, NULL, NULL, NULL); 72 | 73 | va_end(ap); 74 | 75 | /* We want the user to see the message before we cause a kernel panic, 76 | * because a kernel panic obscures the message. But we need to cause 77 | * a kernel panic (by PID 1 exiting), because if the user tells the 78 | * kernel to reboot on panic, we want to make sure this happens. */ 79 | warn("Will cause kernel panic...", NULL); 80 | _exit(1); 81 | } 82 | 83 | void warn(const char *str1, ...) { 84 | va_list ap; 85 | va_start(ap, str1); 86 | 87 | showmsgv(ap, str1, NULL, NULL); 88 | 89 | va_end(ap); 90 | } 91 | -------------------------------------------------------------------------------- /kernel/initramfs/prog-cont/main.c: -------------------------------------------------------------------------------- 1 | #ifdef RACER_STRACE 2 | #undef RACER_STRACE 3 | #endif 4 | #include "fuzzer.inc" 5 | 6 | // main 7 | void racer_cont(void) { 8 | int rv; 9 | 10 | // get mount info 11 | struct mount_info *info = (struct mount_info *) ( 12 | (char *) g_shmem + sizeof(struct shmem_hdr) 13 | ); 14 | 15 | // get bytecode info 16 | char *cur = (char *) g_shmem + IVSHMEM_OFFSET_BYTECODE; 17 | 18 | // parse head segment, locate regions 19 | struct region_head *head = (struct region_head *) cur; 20 | if (memcmp(head->magics, "bytecode", 8) != 0) { 21 | panic(0, "Magic number does not match", NULL); 22 | } 23 | 24 | char *meta = cur + head->offset_meta; 25 | char *code = cur + head->offset_code; 26 | char *heap = cur + head->offset_heap; 27 | 28 | cur += sizeof(struct region_head); 29 | if (cur != (char *) meta) { 30 | panic(0, "Region head corrupted", NULL); 31 | } 32 | 33 | // parse meta_ptr segment, fixup pointers 34 | struct region_meta_ptr *meta_ptr = (struct region_meta_ptr *) cur; 35 | for (size_t i = 0; i < meta_ptr->num_ptrs; i++) { 36 | size_t *offs = (size_t *) (heap + meta_ptr->off_ptrs[i]); 37 | if (*offs) { 38 | *offs += (size_t) heap; 39 | } 40 | } 41 | 42 | cur += sizeof(struct region_meta_ptr) + 43 | sizeof(size_t) * meta_ptr->num_ptrs; 44 | 45 | // parse meta_fd segment, the info will be used to close all fds 46 | struct region_meta_fd *meta_fd = (struct region_meta_fd *) cur; 47 | 48 | cur += sizeof(struct region_meta_fd) + 49 | sizeof(struct lego_pack) * meta_fd->num_fds; 50 | if (cur != code) { 51 | panic(0, "Region meta corrupted", NULL); 52 | } 53 | 54 | // parse code segment 55 | struct region_code *code_hdr = (struct region_code *) cur; 56 | 57 | cur += sizeof(struct region_code) + sizeof(size_t) * code_hdr->num_threads; 58 | if (cur != (code + code_hdr->offset_main)) { 59 | panic(0, "Region code - header part corrupted", NULL); 60 | } 61 | 62 | // close stdin, this is causing hangs 63 | close(0); 64 | 65 | // prepare semaphores, arguments and launch child threads 66 | pthread_t tptrs[RACER_THREAD_MAX]; 67 | struct thread_args targs[RACER_THREAD_MAX]; 68 | 69 | sem_init(&sema_init, 0, 0); 70 | sem_init(&sema_fini, 0, 0); 71 | 72 | for (size_t i = 0; i < code_hdr->num_threads; i++) { 73 | targs[i].code = code + code_hdr->offset_subs[i]; 74 | targs[i].heap = heap; 75 | 76 | rv = pthread_create(&tptrs[i], NULL, thread_func, &targs[i]); 77 | if (rv) { 78 | panic(rv, "Failed to create threads", NULL); 79 | } 80 | } 81 | 82 | // set-up 83 | mount_image(info->mod_main, info->mod_main_num, 84 | info->mod_deps, info->mod_deps_num, 85 | info->fs_type, info->mnt_opts, 86 | LOOP_DEV, 87 | FS_DISK_IMG, FS_DISK_MNT); 88 | 89 | // change directory 90 | dart_ctxt_syscall_enter(SYS_chdir); 91 | rv = chdir(FS_DISK_MNT); 92 | dart_ctxt_syscall_exit(SYS_chdir); 93 | if (rv != 0) { 94 | panic(errno, "Failed to chdir to disk mount point", NULL); 95 | } 96 | 97 | // run the precalls first 98 | interpret(code + code_hdr->offset_main, heap); 99 | 100 | // inform threads that we are ready 101 | for (size_t i = 0; i < code_hdr->num_threads; i++) { 102 | rv = sem_post(&sema_init); 103 | if (rv) { 104 | panic(rv, "Failed to post for init semaphore"); 105 | } 106 | } 107 | 108 | // wait for threads to finish 109 | for (size_t i = 0; i < code_hdr->num_threads; i++) { 110 | rv = sem_wait(&sema_fini); 111 | if (rv) { 112 | panic(rv, "Failed to wait for fini semaphore"); 113 | } 114 | } 115 | 116 | // close all fd ever appeared 117 | for (size_t i = 0; i < meta_fd->num_fds; i++) { 118 | dart_ctxt_syscall_enter(SYS_close); 119 | close(load_slot(&meta_fd->fds[i], heap)); 120 | dart_ctxt_syscall_exit(SYS_close); 121 | } 122 | 123 | // change directory 124 | dart_ctxt_syscall_enter(SYS_chdir); 125 | rv = chdir("/"); 126 | dart_ctxt_syscall_exit(SYS_chdir); 127 | if (rv != 0) { 128 | panic(errno, "Failed to chdir to root directory", NULL); 129 | } 130 | 131 | // tear-down 132 | umount_image(info->mod_names, info->mod_names_num, 133 | LOOP_DEV, FS_DISK_IMG, 134 | FS_DISK_MNT); 135 | 136 | // wait for join all threads 137 | for (size_t i = 0; i < code_hdr->num_threads; i++) { 138 | rv = pthread_join(tptrs[i], NULL); 139 | if (rv) { 140 | panic(rv, "Failed to join threads", NULL); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /kernel/initramfs/prog-fuzz/main.c: -------------------------------------------------------------------------------- 1 | #ifndef RACER_STRACE 2 | #define RACER_STRACE 3 | #endif 4 | #include "fuzzer.inc" 5 | 6 | // main 7 | void racer_fuzz(void) { 8 | int rv; 9 | 10 | // get mount info 11 | struct mount_info *info = (struct mount_info *) ( 12 | (char *) g_shmem + sizeof(struct shmem_hdr) 13 | ); 14 | 15 | // get bytecode info 16 | char *cur = (char *) g_shmem + IVSHMEM_OFFSET_BYTECODE; 17 | 18 | // parse head segment, locate regions 19 | struct region_head *head = (struct region_head *) cur; 20 | if (memcmp(head->magics, "bytecode", 8) != 0) { 21 | panic(0, "Magic number does not match", NULL); 22 | } 23 | 24 | char *meta = cur + head->offset_meta; 25 | char *code = cur + head->offset_code; 26 | char *heap = cur + head->offset_heap; 27 | 28 | cur += sizeof(struct region_head); 29 | if (cur != (char *) meta) { 30 | panic(0, "Region head corrupted", NULL); 31 | } 32 | 33 | // parse meta_ptr segment, fixup pointers 34 | struct region_meta_ptr *meta_ptr = (struct region_meta_ptr *) cur; 35 | for (size_t i = 0; i < meta_ptr->num_ptrs; i++) { 36 | size_t *offs = (size_t *) (heap + meta_ptr->off_ptrs[i]); 37 | if (*offs) { 38 | *offs += (size_t) heap; 39 | } 40 | } 41 | 42 | cur += sizeof(struct region_meta_ptr) + 43 | sizeof(size_t) * meta_ptr->num_ptrs; 44 | 45 | // parse meta_fd segment, the info will be used to close all fds 46 | struct region_meta_fd *meta_fd = (struct region_meta_fd *) cur; 47 | 48 | cur += sizeof(struct region_meta_fd) + 49 | sizeof(struct lego_pack) * meta_fd->num_fds; 50 | if (cur != code) { 51 | panic(0, "Region meta corrupted", NULL); 52 | } 53 | 54 | // parse code segment 55 | struct region_code *code_hdr = (struct region_code *) cur; 56 | 57 | cur += sizeof(struct region_code) + sizeof(size_t) * code_hdr->num_threads; 58 | if (cur != (code + code_hdr->offset_main)) { 59 | panic(0, "Region code - header part corrupted", NULL); 60 | } 61 | 62 | // close stdin, this is causing hangs 63 | close(0); 64 | 65 | // initialize strace first so we could dump information from the execution 66 | strace_init(); 67 | 68 | // prepare semaphores, arguments and launch child threads 69 | pthread_t tptrs[RACER_THREAD_MAX]; 70 | struct thread_args targs[RACER_THREAD_MAX]; 71 | 72 | sem_init(&sema_init, 0, 0); 73 | sem_init(&sema_fini, 0, 0); 74 | 75 | for (size_t i = 0; i < code_hdr->num_threads; i++) { 76 | targs[i].code = code + code_hdr->offset_subs[i]; 77 | targs[i].heap = heap; 78 | 79 | rv = pthread_create(&tptrs[i], NULL, thread_func, &targs[i]); 80 | if (rv) { 81 | panic(rv, "Failed to create threads", NULL); 82 | } 83 | } 84 | 85 | // set-up 86 | mount_image(info->mod_main, info->mod_main_num, 87 | info->mod_deps, info->mod_deps_num, 88 | info->fs_type, info->mnt_opts, 89 | LOOP_DEV, 90 | FS_DISK_IMG, FS_DISK_MNT); 91 | 92 | // change directory 93 | dart_ctxt_syscall_enter(SYS_chdir); 94 | rv = chdir(FS_DISK_MNT); 95 | dart_ctxt_syscall_exit(SYS_chdir); 96 | if (rv != 0) { 97 | panic(errno, "Failed to chdir to disk mount point", NULL); 98 | } 99 | 100 | // run the precalls first 101 | interpret(code + code_hdr->offset_main, heap); 102 | 103 | // inform threads that we are ready 104 | for (size_t i = 0; i < code_hdr->num_threads; i++) { 105 | rv = sem_post(&sema_init); 106 | if (rv) { 107 | panic(rv, "Failed to post for init semaphore"); 108 | } 109 | } 110 | 111 | // wait for threads to finish 112 | for (size_t i = 0; i < code_hdr->num_threads; i++) { 113 | rv = sem_wait(&sema_fini); 114 | if (rv) { 115 | panic(rv, "Failed to wait for fini semaphore"); 116 | } 117 | } 118 | 119 | // close all fd ever appeared 120 | for (size_t i = 0; i < meta_fd->num_fds; i++) { 121 | dart_ctxt_syscall_enter(SYS_close); 122 | close(load_slot(&meta_fd->fds[i], heap)); 123 | dart_ctxt_syscall_exit(SYS_close); 124 | } 125 | 126 | // change directory 127 | dart_ctxt_syscall_enter(SYS_chdir); 128 | rv = chdir("/"); 129 | dart_ctxt_syscall_exit(SYS_chdir); 130 | if (rv != 0) { 131 | panic(errno, "Failed to chdir to root directory", NULL); 132 | } 133 | 134 | // tear-down 135 | umount_image(info->mod_names, info->mod_names_num, 136 | LOOP_DEV, FS_DISK_IMG, 137 | FS_DISK_MNT); 138 | 139 | // wait for join all threads 140 | for (size_t i = 0; i < code_hdr->num_threads; i++) { 141 | rv = pthread_join(tptrs[i], NULL); 142 | if (rv) { 143 | panic(rv, "Failed to join threads", NULL); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /kernel/initramfs/prog-prep/main.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | #ifdef USE_DART 4 | #undef USE_DART 5 | #endif 6 | #include "shared.inc" 7 | 8 | void racer_prep(void) { 9 | // get mount info 10 | struct mount_info *info = (struct mount_info *) ( 11 | (char *) g_shmem + sizeof(struct shmem_hdr) 12 | ); 13 | 14 | // set-up 15 | mount_image(info->mod_main, info->mod_main_num, 16 | info->mod_deps, info->mod_deps_num, 17 | info->fs_type, info->mnt_opts, 18 | LOOP_DEV, 19 | FS_DISK_IMG, FS_DISK_MNT); 20 | #ifdef RACER_DEBUG 21 | warn("Disk image mounted", NULL); 22 | #endif 23 | 24 | // prep bytecode interpreter 25 | char *prep_method = (char *) info + sizeof(struct mount_info); 26 | 27 | if (strcmp(prep_method, "000") == 0) { 28 | // method empty 29 | #ifdef RACER_DEBUG 30 | warn("Preparing using method: empty - ", prep_method, NULL); 31 | #endif 32 | } 33 | // must be one of the designated method 34 | else { 35 | panic(0, "Invalid prep method", NULL); 36 | } 37 | 38 | // tear-down 39 | umount_image(info->mod_names, info->mod_names_num, 40 | LOOP_DEV, FS_DISK_IMG, 41 | FS_DISK_MNT); 42 | #ifdef RACER_DEBUG 43 | warn("Disk image umounted", NULL); 44 | #endif 45 | } 46 | -------------------------------------------------------------------------------- /kernel/initramfs/prog-test/ltp.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_LTP_H_ 2 | #define _RACER_LTP_H_ 3 | 4 | #include "ltp_common.h" 5 | #include "ltp_output.h" 6 | 7 | #include "ltp_safe_op_user.h" 8 | #include "ltp_safe_op_file.h" 9 | 10 | #endif /* _RACER_LTP_H_ */ 11 | -------------------------------------------------------------------------------- /kernel/initramfs/prog-test/ltp_common.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_LTP_COMMON_H_ 2 | #define _RACER_LTP_COMMON_H_ 3 | 4 | // std 5 | #define _GNU_SOURCE 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // sys 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | // unix 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | // linux 29 | #include 30 | 31 | // constants 32 | #define UID_ROOT 0 33 | #define UID_NOBODY 65534 34 | #define GID_ROOT 0 35 | #define GID_NOBODY 65534 36 | 37 | // variadic argument expansion 38 | #define __SELECT(T1, V1, T2, V2, T3, V3, T4, V4, T5, V5, T6, V6, N, ...) N 39 | #define __IGNORE(...) 40 | 41 | #define __NARGS_0(...) void 42 | #define __NARGS_1(T, V, ...) T V 43 | #define __NARGS_2(T, V, ...) T V, __NARGS_1(__VA_ARGS__) 44 | #define __NARGS_3(T, V, ...) T V, __NARGS_2(__VA_ARGS__) 45 | #define __NARGS_4(T, V, ...) T V, __NARGS_3(__VA_ARGS__) 46 | #define __NARGS_5(T, V, ...) T V, __NARGS_4(__VA_ARGS__) 47 | #define __NARGS_6(T, V, ...) T V, __NARGS_5(__VA_ARGS__) 48 | 49 | #define __NARGS_N(...) __SELECT( \ 50 | __VA_ARGS__, \ 51 | __NARGS_6, __IGNORE, \ 52 | __NARGS_5, __IGNORE, \ 53 | __NARGS_4, __IGNORE, \ 54 | __NARGS_3, __IGNORE, \ 55 | __NARGS_2, __IGNORE, \ 56 | __NARGS_1, __IGNORE, \ 57 | __NARGS_0, __IGNORE, \ 58 | )(__VA_ARGS__) 59 | 60 | #define __FARGS_0(...) 61 | #define __FARGS_1(T, V, ...) , T V __FARGS_0(__VA_ARGS__) 62 | #define __FARGS_2(T, V, ...) , T V __FARGS_1(__VA_ARGS__) 63 | #define __FARGS_3(T, V, ...) , T V __FARGS_2(__VA_ARGS__) 64 | #define __FARGS_4(T, V, ...) , T V __FARGS_3(__VA_ARGS__) 65 | #define __FARGS_5(T, V, ...) , T V __FARGS_4(__VA_ARGS__) 66 | #define __FARGS_6(T, V, ...) , T V __FARGS_5(__VA_ARGS__) 67 | 68 | #define __FARGS_N(...) __SELECT( \ 69 | __VA_ARGS__, \ 70 | __FARGS_6, __IGNORE, \ 71 | __FARGS_5, __IGNORE, \ 72 | __FARGS_4, __IGNORE, \ 73 | __FARGS_3, __IGNORE, \ 74 | __FARGS_2, __IGNORE, \ 75 | __FARGS_1, __IGNORE, \ 76 | __FARGS_0, __IGNORE, \ 77 | )(__VA_ARGS__) 78 | 79 | #define __NVALS_0(...) 80 | #define __NVALS_1(T, V, ...) V 81 | #define __NVALS_2(T, V, ...) V, __NVALS_1(__VA_ARGS__) 82 | #define __NVALS_3(T, V, ...) V, __NVALS_2(__VA_ARGS__) 83 | #define __NVALS_4(T, V, ...) V, __NVALS_3(__VA_ARGS__) 84 | #define __NVALS_5(T, V, ...) V, __NVALS_4(__VA_ARGS__) 85 | #define __NVALS_6(T, V, ...) V, __NVALS_5(__VA_ARGS__) 86 | 87 | #define __NVALS_N(...) __SELECT( \ 88 | __VA_ARGS__, \ 89 | __NVALS_6, __IGNORE, \ 90 | __NVALS_5, __IGNORE, \ 91 | __NVALS_4, __IGNORE, \ 92 | __NVALS_3, __IGNORE, \ 93 | __NVALS_2, __IGNORE, \ 94 | __NVALS_1, __IGNORE, \ 95 | __NVALS_0, __IGNORE, \ 96 | )(__VA_ARGS__) 97 | 98 | #define __FVALS_0(...) 99 | #define __FVALS_1(T, V, ...) , V __FVALS_0(__VA_ARGS__) 100 | #define __FVALS_2(T, V, ...) , V __FVALS_1(__VA_ARGS__) 101 | #define __FVALS_3(T, V, ...) , V __FVALS_2(__VA_ARGS__) 102 | #define __FVALS_4(T, V, ...) , V __FVALS_3(__VA_ARGS__) 103 | #define __FVALS_5(T, V, ...) , V __FVALS_4(__VA_ARGS__) 104 | #define __FVALS_6(T, V, ...) , V __FVALS_5(__VA_ARGS__) 105 | 106 | #define __FVALS_N(...) __SELECT( \ 107 | __VA_ARGS__, \ 108 | __FVALS_6, __IGNORE, \ 109 | __FVALS_5, __IGNORE, \ 110 | __FVALS_4, __IGNORE, \ 111 | __FVALS_3, __IGNORE, \ 112 | __FVALS_2, __IGNORE, \ 113 | __FVALS_1, __IGNORE, \ 114 | __FVALS_0, __IGNORE, \ 115 | )(__VA_ARGS__) 116 | 117 | // propogate debug information 118 | #define _LTP_OP_ARGS_DEF_ const char *ltp_file, int ltp_line 119 | #define _LTP_OP_ARGS_USE_ ltp_file, ltp_line 120 | #define _LTP_OP_ARGS_CUR_ __FILE__, __LINE__ 121 | #define _LTP_OP_ARGS_FMT_ "%s:%d" 122 | 123 | // syscall wrapper 124 | #define plat_sys_(name, ...) ltp_sys_##name(__VA_ARGS__) 125 | 126 | // ltp safe syscall 127 | #define LTP_OP_SAFE_SYS_DEF(name, sys_expr, ret_expr, ret_type, ...) \ 128 | static inline long ltp_sys_##name( \ 129 | __NARGS_N(__VA_ARGS__) \ 130 | ) { \ 131 | errno = 0; \ 132 | long ret = (sys_expr); \ 133 | return errno ? -errno : ret; \ 134 | } \ 135 | \ 136 | static inline ret_type _safe_sys_##name( \ 137 | _LTP_OP_ARGS_DEF_ __FARGS_N(__VA_ARGS__) \ 138 | ) { \ 139 | long ret = plat_sys_(name, __NVALS_N(__VA_ARGS__)); \ 140 | (ret_expr); \ 141 | } 142 | 143 | #define _safe_sys(name, ...) _safe_sys_##name(_LTP_OP_ARGS_USE_, ##__VA_ARGS__) 144 | #define safe_sys_(name, ...) _safe_sys_##name(_LTP_OP_ARGS_CUR_, ##__VA_ARGS__) 145 | 146 | // ltp safe libcall 147 | #define LTP_OP_SAFE_LIB_DEC(name, ret_type, ...) \ 148 | ret_type _safe_lib_##name( \ 149 | _LTP_OP_ARGS_DEF_ __FARGS_N(__VA_ARGS__) \ 150 | ) 151 | 152 | #define LTP_OP_SAFE_LIB_DEC_VA(name, ret_type, ...) \ 153 | ret_type _safe_lib_##name( \ 154 | _LTP_OP_ARGS_DEF_ __FARGS_N(__VA_ARGS__), ... \ 155 | ) 156 | 157 | #define _safe_lib(name, ...) _safe_lib_##name(_LTP_OP_ARGS_USE_, ##__VA_ARGS__) 158 | #define safe_lib_(name, ...) _safe_lib_##name(_LTP_OP_ARGS_CUR_, ##__VA_ARGS__) 159 | 160 | #endif /* _RACER_LTP_COMMON_H_ */ 161 | -------------------------------------------------------------------------------- /kernel/initramfs/prog-test/ltp_output.c: -------------------------------------------------------------------------------- 1 | #include "ltp.h" 2 | 3 | static void print_result(_LTP_OP_ARGS_DEF_, 4 | int rv, 5 | const char *fmt, va_list va) { 6 | 7 | // string for res 8 | const char *res; 9 | switch (LTP_RV_GET_RES(rv)) { 10 | case TPASS: 11 | res = "PASS"; 12 | break; 13 | case TWARN: 14 | res = "WARN"; 15 | break; 16 | case TFAIL: 17 | res = "FAIL"; 18 | break; 19 | case TBROK: 20 | res = "BROK"; 21 | break; 22 | case TCONF: 23 | res = "CONF"; 24 | break; 25 | default: 26 | fprintf(stderr, 27 | "[ABRT] " _LTP_OP_ARGS_FMT_ " - invalid result: %d\n", 28 | _LTP_OP_ARGS_USE_, rv); 29 | abort(); 30 | } 31 | 32 | // string for err 33 | int eno = LTP_RV_GET_ERR(rv); 34 | const char *err = eno ? strerror(eno) : "OK"; 35 | 36 | // string for message 37 | char *msg; 38 | if (vasprintf(&msg, fmt, va) < 0) { 39 | fprintf(stderr, 40 | "[ABRT] " _LTP_OP_ARGS_FMT_ " - unable to build message: %d\n", 41 | _LTP_OP_ARGS_USE_, errno); 42 | abort(); 43 | } 44 | 45 | // construct the message 46 | char buf[1024]; 47 | if (snprintf(buf, sizeof(buf), 48 | "[%s] " _LTP_OP_ARGS_FMT_ " (%d) - %s: %s\n", 49 | res, _LTP_OP_ARGS_USE_, eno, err, msg) < 0) { 50 | 51 | fprintf(stderr, 52 | "[ABRT] " _LTP_OP_ARGS_FMT_ " - unable to build result: %d\n", 53 | _LTP_OP_ARGS_USE_, errno); 54 | abort(); 55 | } 56 | 57 | // output 58 | fputs(buf, stderr); 59 | 60 | // clean up 61 | free(msg); 62 | } 63 | 64 | void _ltp_ret(_LTP_OP_ARGS_DEF_, 65 | int rv, 66 | const char *fmt, ...) { 67 | 68 | // show results 69 | va_list va; 70 | 71 | va_start(va, fmt); 72 | print_result(_LTP_OP_ARGS_USE_, rv, fmt, va); 73 | va_end(va); 74 | 75 | // finish 76 | exit((rv & ~(0x1)) ? EXIT_FAILURE : EXIT_SUCCESS); 77 | } -------------------------------------------------------------------------------- /kernel/initramfs/prog-test/ltp_output.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_LTP_OUTPUT_H_ 2 | #define _RACER_LTP_OUTPUT_H_ 3 | 4 | #include "ltp_common.h" 5 | 6 | // ltp result flags 7 | #define TPASS 0x0 // test passed 8 | #define TWARN 0x1 // test warned, passed with concerns 9 | #define TFAIL 0x2 // test failed, assertion not true 10 | #define TBROK 0x4 // test broken, prerequisites not met or failed 11 | #define TCONF 0x8 // test ignore, configuration not appropriate 12 | 13 | // ltp result interpretation 14 | #define _LTP_RES_MASK 0x0F 15 | 16 | #define LTP_RV_GET_RES(rv) ((rv) & _LTP_RES_MASK) 17 | #define LTP_RV_GET_ERR(rv) ((rv) >> 4) 18 | #define LTP_RV_MERGE(res, err) (((int) (-(err))) << 4 | (res)) 19 | 20 | // ltp result to string 21 | static inline char *ltp_rv_get_res_str(int rv) { 22 | switch (LTP_RV_GET_RES(rv)) { 23 | case TPASS: 24 | return "PASS"; 25 | case TWARN: 26 | return "WARN"; 27 | case TFAIL: 28 | return "FAIL"; 29 | case TBROK: 30 | return "BROK"; 31 | case TCONF: 32 | return "CONF"; 33 | default: 34 | return "ABRT"; 35 | } 36 | } 37 | 38 | // ltp finish with result 39 | void _ltp_ret(_LTP_OP_ARGS_DEF_, 40 | int rv, 41 | const char *fmt, ...); 42 | 43 | #define ltp_ret(rv, fmt, ...) \ 44 | _ltp_ret(_LTP_OP_ARGS_USE_, (rv), (fmt), ##__VA_ARGS__) 45 | 46 | #endif /* _RACER_LTP_OUTPUT_H_ */ 47 | -------------------------------------------------------------------------------- /kernel/initramfs/prog-test/ltp_safe_op_file.c: -------------------------------------------------------------------------------- 1 | #include "ltp.h" 2 | 3 | // lib: touch 4 | LTP_OP_SAFE_LIB_DEC( 5 | touch, 6 | void, 7 | const char *, path, mode_t, mode, struct timespec *, times 8 | ) { 9 | 10 | // open_close 11 | unsigned int fd = _safe_sys( 12 | open, 13 | path, 14 | O_CREAT | O_WRONLY | O_TRUNC, 15 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH 16 | ); 17 | _safe_sys(close, fd); 18 | 19 | // chmod if needed 20 | if (mode) { 21 | _safe_sys(chmod, path, mode); 22 | } 23 | 24 | // utimensat if needed 25 | if (times) { 26 | _safe_sys(utimensat, AT_FDCWD, path, times, 0); 27 | } 28 | } 29 | 30 | // lib: file_printf 31 | LTP_OP_SAFE_LIB_DEC_VA( 32 | file_printf, 33 | void, 34 | const char *, path, const char *, fmt 35 | ) { 36 | long ret; 37 | 38 | // prepare buffer 39 | char *buf; 40 | 41 | va_list ap; 42 | va_start(ap, fmt); 43 | 44 | ret = vasprintf(&buf, fmt, ap); 45 | if (ret == -1) { 46 | ltp_ret(LTP_RV_MERGE(TBROK, -errno), 47 | "vasprintf(%s, ...) failed", 48 | fmt); 49 | } 50 | 51 | va_end(ap); 52 | 53 | // open 54 | unsigned int fd = safe_sys_( 55 | open, path, 56 | O_CREAT | O_WRONLY | O_TRUNC, 57 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH 58 | ); 59 | 60 | // write 61 | _safe_sys(write, fd, buf, (size_t) ret); 62 | 63 | // close 64 | _safe_sys(close, fd); 65 | 66 | // clean up resources 67 | free(buf); 68 | } 69 | 70 | // lib: opendir 71 | LTP_OP_SAFE_LIB_DEC( 72 | opendir, 73 | struct dirent *, 74 | const char *, name 75 | ) { 76 | struct dirent *ret; 77 | 78 | errno = 0; 79 | ret = (struct dirent *) opendir(name); 80 | if (errno) { 81 | ltp_ret(LTP_RV_MERGE(TBROK, -errno), 82 | "opendir(%s) failed", 83 | name); 84 | } 85 | 86 | return ret; 87 | } 88 | 89 | // lib: readdir 90 | LTP_OP_SAFE_LIB_DEC( 91 | readdir, 92 | struct dirent *, 93 | struct dirent *, dirp 94 | ) { 95 | struct dirent *ret; 96 | 97 | errno = 0; 98 | ret = (struct dirent *) readdir((DIR *) dirp); 99 | if (errno) { 100 | ltp_ret(LTP_RV_MERGE(TBROK, -errno), 101 | "readdir(%p) failed", 102 | dirp); 103 | } 104 | 105 | return ret; 106 | } 107 | 108 | // lib: closedir 109 | LTP_OP_SAFE_LIB_DEC( 110 | closedir, 111 | void, 112 | struct dirent *, dirp 113 | ) { 114 | errno = 0; 115 | closedir((DIR *) dirp); 116 | if (errno) { 117 | ltp_ret(LTP_RV_MERGE(TBROK, -errno), 118 | "closedir(%p) failed", 119 | dirp); 120 | } 121 | } -------------------------------------------------------------------------------- /kernel/initramfs/prog-test/ltp_safe_op_user.c: -------------------------------------------------------------------------------- 1 | #include "ltp.h" 2 | 3 | LTP_OP_SAFE_LIB_DEC( 4 | set_fsrole, 5 | void, 6 | uid_t, uid, gid_t, gid 7 | ) { 8 | // NOTE: the order is important, re.id has to be set first before fs.id 9 | _safe_sys(setregid, gid, (gid_t) -1); 10 | _safe_sys(setreuid, uid, (uid_t) -1); 11 | 12 | _safe_sys(setfsgid, gid); 13 | _safe_sys(setfsuid, uid); 14 | } -------------------------------------------------------------------------------- /kernel/initramfs/prog-test/ltp_safe_op_user.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_LTP_SAFE_OP_USER_H_ 2 | #define _RACER_LTP_SAFE_OP_USER_H_ 3 | 4 | #include "ltp_common.h" 5 | 6 | LTP_OP_SAFE_SYS_DEF( 7 | setfsuid, 8 | ({ 9 | syscall(SYS_setfsuid, uid); 10 | }), 11 | ({ 12 | if (ret) { 13 | ltp_ret(LTP_RV_MERGE(TBROK, ret), 14 | "setfsuid(%d) failed", 15 | uid); 16 | } 17 | }), 18 | void, 19 | uid_t, uid 20 | ) 21 | 22 | LTP_OP_SAFE_SYS_DEF( 23 | setfsgid, 24 | ({ 25 | syscall(SYS_setfsgid, gid); 26 | }), 27 | ({ 28 | if (ret) { 29 | ltp_ret(LTP_RV_MERGE(TBROK, ret), 30 | "setfsgid(%d) failed", 31 | gid); 32 | } 33 | }), 34 | void, 35 | gid_t, gid 36 | ) 37 | 38 | LTP_OP_SAFE_SYS_DEF( 39 | setreuid, 40 | ({ 41 | syscall(SYS_setreuid, ruid, euid); 42 | }), 43 | ({ 44 | if (ret) { 45 | ltp_ret(LTP_RV_MERGE(TBROK, ret), 46 | "setreuid(%d, %d) failed", 47 | ruid, euid); 48 | } 49 | }), 50 | void, 51 | uid_t, ruid, uid_t, euid 52 | ) 53 | 54 | LTP_OP_SAFE_SYS_DEF( 55 | setregid, 56 | ({ 57 | syscall(SYS_setregid, rgid, egid); 58 | }), 59 | ({ 60 | if (ret) { 61 | ltp_ret(LTP_RV_MERGE(TBROK, ret), 62 | "setregid(%d, %d) failed", 63 | rgid, egid); 64 | } 65 | }), 66 | void, 67 | gid_t, rgid, gid_t, egid 68 | ) 69 | 70 | /* 71 | * Safe function to temporarily change uid/gid for filesystems operations 72 | */ 73 | LTP_OP_SAFE_LIB_DEC( 74 | set_fsrole, 75 | void, 76 | uid_t, uid, gid_t, gid 77 | ); 78 | 79 | #endif /* _RACER_LTP_SAFE_OP_USER_H_ */ 80 | -------------------------------------------------------------------------------- /kernel/initramfs/prog-test/main.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | #ifndef USE_DART 4 | #define USE_DART 5 | #endif 6 | #include "shared.inc" 7 | 8 | void racer_test(void) { 9 | int fd; 10 | const char *buf_in = "HELLO FROM RACER"; 11 | char buf_out[256] = {0}; 12 | 13 | // get mount info 14 | struct mount_info *info = (struct mount_info *) ( 15 | (char *) g_shmem + sizeof(struct shmem_hdr) 16 | ); 17 | 18 | // set-up 19 | mount_image(info->mod_main, info->mod_main_num, 20 | info->mod_deps, info->mod_deps_num, 21 | info->fs_type, info->mnt_opts, 22 | LOOP_DEV, 23 | FS_DISK_IMG, FS_DISK_MNT); 24 | 25 | // test sequence 26 | SYSRUN_VAL(1, SYS_chdir, FS_DISK_MNT); 27 | 28 | // create directory 29 | SYSRUN_VAL(2, SYS_mkdir, "dir_foo", 0777); 30 | fd = SYSRUN_VAL(3, SYS_open, "dir_foo", O_DIRECTORY | O_RDONLY, 0777); 31 | SYSRUN_VAL(2, SYS_dup2, fd, 199); 32 | SYSRUN_VAL(1, SYS_close, 199); 33 | SYSRUN_VAL(1, SYS_close, fd); 34 | 35 | // create file 36 | fd = SYSRUN_VAL(2, SYS_creat, "file_bar", 0777); 37 | SYSRUN_VAL(2, SYS_dup2, fd, 198); 38 | SYSRUN_VAL(1, SYS_close, 198); 39 | SYSRUN_VAL(1, SYS_close, fd); 40 | 41 | // file io 42 | fd = SYSRUN_VAL(3, SYS_open, "file_bar", O_RDWR, 0777); 43 | SYSRUN_VAL(3, SYS_write, fd, buf_in, strlen(buf_in) + 1); 44 | SYSRUN_VAL(1, SYS_close, fd); 45 | 46 | SYSRUN_VAL(1, SYS_chdir, "/"); 47 | 48 | // tear-down 49 | umount_image(info->mod_names, info->mod_names_num, 50 | LOOP_DEV, FS_DISK_IMG, 51 | FS_DISK_MNT); 52 | } 53 | -------------------------------------------------------------------------------- /kernel/initramfs/shared.inc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | // mount fs image 7 | #define LOOP_DEV "/dev/loop0" 8 | 9 | // mount fs module 10 | #define MOD_NAME_MAX 64 11 | #define MOD_PATH_MAX 128 12 | #define MOD_MAIN_MAX 8 13 | #define MOD_DEPS_MAX 32 14 | #define MNT_OPTS_MAX 1024 15 | 16 | struct mount_info { 17 | char fs_type[MOD_NAME_MAX]; 18 | char mnt_opts[MNT_OPTS_MAX]; 19 | unsigned long mod_main_num; 20 | unsigned long mod_deps_num; 21 | unsigned long mod_names_num; 22 | char mod_main[MOD_MAIN_MAX][MOD_PATH_MAX]; 23 | char mod_deps[MOD_DEPS_MAX][MOD_PATH_MAX]; 24 | char mod_names[MOD_MAIN_MAX][MOD_PATH_MAX]; 25 | }; 26 | 27 | static inline void loop_touch(const char *loop) { 28 | int loopfd = open(loop, O_RDWR); 29 | if (loopfd == -1) { 30 | panic(errno, "Failed to open loopfd", NULL); 31 | } 32 | 33 | close(loopfd); 34 | } 35 | 36 | static inline void loop_control( 37 | const char *loop, const char *disk, bool bind 38 | ) { 39 | int rv; 40 | 41 | // create and associate with a loop device 42 | #ifdef USE_DART 43 | dart_ctxt_syscall_enter(SYS_open); 44 | #endif 45 | int loopfd = open(loop, O_RDWR); 46 | #ifdef USE_DART 47 | dart_ctxt_syscall_exit(SYS_open); 48 | #endif 49 | if (loopfd == -1) { 50 | panic(errno, "Failed to open loopfd", NULL); 51 | } 52 | 53 | #ifdef USE_DART 54 | dart_ctxt_syscall_enter(SYS_open); 55 | #endif 56 | int diskfd = open(disk, O_RDWR); 57 | #ifdef USE_DART 58 | dart_ctxt_syscall_exit(SYS_open); 59 | #endif 60 | if (diskfd == -1) { 61 | panic(errno, "Failed to open diskfd", NULL); 62 | } 63 | 64 | #ifdef USE_DART 65 | dart_ctxt_syscall_enter(SYS_ioctl); 66 | #endif 67 | rv = ioctl(loopfd, bind ? LOOP_SET_FD : LOOP_CLR_FD, diskfd); 68 | #ifdef USE_DART 69 | dart_ctxt_syscall_exit(SYS_ioctl); 70 | #endif 71 | if (rv) { 72 | panic(errno, "Failed to associate diskfd and loopfd", NULL); 73 | } 74 | 75 | #ifdef USE_DART 76 | dart_ctxt_syscall_enter(SYS_close); 77 | #endif 78 | close(diskfd); 79 | #ifdef USE_DART 80 | dart_ctxt_syscall_exit(SYS_close); 81 | #endif 82 | 83 | #ifdef USE_DART 84 | dart_ctxt_syscall_enter(SYS_close); 85 | #endif 86 | close(loopfd); 87 | #ifdef USE_DART 88 | dart_ctxt_syscall_exit(SYS_close); 89 | #endif 90 | } 91 | 92 | static inline void mount_image( 93 | const char mod_main[MOD_MAIN_MAX][MOD_PATH_MAX], 94 | unsigned long mod_main_n, 95 | const char mod_deps[MOD_DEPS_MAX][MOD_PATH_MAX], 96 | unsigned long mod_deps_n, 97 | const char *fs_type, const char *fs_opts, 98 | const char *loop, 99 | const char *disk, const char *mptr 100 | ) { 101 | int rv; 102 | 103 | // load extra modules 104 | for (unsigned long i = 0; i < mod_deps_n; i++) { 105 | load_module(mod_deps[i]); 106 | } 107 | 108 | // touch the loop device 109 | loop_touch(loop); 110 | 111 | // prepare the mount point 112 | rv = mkdir(mptr, 0777); 113 | if (rv) { 114 | panic(errno, "Failed to create ", mptr, NULL); 115 | } 116 | 117 | #ifdef USE_DART 118 | // launch dart right before mount 119 | dart_launch(); 120 | #endif 121 | 122 | // load filesystem module 123 | for (unsigned long i = 0; i < mod_main_n; i++) { 124 | load_module(mod_main[i]); 125 | } 126 | 127 | // bind to a loop device 128 | loop_control(loop, disk, true); 129 | 130 | // do the actual mount 131 | #ifdef USE_DART 132 | dart_ctxt_syscall_enter(SYS_mount); 133 | #endif 134 | rv = mount(loop, mptr, fs_type, 0, fs_opts); 135 | #ifdef USE_DART 136 | dart_ctxt_syscall_exit(SYS_mount); 137 | #endif 138 | if (rv) { 139 | panic(errno, "Failed to mount ", disk, NULL); 140 | } 141 | } 142 | 143 | static inline void umount_image( 144 | const char mod_names[MOD_MAIN_MAX][MOD_PATH_MAX], 145 | unsigned long mod_names_n, 146 | const char *loop, 147 | const char *disk, const char *mptr 148 | ) { 149 | int rv; 150 | 151 | // do force umount 152 | #ifdef USE_DART 153 | dart_ctxt_syscall_enter(SYS_umount2); 154 | #endif 155 | rv = umount2(mptr, 0); 156 | #ifdef USE_DART 157 | dart_ctxt_syscall_exit(SYS_umount2); 158 | #endif 159 | if (rv) { 160 | panic(errno, "Failed to umount ", mptr, NULL); 161 | } 162 | 163 | // unbind from a loop device 164 | loop_control(loop, disk, false); 165 | 166 | // unload module 167 | for (unsigned i = 0; i < mod_names_n; i++) { 168 | unload_module(mod_names[i]); 169 | } 170 | 171 | #ifdef USE_DART 172 | // finish dart right after umount 173 | dart_finish(); 174 | #endif 175 | } 176 | 177 | // syscall wrapper by arg number 178 | #define _SYSRUN_ARG_DEF(A) , long A 179 | #define _SYSRUN_ARG_USE(A) , A 180 | 181 | #ifdef RACER_STRACE 182 | #define call_strace(n, sysno, tokn, ret, ...) \ 183 | STRACE_HANDLES_##n[sysno](tokn, ret VARDEF1(_SYSRUN_ARG_USE, , ##__VA_ARGS__)) 184 | #else 185 | #define call_strace(n, sysno, tokn, ret, ...) 186 | #endif 187 | 188 | #define SYSRUN_DEF(n, ...) \ 189 | static inline long sysrun_##n( \ 190 | long sysno \ 191 | VARDEF1(_SYSRUN_ARG_DEF, , ##__VA_ARGS__) \ 192 | ) { \ 193 | call_strace(n, sysno, "->", 0x0, ##__VA_ARGS__); \ 194 | dart_ctxt_syscall_enter(sysno); \ 195 | long ret = syscall( \ 196 | sysno \ 197 | VARDEF1(_SYSRUN_ARG_USE, , ##__VA_ARGS__) \ 198 | ); \ 199 | dart_ctxt_syscall_exit(sysno); \ 200 | if (ret == -1) { \ 201 | ret = -errno; \ 202 | } \ 203 | call_strace(n, sysno, "<-", ret, ##__VA_ARGS__); \ 204 | return ret; \ 205 | } 206 | 207 | SYSRUN_DEF(0) 208 | 209 | SYSRUN_DEF(1, arg0) 210 | 211 | SYSRUN_DEF(2, arg0, arg1) 212 | 213 | SYSRUN_DEF(3, arg0, arg1, arg2) 214 | 215 | SYSRUN_DEF(4, arg0, arg1, arg2, arg3) 216 | 217 | SYSRUN_DEF(5, arg0, arg1, arg2, arg3, arg4) 218 | 219 | SYSRUN_DEF(6, arg0, arg1, arg2, arg3, arg4, arg5) 220 | 221 | #define _SYSRUN_ARG_VAL(A) , (long) (A) 222 | 223 | #define SYSRUN_VAL(n, sys, ...) \ 224 | sysrun_##n(sys VARDEF1(_SYSRUN_ARG_VAL, , ##__VA_ARGS__)); \ 225 | warn(#sys, NULL); 226 | -------------------------------------------------------------------------------- /kernel/initramfs/strace.h: -------------------------------------------------------------------------------- 1 | #include "vardef.h" 2 | 3 | #ifndef _RACER_FUZZ_H_STRACE_H_ 4 | #define _RACER_FUZZ_H_STRACE_H_ 5 | 6 | #define STRACE_SYSCALL_NUM_MAX 1024 7 | 8 | #define STRACE_HANDLE_DECLARE(n, ...) \ 9 | typedef void (*t_strace_##n)(const char *, long, ##__VA_ARGS__); \ 10 | extern t_strace_##n STRACE_HANDLES_##n[STRACE_SYSCALL_NUM_MAX] 11 | 12 | #define STRACE_HANDLE_DEFINE(n) \ 13 | t_strace_##n STRACE_HANDLES_##n[STRACE_SYSCALL_NUM_MAX] = {0} 14 | 15 | STRACE_HANDLE_DECLARE(0); 16 | STRACE_HANDLE_DECLARE(1, long); 17 | STRACE_HANDLE_DECLARE(2, long, long); 18 | STRACE_HANDLE_DECLARE(3, long, long, long); 19 | STRACE_HANDLE_DECLARE(4, long, long, long, long); 20 | STRACE_HANDLE_DECLARE(5, long, long, long, long, long); 21 | STRACE_HANDLE_DECLARE(6, long, long, long, long, long, long); 22 | 23 | // apis 24 | void strace_init(void); 25 | 26 | #endif /* _RACER_FUZZ_H_STRACE_H_ */ 27 | -------------------------------------------------------------------------------- /kernel/initramfs/util.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | static void append_to_buf_v(char *buf, size_t size, va_list ap) { 4 | const char *ptr; 5 | size_t cur_size, rem_size, seg_size; 6 | 7 | cur_size = strlen(buf); 8 | if (cur_size >= size) 9 | return; 10 | 11 | rem_size = size - cur_size; 12 | 13 | for (ptr = va_arg(ap, const char *); ptr; ptr = va_arg(ap, const char *)) { 14 | strncat(buf, ptr, rem_size - 1); 15 | 16 | seg_size = strlen(ptr); 17 | 18 | /* Make sure it's NUL-terminated. */ 19 | if (seg_size >= rem_size - 1) { 20 | buf[size - 1] = '\0'; 21 | break; 22 | } 23 | 24 | rem_size -= seg_size; 25 | } 26 | } 27 | 28 | void app_buf(char *buf, size_t size, ...) { 29 | va_list ap; 30 | 31 | va_start(ap, size); 32 | append_to_buf_v(buf, size, ap); 33 | va_end(ap); 34 | } 35 | 36 | void set_buf(char *buf, size_t size, ...) { 37 | va_list ap; 38 | 39 | va_start(ap, size); 40 | memset(buf, 0, size); 41 | append_to_buf_v(buf, size, ap); 42 | va_end(ap); 43 | } -------------------------------------------------------------------------------- /kernel/spec/.gitignore: -------------------------------------------------------------------------------- 1 | /generated/ 2 | -------------------------------------------------------------------------------- /kernel/spec/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(racer-spec) 3 | 4 | # compile and link 5 | set(CMAKE_CXX_STANDARD 17) 6 | 7 | # debug 8 | add_compile_definitions(RACER_DEBUG) 9 | 10 | # code generation 11 | add_custom_target(codegen 12 | ALL 13 | COMMAND python3 ${CMAKE_SOURCE_DIR}/codegen.py 14 | BYPRODUCTS generated/vardef.h 15 | COMMENT "Generating vardef.h") 16 | 17 | # sources 18 | add_executable(spec 19 | main.cpp) 20 | 21 | add_dependencies(spec codegen) 22 | 23 | target_compile_options(spec PUBLIC 24 | -Wall -Wextra) 25 | -------------------------------------------------------------------------------- /kernel/spec/codegen.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | import os 4 | import string 5 | 6 | from abc import ABC, abstractmethod 7 | 8 | 9 | class Generator(ABC): 10 | 11 | def __init__(self, name: str) -> None: 12 | # basic 13 | self.name = name 14 | 15 | # derived 16 | self.path = 'generated/{}.h'.format(self.name) 17 | self.mark = '_RACER_SPEC_{}_H_'.format(self.name.upper()) 18 | 19 | def gen_warning(self) -> List[str]: 20 | return [ 21 | '/* AUTO-GENERATED ({}) - DO NOT EDIT */'.format(self.name) 22 | ] 23 | 24 | def gen_mark_header(self) -> List[str]: 25 | return [ 26 | '#ifndef {}'.format(self.mark), 27 | '#define {}'.format(self.mark), 28 | ] 29 | 30 | def gen_mark_footer(self) -> List[str]: 31 | return [ 32 | '#endif /* {} */'.format(self.mark), 33 | ] 34 | 35 | @abstractmethod 36 | def generate(self) -> str: 37 | raise RuntimeError('Method not implemented') 38 | 39 | def save(self) -> None: 40 | os.makedirs(os.path.dirname(self.path), exist_ok=True) 41 | with open(self.path, 'w') as f: 42 | f.write(self.generate()) 43 | 44 | 45 | class Generator_VARDEF(Generator): 46 | CHARSET = string.ascii_uppercase 47 | 48 | def __init__(self, num_group: int, max_group_size: int) -> None: 49 | super(Generator_VARDEF, self).__init__('vardef') 50 | self.num_group = num_group 51 | self.max_group_size = max_group_size 52 | 53 | def gen_ignore(self) -> List[str]: 54 | return [ 55 | '#define _VARDEF_IGNORE(...) static_assert(false)' 56 | ] 57 | 58 | def gen_pack(self, num_group: int, group_size: int) -> List[str]: 59 | exprs = [] # type: List[str] 60 | 61 | # common 62 | vardef = 'VARDEF{}'.format(group_size) 63 | prefix = '_' + vardef + '_' 64 | 65 | # generate SELECT 66 | elems = [] # type: List[str] 67 | for i in range(num_group + 1): 68 | for j in range(group_size): 69 | elems.append('{}{}'.format(Generator_VARDEF.CHARSET[j], i)) 70 | 71 | exprs.append( 72 | '#define {}SELECT({}, N, ...) N'.format( 73 | prefix, ', '.join(elems) 74 | ) 75 | ) 76 | 77 | # generate GROUP_X 78 | arg_group = ', '.join([ 79 | Generator_VARDEF.CHARSET[j] for j in range(group_size) 80 | ]) 81 | 82 | exprs.append( 83 | '#define {}GROUP0(Func, None, ...) None'.format( 84 | prefix 85 | ) 86 | ) 87 | for i in range(1, num_group + 1, 1): 88 | exprs.append(' '.join([ 89 | '#define', 90 | '{}GROUP{}(Func, None, {}, ...)'.format(prefix, i, arg_group), 91 | 'Func({})'.format(arg_group), 92 | '{}GROUP{}(Func, None, __VA_ARGS__)'.format(prefix, i - 1), 93 | ])) 94 | 95 | # generate VARDEF 96 | exprs.append(' '.join([ 97 | '#define', 98 | '{}(Func, None, ...)'.format(vardef), 99 | '{}SELECT(, , ##__VA_ARGS__, {})(Func, None, __VA_ARGS__)'.format( 100 | prefix, ', '.join([ 101 | '{}GROUP{}'.format(prefix, i) + 102 | ', _VARDEF_IGNORE' * (group_size - 1) 103 | for i in range(num_group, -1, -1) 104 | ]) 105 | ) 106 | ])) 107 | 108 | return exprs 109 | 110 | def generate(self) -> str: 111 | exprs = self.gen_warning() 112 | exprs += self.gen_mark_header() 113 | exprs += self.gen_ignore() 114 | for i in range(1, self.max_group_size + 1, 1): 115 | exprs += self.gen_pack(self.num_group, i) 116 | exprs += self.gen_mark_footer() 117 | return '\n'.join(exprs) 118 | 119 | 120 | if __name__ == '__main__': 121 | g = Generator_VARDEF(num_group=8, max_group_size=6) 122 | g.save() 123 | -------------------------------------------------------------------------------- /kernel/spec/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "type_int.h" 4 | 5 | using namespace spec; 6 | 7 | int main() { 8 | RandInt ri; 9 | ri.data(2); 10 | ri.validate(); 11 | 12 | TypeInt ti; 13 | cout << ti.size().value() << endl; 14 | 15 | return 0; 16 | } -------------------------------------------------------------------------------- /kernel/spec/type_int.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_SPEC_TYPE_INT_H_ 2 | #define _RACER_SPEC_TYPE_INT_H_ 3 | 4 | #include "common.h" 5 | 6 | namespace spec { 7 | 8 | template 9 | BEAN(RandInt, Rand, 10 | I, data) 11 | }; 12 | 13 | template 14 | BEAN(TypeInt, Type>) 15 | 16 | public: 17 | optional size() const override { 18 | return sizeof(I); 19 | } 20 | 21 | void mutate(Program &prog) const override { 22 | prog.lego(*this); 23 | } 24 | }; 25 | 26 | } // spec namespace 27 | 28 | #endif /* _RACER_SPEC_TYPE_INT_H_ */ 29 | -------------------------------------------------------------------------------- /pass/CMakeCache.txt: -------------------------------------------------------------------------------- 1 | # This is the CMakeCache file. 2 | # For build in directory: /home/seungjunn/git/krace/pass 3 | # It was generated by CMake: /usr/local/bin/cmake 4 | # You can edit this file to change values found and used by cmake. 5 | # If you do not want to change any of the values, simply exit the editor. 6 | # If you do want to change a value, simply edit, save, and exit the editor. 7 | # The syntax for the file is as follows: 8 | # KEY:TYPE=VALUE 9 | # KEY is the name of a variable in the cache. 10 | # TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. 11 | # VALUE is the current value for the KEY. 12 | 13 | ######################## 14 | # EXTERNAL cache entries 15 | ######################## 16 | 17 | 18 | ######################## 19 | # INTERNAL cache entries 20 | ######################## 21 | 22 | //This is the directory where this CMakeCache.txt was created 23 | CMAKE_CACHEFILE_DIR:INTERNAL=/home/seungjunn/git/krace/pass 24 | //Major version of cmake used to create the current loaded cache 25 | CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 26 | //Minor version of cmake used to create the current loaded cache 27 | CMAKE_CACHE_MINOR_VERSION:INTERNAL=11 28 | //Patch version of cmake used to create the current loaded cache 29 | CMAKE_CACHE_PATCH_VERSION:INTERNAL=2 30 | //Path to CMake executable. 31 | CMAKE_COMMAND:INTERNAL=/usr/local/bin/cmake 32 | //Path to cpack program executable. 33 | CMAKE_CPACK_COMMAND:INTERNAL=/usr/local/bin/cpack 34 | //Path to ctest program executable. 35 | CMAKE_CTEST_COMMAND:INTERNAL=/usr/local/bin/ctest 36 | //Path to cache edit program executable. 37 | CMAKE_EDIT_COMMAND:INTERNAL=/usr/local/bin/ccmake 38 | //Name of external makefile project generator. 39 | CMAKE_EXTRA_GENERATOR:INTERNAL= 40 | //Name of generator. 41 | CMAKE_GENERATOR:INTERNAL=Unix Makefiles 42 | //Generator instance identifier. 43 | CMAKE_GENERATOR_INSTANCE:INTERNAL= 44 | //Name of generator platform. 45 | CMAKE_GENERATOR_PLATFORM:INTERNAL= 46 | //Name of generator toolset. 47 | CMAKE_GENERATOR_TOOLSET:INTERNAL= 48 | //Source directory with the top level CMakeLists.txt file for this 49 | // project 50 | CMAKE_HOME_DIRECTORY:INTERNAL=/home/seungjunn/git/krace/pass 51 | //number of local generators 52 | CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 53 | //Path to CMake installation. 54 | CMAKE_ROOT:INTERNAL=/usr/local/share/cmake-3.11 55 | 56 | -------------------------------------------------------------------------------- /pass/CMakeFiles/cmake.check_cache: -------------------------------------------------------------------------------- 1 | # This file is generated by cmake for dependency checking of the CMakeCache.txt file 2 | -------------------------------------------------------------------------------- /pass/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(racer) 3 | 4 | # studio 5 | if (DEFINED ENV{IN_RACER_DOCKER}) 6 | set(RACER_STUDIO "dock") 7 | else () 8 | set(RACER_STUDIO "host") 9 | endif () 10 | 11 | # paths 12 | get_filename_component(RACER_PATH_BASE 13 | ${CMAKE_SOURCE_DIR} DIRECTORY) 14 | 15 | set(RACER_PATH_LLVM 16 | "${RACER_PATH_BASE}/studio/${RACER_STUDIO}/store/llvm") 17 | 18 | set(RACER_PATH_MISC_JSON 19 | "${RACER_PATH_BASE}/misc/json") 20 | 21 | # configs 22 | add_compile_definitions(RACER_DEBUG_ALL) 23 | 24 | # package: llvm 25 | find_package(LLVM REQUIRED 26 | PATHS ${RACER_PATH_LLVM} NO_DEFAULT_PATH) 27 | 28 | # flags: global 29 | set(CMAKE_CXX_STANDARD 11) 30 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 31 | 32 | # project: codegen 33 | add_custom_target(codegen 34 | ALL 35 | COMMAND python3 ${CMAKE_SOURCE_DIR}/codegen.py 36 | BYPRODUCTS dart/vardef.h 37 | COMMENT "Generating code") 38 | 39 | # project: instrument 40 | add_subdirectory(instrument) 41 | 42 | # project: test (only when set) 43 | if (RACER_UNIT_TESTS) 44 | enable_testing() 45 | add_subdirectory(test) 46 | endif () 47 | -------------------------------------------------------------------------------- /pass/codegen.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | import os 4 | import string 5 | 6 | from abc import ABC, abstractmethod 7 | 8 | 9 | class Generator(ABC): 10 | 11 | def __init__(self, path: str) -> None: 12 | self.path = os.path.abspath(os.path.join(__file__, '..', path)) 13 | 14 | @abstractmethod 15 | def gen(self) -> str: 16 | raise RuntimeError('Method not implemented') 17 | 18 | def save(self) -> None: 19 | with open(self.path, 'w') as f: 20 | f.write(self.gen()) 21 | 22 | 23 | class Generator_VARDEF(Generator): 24 | CHARSET = string.ascii_uppercase 25 | 26 | def __init__(self, num_group: int, max_group_size: int) -> None: 27 | super(Generator_VARDEF, self).__init__('dart/vardef.h') 28 | self.num_group = num_group 29 | self.max_group_size = max_group_size 30 | self.mark = '_RACER_DART_VARDEF_H_' 31 | 32 | def gen_header(self) -> List[str]: 33 | return [ 34 | '#ifndef {}'.format(self.mark), 35 | '#define {}'.format(self.mark), 36 | ] 37 | 38 | def gen_footer(self) -> List[str]: 39 | return [ 40 | '#endif /* {} */'.format(self.mark), 41 | ] 42 | 43 | def gen_ignore(self) -> List[str]: 44 | return [ 45 | '#define _VARDEF_IGNORE(...)' 46 | ] 47 | 48 | def gen_pack(self, num_group: int, group_size: int) -> List[str]: 49 | exprs = [] # type: List[str] 50 | 51 | # common 52 | vardef = 'VARDEF{}'.format(group_size) 53 | prefix = '_' + vardef + '_' 54 | 55 | # generate SELECT 56 | elems = [] # type: List[str] 57 | for i in range(num_group + 1): 58 | for j in range(group_size): 59 | elems.append('{}{}'.format(Generator_VARDEF.CHARSET[j], i)) 60 | 61 | exprs.append( 62 | '#define {}SELECT({}, N, ...) N'.format( 63 | prefix, ', '.join(elems) 64 | ) 65 | ) 66 | 67 | # generate GROUP_X 68 | arg_group = ', '.join([ 69 | Generator_VARDEF.CHARSET[j] for j in range(group_size) 70 | ]) 71 | 72 | exprs.append( 73 | '#define {}GROUP0(Func, None, ...) None'.format( 74 | prefix 75 | ) 76 | ) 77 | for i in range(1, num_group + 1, 1): 78 | exprs.append(' '.join([ 79 | '#define', 80 | '{}GROUP{}(Func, None, {}, ...)'.format(prefix, i, arg_group), 81 | 'Func({})'.format(arg_group), 82 | '{}GROUP{}(Func, None, ##__VA_ARGS__)'.format(prefix, i - 1), 83 | ])) 84 | 85 | # generate VARDEF 86 | exprs.append(' '.join([ 87 | '#define', 88 | '{}(Func, None, ...)'.format(vardef), 89 | '{}SELECT({}##__VA_ARGS__, {})(Func, None, ##__VA_ARGS__)'.format( 90 | prefix, ', ' * group_size, ', '.join([ 91 | '{}GROUP{}'.format(prefix, i) + 92 | ', _VARDEF_IGNORE' * (group_size - 1) 93 | for i in range(num_group, -1, -1) 94 | ]) 95 | ) 96 | ])) 97 | 98 | return exprs 99 | 100 | def gen(self) -> str: 101 | stmts = self.gen_header() + self.gen_ignore() 102 | for i in range(1, self.max_group_size + 1, 1): 103 | stmts += self.gen_pack(self.num_group, i) 104 | 105 | stmts += self.gen_footer() 106 | return '\n'.join(stmts) 107 | 108 | 109 | if __name__ == '__main__': 110 | g = Generator_VARDEF(num_group=8, max_group_size=6) 111 | g.save() 112 | -------------------------------------------------------------------------------- /pass/dart/.gitignore: -------------------------------------------------------------------------------- 1 | /compile_commands.json 2 | -------------------------------------------------------------------------------- /pass/dart/Makefile: -------------------------------------------------------------------------------- 1 | obj-$(CONFIG_DART) += dart.o 2 | 3 | dart-y := runtime.o dart_wks.o dart_log.o dart_ctrl.o 4 | 5 | KASAN_SANITIZE := n 6 | KTSAN_SANITIZE := n -------------------------------------------------------------------------------- /pass/dart/dart.h: -------------------------------------------------------------------------------- 1 | #ifndef _DART_H_ 2 | #define _DART_H_ 3 | 4 | #include "dart_common.h" 5 | #include "dart_hash.h" 6 | #include "dart_wks.h" 7 | #include "dart_log.h" 8 | #include "dart_ptid.h" 9 | #include "dart_ctrl.h" 10 | 11 | #endif /* _DART_H_ */ 12 | -------------------------------------------------------------------------------- /pass/dart/dart_common.h: -------------------------------------------------------------------------------- 1 | #ifndef _DART_COMMON_H_ 2 | #define _DART_COMMON_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include "dart_kernel.h" 24 | 25 | extern long dart_iseq; 26 | extern char *dart_shared; 27 | extern char *dart_private; 28 | extern char *dart_reserved; 29 | 30 | /* ivshmem-mapped memory 31 | * 32 | * | 4 MB | -> header 33 | * | 4 MB | -> cov_cfg_edge 34 | * | 4 MB | -> cov_dfg_edge 35 | * | 4 MB | -> cov_alias_inst 36 | * |240 MB | -> (reserved) 37 | * 38 | * --------- (256 MB) header 39 | * 40 | * | 2 MB | -> metadata (userspace: mount options, etc) 41 | * | 48 MB | -> bytecode (userspace: program to interpret) 42 | * | 12 MB | -> strace (userspace: syscall logs) 43 | * | 2 MB | -> rtinfo (kernel : runtime info) 44 | * | 64 MB | -> rtrace (kernel : racing access logs) 45 | * 46 | * --------- (128 MB) instance 47 | */ 48 | 49 | #define _MB(i) (i * (1ul << 20)) 50 | 51 | #define INSTMEM_OFFSET_USER 0 52 | #define INSTMEM_OFFSET_METADATA 0 53 | #define INSTMEM_OFFSET_BYTECODE (INSTMEM_OFFSET_METADATA + _MB(2)) 54 | #define INSTMEM_OFFSET_STRACE (INSTMEM_OFFSET_BYTECODE + _MB(48)) 55 | #define INSTMEM_SIZE_USER (INSTMEM_OFFSET_STRACE + _MB(12)) 56 | 57 | #define INSTMEM_OFFSET_KERN (INSTMEM_OFFSET_USER + INSTMEM_SIZE_USER) 58 | #define INSTMEM_OFFSET_RTINFO 0 59 | #define INSTMEM_OFFSET_RTRACE (INSTMEM_OFFSET_RTINFO + _MB(2)) 60 | #define INSTMEM_SIZE_KERN (INSTMEM_OFFSET_RTRACE + _MB(64)) 61 | 62 | #define INSTMEM_SIZE (INSTMEM_SIZE_USER + INSTMEM_SIZE_KERN) 63 | 64 | #define IVSHMEM_OFFSET_HEADER 0 65 | #define IVSHMEM_OFFSET_COV_CFG_EDGE (IVSHMEM_OFFSET_HEADER + _MB(4)) 66 | #define IVSHMEM_OFFSET_COV_DFG_EDGE (IVSHMEM_OFFSET_COV_CFG_EDGE + _MB(4)) 67 | #define IVSHMEM_OFFSET_COV_ALIAS_INST (IVSHMEM_OFFSET_COV_DFG_EDGE + _MB(4)) 68 | #define IVSHMEM_OFFSET_RESERVED (IVSHMEM_OFFSET_COV_ALIAS_INST + _MB(4)) 69 | #define IVSHMEM_OFFSET_INSTANCES (IVSHMEM_OFFSET_RESERVED + _MB(240)) 70 | 71 | #define INSTMEM_OFFSET(i) (IVSHMEM_OFFSET_INSTANCES + INSTMEM_SIZE * (i)) 72 | #define IVSHMEM_SHARED IVSHMEM_OFFSET_RESERVED 73 | 74 | /* specify the dart syscall */ 75 | #define CMD_DART_LAUNCH 1 76 | #define CMD_DART_FINISH 2 77 | #define CMD_DART_CTXT_SYSCALL_START 3 78 | #define CMD_DART_CTXT_SYSCALL_EXIT 4 79 | 80 | /* printing */ 81 | #define _dart_pr(level, fmt, ...) \ 82 | printk(level "[DART] " fmt "\n", ##__VA_ARGS__) 83 | 84 | #define dart_pr_debug(fmt, ...) _dart_pr(KERN_INFO, fmt, ##__VA_ARGS__) 85 | #define dart_pr_info(fmt, ...) _dart_pr(KERN_NOTICE, fmt, ##__VA_ARGS__) 86 | #define dart_pr_warn(fmt, ...) _dart_pr(KERN_WARNING, fmt, ##__VA_ARGS__) 87 | #define dart_pr_err(fmt, ...) _dart_pr(KERN_ERR, fmt, ##__VA_ARGS__) 88 | 89 | /* bugging */ 90 | #ifdef DART_LOGGING 91 | #define DART_BUG() \ 92 | do { \ 93 | dart_ledger_transfer_ro_reserve(g_ledger, g_reserve_ledger); \ 94 | BUG(); \ 95 | } while (0) 96 | #define DART_BUG_ON(condition) \ 97 | do { \ 98 | if (unlikely(condition)) \ 99 | dart_ledger_transfer_ro_reserve(g_ledger, g_reserve_ledger); \ 100 | BUG(); \ 101 | \ 102 | } while (0) 103 | #else 104 | #define DART_BUG BUG 105 | #define DART_BUG_ON BUG_ON 106 | #endif 107 | 108 | /* memory shadowing */ 109 | #define SHADOW_SIZE 8 110 | #define ADDR_TO_SHADOW(addr) ((addr) & ~(0x7ul)) 111 | #define ADDR_TO_OFFSET(addr) ((addr) & 0x7ul) 112 | 113 | #endif /* _DART_COMMON_H_ */ 114 | -------------------------------------------------------------------------------- /pass/dart/dart_ctrl.c: -------------------------------------------------------------------------------- 1 | #include "dart.h" 2 | 3 | /* global switch */ 4 | atomic_t dart_switch_meta = ATOMIC_INIT(0); 5 | EXPORT_SYMBOL(dart_switch_meta); 6 | 7 | atomic_t dart_switch_data = ATOMIC_INIT(0); 8 | EXPORT_SYMBOL(dart_switch_data); 9 | 10 | /* control block */ 11 | struct __ht_dart_cb *g_dart_cb_ht = NULL; 12 | 13 | /* async info */ 14 | struct __ht_dart_async *g_dart_async_ht = NULL; 15 | struct __ht_dart_event *g_dart_event_ht = NULL; 16 | 17 | /* memory cell */ 18 | struct __ht_dart_mc *g_dart_mc_reader_ht = NULL; 19 | struct __ht_dart_mc *g_dart_mc_writer_ht = NULL; 20 | 21 | /* ignored events TODO (for debug purpose only, removed later) */ 22 | atomic_t g_dart_ignored_events = ATOMIC_INIT(0); -------------------------------------------------------------------------------- /pass/dart/dart_hash.h: -------------------------------------------------------------------------------- 1 | #ifndef _DART_HASH_H_ 2 | #define _DART_HASH_H_ 3 | 4 | #include "dart_common.h" 5 | 6 | /* hash functions */ 7 | #define DART_HASH_DEFINE(ilen, bits) \ 8 | typedef uint##ilen ## _t hash##bits ## _t; \ 9 | static inline hash##bits ## _t hash_u64_into_h##bits(uint64_t n) { \ 10 | return (hash##bits ## _t) hash_64(n, bits); \ 11 | } \ 12 | static inline hash##bits ## _t hash_u32_into_h##bits(uint32_t n) { \ 13 | return (hash##bits ## _t) hash_32(n, bits); \ 14 | } \ 15 | static inline hash##bits ## _t hash_u64_into_h##bits ## _chain( \ 16 | uint64_t n, uint64_t m \ 17 | ) { \ 18 | return hash_u64_into_h##bits(_CANTOR_PAIR(n, m)); \ 19 | } \ 20 | static inline hash##bits ## _t hash_u32_into_h##bits ## _chain( \ 21 | uint32_t n, uint32_t m \ 22 | ) { \ 23 | return hash_u32_into_h##bits(_CANTOR_PAIR(n, m)); \ 24 | } \ 25 | 26 | DART_HASH_DEFINE(32, 24) 27 | 28 | DART_HASH_DEFINE(32, 20) 29 | 30 | DART_HASH_DEFINE(16, 16) 31 | 32 | DART_HASH_DEFINE(16, 12) 33 | 34 | /* hash tables */ 35 | #define atomic32_t atomic_t 36 | #define atomic32_read atomic_read 37 | #define atomic32_set atomic_set 38 | 39 | #define DART_HMAP_DEFINE(name, bits, klen) \ 40 | /* typedef */ \ 41 | typedef struct __ht_##name { \ 42 | DECLARE_BITMAP(bmap, (1 << bits)); \ 43 | struct __htcell_##name { \ 44 | atomic##klen ## _t key; \ 45 | struct name val; \ 46 | } cell[1 << bits]; \ 47 | } ht_##name ## _t; \ 48 | \ 49 | /* functions */ \ 50 | static inline struct name * \ 51 | ht_##name ## _get_slot( \ 52 | struct __ht_##name *ht, uint##klen ## _t k \ 53 | ) { \ 54 | uint##klen ## _t e; \ 55 | hash##bits ## _t i = hash_u##klen ## _into_h##bits(k); \ 56 | hash##bits ## _t o = 0; \ 57 | \ 58 | while (test_and_set_bit(i, ht->bmap)) { \ 59 | /* in case someone acquired the bit but has not set it yet */ \ 60 | do { \ 61 | e = atomic##klen ## _read(&(ht->cell[i].key)); \ 62 | } while (!e); \ 63 | \ 64 | /* return an existing slot */ \ 65 | if (e == k) { \ 66 | return &(ht->cell[i].val); \ 67 | } \ 68 | \ 69 | /* move on */ \ 70 | i = (i + 1) % (1 << bits); \ 71 | BUG_ON((++o) == (1 << bits)); \ 72 | } \ 73 | \ 74 | /* we are the first to set the bit */ \ 75 | atomic##klen ## _set(&(ht->cell[i].key), k); \ 76 | return &(ht->cell[i].val); \ 77 | } \ 78 | \ 79 | static inline struct name * \ 80 | ht_##name ## _has_slot( \ 81 | struct __ht_##name *ht, uint##klen ## _t k \ 82 | ) { \ 83 | uint##klen ## _t e; \ 84 | hash##bits ## _t i = hash_u##klen ## _into_h##bits(k); \ 85 | hash##bits ## _t o = 0; \ 86 | \ 87 | while (test_bit(i, ht->bmap)) { \ 88 | /* in case someone acquired the bit but has not set it yet */ \ 89 | do { \ 90 | e = atomic##klen ## _read(&(ht->cell[i].key)); \ 91 | } while (!e); \ 92 | \ 93 | /* check existence */ \ 94 | if (e == k) { \ 95 | return &(ht->cell[i].val); \ 96 | } \ 97 | \ 98 | /* move on */ \ 99 | i = (i + 1) % (1 << bits); \ 100 | BUG_ON((++o) == (1 << bits)); \ 101 | } \ 102 | \ 103 | return NULL; \ 104 | } \ 105 | \ 106 | static inline void \ 107 | ht_##name ## _for_each( \ 108 | struct __ht_##name *ht, \ 109 | void (*func)( \ 110 | uint##klen ## _t key, struct name *val, void *arg \ 111 | ), \ 112 | void *arg \ 113 | ) { \ 114 | hash##bits ## _t t; \ 115 | hash##bits ## _t i = find_first_bit(ht->bmap, 1 << bits); \ 116 | /* break if there is no bit set in the map */ \ 117 | if (unlikely(i == (1 << bits))) { \ 118 | return; \ 119 | } \ 120 | \ 121 | while (true) { \ 122 | t = i; \ 123 | func( \ 124 | atomic##klen ## _read(&(ht->cell[i].key)), \ 125 | &ht->cell[i].val, \ 126 | arg \ 127 | ); \ 128 | i = find_next_bit(ht->bmap, (1 << bits), i + 1); \ 129 | \ 130 | if (i == (1 << bits) || i <= t) { \ 131 | break; \ 132 | } \ 133 | } \ 134 | } \ 135 | 136 | #endif /* _DART_HASH_H_ */ 137 | -------------------------------------------------------------------------------- /pass/dart/dart_kernel.h: -------------------------------------------------------------------------------- 1 | #ifndef _DART_KERNEL_H_ 2 | #define _DART_KERNEL_H_ 3 | 4 | #define DART_DEBUG 5 | #define DART_ASSERT 6 | 7 | #ifdef CONFIG_DART_DEVEL 8 | #define DART_LOGGING 9 | #endif 10 | 11 | /* types */ 12 | typedef u64 info_64_t; 13 | typedef u64 hval_64_t; 14 | typedef u64 data_64_t; 15 | typedef u32 ptid_32_t; 16 | 17 | #include "apidef.inc" 18 | 19 | /* utils */ 20 | #define _CANTOR_PAIR(n, m) ((n) + (m)) * ((n) + (m) + 1) / 2 + (m) 21 | 22 | /* declare the wraps */ 23 | #define DART_FUNC DART_FUNC_LIB_DECLARE 24 | #include "apidef.inc" 25 | #undef DART_FUNC 26 | 27 | /* declare the enums */ 28 | #define DART_FUNC DART_ENUM_DEF 29 | enum DART_API_ENUM { 30 | DART_API_BEGIN_OF_ENUM = 0, 31 | #include "apidef.inc" 32 | DART_API_END_OF_ENUM 33 | }; 34 | #undef DART_FUNC 35 | 36 | /* shortcuts */ 37 | #define dart_mark(mval) DART_FUNC_LIB_CALL_WRAP(mark, v0, DART_FLAG_NONE, mval) 38 | 39 | /* configs */ 40 | #define DART_TIMER_LIMIT_IN_SECONDS 10 41 | 42 | /* export info from kernel to dart */ 43 | extern data_64_t _dart_info_bio_slabs_addr; 44 | extern data_64_t _dart_info_bio_slabs_size; 45 | 46 | #endif /* _DART_KERNEL_H_ */ 47 | -------------------------------------------------------------------------------- /pass/dart/dart_log.c: -------------------------------------------------------------------------------- 1 | #include "dart.h" 2 | 3 | struct dart_ledger *g_ledger = NULL; 4 | struct dart_reserve_ledger *g_reserve_ledger = NULL; -------------------------------------------------------------------------------- /pass/dart/dart_log.h: -------------------------------------------------------------------------------- 1 | #ifndef _DART_LOG_H_ 2 | #define _DART_LOG_H_ 3 | 4 | #include "dart_common.h" 5 | 6 | /* ledger */ 7 | #define LEDGER_SIZE _MB(256) 8 | #define LEDGER_NAME "/host/ledger" 9 | #define RESERVE_LEDGER_SIZE (IVSHMEM_OFFSET_INSTANCES - IVSHMEM_OFFSET_RESERVED) 10 | 11 | /* structs */ 12 | struct dart_ledger { 13 | atomic64_t count; /* number of entries in the ledger */ 14 | atomic64_t cursor; /* current offset into the buffer */ 15 | char buffer[0]; /* buffer of unlimited size */ 16 | }; 17 | 18 | struct dart_reserve_ledger { 19 | atomic64_t cursor; 20 | char buffer[0]; 21 | }; 22 | 23 | /* globals */ 24 | extern struct dart_ledger *g_ledger; 25 | extern struct dart_reserve_ledger *g_reserve_ledger; 26 | 27 | /* ledger manipulations */ 28 | static inline char * 29 | dart_ledger_next_entry(struct dart_ledger *ledger, size_t size) { 30 | size_t offset; 31 | 32 | atomic64_inc(&ledger->count); 33 | offset = atomic64_fetch_add((int) size, &ledger->cursor); 34 | 35 | /* check if ledger may overflow */ 36 | if (offset + size >= LEDGER_SIZE) { 37 | return NULL; 38 | } 39 | 40 | return ledger->buffer + offset; 41 | } 42 | 43 | static inline void dart_ledger_transfer_ro_reserve( 44 | struct dart_ledger *ledger, struct dart_reserve_ledger *reserve 45 | ) { 46 | size_t length, chunks, offset; 47 | char *cursor; 48 | 49 | /* find the cursor */ 50 | length = atomic64_read(&ledger->cursor); 51 | chunks = length + 8 + sizeof(struct dart_ledger); 52 | offset = atomic64_fetch_add(chunks, &reserve->cursor); 53 | 54 | if (offset + chunks >= RESERVE_LEDGER_SIZE) { 55 | return; 56 | } 57 | cursor = reserve->buffer + offset; 58 | 59 | /* put the instance id there first */ 60 | (*(long *) cursor) = dart_iseq; 61 | cursor += sizeof(long); 62 | 63 | /* put the dart_ledger header there */ 64 | memcpy(cursor, ledger, sizeof(struct dart_ledger)); 65 | cursor += sizeof(struct dart_ledger); 66 | 67 | /* copy the content */ 68 | memcpy(cursor, ledger->buffer, length); 69 | } 70 | 71 | #endif /* _DART_LOG_H_ */ 72 | -------------------------------------------------------------------------------- /pass/dart/dart_ptid.h: -------------------------------------------------------------------------------- 1 | #ifndef _DART_PTID_H_ 2 | #define _DART_PTID_H_ 3 | 4 | #include "dart_common.h" 5 | 6 | /* kernel vs user context */ 7 | static inline bool in_task_kernel(void) { 8 | return in_task() && (current->flags & PF_KTHREAD); 9 | } 10 | 11 | static inline bool in_task_user(void) { 12 | return in_task() && !(current->flags & PF_KTHREAD); 13 | } 14 | 15 | /* 16 | * ptid: process or context id 17 | * (hi 16 bits) ---- : pid (task) user 18 | * (hi 16 bits) ---1 : pid (task) kernel 19 | * (hi 16 bits) -1XX : cpuid (softirq) 20 | * (hi 16 bits) -2XX : cpuid (hardirq) 21 | * (hi 16 bits) -4XX : cpuid (nmi) 22 | */ 23 | static inline ptid_32_t _ptid_in_task_user(void) { 24 | ptid_32_t ptid = current->pid; 25 | #ifdef DART_ASSERT 26 | BUG_ON(ptid >= (1 << 16)); 27 | #endif 28 | return ptid; 29 | } 30 | 31 | static inline ptid_32_t _ptid_in_task_kernel(void) { 32 | ptid_32_t ptid = current->pid; 33 | #ifdef DART_ASSERT 34 | BUG_ON(ptid >= (1 << 16)); 35 | #endif 36 | return (1 << 16) + ptid; 37 | } 38 | 39 | static inline ptid_32_t _ptid_in_softirq(void) { 40 | return ((1 << 8) + smp_processor_id()) << 16; 41 | } 42 | 43 | static inline ptid_32_t _ptid_in_hardirq(void) { 44 | return ((1 << 9) + smp_processor_id()) << 16; 45 | } 46 | 47 | static inline ptid_32_t _ptid_in_nmi(void) { 48 | return ((1 << 10) + smp_processor_id()) << 16; 49 | } 50 | 51 | /* get ptid without knowing the context */ 52 | static inline ptid_32_t dart_ptid(void) { 53 | if (in_nmi()) { 54 | return _ptid_in_nmi(); 55 | } 56 | 57 | if (in_irq()) { 58 | return _ptid_in_hardirq(); 59 | } 60 | 61 | if (in_serving_softirq()) { 62 | return _ptid_in_softirq(); 63 | } 64 | 65 | if (in_task_kernel()) { 66 | return _ptid_in_task_kernel(); 67 | } 68 | 69 | #ifdef DART_ASSERT 70 | BUG_ON(!in_task_user()); 71 | #endif 72 | return _ptid_in_task_user(); 73 | } 74 | 75 | #endif /* _DART_PTID_H_ */ 76 | -------------------------------------------------------------------------------- /pass/dart/dart_wks.c: -------------------------------------------------------------------------------- 1 | #include "dart.h" 2 | 3 | /* shared info */ 4 | unsigned long *g_cov_cfg_edge = NULL; 5 | unsigned long *g_cov_dfg_edge = NULL; 6 | unsigned long *g_cov_alias_inst = NULL; 7 | 8 | /* private info */ 9 | struct dart_rtinfo *g_rtinfo = NULL; 10 | struct dart_rtrace *g_rtrace = NULL; -------------------------------------------------------------------------------- /pass/dart/dart_wks.h: -------------------------------------------------------------------------------- 1 | #ifndef _DART_WKS_H_ 2 | #define _DART_WKS_H_ 3 | 4 | #include "dart_common.h" 5 | #include "dart_hash.h" 6 | 7 | /* shared info */ 8 | #define _COV_CFG_EDGE_BITS (1 << 24) 9 | extern unsigned long *g_cov_cfg_edge; 10 | 11 | #define _COV_DFG_EDGE_BITS (1 << 24) 12 | extern unsigned long *g_cov_dfg_edge; 13 | 14 | #define _COV_ALIAS_INST_BITS (1 << 24) 15 | extern unsigned long *g_cov_alias_inst; 16 | 17 | #define _RTRACE_ENTRY_MAX (14 * (1 << 20) / (4 * sizeof(u64))) 18 | 19 | /* private info */ 20 | struct dart_rtinfo { 21 | /* states */ 22 | atomic64_t has_proper_exit; 23 | atomic64_t has_warning_or_error; 24 | 25 | /* coverage */ 26 | atomic64_t cov_cfg_edge_incr; 27 | atomic64_t cov_dfg_edge_incr; 28 | atomic64_t cov_alias_inst_incr; 29 | }; 30 | 31 | struct dart_rtrace { 32 | atomic64_t count; /* number of entries in the rtrace */ 33 | u64 buffer[0]; /* buffer of unlimited size */ 34 | }; 35 | 36 | extern struct dart_rtinfo *g_rtinfo; 37 | extern struct dart_rtrace *g_rtrace; 38 | 39 | /* operations */ 40 | static inline void cov_cfg_add_edge(hash24_t edge) { 41 | if (!test_and_set_bit(edge, g_cov_cfg_edge)) { 42 | atomic64_inc(&g_rtinfo->cov_cfg_edge_incr); 43 | } 44 | } 45 | 46 | static inline void cov_dfg_add_edge(hash24_t edge) { 47 | if (!test_and_set_bit(edge, g_cov_dfg_edge)) { 48 | atomic64_inc(&g_rtinfo->cov_dfg_edge_incr); 49 | } 50 | } 51 | 52 | static inline void cov_alias_add_pair(hash24_t pair) { 53 | if (!test_and_set_bit(pair, g_cov_alias_inst)) { 54 | atomic64_inc(&g_rtinfo->cov_alias_inst_incr); 55 | } 56 | } 57 | 58 | static inline void rtrace_record( 59 | hval_64_t from, hval_64_t into, data_64_t addr, u64 size 60 | ) { 61 | unsigned long offset; 62 | 63 | /* calculate the offset */ 64 | offset = atomic64_fetch_inc(&g_rtrace->count); 65 | if (offset >= _RTRACE_ENTRY_MAX) { 66 | return; 67 | } 68 | offset *= 4; 69 | 70 | /* do the recording */ 71 | g_rtrace->buffer[offset + 0] = from; 72 | g_rtrace->buffer[offset + 1] = into; 73 | g_rtrace->buffer[offset + 2] = addr; 74 | g_rtrace->buffer[offset + 3] = size; 75 | } 76 | 77 | #endif /* _DART_WKS_H_ */ 78 | -------------------------------------------------------------------------------- /pass/dart/rt_async.inc: -------------------------------------------------------------------------------- 1 | #define ASYNC_REGISTER(name) \ 2 | DART_FUNC(async, name##_register, data_64_t, func) { \ 3 | struct dart_async *slot; \ 4 | \ 5 | slot = ht_dart_async_get_slot(g_dart_async_ht, hval); \ 6 | BUG_ON(!slot); \ 7 | \ 8 | /* checks */ \ 9 | if (unlikely(slot->func)) { \ 10 | dart_pr_err( \ 11 | #name " register [%ps]: dangling - %ps", func, slot->func \ 12 | ); \ 13 | DART_BUG(); \ 14 | } \ 15 | \ 16 | slot->func = func; \ 17 | } 18 | 19 | #define ASYNC_CANCEL(name) \ 20 | DART_FUNC(async, name##_cancel, data_64_t, func) { \ 21 | struct dart_async *slot; \ 22 | \ 23 | slot = ht_dart_async_has_slot(g_dart_async_ht, hval); \ 24 | if (unlikely(!slot)) { \ 25 | dart_pr_err( \ 26 | #name " cancel without registration: %lu [%ps]", \ 27 | hval, func \ 28 | ); \ 29 | DART_BUG(); \ 30 | } \ 31 | \ 32 | slot->func = 0; \ 33 | } 34 | 35 | #define ASYNC_ATTACH(name) \ 36 | DART_FUNC(async, name##_attach, data_64_t, func) { \ 37 | struct dart_async *slot; \ 38 | \ 39 | slot = ht_dart_async_has_slot(g_dart_async_ht, hval); \ 40 | if (unlikely(!slot)) { \ 41 | dart_pr_err( \ 42 | #name " attach without registration: %lu [%ps]", \ 43 | hval, func \ 44 | ); \ 45 | DART_BUG(); \ 46 | } \ 47 | \ 48 | if (unlikely(slot->func != func)) { \ 49 | if (unlikely(slot->func)) { \ 50 | dart_pr_err( \ 51 | #name " attach (func mismatch): %ps | %ps", \ 52 | slot->func, func \ 53 | ); \ 54 | DART_BUG(); \ 55 | } \ 56 | if (unlikely(slot->serving != func)) { \ 57 | dart_pr_err( \ 58 | #name " attach (serving mismatch): %ps | %ps", \ 59 | slot->serving, func \ 60 | ); \ 61 | DART_BUG(); \ 62 | } \ 63 | } \ 64 | } 65 | 66 | ASYNC_REGISTER(rcu) 67 | 68 | ASYNC_REGISTER(work) 69 | 70 | ASYNC_CANCEL(work) 71 | 72 | ASYNC_ATTACH(work) 73 | 74 | ASYNC_REGISTER(task) 75 | 76 | ASYNC_CANCEL(task) 77 | 78 | ASYNC_REGISTER(timer) 79 | 80 | ASYNC_CANCEL(timer) 81 | 82 | ASYNC_ATTACH(timer) 83 | 84 | ASYNC_REGISTER(krun) 85 | 86 | ASYNC_REGISTER(block) 87 | 88 | ASYNC_REGISTER(ipi) 89 | 90 | ASYNC_REGISTER(custom) 91 | 92 | ASYNC_ATTACH(custom) -------------------------------------------------------------------------------- /pass/dart/rt_cov.inc: -------------------------------------------------------------------------------- 1 | DART_FUNC (cov, cfg) { 2 | struct dart_cb *cb = (struct dart_cb *) info; 3 | cov_cfg_add_edge(hash_u64_into_h24_chain(cb->last_blk, hval)); 4 | cb->last_blk = hval; 5 | } -------------------------------------------------------------------------------- /pass/dart/rt_exec.inc: -------------------------------------------------------------------------------- 1 | DART_FUNC (exec, func_enter, data_64_t, addr) { 2 | struct dart_cb *cb = (struct dart_cb *) info; 3 | cb->stack_depth++; 4 | } 5 | 6 | DART_FUNC (exec, func_exit, data_64_t, addr) { 7 | struct dart_cb *cb = (struct dart_cb *) info; 8 | cb->stack_depth--; 9 | 10 | #ifdef DART_ASSERT 11 | if (unlikely(cb->stack_depth < 0)) { 12 | dart_pr_err("Call stack corrupted: %d", cb->ptid); 13 | DART_BUG(); 14 | } 15 | #endif 16 | } 17 | 18 | static inline bool exec_to_background(struct dart_cb *cb, hval_64_t hval) { 19 | struct dart_async *slot; 20 | struct dart_cb tmp; 21 | 22 | /* get slot */ 23 | slot = ht_dart_async_has_slot(g_dart_async_ht, hval); 24 | if (!slot || !slot->serving) { 25 | /* TODO 26 | * some unknown callback gets executed... 27 | * this should not happen, but lets debug later 28 | */ 29 | return false; 30 | } 31 | 32 | /* treat as exec_pause if there is no host */ 33 | if (!slot->info) { 34 | cb->paused++; 35 | return false; 36 | } 37 | 38 | /* exchange control block */ 39 | memcpy(&tmp, cb, sizeof(struct dart_cb)); 40 | memcpy(cb, &slot->host, sizeof(struct dart_cb)); 41 | memcpy(&slot->host, &tmp, sizeof(struct dart_cb)); 42 | 43 | return true; 44 | } 45 | 46 | static inline bool exec_to_foreground(struct dart_cb *cb, hval_64_t hval) { 47 | struct dart_async *slot; 48 | struct dart_cb tmp; 49 | 50 | /* get slot */ 51 | slot = ht_dart_async_has_slot(g_dart_async_ht, hval); 52 | if (!slot || !slot->serving) { 53 | /* TODO 54 | * some unknown callback gets executed... 55 | * this should not happen, but lets debug later 56 | */ 57 | return false; 58 | } 59 | 60 | /* treat as exec_resume if there is no host */ 61 | if (!slot->info) { 62 | cb->paused--; 63 | return false; 64 | } 65 | 66 | /* exchange control block */ 67 | memcpy(&tmp, cb, sizeof(struct dart_cb)); 68 | memcpy(cb, &slot->host, sizeof(struct dart_cb)); 69 | memcpy(&slot->host, &tmp, sizeof(struct dart_cb)); 70 | 71 | return true; 72 | } 73 | -------------------------------------------------------------------------------- /pass/dart/rt_mark.inc: -------------------------------------------------------------------------------- 1 | DART_FUNC (mark, v0) { 2 | } 3 | 4 | DART_FUNC (mark, v1, data_64_t, mark1) { 5 | } 6 | 7 | DART_FUNC (mark, v2, data_64_t, mark1, data_64_t, mark2) { 8 | } 9 | 10 | DART_FUNC (mark, v3, data_64_t, mark1, data_64_t, mark2, data_64_t, mark3) { 11 | } -------------------------------------------------------------------------------- /pass/dart/rt_mem_access.inc: -------------------------------------------------------------------------------- 1 | /* generics */ 2 | #define mem_check_alias(rw) \ 3 | static inline void mem_check_alias_##rw( \ 4 | ptid_32_t ptid, hval_64_t inst, data_64_t addr, \ 5 | hval_64_t *s, hval_64_t *p \ 6 | ) { \ 7 | struct dart_mc *cell; \ 8 | \ 9 | cell = ht_dart_mc_has_slot(g_dart_mc_## rw ## _ht, addr); \ 10 | if (!cell) { \ 11 | /* exit if no counterpart cell exists */ \ 12 | *s = 0; \ 13 | *p = 0; \ 14 | } \ 15 | \ 16 | else if (cell->ptid == ptid) { \ 17 | /* found an memdu pair, report it */ \ 18 | *s = cell->inst; \ 19 | *p = 0; \ 20 | } \ 21 | \ 22 | else { \ 23 | /* found an alias pair, report it */ \ 24 | *s = 0; \ 25 | *p = cell->inst; \ 26 | } \ 27 | } 28 | 29 | mem_check_alias(reader) 30 | 31 | mem_check_alias(writer) 32 | 33 | #define ALIAS_CHECK_DECLARE(icur, pcur) \ 34 | u64 icur; \ 35 | hval_64_t pcur; \ 36 | 37 | #define ALIAS_CHECK_INIT(icur, pcur) \ 38 | icur = 0; \ 39 | pcur = 0; \ 40 | 41 | #define ALIAS_CHECK_LOOP(hval, addr, i, p, icur, pcur) \ 42 | if (pcur != p) { \ 43 | if (pcur) { \ 44 | cov_alias_add_pair(hash_u64_into_h24_chain(pcur, hval)); \ 45 | rtrace_record(pcur, hval, addr + icur, i - icur + 1); \ 46 | } \ 47 | pcur = p; \ 48 | icur = i; \ 49 | } \ 50 | 51 | #define ALIAS_CHECK_FINI(hval, addr, size, icur, pcur) \ 52 | if (pcur) { \ 53 | cov_alias_add_pair(hash_u64_into_h24_chain(pcur, hval)); \ 54 | rtrace_record(pcur, hval, addr + icur, size - icur); \ 55 | } \ 56 | 57 | #define MEMDU_CHECK_DECLARE(scur) \ 58 | hval_64_t scur; \ 59 | 60 | #define MEMDU_CHECK_INIT(scur) \ 61 | scur = 0; \ 62 | 63 | #define MEMDU_CHECK_LOOP(hval, i, s, scur) \ 64 | if (scur != s) { \ 65 | if (scur) { \ 66 | cov_dfg_add_edge(hash_u64_into_h24_chain(scur, hval)); \ 67 | } \ 68 | scur = s; \ 69 | } \ 70 | 71 | #define MEMDU_CHECK_FINI(hval, scur) \ 72 | if (scur) { \ 73 | cov_dfg_add_edge(hash_u64_into_h24_chain(scur, hval)); \ 74 | } \ 75 | 76 | 77 | /* specifics */ 78 | DART_FUNC (mem, read, data_64_t, addr, data_64_t, size) { 79 | struct dart_cb *cb; 80 | struct dart_mc *cell; 81 | u64 i; 82 | hval_64_t p, s; 83 | ALIAS_CHECK_DECLARE(iw_cur, pw_cur) 84 | MEMDU_CHECK_DECLARE(sw_cur) 85 | 86 | cb = (struct dart_cb *) info; 87 | 88 | /* init the cursors */ 89 | ALIAS_CHECK_INIT(iw_cur, pw_cur) 90 | MEMDU_CHECK_INIT(sw_cur) 91 | 92 | for (i = 0; i < size; i++) { 93 | /* check memory alias pair (w -> r) */ 94 | mem_check_alias_writer(cb->ptid, hval, addr + i, &s, &p); 95 | 96 | /* check if we need to record alias */ 97 | ALIAS_CHECK_LOOP(hval, addr, i, p, iw_cur, pw_cur) 98 | 99 | /* check if we need to report memdu */ 100 | MEMDU_CHECK_LOOP(hval, i, s, sw_cur) 101 | 102 | /* take ownership of the cell */ 103 | cell = ht_dart_mc_get_slot(g_dart_mc_reader_ht, addr + i); 104 | 105 | cell->ptid = cb->ptid; 106 | cell->ctxt = cb->ctxt; 107 | cell->inst = hval; 108 | } 109 | 110 | /* record at the end of trace */ 111 | ALIAS_CHECK_FINI(hval, addr, size, iw_cur, pw_cur) 112 | MEMDU_CHECK_FINI(hval, sw_cur) 113 | } 114 | 115 | DART_FUNC (mem, write, data_64_t, addr, data_64_t, size) { 116 | struct dart_cb *cb; 117 | struct dart_mc *cell; 118 | u64 i; 119 | hval_64_t p, s; 120 | ALIAS_CHECK_DECLARE(ir_cur, pr_cur) 121 | ALIAS_CHECK_DECLARE(iw_cur, pw_cur) 122 | MEMDU_CHECK_DECLARE(sr_cur) 123 | MEMDU_CHECK_DECLARE(sw_cur) 124 | 125 | cb = (struct dart_cb *) info; 126 | 127 | /* init the cursors */ 128 | ALIAS_CHECK_INIT(ir_cur, pr_cur) 129 | ALIAS_CHECK_INIT(iw_cur, pw_cur) 130 | MEMDU_CHECK_INIT(sr_cur) 131 | MEMDU_CHECK_INIT(sw_cur) 132 | 133 | for (i = 0; i < size; i++) { 134 | /* check memory alias pair (r -> w) */ 135 | mem_check_alias_reader(cb->ptid, hval, addr + i, &s, &p); 136 | 137 | /* check if we need to report alias */ 138 | ALIAS_CHECK_LOOP(hval, addr, i, p, ir_cur, pr_cur) 139 | 140 | /* check if we need to report memdu */ 141 | MEMDU_CHECK_LOOP(hval, i, s, sr_cur) 142 | 143 | /* check memory alias pair (w -> w) */ 144 | mem_check_alias_writer(cb->ptid, hval, addr + i, &s, &p); 145 | 146 | /* check if we need to report alias */ 147 | ALIAS_CHECK_LOOP(hval, addr, i, p, iw_cur, pw_cur) 148 | 149 | /* check if we need to report memdu */ 150 | MEMDU_CHECK_LOOP(hval, i, s, sw_cur) 151 | 152 | /* take ownership of the cell */ 153 | cell = ht_dart_mc_get_slot(g_dart_mc_writer_ht, addr + i); 154 | 155 | cell->ptid = cb->ptid; 156 | cell->ctxt = cb->ctxt; 157 | cell->inst = hval; 158 | } 159 | 160 | /* record at the end of trace */ 161 | ALIAS_CHECK_FINI(hval, addr, size, ir_cur, pr_cur) 162 | ALIAS_CHECK_FINI(hval, addr, size, iw_cur, pw_cur) 163 | MEMDU_CHECK_FINI(hval, sr_cur) 164 | MEMDU_CHECK_FINI(hval, sw_cur) 165 | } -------------------------------------------------------------------------------- /pass/dart/rt_mem_heap.inc: -------------------------------------------------------------------------------- 1 | DART_FUNC (mem, heap_alloc, data_64_t, addr, data_64_t, size) { 2 | } 3 | 4 | DART_FUNC (mem, heap_free, data_64_t, addr) { 5 | } -------------------------------------------------------------------------------- /pass/dart/rt_mem_percpu.inc: -------------------------------------------------------------------------------- 1 | DART_FUNC (mem, percpu_alloc, data_64_t, addr, data_64_t, size) { 2 | } 3 | 4 | DART_FUNC (mem, percpu_free, data_64_t, addr) { 5 | } -------------------------------------------------------------------------------- /pass/dart/rt_mem_stack.inc: -------------------------------------------------------------------------------- 1 | DART_FUNC (mem, stack_push, data_64_t, addr, data_64_t, size) { 2 | } 3 | 4 | DART_FUNC (mem, stack_pop, data_64_t, addr, data_64_t, size) { 5 | } -------------------------------------------------------------------------------- /pass/dart/rt_order.inc: -------------------------------------------------------------------------------- 1 | DART_FUNC (order, ps_publish, data_64_t, addr) { 2 | } 3 | 4 | DART_FUNC (order, ps_subscribe, data_64_t, addr) { 5 | } 6 | 7 | DART_FUNC (order, obj_deposit, data_64_t, addr, data_64_t, objv) { 8 | } 9 | 10 | DART_FUNC (order, obj_consume, data_64_t, addr) { 11 | } 12 | -------------------------------------------------------------------------------- /pass/dart/rt_sync.inc: -------------------------------------------------------------------------------- 1 | DART_FUNC (sync, gen_lock, data_64_t, lock) { 2 | } 3 | 4 | DART_FUNC (sync, gen_unlock, data_64_t, lock) { 5 | } 6 | 7 | DART_FUNC (sync, seq_lock, data_64_t, lock) { 8 | } 9 | 10 | DART_FUNC (sync, seq_unlock, data_64_t, lock) { 11 | } 12 | 13 | DART_FUNC (sync, rcu_lock, data_64_t, lock) { 14 | } 15 | 16 | DART_FUNC (sync, rcu_unlock, data_64_t, lock) { 17 | } -------------------------------------------------------------------------------- /pass/dart/runtime.c: -------------------------------------------------------------------------------- 1 | #include "dart.h" 2 | 3 | /* globals */ 4 | long dart_iseq = 0; 5 | EXPORT_SYMBOL(dart_iseq); 6 | 7 | char *dart_shared = NULL; 8 | EXPORT_SYMBOL(dart_shared); 9 | 10 | char *dart_private = NULL; 11 | EXPORT_SYMBOL(dart_private); 12 | 13 | char *dart_reserved = NULL; 14 | EXPORT_SYMBOL(dart_reserved); 15 | 16 | /* define the implementations */ 17 | #define DART_FUNC DART_FUNC_LIB_IMPL 18 | #include "rt_sys.inc" 19 | #include "rt_mark.inc" 20 | #include "rt_ctxt.inc" 21 | #include "rt_exec.inc" 22 | #include "rt_async.inc" 23 | #include "rt_event.inc" 24 | #include "rt_cov.inc" 25 | #include "rt_mem_stack.inc" 26 | #include "rt_mem_heap.inc" 27 | #include "rt_mem_percpu.inc" 28 | #include "rt_mem_access.inc" 29 | #include "rt_sync.inc" 30 | #include "rt_order.inc" 31 | #undef DART_FUNC 32 | 33 | /* define the wraps */ 34 | #define DART_FUNC DART_FUNC_LIB_DEFINE 35 | #include "apidef.inc" 36 | #undef DART_FUNC 37 | 38 | /* export info from kernel to dart */ 39 | data_64_t _dart_info_bio_slabs_addr = 0; 40 | data_64_t _dart_info_bio_slabs_size = 0; 41 | 42 | /* define the syscall */ 43 | SYSCALL_DEFINE2(dart, unsigned long, cmd, unsigned long, arg) { 44 | switch (cmd) { 45 | case CMD_DART_LAUNCH: 46 | DART_FUNC_LIB_CALL_IMPL(sys, launch, 47 | DART_FLAG_NONE, 0); 48 | break; 49 | 50 | case CMD_DART_FINISH: 51 | DART_FUNC_LIB_CALL_IMPL(sys, finish, 52 | DART_FLAG_NONE, 0); 53 | break; 54 | 55 | case CMD_DART_CTXT_SYSCALL_START: 56 | DART_FUNC_LIB_CALL_IMPL(ctxt, syscall_enter, 57 | DART_FLAG_CTRL_CTXT_CHANGE, arg); 58 | break; 59 | 60 | case CMD_DART_CTXT_SYSCALL_EXIT: 61 | DART_FUNC_LIB_CALL_IMPL(ctxt, syscall_exit, 62 | DART_FLAG_CTRL_CTXT_CHANGE, arg); 63 | break; 64 | 65 | default: 66 | dart_pr_err("invalid syscall command: %lu", cmd); 67 | return -1; 68 | } 69 | 70 | return 0; 71 | } 72 | 73 | /* boot parameter */ 74 | static __init int dart_instance_cmd(char *str) { 75 | if (kstrtol(str, 10, &dart_iseq)) { 76 | return -1; 77 | } 78 | 79 | return 0; 80 | } 81 | 82 | __setup("dart_instance=", dart_instance_cmd); -------------------------------------------------------------------------------- /pass/instrument/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # sources 2 | set(RACER_INSTRUMENT_SOURCES 3 | lib/util/Logger.cpp 4 | lib/util/Lower.cpp 5 | lib/analysis/Oracle.cpp 6 | lib/analysis/Probe.cpp 7 | lib/dart/API.cpp 8 | lib/base/Plugin.cpp 9 | Main.cpp) 10 | 11 | # RacerInstrument: target 12 | add_library(RacerInstrument MODULE 13 | ${RACER_INSTRUMENT_SOURCES}) 14 | 15 | add_dependencies(RacerInstrument codegen) 16 | 17 | # RacerInstrument: definitions 18 | target_compile_definitions(RacerInstrument PRIVATE 19 | ${LLVM_DEFINITIONS}) 20 | 21 | # RacerInstrument: includes 22 | target_include_directories(RacerInstrument PRIVATE 23 | ${LLVM_INCLUDE_DIRS} 24 | ${RACER_PATH_MISC_JSON}/single_include 25 | ${CMAKE_SOURCE_DIR}/instrument/include 26 | ${CMAKE_SOURCE_DIR}/dart) 27 | 28 | # RacerInstrument: compile flags 29 | target_compile_options(RacerInstrument PRIVATE 30 | "-O3" 31 | "-fexceptions") 32 | 33 | # RacerInstrument: link flags 34 | if (CMAKE_BUILD_TYPE_REPR STREQUAL "RELEASE") 35 | set_target_properties(RacerInstrument 36 | PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) 37 | endif () 38 | 39 | # RacerInstrument: install 40 | install(TARGETS RacerInstrument DESTINATION lib) 41 | -------------------------------------------------------------------------------- /pass/instrument/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "base/Plugin.h" 2 | #include "analysis/Oracle.h" 3 | #include "util/Logger.h" 4 | #include "util/Lower.h" 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace racer { 12 | 13 | // pass info 14 | char Racer::ID = 0; 15 | static RegisterPass X("Racer", "Kernel Race Checker", false, false); 16 | 17 | // options 18 | cl::opt MODE("racer-mode", 19 | cl::Required, 20 | cl::desc("")); 21 | cl::opt INPUT("racer-input", 22 | cl::Required, 23 | cl::desc("")); 24 | cl::opt OUTPUT("racer-output", 25 | cl::Required, 26 | cl::desc("")); 27 | 28 | static void interruptHandler(int signal) { 29 | #if defined(RACER_DEBUG) && defined(RACER_DEBUG_STATUS) 30 | STAT.show() << "Terminated with signal: " << signal; 31 | STAT.done(); 32 | #endif 33 | 34 | // directly terminate all threads 35 | exit(-1); 36 | } 37 | 38 | // class Racer 39 | Racer::Racer( 40 | const string &_mode, const string &_input, const string &_output 41 | ) 42 | : ModulePass(ID), 43 | mode(_mode), input(_input), output(_output) { 44 | 45 | // register signal handlers 46 | signal(SIGINT, interruptHandler); 47 | } 48 | 49 | Racer::Racer() 50 | : Racer(MODE.getValue(), INPUT.getValue(), OUTPUT.getValue()) { 51 | } 52 | 53 | Racer::~Racer() { 54 | #ifdef RACER_DEBUG 55 | SLOG.dump(output); 56 | #endif 57 | } 58 | 59 | void Racer::getAnalysisUsage(AnalysisUsage &au) const { 60 | // conservatively think that we changed everything... 61 | // so, do nothing here 62 | } 63 | 64 | bool Racer::runOnModule(Module &m) { 65 | #if defined(RACER_DEBUG) && defined(RACER_DEBUG_STATUS) 66 | STAT.show() << m.getName(); 67 | STAT.done(); 68 | #endif 69 | 70 | // check assumptions 71 | Lowering::checkAssumptions(m); 72 | 73 | // instrument 74 | Instrumentor(m, input).run(mode); 75 | 76 | // end of instrumentation 77 | #if defined(RACER_DEBUG) && defined(RACER_DEBUG_STATUS) 78 | STAT.show() << "Instrumentation finished"; 79 | STAT.done(); 80 | #endif 81 | 82 | // mark we have touched things in the module 83 | return true; 84 | } 85 | 86 | void Racer::print(raw_ostream &os, const Module *m) const { 87 | os << "Racer completed on " << m->getName() << "\n"; 88 | } 89 | 90 | // automatically run the pass 91 | static void registerRacerPass(const PassManagerBuilder &, 92 | legacy::PassManagerBase &PM) { 93 | 94 | PM.add(new Racer()); 95 | } 96 | 97 | static RegisterStandardPasses 98 | RegisterPassRacer_Ox(PassManagerBuilder::EP_OptimizerLast, 99 | registerRacerPass); 100 | static RegisterStandardPasses 101 | RegisterPassRacer_O0(PassManagerBuilder::EP_EnabledOnOptLevel0, 102 | registerRacerPass); 103 | 104 | } /* namespace racer */ 105 | -------------------------------------------------------------------------------- /pass/instrument/include/analysis/Oracle.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_ANALYSIS_ORACLE_H_ 2 | #define _RACER_ANALYSIS_ORACLE_H_ 3 | 4 | #include "base/Common.h" 5 | 6 | namespace racer { 7 | 8 | class FuncOracle { 9 | public: 10 | FuncOracle(Function &f, const DataLayout &dl, TargetLibraryInfo &tli) 11 | : ac(f), dt(f), li(dt), se(f, tli, ac, dt, li) { 12 | dt.verify(); 13 | li.verify(dt); 14 | } 15 | 16 | ~FuncOracle() = default; 17 | 18 | public: 19 | // dominance 20 | bool dominates(BasicBlock *dom, BasicBlock *bb) { 21 | return dt.dominates(dom, bb); 22 | } 23 | 24 | BasicBlock *getIDom(BasicBlock *bb); 25 | 26 | // loop 27 | Loop *getOuterLoopInScope(Loop *scope, BasicBlock *bb); 28 | 29 | Loop *getInnerLoop(BasicBlock *bb) { 30 | return li.getLoopFor(bb); 31 | } 32 | 33 | Loop *getOuterLoop(BasicBlock *bb) { 34 | return getOuterLoopInScope(nullptr, bb); 35 | } 36 | 37 | // scala evolution 38 | SCEV *getSCEV(Value *v) { 39 | assert(se.isSCEVable(v->getType())); 40 | return const_cast(se.getSCEV(v)); 41 | } 42 | 43 | protected: 44 | // basics 45 | AssumptionCache ac; 46 | 47 | // analysis 48 | DominatorTree dt; 49 | LoopInfo li; 50 | ScalarEvolution se; 51 | }; 52 | 53 | class ModuleOracle { 54 | public: 55 | explicit ModuleOracle(Module &m) 56 | : dl(m.getDataLayout()), 57 | tli(TargetLibraryInfoImpl( 58 | Triple(Twine(m.getTargetTriple())))) { 59 | 60 | // platform checks 61 | assert(dl.getPointerSizeInBits() == BITS * 8); 62 | assert(dl.isLittleEndian()); 63 | 64 | // llvm checks 65 | assert(sizeof(hash_code) == 8); 66 | } 67 | 68 | ~ModuleOracle() = default; 69 | 70 | public: 71 | // data layout 72 | const DataLayout &getDataLayout() { 73 | return dl; 74 | } 75 | 76 | TargetLibraryInfo &getTargetLibraryInfo() { 77 | return tli; 78 | } 79 | 80 | unsigned getBits() { 81 | return BITS; 82 | } 83 | 84 | unsigned getPointerSize() { 85 | return dl.getPointerSize(); 86 | } 87 | 88 | unsigned getPointerWidth() { 89 | return dl.getPointerSizeInBits(); 90 | } 91 | 92 | unsigned getTypeAllocatedSize(Type *ty) { 93 | return (unsigned) dl.getTypeAllocSize(ty); 94 | } 95 | 96 | unsigned getTypeAllocatedWidth(Type *ty) { 97 | return (unsigned) dl.getTypeAllocSizeInBits(ty); 98 | } 99 | 100 | unsigned getTypeStoreSize(Type *ty) { 101 | return dl.getTypeStoreSize(ty); 102 | } 103 | 104 | unsigned getTypeStoreWidth(Type *ty) { 105 | return dl.getTypeStoreSizeInBits(ty); 106 | } 107 | 108 | bool isReintPointerType(Type *ty) { 109 | return ty->isPointerTy() || 110 | (ty->isIntegerTy() && 111 | ty->getIntegerBitWidth() == getPointerWidth()); 112 | } 113 | 114 | // function oracles 115 | void addOracle(Function *f, FuncOracle *fo) { 116 | fos[f] = fo; 117 | } 118 | 119 | FuncOracle &getOracle(Function *f) { 120 | return *fos[f]; 121 | } 122 | 123 | FuncOracle &getOracle(BasicBlock *b) { 124 | return getOracle(b->getParent()); 125 | } 126 | 127 | FuncOracle &getOracle(Instruction *i) { 128 | return getOracle(i->getParent()); 129 | } 130 | 131 | unsigned long numOracles() { 132 | return fos.size(); 133 | } 134 | 135 | protected: 136 | // info provider 137 | const DataLayout &dl; 138 | TargetLibraryInfo tli; 139 | 140 | // function oracles 141 | map fos; 142 | 143 | // consts 144 | const unsigned BITS = 8; 145 | }; 146 | 147 | } /* namespace racer */ 148 | 149 | #endif /* _RACER_ANALYSIS_ORACLE_H_ */ 150 | -------------------------------------------------------------------------------- /pass/instrument/include/analysis/Probe.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_ANALYSIS_PROBE_H_ 2 | #define _RACER_ANALYSIS_PROBE_H_ 3 | 4 | #include "base/Common.h" 5 | 6 | namespace racer { 7 | 8 | // basic structs 9 | struct API { 10 | string func; 11 | flag_t flag; 12 | }; 13 | 14 | template 15 | struct APIDesc { 16 | string name; 17 | vector apis; 18 | T info; 19 | flag_t flag; 20 | }; 21 | 22 | struct LOC { 23 | string file; 24 | unsigned line; 25 | unsigned column; 26 | unsigned opcode; 27 | flag_t flag; 28 | }; 29 | 30 | #define LOC_OPCODE_CALL_ASM Instruction::Call + 0x1000 31 | 32 | template 33 | struct LOCDesc { 34 | string name; 35 | vector locs; 36 | T info; 37 | flag_t flag; 38 | }; 39 | 40 | // MEM 41 | struct MemSetInfo { 42 | int argAddr; 43 | int argSize; 44 | }; 45 | 46 | struct MemCpyInfo { 47 | int argSrc; 48 | int argDst; 49 | int argSize; 50 | }; 51 | 52 | extern const vector> MEMSET_APIS_AVAILS; 53 | extern const vector> MEMCPY_APIS_AVAILS; 54 | 55 | // probing utilities 56 | template 57 | using APIPack = pair *>; 58 | 59 | template 60 | void probeAPIs(Module &m, 61 | const vector> &in, 62 | map> &out); 63 | 64 | template 65 | using LOCPack = pair *>; 66 | 67 | template 68 | void probeLOCs(Module &m, 69 | const vector> &in, 70 | map> &out); 71 | 72 | } /* namespace racer */ 73 | 74 | #endif /* _RACER_ANALYSIS_PROBE_H_ */ 75 | -------------------------------------------------------------------------------- /pass/instrument/include/base/Common.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_BASE_COMMON_H_ 2 | #define _RACER_BASE_COMMON_H_ 3 | 4 | // c/c++ basics 5 | #include 6 | #include 7 | 8 | // stl data structs 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // llvm pass 16 | #include 17 | 18 | // llvm traits 19 | #include 20 | #include 21 | #include 22 | 23 | // llvm IR basics 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | // llvm analysis 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | // llvm instrumentation 52 | #include 53 | 54 | // llvm support 55 | #include 56 | #include 57 | 58 | // used namespaces 59 | using namespace std; 60 | using namespace llvm; 61 | 62 | // json 63 | #include 64 | using json = nlohmann::json; 65 | 66 | // debug config 67 | #ifdef RACER_DEBUG_ALL 68 | #define RACER_DEBUG 69 | #define RACER_DEBUG_STATUS 70 | #endif 71 | 72 | // types 73 | typedef uint64_t flag_t; 74 | 75 | #endif /* _RACER_BASE_COMMON_H_ */ 76 | -------------------------------------------------------------------------------- /pass/instrument/include/dart/API.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_DART_API_H_ 2 | #define _RACER_DART_API_H_ 3 | 4 | #include "base/Common.h" 5 | #include "apidef.inc" 6 | 7 | namespace racer { 8 | 9 | class DartAPI { 10 | public: 11 | explicit DartAPI(Module &module) 12 | : ctxt(module.getContext()), 13 | // dart types 14 | void_t(Type::getVoidTy(ctxt)), 15 | info_64_t(Type::getInt64Ty(ctxt)), 16 | hval_64_t(Type::getInt64Ty(ctxt)), 17 | data_64_t(Type::getInt64Ty(ctxt)), 18 | // dart functions 19 | #define DART_FUNC DART_FUNC_API_CONSTRUCT 20 | #include "apidef.inc" 21 | #undef DART_FUNC 22 | end_of_fields(true) { 23 | } 24 | 25 | ~DartAPI() = default; 26 | 27 | protected: 28 | Value *prepIntOrPtr(IRBuilder<> &builder, Value *val) { 29 | Type *ty = val->getType(); 30 | 31 | if (ty->isPointerTy()) { 32 | return builder.CreatePtrToInt(val, data_64_t); 33 | } 34 | 35 | assert(ty->isIntegerTy()); 36 | unsigned bits = ty->getPrimitiveSizeInBits(); 37 | 38 | if (bits < data_64_t->getPrimitiveSizeInBits()) { 39 | return builder.CreateZExt(val, data_64_t); 40 | } 41 | 42 | assert(bits == data_64_t->getPrimitiveSizeInBits()); 43 | return val; 44 | } 45 | 46 | vector prepDartArgs(IRBuilder<> &builder, 47 | flag_t flag, const hash_code &hval, 48 | initializer_list data) { 49 | 50 | vector vec; 51 | 52 | vec.push_back(ConstantInt::get(info_64_t, flag)); 53 | vec.push_back(ConstantInt::get(hval_64_t, size_t(hval))); 54 | 55 | for (Value *v : data) { 56 | if (v != nullptr) { 57 | vec.push_back(prepIntOrPtr(builder, v)); 58 | } 59 | } 60 | 61 | return vec; 62 | } 63 | 64 | public: 65 | Value *createDataValue(int v) { 66 | return ConstantInt::get(data_64_t, v); 67 | } 68 | 69 | Value *createDataValue(unsigned int v) { 70 | return ConstantInt::get(data_64_t, v); 71 | } 72 | 73 | Value *createDataValue(long v) { 74 | return ConstantInt::get(data_64_t, v); 75 | } 76 | 77 | Value *createDataValue(unsigned long v) { 78 | return ConstantInt::get(data_64_t, v); 79 | } 80 | 81 | public: 82 | // dart hooks 83 | #define DART_FUNC DART_FUNC_API_HOOK 84 | #include "apidef.inc" 85 | #undef DART_FUNC 86 | 87 | protected: 88 | // context 89 | LLVMContext &ctxt; 90 | 91 | // dart types 92 | Type *void_t; 93 | Type *info_64_t; 94 | Type *hval_64_t; 95 | Type *data_64_t; 96 | 97 | // dart functions 98 | #define DART_FUNC DART_FUNC_API_DECLARE 99 | #include "apidef.inc" 100 | #undef DART_FUNC 101 | 102 | // dummy 103 | bool end_of_fields; 104 | }; 105 | 106 | } /* namespace racer */ 107 | 108 | #endif /* _RACER_DART_API_H_ */ 109 | -------------------------------------------------------------------------------- /pass/instrument/include/util/Logger.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_UTIL_LOGGER_H_ 2 | #define _RACER_UTIL_LOGGER_H_ 3 | 4 | #include "base/Common.h" 5 | 6 | namespace racer { 7 | 8 | class Logger { 9 | public: 10 | Logger() 11 | : rec(json::object()), cur(&rec) { 12 | stk.push(cur); 13 | } 14 | 15 | ~Logger() = default; 16 | 17 | // level + 1 18 | void vec(); 19 | void vec(const string &key); 20 | 21 | void map(); 22 | void map(const string &key); 23 | 24 | // stay on same level 25 | template 26 | void log(const T &msg); 27 | void log(const char *msg); 28 | 29 | template 30 | void log(const string &key, const T &msg); 31 | void log(const string &key, const char *msg); 32 | 33 | // record pointer 34 | void ptr(void *ptr); 35 | void ptr(const string &key, void *ptr); 36 | 37 | // level - 1 38 | void pop(); 39 | 40 | // move data 41 | void add(Logger &other); 42 | void add(const string &key, Logger &other); 43 | 44 | // test 45 | bool isVec(); 46 | bool isMap(); 47 | 48 | // dump to file 49 | void dump(raw_ostream &stm, int indent = 2); 50 | void dump(const string &fn, int indent = 2); 51 | 52 | protected: 53 | json rec; 54 | json *cur; 55 | stack stk; 56 | }; 57 | 58 | class Status { 59 | public: 60 | Status() 61 | : stm(errs()) { 62 | } 63 | 64 | ~Status() { 65 | stm.flush(); 66 | } 67 | 68 | public: 69 | raw_ostream &show(); 70 | raw_ostream &cont(); 71 | raw_ostream &warn(); 72 | void done(); 73 | 74 | protected: 75 | raw_ostream &stm; 76 | }; 77 | 78 | class Dumper { 79 | public: 80 | // llvm value 81 | static string getValueName(const Value *v); 82 | static string getValueType(const Value *v); 83 | static string getValueRepr(const Value *v); 84 | static string getDebugRepr(const DebugLoc *d); 85 | 86 | // llvm type 87 | static string getTypeName(Type *t); 88 | static string getTypeRepr(Type *t); 89 | 90 | // constructor / destructor 91 | Dumper() = default; 92 | ~Dumper() = default; 93 | 94 | // llvm value 95 | void namedValue(Value *v); 96 | void typedValue(Value *v); 97 | void ctypeValue(Value *v); 98 | 99 | // llvm type 100 | void namedType(Type *t); 101 | 102 | // llvm debug info 103 | void debugRepr(const DebugLoc *d); 104 | }; 105 | 106 | // globals 107 | #ifdef RACER_DEBUG 108 | extern Logger SLOG; 109 | extern Status STAT; 110 | #endif 111 | extern Dumper DUMP; 112 | 113 | } 114 | 115 | #endif /* _RACER_UTIL_LOGGER_H_ */ 116 | -------------------------------------------------------------------------------- /pass/instrument/include/util/Lower.h: -------------------------------------------------------------------------------- 1 | #ifndef _RACER_UTIL_LOWER_H_ 2 | #define _RACER_UTIL_LOWER_H_ 3 | 4 | #include "base/Common.h" 5 | 6 | namespace racer { 7 | 8 | class Lowering { 9 | public: 10 | // checks 11 | static void checkAssumptions(Module &m); 12 | 13 | // load file 14 | static bool findInSourceLine(const char *target, const DebugLoc &loc); 15 | }; 16 | 17 | } /* namespace racer */ 18 | 19 | #endif /* _RACER_UTIL_LOWER_H_ */ 20 | -------------------------------------------------------------------------------- /pass/instrument/lib/analysis/Oracle.cpp: -------------------------------------------------------------------------------- 1 | #include "analysis/Oracle.h" 2 | 3 | namespace racer { 4 | 5 | // dominator 6 | BasicBlock *FuncOracle::getIDom(BasicBlock *bb) { 7 | DomTreeNodeBase *node = dt.getNode(bb); 8 | assert(node != nullptr); 9 | 10 | DomTreeNodeBase *idom = node->getIDom(); 11 | if (idom == nullptr) { 12 | return nullptr; 13 | } 14 | 15 | return idom->getBlock(); 16 | } 17 | 18 | // loop 19 | Loop *FuncOracle::getOuterLoopInScope(Loop *scope, BasicBlock *bb) { 20 | Loop *l = li.getLoopFor(bb); 21 | Loop *c = nullptr; 22 | 23 | while (l != scope) { 24 | c = l; 25 | l = l->getParentLoop(); 26 | } 27 | 28 | return c; 29 | } 30 | 31 | } /* namespace racer */ 32 | -------------------------------------------------------------------------------- /pass/instrument/lib/dart/API.cpp: -------------------------------------------------------------------------------- 1 | #include "dart/API.h" -------------------------------------------------------------------------------- /pass/instrument/lib/util/Lower.cpp: -------------------------------------------------------------------------------- 1 | #include "util/Lower.h" 2 | 3 | namespace racer { 4 | 5 | void Lowering::checkAssumptions(Module &m) { 6 | for (Function &f : m) { 7 | // only leaf intrinsics are allowed and donothing is not allowed 8 | if (f.isIntrinsic()) { 9 | assert(Intrinsic::isLeaf(f.getIntrinsicID())); 10 | assert(f.getIntrinsicID() != Intrinsic::donothing); 11 | } 12 | 13 | for (BasicBlock &b : f) { 14 | for (Instruction &i : b) { 15 | // kernel should have no InvokeInst 16 | assert(!isa(i)); 17 | // kernel should have no ResumeInst 18 | assert(!isa(i)); 19 | } 20 | } 21 | } 22 | } 23 | 24 | static bool findInSourceLinePerLoc(const char *target, 25 | const string &fn, unsigned ln) { 26 | 27 | std::ifstream file(fn, std::ifstream::in); 28 | 29 | if (ln) { 30 | for (unsigned i = 0; i < ln - 1; i++) { 31 | file.ignore(std::numeric_limits::max(), '\n'); 32 | } 33 | } 34 | 35 | string line; 36 | std::getline(file, line); 37 | file.close(); 38 | 39 | return line.find(target) != string::npos; 40 | } 41 | 42 | bool Lowering::findInSourceLine(const char *target, const DebugLoc &loc) { 43 | DILocation *dl = loc.get(); 44 | 45 | while (dl != nullptr) { 46 | if (findInSourceLinePerLoc( 47 | target, dl->getFilename().str(), dl->getLine() 48 | )) { 49 | return true; 50 | } 51 | 52 | dl = dl->getInlinedAt(); 53 | } 54 | 55 | return false; 56 | } 57 | 58 | } /* namespace racer */ 59 | -------------------------------------------------------------------------------- /pass/profile/linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "special": { 3 | }, 4 | "ignored": { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /script/.gitignore: -------------------------------------------------------------------------------- 1 | # python cache 2 | /__pycache__/ 3 | 4 | # mypy 5 | /.mypy_cache/ 6 | 7 | # ide 8 | /.idea/ 9 | -------------------------------------------------------------------------------- /script/admin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from typing import List 4 | 5 | import os 6 | import sys 7 | import shutil 8 | import logging 9 | 10 | from argparse import ArgumentParser 11 | 12 | from fuzz_stat import iter_seed_exec_inc 13 | 14 | from util import enable_coloring_in_logging, prepfn 15 | 16 | import config 17 | 18 | STORAGE_BASE = '/home/changseok/racer' 19 | 20 | 21 | def move_files() -> None: 22 | base = os.path.join(config.STUDIO_BATCH, config.OPTION().tag) 23 | 24 | for pack in iter_seed_exec_inc(): 25 | path_racer = os.path.join(pack.path, 'console-racer') 26 | path_ledger = os.path.join(pack.path, 'ledger') 27 | if os.path.exists(path_racer) and not os.path.islink(path_ledger): 28 | path_rel = os.path.relpath(path_ledger, base) 29 | path_new = os.path.join(STORAGE_BASE, path_rel) 30 | 31 | # copy things over 32 | if not os.path.exists(path_new): 33 | prepfn(path_new) 34 | shutil.copy2(path_ledger, path_new) 35 | 36 | # build the symlink 37 | os.unlink(path_ledger) 38 | os.symlink(path_new, path_ledger) 39 | 40 | # done 41 | logging.info('Moved: {}'.format(path_rel)) 42 | 43 | 44 | def main(argv: List[str]) -> int: 45 | # prepare parser 46 | parser = ArgumentParser() 47 | 48 | # logging configs 49 | parser.add_argument( 50 | '-v', '--verbose', action='count', default=1, 51 | help='Verbosity level, can be specified multiple times, default to 1', 52 | ) 53 | 54 | subs = parser.add_subparsers(dest='cmd') 55 | subs.add_parser('move') 56 | 57 | # handle args 58 | args = parser.parse_args(argv) 59 | 60 | # prepare logs 61 | enable_coloring_in_logging() 62 | logging.basicConfig( 63 | format='%(asctime)s %(levelname)s %(message)s', 64 | level=logging.WARNING - (logging.DEBUG - logging.NOTSET) * args.verbose 65 | ) 66 | 67 | # run action 68 | if args.cmd == 'move': 69 | move_files() 70 | 71 | return 0 72 | 73 | 74 | if __name__ == '__main__': 75 | sys.exit(main(sys.argv[1:])) 76 | -------------------------------------------------------------------------------- /script/build.mk: -------------------------------------------------------------------------------- 1 | define racer_build 2 | $(eval goal := $(patsubst build-%,%,$1)) 3 | $(eval args := $(subst -, ,$(goal))) 4 | $(eval opts := $(if $(findstring $1,$(MAKECMDGOALS)),$(EXTRA),)) 5 | $(eval vals := $(if $(findstring $1,$(MAKECMDGOALS)),$(VALUE),)) 6 | python3 script/build.py $(opts) $(args) $(vals) 7 | endef 8 | 9 | .PHONY: build-help 10 | build-help: 11 | @echo "build-: binutils llvm" 12 | @echo "build-: qemu musl" 13 | @echo "build-: linux" 14 | @echo "build-: initramfs" 15 | @echo "build-: e2fsprogs btrfsprogs xfsprogs" 16 | @echo "build-: racer" 17 | @echo "build-: all" 18 | 19 | .PHONY: build-binutils 20 | build-binutils: 21 | $(call racer_build,$@) 22 | 23 | .PHONY: build-llvm 24 | build-llvm: 25 | $(call racer_build,$@) 26 | 27 | .PHONY: build-qemu 28 | build-qemu: 29 | $(call racer_build,$@) 30 | 31 | .PHONY: build-musl 32 | build-musl: 33 | $(call racer_build,$@) 34 | 35 | .PHONY: build-linux 36 | build-linux: build-llvm build-racer 37 | $(call racer_build,$@) 38 | 39 | .PHONY: build-initramfs 40 | build-initramfs: build-musl build-linux 41 | $(call racer_build,$@) 42 | 43 | .PHONY: build-e2fsprogs 44 | build-e2fsprogs: 45 | $(call racer_build,$@) 46 | 47 | .PHONY: build-btrfsprogs 48 | build-btrfsprogs: 49 | $(call racer_build,$@) 50 | 51 | .PHONY: build-xfsprogs 52 | build-xfsprogs: 53 | $(call racer_build,$@) 54 | 55 | .PHONY: build-racer 56 | build-racer: build-llvm 57 | $(call racer_build,$@) 58 | 59 | .PHONY: build-all 60 | build-all: \ 61 | build-binutils \ 62 | build-llvm \ 63 | build-qemu \ 64 | build-musl \ 65 | build-linux \ 66 | build-initramfs \ 67 | build-e2fsprogs \ 68 | build-btrfsprogs \ 69 | build-xfsprogs \ 70 | build-racer 71 | -------------------------------------------------------------------------------- /script/build.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | import sys 4 | import logging 5 | 6 | from argparse import ArgumentParser 7 | 8 | from pkg import Package 9 | 10 | from pkg_binutils import Package_BINUTILS 11 | from pkg_gcc import Package_GCC 12 | from pkg_llvm import Package_LLVM 13 | 14 | from pkg_qemu import Package_QEMU 15 | 16 | from pkg_musl import Package_MUSL 17 | from pkg_initramfs import Package_INITRAMFS 18 | 19 | from pkg_linux import Package_LINUX 20 | 21 | from pkg_e2fsprogs import Package_E2FSPROGS 22 | from pkg_btrfsprogs import Package_BTRFSPROGS 23 | from pkg_xfsprogs import Package_XFSPROGS 24 | 25 | from pkg_racer import Package_Racer 26 | 27 | from util import enable_coloring_in_logging 28 | 29 | 30 | def main(argv: List[str]) -> int: 31 | # setup argument parser 32 | parser = ArgumentParser() 33 | 34 | # logging configs 35 | parser.add_argument( 36 | '-v', '--verbose', action='count', default=1, 37 | help='Verbosity level, can be specified multiple times, default to 1', 38 | ) 39 | 40 | # override flag 41 | parser.add_argument( 42 | '-c', '--clean', action='count', default=0, 43 | help='Cleaning level, 0 - no clean, 1 - clean build, >1 - clean setup', 44 | ) 45 | 46 | # action selection 47 | subs = parser.add_subparsers(dest='cmd') 48 | 49 | subs.add_parser( 50 | 'binutils', 51 | help='Package binutils', 52 | ) 53 | 54 | subs.add_parser( 55 | 'gcc', 56 | help='Package gcc', 57 | ) 58 | 59 | subs.add_parser( 60 | 'llvm', 61 | help='Package llvm', 62 | ) 63 | 64 | subs.add_parser( 65 | 'qemu', 66 | help='Package qemu', 67 | ) 68 | 69 | subs.add_parser( 70 | 'e2fsprogs', 71 | help='Package e2fs-progs', 72 | ) 73 | 74 | subs.add_parser( 75 | 'btrfsprogs', 76 | help='Package btrfs-progs', 77 | ) 78 | 79 | subs.add_parser( 80 | 'xfsprogs', 81 | help='Package xfs-progs', 82 | ) 83 | 84 | subs.add_parser( 85 | 'musl', 86 | help='Package musl', 87 | ) 88 | 89 | subs.add_parser( 90 | 'linux', 91 | help='Package linux', 92 | ) 93 | 94 | subs.add_parser( 95 | 'initramfs', 96 | help='Package initramfs', 97 | ) 98 | 99 | subs.add_parser( 100 | 'racer', 101 | help='Package racer', 102 | ) 103 | 104 | # parse 105 | args = parser.parse_args(argv) 106 | 107 | # prepare logs 108 | enable_coloring_in_logging() 109 | logging.basicConfig( 110 | format='%(asctime)s %(levelname)s %(message)s', 111 | level=logging.WARNING - (logging.DEBUG - logging.NOTSET) * args.verbose 112 | ) 113 | 114 | # construct the instance 115 | instance = None # type: Optional[Package] 116 | 117 | if args.cmd == 'binutils': 118 | instance = Package_BINUTILS() 119 | 120 | elif args.cmd == 'gcc': 121 | instance = Package_GCC() 122 | 123 | elif args.cmd == 'llvm': 124 | instance = Package_LLVM() 125 | 126 | elif args.cmd == 'qemu': 127 | instance = Package_QEMU() 128 | 129 | elif args.cmd == 'musl': 130 | instance = Package_MUSL() 131 | 132 | elif args.cmd == 'linux': 133 | instance = Package_LINUX() 134 | 135 | elif args.cmd == 'initramfs': 136 | instance = Package_INITRAMFS() 137 | 138 | elif args.cmd == 'e2fsprogs': 139 | instance = Package_E2FSPROGS() 140 | 141 | elif args.cmd == 'btrfsprogs': 142 | instance = Package_BTRFSPROGS() 143 | 144 | elif args.cmd == 'xfsprogs': 145 | instance = Package_XFSPROGS() 146 | 147 | elif args.cmd == 'racer': 148 | instance = Package_Racer() 149 | 150 | else: 151 | parser.print_help() 152 | return -1 153 | 154 | try: 155 | instance.make(args.clean) 156 | except Exception as ex: 157 | logging.error('Unexpected error: {}'.format(ex)) 158 | return -2 159 | 160 | return 0 161 | 162 | 163 | if __name__ == '__main__': 164 | sys.exit(main(sys.argv[1:])) 165 | -------------------------------------------------------------------------------- /script/cmd.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from abc import ABC, abstractmethod 4 | 5 | from argparse import ArgumentParser, Namespace 6 | 7 | 8 | class Parser(ABC): 9 | 10 | def __init__(self) -> None: 11 | self.parser = type(self).build() 12 | 13 | @classmethod 14 | @abstractmethod 15 | def build(cls) -> ArgumentParser: 16 | raise RuntimeError('Method not implemented') 17 | 18 | def parse(self, argv: List[str]) -> Namespace: 19 | args, rems = self.parser.parse_known_args(argv) 20 | 21 | if len(rems) != 0: 22 | raise RuntimeError('Unknown arguments: {}'.format(' '.join(rems))) 23 | 24 | return args 25 | 26 | 27 | class Parser_CC(Parser): 28 | 29 | @classmethod 30 | def build(cls) -> ArgumentParser: 31 | parser = ArgumentParser(add_help=False) 32 | 33 | # output 34 | parser.add_argument('-o', type=str, default=None) 35 | 36 | # c/c++ standard 37 | parser.add_argument('-std', type=str, default=None) 38 | 39 | # optimization 40 | parser.add_argument('-O', type=str, default=None) 41 | 42 | # operation mode 43 | parser.add_argument('-c', action='store_true') 44 | parser.add_argument('-E', action='store_true') 45 | parser.add_argument('-S', action='store_true') 46 | 47 | # keys 48 | parser.add_argument('-ansi', action='store_true') 49 | parser.add_argument('-nostdinc', action='store_true') 50 | parser.add_argument('-nostdlib', action='store_true') 51 | parser.add_argument('-no-integrated-as', action='store_true') 52 | 53 | # control 54 | parser.add_argument('-C', action='store_true') 55 | parser.add_argument('-P', action='store_true') 56 | 57 | parser.add_argument('-s', action='store_true') 58 | parser.add_argument('-w', action='store_true') 59 | 60 | parser.add_argument('-r', action='store_true') 61 | parser.add_argument('-x', type=str, default=None) 62 | parser.add_argument('-G', type=str, default=None) 63 | 64 | parser.add_argument('-shared', action='store_true') 65 | 66 | # misc 67 | parser.add_argument('-pipe', action='store_true') 68 | 69 | # debug 70 | parser.add_argument('-g', action='store_true') 71 | parser.add_argument('-gdwarf-2', action='store_true') 72 | parser.add_argument('-gdwarf-4', action='store_true') 73 | parser.add_argument('-pg', action='store_true') 74 | 75 | # metadata 76 | parser.add_argument('-MD', action='store_true') 77 | parser.add_argument('-MG', action='store_true') 78 | parser.add_argument('-MM', action='store_true') 79 | parser.add_argument('-MP', action='store_true') 80 | parser.add_argument('-MF', type=str, default=None) 81 | 82 | # defines 83 | parser.add_argument('-D', type=str, action='append', default=[]) 84 | # undefs 85 | parser.add_argument('-U', type=str, action='append', default=[]) 86 | 87 | # includes 88 | parser.add_argument('-I', type=str, action='append', default=[]) 89 | # include headers 90 | parser.add_argument('-include', type=str, action='append', default=[]) 91 | # include system 92 | parser.add_argument('-isystem', type=str, action='append', default=[]) 93 | 94 | # libs 95 | parser.add_argument('-l', type=str, action='append', default=[]) 96 | 97 | # warnings 98 | parser.add_argument('-W', type=str, action='append', default=[]) 99 | 100 | # flags 101 | parser.add_argument('-f', type=str, action='append', default=[]) 102 | 103 | # machine 104 | parser.add_argument('-m', type=str, action='append', default=[]) 105 | 106 | # extra params 107 | parser.add_argument('--param', type=str, action='append', default=[]) 108 | 109 | # dump results 110 | parser.add_argument('-dA', action='store_true') 111 | parser.add_argument('-dD', action='store_true') 112 | parser.add_argument('-dI', action='store_true') 113 | parser.add_argument('-dM', action='store_true') 114 | 115 | # quiet 116 | parser.add_argument('-Q', action='append', default=[]) 117 | 118 | # feature testing 119 | parser.add_argument('--version', action='store_true') 120 | parser.add_argument('-print-file-name', type=str, default=None) 121 | 122 | # src file 123 | parser.add_argument('inputs', type=str, nargs='*') 124 | 125 | # finish 126 | return parser 127 | -------------------------------------------------------------------------------- /script/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import multiprocessing 4 | 5 | from config_option import Option 6 | 7 | # system tuning 8 | sys.setrecursionlimit(10000) 9 | 10 | 11 | # option settings 12 | def OPTION() -> Option: 13 | return Option() 14 | 15 | 16 | # project configs 17 | PROJ_PATH = os.path.abspath(os.path.join(__file__, '..', '..')) 18 | 19 | # system configs 20 | NCPU = multiprocessing.cpu_count() 21 | 22 | if NCPU <= 64: 23 | FUZZ_INSTANCE_MAX = 62 24 | elif NCPU <= 128: 25 | FUZZ_INSTANCE_MAX = 126 26 | else: 27 | FUZZ_INSTANCE_MAX = 254 28 | 29 | # docker configs 30 | DOCKER_PATH = os.path.join(PROJ_PATH, 'docker') 31 | DOCKER_REPO = 'racer' 32 | DOCKER_MPTR = '/racer' 33 | DOCKER_MARK = 'IN_RACER_DOCKER' 34 | 35 | DOCKER_TMP_SIZE_IN_MB = 128 * (FUZZ_INSTANCE_MAX + 2) + 512 36 | DOCKER_SHM_SIZE_IN_MB = 128 * (FUZZ_INSTANCE_MAX + 2) + 512 37 | 38 | DOCKERIZED = DOCKER_MARK in os.environ 39 | 40 | # studio configs 41 | STUDIO_PATH = os.path.join( 42 | PROJ_PATH, 'studio', 'dock' if DOCKERIZED else 'host' 43 | ) 44 | 45 | STUDIO_BUILD = os.path.join(STUDIO_PATH, 'build') 46 | STUDIO_STORE = os.path.join(STUDIO_PATH, 'store') 47 | 48 | STUDIO_MARKS = os.path.join(STUDIO_PATH, 'marks') 49 | STUDIO_WORKS = os.path.join(STUDIO_PATH, 'works') 50 | 51 | STUDIO_BATCH = os.path.join(STUDIO_PATH, 'batch') 52 | 53 | # asset configs 54 | ASSET_PATH = os.path.join(PROJ_PATH, 'studio', 'asset') 55 | ASSET_SYSCALL = os.path.join(ASSET_PATH, 'syscall') 56 | 57 | # script configs 58 | SCRIPT_PATH = os.path.join(PROJ_PATH, 'script') 59 | 60 | # pass configs 61 | PASS_PATH = os.path.join(PROJ_PATH, 'pass') 62 | 63 | # linux configs 64 | LINUX_VERSION = 'v5.4-rc5' 65 | LINUX_MOD_MAIN_MAX = 8 66 | LINUX_MOD_DEPS_MAX = 32 67 | 68 | # virtex machine configs 69 | VIRTEX_SMP = 4 70 | VIRTEX_MEM_SIZE = 16 * (1 << 10) 71 | 72 | # virtex execute configs 73 | VIRTEX_SHM_DIR = '/dev/shm' 74 | VIRTEX_TMP_DIR = '/tmp' 75 | 76 | # virtex sharing configs 77 | VIRTEX_DISK_IMG_NAME = 'disk.img' 78 | VIRTEX_LEDGER_NAME = 'ledger' 79 | 80 | # virtex multi-threading configs 81 | VIRTEX_THREAD_NUM = 4 82 | 83 | # timeout 84 | VIRTEX_TIMEOUT = 120 85 | 86 | 87 | # instmem and ivshmem configs (all unit in MB) 88 | 89 | # 90 | # | 4 MB | -> header 91 | # | 4 MB | -> cov_cfg_edge 92 | # | 4 MB | -> cov_dfg_edge 93 | # | 4 MB | -> cov_alias_inst 94 | # |240 MB | -> (reserved) 95 | # 96 | # --------- (256 MB) header 97 | # 98 | # | 2 MB | -> metadata (userspace: mount options, etc) 99 | # | 48 MB | -> bytecode (userspace: program to interpret) 100 | # | 12 MB | -> strace (userspace: syscall logs) 101 | # | 2 MB | -> rtinfo (kernel : runtime info) 102 | # | 64 MB | -> rtrace (kernel : racing access logs) 103 | # 104 | # --------- (128 MB) instance-specific workspace 105 | # 106 | 107 | def _MB(i: int) -> int: 108 | return i * (1 << 20) 109 | 110 | 111 | INSTMEM_OFFSET_METADATA = 0 112 | INSTMEM_OFFSET_BYTECODE = INSTMEM_OFFSET_METADATA + _MB(2) 113 | INSTMEM_OFFSET_STRACE = INSTMEM_OFFSET_BYTECODE + _MB(48) 114 | INSTMEM_OFFSET_RTINFO = INSTMEM_OFFSET_STRACE + _MB(12) 115 | INSTMEM_OFFSET_RTRACE = INSTMEM_OFFSET_RTINFO + _MB(2) 116 | INSTMEM_SIZE = INSTMEM_OFFSET_RTRACE + _MB(64) 117 | 118 | IVSHMEM_OFFSET_HEADER = 0 119 | IVSHMEM_OFFSET_COV_CFG_EDGE = IVSHMEM_OFFSET_HEADER + _MB(4) 120 | IVSHMEM_OFFSET_COV_DFG_EDGE = IVSHMEM_OFFSET_COV_CFG_EDGE + _MB(4) 121 | IVSHMEM_OFFSET_COV_ALIAS_INST = IVSHMEM_OFFSET_COV_DFG_EDGE + _MB(4) 122 | IVSHMEM_OFFSET_RESERVED = IVSHMEM_OFFSET_COV_ALIAS_INST + _MB(4) 123 | IVSHMEM_OFFSET_INSTANCES = IVSHMEM_OFFSET_RESERVED + _MB(240) 124 | IVSHMEM_SIZE = IVSHMEM_OFFSET_INSTANCES + INSTMEM_SIZE * FUZZ_INSTANCE_MAX 125 | 126 | 127 | def INSTMEM_OFFSET(instance: int) -> int: 128 | return IVSHMEM_OFFSET_INSTANCES + INSTMEM_SIZE * instance 129 | 130 | 131 | # runtime info 132 | BITMAP_COV_CFG_EDGE_SIZE = (1 << 24) // 8 133 | BITMAP_COV_DFG_EDGE_SIZE = (1 << 24) // 8 134 | BITMAP_COV_ALIAS_INST_SIZE = (1 << 24) // 8 135 | 136 | OUTPUT_LEDGER_SIZE = _MB(2048) 137 | 138 | # refresh rate 139 | REFRESH_RATE = 20 140 | 141 | # iteration limits 142 | TTL_REP_LOOP = 5 143 | TTL_MOD_LOOP = 10 144 | TTL_EXT_LOOP = 10 145 | TTL_MERGE_LOOP = 10 146 | TTL_CHECK_LOOP = 20 147 | 148 | # probe configs 149 | PROBE_SLICE_LEN = 1000 150 | 151 | # validation configs 152 | VALIDATION_WORKER_PATH = os.path.join(VIRTEX_TMP_DIR, 'racer-validation') 153 | VALIDATION_FAILED_PATH = os.path.join(VIRTEX_TMP_DIR, 'racer-error') 154 | 155 | # test configs 156 | TEST_RESULT_PATH = os.path.join(VIRTEX_TMP_DIR, 'racer-test') 157 | -------------------------------------------------------------------------------- /script/config_option.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import os 4 | 5 | from util import Singleton 6 | 7 | 8 | class Option(metaclass=Singleton): 9 | 10 | def __init__(self) -> None: 11 | self._flavor = os.environ.get('F', None) # type: Optional[str] 12 | self._intent = os.environ.get('I', None) # type: Optional[str] 13 | self._action = os.environ.get('A', None) # type: Optional[str] 14 | self._tag = os.environ.get('T', None) # type: Optional[str] 15 | 16 | # single properties 17 | @property 18 | def flavor(self) -> str: 19 | assert self._flavor is not None 20 | return self._flavor 21 | 22 | @flavor.setter 23 | def flavor(self, value: str) -> None: 24 | assert self._flavor is None 25 | self._flavor = value 26 | 27 | @property 28 | def intent(self) -> str: 29 | assert self._intent is not None 30 | return self._intent 31 | 32 | @intent.setter 33 | def intent(self, value: str) -> None: 34 | assert self._intent is None 35 | self._intent = value 36 | 37 | @property 38 | def action(self) -> str: 39 | assert self._action is not None 40 | return self._action 41 | 42 | @action.setter 43 | def action(self, value: str) -> None: 44 | assert self._action is None 45 | self._action = value 46 | 47 | @property 48 | def tag(self) -> str: 49 | assert self._tag is not None 50 | return self._tag 51 | 52 | @tag.setter 53 | def tag(self, value: str) -> None: 54 | assert self._tag is None 55 | self._tag = value 56 | 57 | # composed properties 58 | @property 59 | def shape(self) -> str: 60 | return '-'.join([self.flavor, self.intent]) 61 | 62 | @property 63 | def label(self) -> str: 64 | return '-'.join([self.flavor, self.intent, self.action]) 65 | -------------------------------------------------------------------------------- /script/dart_viz_depth.json: -------------------------------------------------------------------------------- 1 | { 2 | "src": { 3 | "FORK": null, 4 | "JOIN": null, 5 | "EMBED": 1, 6 | "QUEUE": 0, 7 | "ORDER": 0, 8 | "FIFO": 0 9 | }, 10 | "dst": { 11 | "FORK": null, 12 | "JOIN": null, 13 | "EMBED": 1, 14 | "QUEUE": 0, 15 | "ORDER": 0, 16 | "FIFO": 0 17 | } 18 | } -------------------------------------------------------------------------------- /script/docker.mk: -------------------------------------------------------------------------------- 1 | define racer_docker 2 | $(eval goal := $(patsubst docker-%,%,$1)) 3 | $(eval args := $(subst -, ,$(goal))) 4 | $(eval opts := $(if $(findstring $1,$(MAKECMDGOALS)),$(EXTRA),)) 5 | $(eval vals := $(if $(findstring $1,$(MAKECMDGOALS)),$(VALUE),)) 6 | python3 script/docker.py $(opts) $(args) $(vals) 7 | endef 8 | 9 | .PHONY: docker-help 10 | docker-help: 11 | @echo "docker-: help status mkleaf mkroot" 12 | @echo "docker-: build-[base]" 13 | @echo "docker-: start-[base]" 14 | @echo "docker-: shell-[base]" 15 | @echo "docker-: reset-[base]" 16 | @echo "docker-: clean-[base]" 17 | 18 | .PHONY: docker-status 19 | docker-status: 20 | $(call racer_docker,$@) 21 | 22 | .PHONY: docker-mkleaf 23 | docker-mkleaf: 24 | $(call racer_docker,$@) 25 | 26 | .PHONY: docker-mkroot 27 | docker-mkroot: 28 | $(call racer_docker,$@) 29 | 30 | .PHONY: docker-build-base 31 | docker-build-base: 32 | $(call racer_docker,$@) 33 | 34 | .PHONY: docker-start-base 35 | docker-start-base: 36 | $(call racer_docker,$@) 37 | 38 | .PHONY: docker-shell-base 39 | docker-shell-base: 40 | $(call racer_docker,$@) 41 | 42 | .PHONY: docker-reset-base 43 | docker-reset-base: 44 | $(call racer_docker,$@) 45 | 46 | .PHONY: docker-clean-base 47 | docker-clean-base: 48 | $(call racer_docker,$@) 49 | -------------------------------------------------------------------------------- /script/emu.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple, Optional, Iterator 2 | 3 | import os 4 | import uuid 5 | import shutil 6 | 7 | from contextlib import contextmanager 8 | 9 | from pkg_qemu import Package_QEMU 10 | from pkg_linux import Package_LINUX 11 | from pkg_initramfs import Package_INITRAMFS 12 | 13 | from util import execute0, prepdn, touch 14 | 15 | import config 16 | 17 | 18 | class Emulator(object): 19 | 20 | def __init__(self) -> None: 21 | # qemu 22 | qemu = Package_QEMU() 23 | self.path_qemu = os.path.join( 24 | qemu.path_store, 'bin', 'qemu-system-x86_64' 25 | ) 26 | 27 | # linux 28 | linux = Package_LINUX() 29 | self.path_kernel = os.path.join(linux.path_store, 'bin', 'bzImage') 30 | 31 | # initramfs 32 | initramfs = Package_INITRAMFS() 33 | self.path_initrd = os.path.join(initramfs.path_store, 'initrd.img') 34 | 35 | # session 36 | self.session_sid = uuid.uuid4() 37 | 38 | self.session_shm = os.path.join( 39 | config.VIRTEX_SHM_DIR, 40 | 'racer-ivshmem-{}'.format(config.OPTION().label), 41 | ) 42 | 43 | self.session_tmp = os.path.join( 44 | config.VIRTEX_TMP_DIR, 45 | 'racer-fsshare-{}'.format(config.OPTION().label), 46 | self.session_sid.hex 47 | ) 48 | 49 | # arguments 50 | self.qemu_args_machine = [ 51 | '-enable-kvm', 52 | '-smp', str(config.VIRTEX_SMP), 53 | '-m', '{}M'.format(config.VIRTEX_MEM_SIZE), 54 | ] 55 | 56 | self.qemu_args_ivshmem = [ 57 | '-object', ','.join([ 58 | 'memory-backend-file', 59 | 'size={}M'.format(config.IVSHMEM_SIZE // (1 << 20)), 60 | 'share', 61 | 'mem-path={}'.format(self.session_shm), 62 | 'id=ivshmem', 63 | ]), 64 | '-device', ','.join([ 65 | 'ivshmem-plain', 66 | 'memdev=ivshmem', 67 | ]), 68 | ] 69 | 70 | self.qemu_args_fsshare = [ 71 | '-fsdev', ','.join([ 72 | 'local', 73 | 'security_model=mapped-file', 74 | 'id=fsdev9p', 75 | 'path={}'.format(self.session_tmp), 76 | ]), 77 | '-device', ','.join([ 78 | 'virtio-9p-pci', 79 | 'fsdev=fsdev9p', 80 | 'id=fs9p', 81 | 'mount_tag=fsshare', 82 | ]), 83 | ] 84 | 85 | self.qemu_args_pvpanic = [ 86 | '-device', 'pvpanic', 87 | '-no-reboot', 88 | ] 89 | 90 | self.qemu_args_monitor = [ 91 | '-nographic', 92 | '-serial', 'mon:stdio', 93 | ] 94 | 95 | self.boot_args = [ 96 | 'console=ttyS0', 97 | 'earlyprintk=ttyS0', 98 | ] 99 | 100 | @staticmethod 101 | def _run(qemu_path: str, qemu_args: List[str], 102 | boot_kernel: str, boot_initrd: str, boot_args: List[str], 103 | timeout: Optional[int] = None) -> Tuple[str, str]: 104 | return execute0([ 105 | qemu_path, 106 | '-kernel', boot_kernel, 107 | '-initrd', boot_initrd, 108 | '-append', ' '.join(boot_args), 109 | *qemu_args, 110 | ], timeout=timeout, timeout_allowed=True) 111 | 112 | def virtex_set_up(self, oneoff: bool) -> None: 113 | if oneoff: 114 | # create the ivshmem shm 115 | if os.path.exists(self.session_shm): 116 | os.unlink(self.session_shm) 117 | 118 | touch(self.session_shm, config.IVSHMEM_SIZE) 119 | 120 | # create the fsshare dir 121 | prepdn(self.session_tmp) 122 | os.chmod(self.session_tmp, 0o777) 123 | 124 | def virtex_tear_down(self, oneoff: bool) -> None: 125 | # destroy the ivshmem shm 126 | if oneoff and os.path.exists(self.session_shm): 127 | os.unlink(self.session_shm) 128 | 129 | # destroy the fsshare dir 130 | if os.path.exists(self.session_tmp): 131 | shutil.rmtree(self.session_tmp) 132 | 133 | def launch(self) -> Tuple[str, str]: 134 | qemu_args = \ 135 | self.qemu_args_machine + \ 136 | self.qemu_args_ivshmem + \ 137 | self.qemu_args_fsshare + \ 138 | self.qemu_args_pvpanic + \ 139 | self.qemu_args_monitor 140 | 141 | boot_args = self.boot_args 142 | 143 | return Emulator._run( 144 | self.path_qemu, qemu_args, 145 | self.path_kernel, self.path_initrd, boot_args, 146 | timeout=config.VIRTEX_TIMEOUT 147 | ) 148 | 149 | 150 | @contextmanager 151 | def create_emulator(oneoff: bool = False) -> Iterator[Emulator]: 152 | emulator = Emulator() 153 | emulator.virtex_set_up(oneoff) 154 | try: 155 | yield emulator 156 | finally: 157 | emulator.virtex_tear_down(oneoff) 158 | 159 | 160 | @contextmanager 161 | def attach_emulator() -> Iterator[Emulator]: 162 | emulator = Emulator() 163 | try: 164 | yield emulator 165 | finally: 166 | pass 167 | -------------------------------------------------------------------------------- /script/exec.mk: -------------------------------------------------------------------------------- 1 | define racer_exec 2 | $(eval goal := $(patsubst exec-%,%,$1)) 3 | $(eval args := $(subst -, ,$(goal))) 4 | $(eval opts := $(if $(findstring $1,$(MAKECMDGOALS)),$(EXTRA),)) 5 | $(eval vals := $(if $(findstring $1,$(MAKECMDGOALS)),$(VALUE),)) 6 | python3 script/exec.py $(opts) $(args) $(vals) 7 | endef 8 | 9 | .PHONY: exec-help 10 | exec-help: 11 | @echo "exec-: test" 12 | 13 | .PHONY: exec-test 14 | exec-test: build-qemu build-linux build-initramfs 15 | $(call racer_exec,$@) -------------------------------------------------------------------------------- /script/fs.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | import os 4 | import shutil 5 | import struct 6 | import logging 7 | 8 | from abc import ABC, abstractmethod 9 | 10 | from emu import create_emulator 11 | 12 | from util import ascii_encode, prepfn, execute, dump_execute_outputs 13 | 14 | import config 15 | 16 | FS_SAMPLES = { 17 | 'empty': '000' 18 | } 19 | 20 | 21 | class FSConfig(ABC): 22 | 23 | def __init__(self, tag: str, size: int) -> None: 24 | self.tag = tag 25 | self.size = size 26 | 27 | 28 | class FSWorker(ABC): 29 | 30 | def __init__(self, name: str, conf: FSConfig) -> None: 31 | # basic 32 | self.name = name 33 | self.conf = conf 34 | 35 | # derived 36 | self.path_work = os.path.join(config.STUDIO_WORKS, self.name) 37 | 38 | # fs image configs 39 | @abstractmethod 40 | def mkfs(self, path: str) -> None: 41 | raise RuntimeError('Method not implemented') 42 | 43 | @abstractmethod 44 | def pack_mount(self) -> bytes: 45 | raise RuntimeError('Method not implemented') 46 | 47 | def _pack_mount_info( 48 | self, opts: str, main: List[str], deps: List[str], names: List[str] 49 | ) -> bytes: 50 | # prepare the package 51 | data = struct.pack( 52 | '@64s1024sQQQ', 53 | ascii_encode(self.name), 54 | ascii_encode(opts), 55 | len(main), 56 | len(deps), 57 | len(names), 58 | ) 59 | 60 | # pack main 61 | for d in main: 62 | data += struct.pack('128s', ascii_encode(d)) 63 | 64 | for i in range(config.LINUX_MOD_MAIN_MAX - len(main)): 65 | data += struct.pack('128s', b'') 66 | 67 | # pack deps 68 | for d in deps: 69 | data += struct.pack('128s', ascii_encode(d)) 70 | 71 | for i in range(config.LINUX_MOD_DEPS_MAX - len(deps)): 72 | data += struct.pack('128s', b'') 73 | 74 | # pack names 75 | for d in names: 76 | data += struct.pack('128s', ascii_encode(d)) 77 | 78 | for i in range(config.LINUX_MOD_MAIN_MAX - len(names)): 79 | data += struct.pack('128s', b'') 80 | 81 | return data 82 | 83 | # sample creation 84 | def path_sample(self, sample: str) -> str: 85 | return os.path.join( 86 | os.path.join(self.path_work, 'samples'), 87 | '{}-{}.img'.format(self.conf.tag, sample) 88 | ) 89 | 90 | def _sample_empty_bytecode(self) -> bytes: 91 | return b'' 92 | 93 | def _mk_sample(self, sample: str) -> None: 94 | # get path 95 | path = self.path_sample(sample) 96 | prepfn(path, True) 97 | 98 | # create empty disk 99 | execute([ 100 | 'dd', 101 | 'if=/dev/zero', 'of={}'.format(path), 102 | 'bs=1024', 'count={}'.format(self.conf.size * 1024), 103 | ]) 104 | 105 | # initialize the fs image 106 | self.mkfs(path) 107 | 108 | # prepare the emulator 109 | with create_emulator(oneoff=True) as emulator: 110 | # copy over the image 111 | shutil.copy2( 112 | path, 113 | os.path.join(emulator.session_tmp, config.VIRTEX_DISK_IMG_NAME) 114 | ) 115 | 116 | # prepare the shmem 117 | with open(emulator.session_shm, 'r+b') as f: 118 | # seek to the location for machine 0 119 | f.seek(config.INSTMEM_OFFSET( 120 | 0 121 | ) + config.INSTMEM_OFFSET_METADATA) 122 | f.write(struct.pack( 123 | '@c7sQ', 124 | ascii_encode('p'), 125 | ascii_encode('prep'), 126 | 0, 127 | )) 128 | 129 | # mount options 130 | f.write(self.pack_mount()) 131 | 132 | # prep code 133 | f.write(struct.pack('4s', ascii_encode(FS_SAMPLES[sample]))) 134 | 135 | # prep instruction 136 | if sample == 'empty': 137 | bytecode = self._sample_empty_bytecode() 138 | 139 | else: 140 | raise RuntimeError('Unknown prepare method') 141 | 142 | f.write(bytecode) 143 | 144 | # launch 145 | stdout, stderr = emulator.launch() 146 | dump_execute_outputs(stdout, stderr) 147 | 148 | # check exit status 149 | with open(emulator.session_shm, 'rb') as f: 150 | f.seek(config.INSTMEM_OFFSET( 151 | 0 152 | ) + config.INSTMEM_OFFSET_METADATA + 8) 153 | status = struct.unpack('Q', f.read(8))[0] 154 | 155 | if status == 0: 156 | logging.error('emulator does not exit correctly') 157 | 158 | def prep(self, override: bool = False) -> None: 159 | for sample in FS_SAMPLES: 160 | path = self.path_sample(sample) 161 | if os.path.exists(path) and not override: 162 | logging.info('Image {} existed, do nothing'.format(path)) 163 | continue 164 | 165 | self._mk_sample(sample) 166 | -------------------------------------------------------------------------------- /script/fs_btrfs.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from fs import FSConfig, FSWorker 4 | 5 | from pkg_linux import Package_LINUX 6 | from pkg_btrfsprogs import Package_BTRFSPROGS 7 | 8 | from util import execute, envldpaths 9 | 10 | 11 | class FSConfig_BTRFS(FSConfig): 12 | 13 | def __init__(self, tag: str, size: int) -> None: 14 | super(FSConfig_BTRFS, self).__init__(tag, size) 15 | 16 | 17 | FS_CONFIGS_BTRFS = { 18 | '000': FSConfig_BTRFS( 19 | '000', 128 20 | ) 21 | } 22 | 23 | 24 | class FSWorker_BTRFS(FSWorker): 25 | 26 | def __init__(self, conf: FSConfig_BTRFS) -> None: 27 | super(FSWorker_BTRFS, self).__init__('btrfs', conf) 28 | 29 | def mkfs(self, path: str) -> None: 30 | progs = Package_BTRFSPROGS() 31 | 32 | with envldpaths(os.path.join(progs.path_store, 'lib')): 33 | execute([ 34 | os.path.join(progs.path_store, 'bin', 'mkfs.btrfs'), 35 | path, 36 | ]) 37 | 38 | def _get_mount_opts(self) -> str: 39 | return 'autodefrag,check_int,check_int_data,compress' 40 | 41 | def pack_mount(self) -> bytes: 42 | opts = self._get_mount_opts() 43 | assert len(opts) + 1 < 1024 44 | 45 | # extract module dependencies 46 | deps = Package_LINUX().module_order(['kernel/fs/btrfs/btrfs.ko']) 47 | main = [ 48 | '/mod/fs/btrfs/btrfs.ko' 49 | ] 50 | names = [ 51 | 'btrfs' 52 | ] 53 | 54 | return self._pack_mount_info(opts, main, deps, names) 55 | -------------------------------------------------------------------------------- /script/fs_ext4.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from fs import FSConfig, FSWorker 4 | from pkg_e2fsprogs import Package_E2FSPROGS 5 | 6 | from util import execute, envldpaths 7 | 8 | 9 | class FSConfig_EXT4(FSConfig): 10 | 11 | def __init__(self, tag: str, size: int) -> None: 12 | super(FSConfig_EXT4, self).__init__(tag, size) 13 | 14 | 15 | FS_CONFIGS_EXT4 = { 16 | '000': FSConfig_EXT4( 17 | '000', 64 18 | ) 19 | } 20 | 21 | 22 | class FSWorker_EXT4(FSWorker): 23 | 24 | def __init__(self, conf: FSConfig_EXT4) -> None: 25 | super(FSWorker_EXT4, self).__init__('ext4', conf) 26 | 27 | def mkfs(self, path: str) -> None: 28 | progs = Package_E2FSPROGS() 29 | 30 | with envldpaths(os.path.join(progs.path_store, 'lib')): 31 | execute([ 32 | os.path.join(progs.path_store, 'sbin', 'mkfs.ext4'), 33 | path, 34 | ]) 35 | 36 | def _get_mount_opts(self) -> str: 37 | return '' 38 | 39 | def pack_mount(self) -> bytes: 40 | opts = self._get_mount_opts() 41 | assert len(opts) + 1 < 1024 42 | 43 | # extract module dependencies 44 | deps = [ 45 | '/mod/lib/crc16.ko', 46 | '/mod/fs/mbcache.ko', 47 | ] 48 | main = [ 49 | '/mod/fs/jbd2/jbd2.ko', 50 | '/mod/fs/ext4/ext4.ko', 51 | ] 52 | names = [ 53 | 'ext4', 54 | 'jbd2', 55 | ] 56 | 57 | return self._pack_mount_info(opts, main, deps, names) 58 | -------------------------------------------------------------------------------- /script/fs_xfs.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | import os 4 | 5 | from fs import FSConfig, FSWorker 6 | from pkg_xfsprogs import Package_XFSPROGS 7 | 8 | from util import execute, envldpaths 9 | 10 | 11 | class FSConfig_XFS(FSConfig): 12 | 13 | def __init__(self, tag: str, size: int) -> None: 14 | super(FSConfig_XFS, self).__init__(tag, size) 15 | 16 | 17 | FS_CONFIGS_XFS = { 18 | '000': FSConfig_XFS( 19 | '000', 64 20 | ) 21 | } 22 | 23 | 24 | class FSWorker_XFS(FSWorker): 25 | 26 | def __init__(self, conf: FSConfig_XFS) -> None: 27 | super(FSWorker_XFS, self).__init__('xfs', conf) 28 | 29 | def mkfs(self, path: str) -> None: 30 | progs = Package_XFSPROGS() 31 | 32 | with envldpaths(os.path.join(progs.path_store, 'lib')): 33 | execute([ 34 | os.path.join(progs.path_store, 'sbin', 'mkfs.xfs'), 35 | path, 36 | ]) 37 | 38 | def _get_mount_opts(self) -> str: 39 | return '' 40 | 41 | def pack_mount(self) -> bytes: 42 | opts = self._get_mount_opts() 43 | assert len(opts) + 1 < 1024 44 | 45 | # extract module dependencies 46 | deps = [] # type: List[str] 47 | main = [ 48 | '/mod/fs/xfs/xfs.ko', 49 | ] 50 | names = [ 51 | 'xfs', 52 | ] 53 | 54 | return self._pack_mount_info(opts, main, deps, names) 55 | -------------------------------------------------------------------------------- /script/fuzz.mk: -------------------------------------------------------------------------------- 1 | define racer_fuzz 2 | $(eval goal := $(patsubst fuzz-%,%,$1)) 3 | $(eval args := $(subst -, ,$(goal))) 4 | $(eval opts := $(if $(findstring $1,$(MAKECMDGOALS)),$(EXTRA),)) 5 | $(eval vals := $(if $(findstring $1,$(MAKECMDGOALS)),$(VALUE),)) 6 | python3 script/fuzz.py $(opts) $(args) $(vals) 7 | endef 8 | 9 | .PHONY: fuzz-help 10 | fuzz-help: 11 | @echo "fuzz-: launch" 12 | @echo "fuzz-: probe" 13 | @echo "fuzz-: validate" 14 | 15 | .PHONY: fuzz-launch 16 | fuzz-launch: build-qemu build-linux build-initramfs spec-compose 17 | $(call racer_fuzz,$@) 18 | 19 | .PHONY: fuzz-probe 20 | fuzz-probe: build-qemu build-linux build-initramfs spec-compose 21 | $(call racer_fuzz,$@) 22 | 23 | .PHONY: fuzz-validate 24 | fuzz-validate: build-qemu build-linux build-initramfs spec-compose 25 | $(call racer_fuzz,$@) -------------------------------------------------------------------------------- /script/fuzz.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | import sys 4 | import logging 5 | 6 | from argparse import ArgumentParser 7 | 8 | from fs import FSWorker 9 | from fs_ext4 import FS_CONFIGS_EXT4, FSWorker_EXT4 10 | from fs_btrfs import FS_CONFIGS_BTRFS, FSWorker_BTRFS 11 | from fs_xfs import FS_CONFIGS_XFS, FSWorker_XFS 12 | from fuzz_check import ValidatorMaster 13 | from fuzz_probe import ProbeMaster 14 | from fuzz_engine import FuzzMaster, FuzzBase, Seed 15 | 16 | from util import enable_coloring_in_logging 17 | 18 | import config 19 | 20 | 21 | def main(argv: List[str]) -> int: 22 | # setup argument parser 23 | parser = ArgumentParser() 24 | 25 | # logging configs 26 | parser.add_argument( 27 | '-v', '--verbose', action='count', default=1, 28 | help='Verbosity level, can be specified multiple times, default to 1', 29 | ) 30 | 31 | # override flag 32 | parser.add_argument( 33 | '-c', '--clean', action='store_true', 34 | help='Clean existing files', 35 | ) 36 | 37 | # tag selection 38 | parser.add_argument( 39 | '-t', '--tag', default='000', 40 | help='Tag of the filesystem configuration (default to 000)', 41 | ) 42 | 43 | # img selection 44 | parser.add_argument( 45 | '-i', '--img', default='empty', 46 | help='Filesystem image (default to empty)', 47 | ) 48 | 49 | # actions 50 | subs = parser.add_subparsers(dest='cmd') 51 | 52 | # launch 53 | sub_launch = subs.add_parser( 54 | 'launch', 55 | help='Launch fuzzer', 56 | ) 57 | 58 | # launch: overall setting 59 | sub_launch.add_argument( 60 | '-p', '--nproc', type=int, default=None, 61 | help='Number of procs for fuzzing' 62 | ) 63 | sub_launch.add_argument( 64 | '-s', '--nstep', type=int, default=None, 65 | help='Number of steps for fuzzing' 66 | ) 67 | 68 | # launch: action selection 69 | sub_launch.add_argument( 70 | '-t', '--trial', default=None, 71 | help='Trial run on one seed instead of start fuzzing' 72 | ) 73 | 74 | # probe 75 | sub_probe = subs.add_parser( 76 | 'probe', 77 | help='Probe seeds' 78 | ) 79 | 80 | # probe: overall setting 81 | sub_probe.add_argument( 82 | '-p', '--nproc', type=int, default=None, 83 | help='Number of procs for fuzzing' 84 | ) 85 | sub_probe.add_argument( 86 | '-s', '--nstep', type=int, default=None, 87 | help='Number of steps for fuzzing' 88 | ) 89 | 90 | # validate 91 | sub_validate = subs.add_parser( 92 | 'validate', 93 | help='Validate seeds' 94 | ) 95 | 96 | # validate: baseline selection 97 | sub_validate.add_argument( 98 | '-f', '--flavor', default=config.OPTION().flavor, 99 | help='Flavor of the fuzzing session', 100 | ) 101 | sub_validate.add_argument( 102 | '-i', '--intent', default='dart-dev', 103 | help='Intent of the fuzzing session', 104 | ) 105 | sub_validate.add_argument( 106 | '-a', '--action', default='fuzz-launch', 107 | help='Action of the fuzzing session', 108 | ) 109 | 110 | # validate: overall setting 111 | sub_validate.add_argument( 112 | '-p', '--nproc', type=int, default=None, 113 | help='Number of procs for fuzzing' 114 | ) 115 | sub_validate.add_argument( 116 | '-s', '--nstep', type=int, default=None, 117 | help='Number of steps for validation' 118 | ) 119 | 120 | # validate: action selection 121 | sub_validate.add_argument( 122 | '-r', '--recency', action='store_true', 123 | help='Process the seeds in recency order (default: discovery order)' 124 | ) 125 | 126 | # parse 127 | args = parser.parse_args(argv) 128 | 129 | # prepare logs 130 | enable_coloring_in_logging() 131 | logging.basicConfig( 132 | format='%(asctime)s %(levelname)s %(message)s', 133 | level=logging.WARNING - (logging.DEBUG - logging.NOTSET) * args.verbose 134 | ) 135 | 136 | # prepare options 137 | cmd = args.cmd 138 | config.OPTION().action = '-'.join(['fuzz', cmd]) 139 | 140 | # construct the filesystem instance 141 | fswork = None # type: Optional[FSWorker] 142 | 143 | fsname = config.OPTION().flavor 144 | if fsname == 'ext4': 145 | fswork = FSWorker_EXT4(FS_CONFIGS_EXT4[args.tag]) 146 | 147 | elif fsname == 'btrfs': 148 | fswork = FSWorker_BTRFS(FS_CONFIGS_BTRFS[args.tag]) 149 | 150 | elif fsname == 'xfs': 151 | fswork = FSWorker_XFS(FS_CONFIGS_XFS[args.tag]) 152 | 153 | else: 154 | logging.error('Invalid filesystem: {}'.format(fsname)) 155 | parser.print_help() 156 | return -1 157 | 158 | # choose action 159 | if cmd == 'launch': 160 | if args.trial is not None: 161 | # trial run, only invoke the worker 162 | toks = args.trial.split(':') 163 | worker = FuzzBase(fswork, args.img) 164 | worker.run_once(0, Seed(toks[0], toks[1], int(toks[2])), args.clean) 165 | 166 | else: 167 | # actual run, invoke the master 168 | fuzzer = FuzzMaster(fswork, args.img, args.clean) 169 | fuzzer.launch(args.nproc, args.nstep) 170 | 171 | elif cmd == 'probe': 172 | prober = ProbeMaster(fswork, args.img, args.clean) 173 | prober.launch(args.nproc, args.nstep) 174 | 175 | elif cmd == 'validate': 176 | config.OPTION().tag = '-'.join([args.flavor, args.intent, args.action]) 177 | validator = ValidatorMaster() 178 | validator.launch(args.nproc, args.nstep, args.recency) 179 | 180 | else: 181 | parser.print_help() 182 | return -1 183 | 184 | return 0 185 | 186 | 187 | if __name__ == '__main__': 188 | sys.exit(main(sys.argv[1:])) 189 | -------------------------------------------------------------------------------- /script/fuzz_check.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import os 4 | import sys 5 | import logging 6 | import traceback 7 | 8 | from queue import Empty 9 | from dataclasses import dataclass 10 | from multiprocessing import Event, Queue, Process 11 | 12 | from fuzz_stat import iter_seed_exec_inc, iter_seed_exec_dec 13 | from dart_viz import VizRuntime 14 | 15 | from util import disable_interrupt 16 | 17 | import config 18 | 19 | 20 | @dataclass 21 | class ValidatorSync(object): 22 | event_interrupted: Event # type: ignore 23 | queue_seed: Queue 24 | queue_retv: Queue 25 | 26 | 27 | class ValidatorWorker(object): 28 | 29 | def __init__(self, iseq: int, sync: ValidatorSync) -> None: 30 | self.iseq = iseq 31 | self.sync = sync 32 | 33 | def _analyze(self, base: str) -> Optional[int]: 34 | runtime = VizRuntime() 35 | console = os.path.join(base, 'console') 36 | failure = False 37 | 38 | try: 39 | runtime.process(os.path.join(base, 'ledger')) 40 | except Exception as ex: 41 | failure = True 42 | with open(os.path.join(console + '-error'), 'w') as t: 43 | t.write(str(ex)) 44 | t.write('\n-------- EXCEPTION --------\n') 45 | traceback.print_tb(sys.exc_info()[2], file=t) 46 | 47 | # save the console output 48 | if failure: 49 | with open(console, 'w') as t: 50 | t.write('\n'.join(runtime.records)) 51 | return None 52 | 53 | # save the races 54 | runtime.dump_races(console + '-racer') 55 | 56 | # return the runtime states 57 | return len(runtime.races) 58 | 59 | def run(self) -> None: 60 | while not self.sync.event_interrupted.is_set(): # type: ignore 61 | # try to get seed 62 | try: 63 | path = self.sync.queue_seed.get(timeout=1) 64 | except Empty: 65 | continue 66 | 67 | # log start of validation 68 | sketch, digest, bucket, seqnum = path.split('/')[-4:] 69 | logging.info('[{}] processing {}-{}-{}-{}'.format( 70 | self.iseq, sketch, digest, bucket, seqnum 71 | )) 72 | 73 | # analyze the seed 74 | result = self._analyze(path) 75 | if result is None: 76 | logging.error('[{}] failed'.format(self.iseq)) 77 | elif result != 0: 78 | logging.warning('[{}] race found: {}'.format(self.iseq, result)) 79 | 80 | self.sync.queue_retv.put(result) 81 | 82 | 83 | class ValidatorMaster(object): 84 | 85 | def __init__(self) -> None: 86 | self.sync = ValidatorSync( 87 | event_interrupted=Event(), 88 | queue_seed=Queue(), 89 | queue_retv=Queue(), 90 | ) 91 | 92 | def launch( 93 | self, 94 | nproc: Optional[int] = None, 95 | nstep: Optional[int] = None, 96 | recency: bool = False, 97 | ) -> None: 98 | # set params properly 99 | if nproc is None: 100 | nproc = min(4, config.NCPU // 8) if nstep is None else 1 101 | 102 | # select iterator 103 | seed_iterator = iter_seed_exec_dec if recency else iter_seed_exec_inc 104 | 105 | # prepare the seed queue 106 | count = 0 107 | 108 | # iterate programs in sequence 109 | for pack in seed_iterator(): 110 | base = pack.path 111 | 112 | # check if we have validated this execution 113 | path_error = os.path.join(base, 'console-error') 114 | path_racer = os.path.join(base, 'console-racer') 115 | if os.path.exists(path_error) or os.path.exists(path_racer): 116 | continue 117 | 118 | # send the seed to the queue 119 | self.sync.queue_seed.put(base) 120 | count += 1 121 | 122 | # early exit if we only need to execute a few things 123 | if nstep is not None and count == nstep: 124 | break 125 | 126 | # build the validation processes 127 | processes = [ 128 | Process( 129 | target=validation_process, 130 | args=(i, self.sync) 131 | ) 132 | for i in range(nproc) 133 | ] 134 | 135 | # start the fuzzing processes 136 | for p in processes: 137 | p.start() 138 | 139 | # wait for the results 140 | interrupted = False 141 | 142 | try: 143 | num_retv = 0 144 | while num_retv != count: 145 | self.sync.queue_retv.get() 146 | num_retv += 1 147 | 148 | except KeyboardInterrupt: 149 | logging.warning('Interrupted') 150 | interrupted = True 151 | 152 | # exit procedure 153 | self.sync.event_interrupted.set() # type: ignore 154 | for i, p in enumerate(processes): 155 | if not p.is_alive(): 156 | continue 157 | 158 | if not interrupted: 159 | p.join(10) 160 | if not p.is_alive(): 161 | continue 162 | 163 | logging.warning('killing instance {}'.format(i)) 164 | p.kill() 165 | 166 | 167 | def validation_process(iseq: int, sync: ValidatorSync) -> None: 168 | worker = ValidatorWorker(iseq, sync) 169 | with disable_interrupt(): 170 | worker.run() 171 | -------------------------------------------------------------------------------- /script/fuzz_primitive.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from typing import List, Dict, Tuple 4 | 5 | import os 6 | import sys 7 | import json 8 | import pickle 9 | import logging 10 | 11 | from argparse import ArgumentParser 12 | 13 | from fuzz_exec import Seed 14 | from fuzz_stat import iter_seed_exec_inc 15 | from spec_basis import Syscall, Program 16 | 17 | from util import enable_coloring_in_logging 18 | 19 | 20 | def collect_syscall_primitives_from_probe() -> None: 21 | progs = {} # type: Dict[str, Program] 22 | seed_succ = {} # type: Dict[Tuple[Seed, int, int], Syscall] 23 | seed_fail = {} # type: Dict[int, Dict[Tuple[Seed, int, int], Syscall]] 24 | 25 | for pack in iter_seed_exec_inc(): 26 | base = os.path.dirname(pack.path) 27 | if base not in progs: 28 | with open(os.path.join(base, 'program'), 'rb') as f: 29 | progs[base] = pickle.load(f) 30 | 31 | prog = progs[base] 32 | with open(os.path.join(pack.path, 'outcome')) as t: 33 | retv = json.load(t)['subs'] 34 | 35 | assert len(prog.thread_subs) == len(retv) 36 | i_sub = 0 37 | for p_sub, r_sub in zip(prog.thread_subs, retv): 38 | assert len(p_sub) == len(r_sub) 39 | i_sys = 0 40 | for s, r in zip(p_sub, r_sub): 41 | key = (pack.seed, i_sub, i_sys) 42 | 43 | # failed executions 44 | if -4096 < r < 0: 45 | if r not in seed_fail: 46 | seed_fail[r] = {} 47 | 48 | if key in seed_fail[r]: 49 | continue 50 | seed_fail[r][key] = s 51 | 52 | # succeed executions 53 | else: 54 | if key in seed_succ: 55 | continue 56 | seed_succ[key] = s 57 | 58 | # show the progress 59 | logging.info('{} = {}'.format(s.show(), r)) 60 | i_sys += 1 61 | i_sub += 1 62 | 63 | 64 | def main(argv: List[str]) -> int: 65 | # prepare parser 66 | parser = ArgumentParser() 67 | 68 | # logging configs 69 | parser.add_argument( 70 | '-v', '--verbose', action='count', default=1, 71 | help='Verbosity level, can be specified multiple times, default to 1', 72 | ) 73 | 74 | # commands 75 | subs = parser.add_subparsers(dest='cmd') 76 | 77 | # parse 78 | sub_show = subs.add_parser('parse') 79 | sub_show.add_argument('type', choices={'p'}) 80 | 81 | # handle args 82 | args = parser.parse_args(argv) 83 | 84 | # prepare logs 85 | enable_coloring_in_logging() 86 | logging.basicConfig( 87 | format='%(asctime)s %(levelname)s %(message)s', 88 | level=logging.WARNING - (logging.DEBUG - logging.NOTSET) * args.verbose 89 | ) 90 | 91 | # run action 92 | if args.cmd == 'parse': 93 | if args.type == 'p': 94 | collect_syscall_primitives_from_probe() 95 | 96 | else: 97 | parser.print_help() 98 | return -1 99 | 100 | return 0 101 | 102 | 103 | if __name__ == '__main__': 104 | sys.exit(main(sys.argv[1:])) 105 | -------------------------------------------------------------------------------- /script/lint.ini: -------------------------------------------------------------------------------- 1 | [flake8] 2 | select = B,C,E,F,P,T4,W,B9 3 | max-line-length = 80 4 | ignore = W504 5 | max-complexity = 128 6 | 7 | [mypy] 8 | incremental = False 9 | strict_optional = True 10 | no_implicit_optional = True 11 | disallow_untyped_defs = True 12 | disallow_untyped_calls = True 13 | disallow_untyped_decorators = True 14 | disallow_incomplete_defs = True 15 | check_untyped_defs = True 16 | disallow_any_unimported = True 17 | disallow_subclassing_any = True 18 | ignore_missing_imports = False 19 | warn_no_return = True 20 | warn_return_any = True 21 | warn_unused_ignores = True 22 | warn_redundant_casts = True 23 | -------------------------------------------------------------------------------- /script/pkg.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | 4 | from abc import ABC, abstractmethod 5 | 6 | from util import cd, execute0, prepdn, prepfn 7 | 8 | import config 9 | 10 | 11 | class Mark(object): 12 | 13 | def __init__(self, name: str, item: str, hval: str) -> None: 14 | self.path = os.path.join( 15 | config.STUDIO_MARKS, '{}-{}'.format(name, item) 16 | ) 17 | self.hval = hval 18 | 19 | def exist(self) -> bool: 20 | if not os.path.exists(self.path): 21 | return False 22 | 23 | with open(self.path) as f: 24 | if f.read().strip() != self.hval: 25 | return False 26 | 27 | return True 28 | 29 | def touch(self) -> None: 30 | prepfn(self.path) 31 | with open(self.path, 'w') as f: 32 | f.write(self.hval) 33 | 34 | 35 | class Package(ABC): 36 | 37 | def __init__(self, repo: str, name: str, path: str) -> None: 38 | # basics 39 | self.repo = repo 40 | self.name = name 41 | 42 | # paths 43 | self.path_src = path 44 | self.path_build = os.path.join(config.STUDIO_BUILD, self.name) 45 | self.path_store = os.path.join(config.STUDIO_STORE, self.name) 46 | 47 | # status 48 | with cd(config.PROJ_PATH): 49 | outs, _ = execute0(['git', 'ls-tree', 'HEAD', self.path_src]) 50 | self.hash = outs.strip().split()[2] 51 | 52 | @abstractmethod 53 | def _setup_impl(self, override: bool) -> None: 54 | raise RuntimeError('Method not implemented') 55 | 56 | def setup(self, override: bool = False) -> None: 57 | mark = Mark(self.name, 'setup', self.hash) 58 | 59 | if mark.exist() and not override: 60 | logging.info('Mark {} existed, do nothing'.format(mark.path)) 61 | return 62 | 63 | prepdn(self.path_build, True) 64 | prepdn(self.path_store, True) 65 | self._setup_impl(override) 66 | 67 | logging.info('[Done] Setup') 68 | mark.touch() 69 | 70 | @abstractmethod 71 | def _build_impl(self, override: bool) -> None: 72 | raise RuntimeError('Method not implemented') 73 | 74 | def build(self, override: bool = False) -> None: 75 | mark = Mark(self.name, 'build', self.hash) 76 | 77 | if mark.exist() and not override: 78 | logging.info('Mark {} existed, do nothing'.format(mark.path)) 79 | return 80 | 81 | prepdn(self.path_build, False) 82 | prepdn(self.path_store, False) 83 | self._build_impl(override) 84 | 85 | logging.info('[Done] Build') 86 | mark.touch() 87 | 88 | @abstractmethod 89 | def _store_impl(self, override: bool) -> None: 90 | raise RuntimeError('Method not implemented') 91 | 92 | def store(self, override: bool = False) -> None: 93 | mark = Mark(self.name, 'store', self.hash) 94 | 95 | if mark.exist() and not override: 96 | logging.info('Mark {} existed, do nothing'.format(mark.path)) 97 | return 98 | 99 | prepdn(self.path_build, False) 100 | prepdn(self.path_store, False) 101 | self._store_impl(override) 102 | 103 | logging.info('[Done] Store') 104 | mark.touch() 105 | 106 | def make(self, override: int = 0) -> None: 107 | self.setup(override > 2) 108 | self.build(override > 1) 109 | self.store(override > 0) 110 | -------------------------------------------------------------------------------- /script/pkg_binutils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pkg import Package 4 | 5 | from util import cd, execute 6 | 7 | import config 8 | 9 | 10 | class Package_BINUTILS(Package): 11 | 12 | def __init__(self) -> None: 13 | super(Package_BINUTILS, self).__init__( 14 | 'binutils', 'binutils', 15 | os.path.join(config.PROJ_PATH, 'tool', 'binutils') 16 | ) 17 | 18 | def _setup_impl(self, override: bool = False) -> None: 19 | with cd(self.path_build): 20 | execute([ 21 | os.path.join(self.path_src, 'configure'), 22 | '--prefix={}'.format(self.path_store), 23 | '--enable-ld=yes', 24 | '--disable-gdb', 25 | ]) 26 | 27 | def _build_impl(self, override: bool = False) -> None: 28 | with cd(self.path_build): 29 | execute([ 30 | 'make', '-j{}'.format(config.NCPU), 31 | ]) 32 | 33 | def _store_impl(self, override: bool = False) -> None: 34 | with cd(self.path_build): 35 | execute([ 36 | 'make', 'install', 37 | ]) 38 | -------------------------------------------------------------------------------- /script/pkg_btrfsprogs.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pkg import Package 4 | 5 | from util import cd, inplace_replace, execute 6 | 7 | import config 8 | 9 | 10 | class Package_BTRFSPROGS(Package): 11 | 12 | def __init__(self) -> None: 13 | super(Package_BTRFSPROGS, self).__init__( 14 | 'btrfs-progs', 'btrfs-progs', 15 | os.path.join(config.PROJ_PATH, 'fs', 'btrfs', 'btrfs-progs') 16 | ) 17 | 18 | def _setup_impl(self, override: bool = False) -> None: 19 | with cd(self.path_src): 20 | # TODO: disable installation of udev rules to root fs 21 | inplace_replace( 22 | os.path.join('configure.ac'), 23 | 'UDEVDIR="$(${PKG_CONFIG} udev --variable=udevdir)"', 24 | os.path.join(self.path_store, 'lib', 'udev'), 25 | ) 26 | 27 | execute([ 28 | os.path.join(self.path_src, 'autogen.sh'), 29 | ]) 30 | 31 | execute([ 32 | os.path.join(self.path_src, 'configure'), 33 | '--prefix={}'.format(self.path_store), 34 | '--disable-convert', 35 | '--disable-documentation', 36 | ]) 37 | 38 | # TODO: revert the changes 39 | inplace_replace( 40 | os.path.join('configure.ac'), 41 | os.path.join(self.path_store, 'lib', 'udev'), 42 | 'UDEVDIR="$(${PKG_CONFIG} udev --variable=udevdir)"', 43 | ) 44 | 45 | def _build_impl(self, override: bool = False) -> None: 46 | with cd(self.path_src): 47 | execute([ 48 | 'make', '-j{}'.format(config.NCPU), 49 | ]) 50 | 51 | def _store_impl(self, override: bool = False) -> None: 52 | with cd(self.path_src): 53 | execute([ 54 | 'make', 'install', 55 | ]) 56 | 57 | execute([ 58 | 'make', 'clean-all', 'clean-gen', 59 | ]) 60 | -------------------------------------------------------------------------------- /script/pkg_e2fsprogs.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pkg import Package 4 | 5 | from util import cd, execute 6 | 7 | import config 8 | 9 | 10 | class Package_E2FSPROGS(Package): 11 | 12 | def __init__(self) -> None: 13 | super(Package_E2FSPROGS, self).__init__( 14 | 'e2fsprogs', 'e2fsprogs', 15 | os.path.join(config.PROJ_PATH, 'fs', 'ext4', 'e2fsprogs') 16 | ) 17 | 18 | def _setup_impl(self, override: bool = False) -> None: 19 | with cd(self.path_build): 20 | execute([ 21 | os.path.join(self.path_src, 'configure'), 22 | '--prefix={}'.format(self.path_store), 23 | '--enable-elf-shlibs', 24 | '--enable-libuuid', 25 | '--enable-libblkid', 26 | '--with-udev-rules-dir={}'.format(os.path.join( 27 | self.path_store, 'lib', 'udev', 'rules.d' 28 | )), 29 | '--with-crond-dir={}'.format(os.path.join( 30 | self.path_store, 'etc', 'cron.d' 31 | )), 32 | '--with-systemd-unit-dir={}'.format(os.path.join( 33 | self.path_store, 'lib', 'systemd', 'system' 34 | )), 35 | ]) 36 | 37 | def _build_impl(self, override: bool = False) -> None: 38 | with cd(self.path_build): 39 | execute([ 40 | 'make', '-j{}'.format(config.NCPU), 41 | ]) 42 | 43 | def _store_impl(self, override: bool = False) -> None: 44 | with cd(self.path_build): 45 | execute([ 46 | 'make', 'install', 47 | ]) 48 | -------------------------------------------------------------------------------- /script/pkg_gcc.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pkg import Package 4 | 5 | from util import cd, execute 6 | 7 | import config 8 | 9 | 10 | class Package_GCC(Package): 11 | 12 | def __init__(self) -> None: 13 | super(Package_GCC, self).__init__( 14 | 'gcc', 'gcc', 15 | os.path.join(config.PROJ_PATH, 'tool', 'gcc') 16 | ) 17 | 18 | def _setup_impl(self, override: bool = False) -> None: 19 | with cd(self.path_src): 20 | execute([ 21 | os.path.join('.', 'contrib', 'download_prerequisites'), 22 | ]) 23 | 24 | with cd(self.path_build): 25 | execute([ 26 | os.path.join(self.path_src, 'configure'), 27 | '--prefix={}'.format(self.path_store), 28 | '--enable-languages=c,c++', 29 | '--enable-shared', 30 | '--enable-lto', 31 | '--disable-multilib', 32 | '--disable-nls', 33 | ]) 34 | 35 | def _build_impl(self, override: bool = False) -> None: 36 | with cd(self.path_build): 37 | execute([ 38 | 'make', '-j{}'.format(config.NCPU), 39 | ]) 40 | 41 | def _store_impl(self, override: bool = False) -> None: 42 | with cd(self.path_build): 43 | execute([ 44 | 'make', 'install', 45 | ]) 46 | -------------------------------------------------------------------------------- /script/pkg_initramfs.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | from pkg import Package 5 | from pkg_linux import Package_LINUX 6 | 7 | from util import cd, prepdn, execute 8 | 9 | import config 10 | 11 | 12 | class Package_INITRAMFS(Package): 13 | 14 | def __init__(self) -> None: 15 | super(Package_INITRAMFS, self).__init__( 16 | 'initramfs', 'initramfs-{}'.format(config.OPTION().shape), 17 | os.path.join(config.PROJ_PATH, 'kernel', 'initramfs') 18 | ) 19 | self.flavor = config.OPTION().flavor 20 | self.intent = config.OPTION().intent 21 | 22 | linux = Package_LINUX() 23 | self.linux_build = os.path.join(linux.path_build) 24 | self.linux_store = os.path.join(linux.path_store) 25 | 26 | def _setup_impl(self, override: bool = False) -> None: 27 | with cd(self.path_build): 28 | execute([ 29 | 'cmake', os.path.join(self.path_src), 30 | '-G', 'Unix Makefiles', 31 | '-DCMAKE_INSTALL_PREFIX={}'.format(self.path_store), 32 | '-DCMAKE_BUILD_TYPE=Release', 33 | '-DLINUX_FLAVOR={}'.format(self.flavor), 34 | '-DLINUX_INTENT={}'.format(self.intent), 35 | ]) 36 | 37 | def _build_impl(self, override: bool = False) -> None: 38 | with cd(self.path_build): 39 | execute([ 40 | 'make', '-j{}'.format(config.NCPU), 41 | ]) 42 | 43 | def _store_impl(self, override: bool = False) -> None: 44 | with cd(self.path_build): 45 | execute([ 46 | 'make', 'install', 47 | ]) 48 | 49 | # create directory layouts in initramfs 50 | path_initramfs = os.path.join(self.path_store, 'rootfs') 51 | prepdn(path_initramfs, override=True) 52 | 53 | path_initramfs_dev = os.path.join(path_initramfs, 'dev') 54 | path_initramfs_mod = os.path.join(path_initramfs, 'mod') 55 | 56 | os.makedirs(path_initramfs_dev) 57 | os.makedirs(path_initramfs_mod) 58 | 59 | # copy modules 60 | path_kernel_lib = os.path.join(self.linux_store, 'lib', 'modules') 61 | assert len(os.listdir(path_kernel_lib)) == 1 62 | kernel_version = os.listdir(path_kernel_lib)[0] 63 | 64 | path_mod = os.path.join(path_kernel_lib, kernel_version, 'kernel') 65 | for item in os.listdir(path_mod): 66 | shutil.copytree( 67 | os.path.join(path_mod, item), 68 | os.path.join(path_initramfs_mod, item) 69 | ) 70 | 71 | # copy init 72 | shutil.copy2( 73 | os.path.join(self.path_store, 'bin', 'init'), 74 | os.path.join(path_initramfs, 'init') 75 | ) 76 | 77 | # make an image 78 | with cd(path_initramfs): 79 | os.system( 80 | 'find . | cpio -o --quiet -R 0:0 -H newc | gzip > ../initrd.img' 81 | ) 82 | -------------------------------------------------------------------------------- /script/pkg_llvm.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pkg import Package 4 | 5 | from util import cd, execute 6 | 7 | import config 8 | 9 | 10 | class Package_LLVM(Package): 11 | 12 | def __init__(self) -> None: 13 | super(Package_LLVM, self).__init__( 14 | 'llvm', 'llvm', 15 | os.path.join(config.PROJ_PATH, 'tool', 'llvm') 16 | ) 17 | 18 | def _setup_impl(self, override: bool = False) -> None: 19 | with cd(self.path_build): 20 | execute([ 21 | 'cmake', os.path.join(self.path_src, 'llvm'), 22 | '-G', 'Unix Makefiles', 23 | '-DLLVM_ENABLE_PROJECTS={}'.format(';'.join([ 24 | 'clang', 25 | 'clang-tools-extra', 26 | 'compiler-rt', 27 | 'lld', 28 | 'polly', 29 | ])), 30 | '-DCMAKE_INSTALL_PREFIX={}'.format(self.path_store), 31 | '-DCMAKE_BUILD_TYPE=Release', 32 | '-DBUILD_SHARED_LIBS=On', 33 | '-DLLVM_ENABLE_RTTI=On', 34 | '-DLLVM_ENABLE_EH=On', 35 | '-DLLVM_ENABLE_THREADS=On', 36 | '-DLLVM_ENABLE_CXX1Y=On', 37 | ]) 38 | 39 | def _build_impl(self, override: bool = False) -> None: 40 | with cd(self.path_build): 41 | execute([ 42 | 'make', '-j{}'.format(config.NCPU), 43 | ]) 44 | 45 | def _store_impl(self, override: bool = False) -> None: 46 | with cd(self.path_build): 47 | execute([ 48 | 'make', 'install', 49 | ]) 50 | -------------------------------------------------------------------------------- /script/pkg_musl.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pkg import Package 4 | 5 | from util import cd, execute 6 | 7 | import config 8 | 9 | 10 | class Package_MUSL(Package): 11 | 12 | def __init__(self) -> None: 13 | super(Package_MUSL, self).__init__( 14 | 'musl', 'musl', 15 | os.path.join(config.PROJ_PATH, 'tool', 'musl') 16 | ) 17 | 18 | def _setup_impl(self, override: bool = False) -> None: 19 | with cd(self.path_build): 20 | execute([ 21 | os.path.join(self.path_src, 'configure'), 22 | '--prefix={}'.format(self.path_store), 23 | '--exec-prefix={}'.format(self.path_store), 24 | '--syslibdir={}'.format(self.path_store), 25 | ]) 26 | 27 | def _build_impl(self, override: bool = False) -> None: 28 | with cd(self.path_build): 29 | execute([ 30 | 'make', '-j{}'.format(config.NCPU), 31 | ]) 32 | 33 | def _store_impl(self, override: bool = False) -> None: 34 | with cd(self.path_build): 35 | execute([ 36 | 'make', 'install', 37 | ]) 38 | -------------------------------------------------------------------------------- /script/pkg_qemu.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pkg import Package 4 | 5 | from util import cd, execute 6 | 7 | import config 8 | 9 | 10 | class Package_QEMU(Package): 11 | 12 | def __init__(self) -> None: 13 | super(Package_QEMU, self).__init__( 14 | 'qemu', 'qemu', 15 | os.path.join(config.PROJ_PATH, 'tool', 'qemu') 16 | ) 17 | 18 | def _setup_impl(self, override: bool = False) -> None: 19 | with cd(self.path_build): 20 | execute([ 21 | os.path.join(self.path_src, 'configure'), 22 | '--prefix={}'.format(self.path_store), 23 | '--enable-kvm', 24 | '--enable-virtfs', 25 | '--target-list=x86_64-softmmu', 26 | ]) 27 | 28 | def _build_impl(self, override: bool = False) -> None: 29 | with cd(self.path_build): 30 | execute([ 31 | 'make', '-j{}'.format(config.NCPU), 32 | ]) 33 | 34 | def _store_impl(self, override: bool = False) -> None: 35 | with cd(self.path_build): 36 | execute([ 37 | 'make', 'install', 38 | ]) 39 | -------------------------------------------------------------------------------- /script/pkg_racer.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pkg import Package 4 | 5 | from util import cd, execute 6 | 7 | import config 8 | 9 | 10 | class Package_Racer(Package): 11 | 12 | def __init__(self) -> None: 13 | super(Package_Racer, self).__init__( 14 | 'racer', 'racer', 15 | os.path.join(config.PROJ_PATH, 'pass') 16 | ) 17 | 18 | def _setup_impl(self, override: bool = False) -> None: 19 | with cd(self.path_build): 20 | execute([ 21 | 'cmake', os.path.join(self.path_src), 22 | '-G', 'Unix Makefiles', 23 | '-DCMAKE_INSTALL_PREFIX={}'.format(self.path_store), 24 | '-DCMAKE_BUILD_TYPE=Release', 25 | self.path_src, 26 | ]) 27 | 28 | def _build_impl(self, override: bool = False) -> None: 29 | with cd(self.path_build): 30 | execute([ 31 | 'make', '-j{}'.format(config.NCPU), 32 | ]) 33 | 34 | def _store_impl(self, override: bool = False) -> None: 35 | with cd(self.path_build): 36 | execute([ 37 | 'make', 'install', 38 | ]) 39 | -------------------------------------------------------------------------------- /script/pkg_xfsprogs.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pkg import Package 4 | 5 | from util import cd, execute 6 | 7 | import config 8 | 9 | 10 | class Package_XFSPROGS(Package): 11 | 12 | def __init__(self) -> None: 13 | super(Package_XFSPROGS, self).__init__( 14 | 'xfsprogs', 'xfsprogs', 15 | os.path.join(config.PROJ_PATH, 'fs', 'xfs', 'xfsprogs') 16 | ) 17 | 18 | def _setup_impl(self, override: bool = False) -> None: 19 | with cd(self.path_src): 20 | execute([ 21 | 'make', 'configure', 22 | ]) 23 | 24 | execute([ 25 | os.path.join(self.path_src, 'configure'), 26 | '--prefix={}'.format(self.path_store), 27 | '--with-crond-dir={}'.format(os.path.join( 28 | self.path_store, 'etc', 'cron.d' 29 | )), 30 | '--with-systemd-unit-dir={}'.format(os.path.join( 31 | self.path_store, 'lib', 'systemd', 'system' 32 | )), 33 | ]) 34 | 35 | def _build_impl(self, override: bool = False) -> None: 36 | with cd(self.path_src): 37 | execute([ 38 | 'make', '-j{}'.format(config.NCPU), 39 | ]) 40 | 41 | def _store_impl(self, override: bool = False) -> None: 42 | with cd(self.path_src): 43 | execute([ 44 | 'make', 'install', 45 | ]) 46 | 47 | execute([ 48 | 'make', 'install-dev', 49 | ]) 50 | 51 | execute([ 52 | 'make', 'clean', 53 | ]) 54 | -------------------------------------------------------------------------------- /script/racer_query_compile_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from typing import List, Set 4 | 5 | import sys 6 | 7 | from argparse import ArgumentParser 8 | 9 | from pkg_linux import Package_LINUX 10 | 11 | from racer_parse_compile_data import \ 12 | iter_compile_logs_by_module, \ 13 | iter_compile_logs_by_func, \ 14 | iter_compile_logs_by_block, \ 15 | iter_compile_logs_by_inst 16 | 17 | 18 | def find_instruction(path: str, goal: str) -> None: 19 | hval = int(goal) 20 | 21 | for block in iter_compile_logs_by_block(path): 22 | if hval in block.insts: 23 | func = block.get_parent() 24 | print('Instruction: ' + block.insts[hval].text) 25 | print('Function: ' + func.name) 26 | print('--------') 27 | func.show_cfg({hval}) 28 | return 29 | 30 | print('Instruction not found') 31 | 32 | 33 | def find_block(path: str, goal: str) -> None: 34 | hval = int(goal) 35 | 36 | for func in iter_compile_logs_by_func(path): 37 | if hval in func.blocks: 38 | print('Function: ' + func.name) 39 | print('--------') 40 | func.show_cfg(set(func.blocks[hval].insts.keys())) 41 | return 42 | 43 | print('Block not found') 44 | 45 | 46 | def find_string(path: str, goal: str) -> None: 47 | for inst in iter_compile_logs_by_inst(path): 48 | if goal in inst.text: 49 | func = inst.get_parent().get_parent() 50 | print('Instruction: ' + inst.text) 51 | print('Function: ' + func.name) 52 | print('--------') 53 | func.show_cfg({inst.hval}) 54 | return 55 | 56 | print('String not found') 57 | 58 | 59 | def find_location(path: str, goal: str) -> None: 60 | for inst in iter_compile_logs_by_inst(path): 61 | if goal in inst.get_locs(): 62 | func = inst.get_parent().get_parent() 63 | print('Instruction: ' + inst.text) 64 | print('Function: ' + func.name) 65 | print('--------') 66 | func.show_cfg({inst.hval}) 67 | return 68 | 69 | print('String not found') 70 | 71 | 72 | def find_function(path: str, goal: str) -> None: 73 | try: 74 | hval = int(goal) 75 | except ValueError: 76 | hval = 0 77 | 78 | for module in iter_compile_logs_by_module(path): 79 | if hval in module.funcsByHval: 80 | module.funcsByHval[hval].show_cfg() 81 | return 82 | 83 | if goal in module.funcsByName: 84 | module.funcsByName[goal].show_cfg() 85 | return 86 | 87 | print('Function not found') 88 | 89 | 90 | def list_module(path: str) -> None: 91 | mods = set() # type: Set[str] 92 | 93 | for module in iter_compile_logs_by_module(path): 94 | mods.add(module.name) 95 | 96 | for i in sorted(mods): 97 | print(i) 98 | 99 | 100 | def list_function(path: str) -> None: 101 | funcs = set() # type: Set[str] 102 | 103 | for module in iter_compile_logs_by_module(path): 104 | funcs.update(module.funcsByName.keys()) 105 | 106 | for i in sorted(funcs): 107 | print(i) 108 | 109 | 110 | def list_location(path: str) -> None: 111 | locs = set() # type: Set[str] 112 | 113 | for inst in iter_compile_logs_by_inst(path): 114 | locs.update(inst.info) 115 | 116 | for i in sorted(locs): 117 | print(i) 118 | 119 | 120 | def list_api(path: str) -> None: 121 | apis = set() # type: Set[str] 122 | funcs = set() # type: Set[str] 123 | 124 | for module in iter_compile_logs_by_module(path): 125 | apis.update(module.apis) 126 | funcs.update(module.funcsByName.keys()) 127 | 128 | apis.difference_update(funcs) 129 | 130 | for i in sorted(apis): 131 | print(i) 132 | 133 | 134 | def list_gvar(path: str) -> None: 135 | gvars = set() # type: Set[str] 136 | 137 | for module in iter_compile_logs_by_module(path): 138 | gvars.update(module.gvar) 139 | 140 | for i in sorted(gvars): 141 | print(i) 142 | 143 | 144 | def list_type(path: str) -> None: 145 | types = set() # type: Set[str] 146 | 147 | for module in iter_compile_logs_by_module(path): 148 | types.update(module.structs) 149 | 150 | for i in sorted(types): 151 | print(i) 152 | 153 | 154 | def main(argv: List[str]) -> int: 155 | # prepare parser 156 | parser = ArgumentParser() 157 | 158 | subs = parser.add_subparsers(dest='cmd') 159 | 160 | # find 161 | sub_find = subs.add_parser('find') 162 | sub_find.add_argument('type', choices={'i', 's', 'l', 'b', 'f'}) 163 | sub_find.add_argument('item') 164 | 165 | # list 166 | sub_list = subs.add_parser('list') 167 | sub_list.add_argument('type', choices={'m', 'f', 'l', 'a', 'g', 't'}) 168 | 169 | # handle args 170 | args = parser.parse_args(argv) 171 | path = Package_LINUX().path_build 172 | 173 | # run action 174 | if args.cmd == 'find': 175 | if args.type == 'i': 176 | find_instruction(path, args.item) 177 | elif args.type == 's': 178 | find_string(path, args.item) 179 | elif args.type == 'l': 180 | find_location(path, args.item) 181 | elif args.type == 'b': 182 | find_block(path, args.item) 183 | elif args.type == 'f': 184 | find_function(path, args.item) 185 | 186 | elif args.cmd == 'list': 187 | if args.type == 'm': 188 | list_module(path) 189 | elif args.type == 'f': 190 | list_function(path) 191 | elif args.type == 'l': 192 | list_location(path) 193 | elif args.type == 'a': 194 | list_api(path) 195 | elif args.type == 'g': 196 | list_gvar(path) 197 | elif args.type == 't': 198 | list_type(path) 199 | 200 | return 0 201 | 202 | 203 | if __name__ == '__main__': 204 | sys.exit(main(sys.argv[1:])) 205 | -------------------------------------------------------------------------------- /script/spec.mk: -------------------------------------------------------------------------------- 1 | define racer_spec 2 | $(eval goal := $(patsubst spec-%,%,$1)) 3 | $(eval args := $(subst -, ,$(goal))) 4 | $(eval opts := $(if $(findstring $1,$(MAKECMDGOALS)),$(EXTRA),)) 5 | $(eval vals := $(if $(findstring $1,$(MAKECMDGOALS)),$(VALUE),)) 6 | python3 script/spec.py $(opts) $(args) $(vals) 7 | endef 8 | 9 | .PHONY: spec-help 10 | spec-help: 11 | @echo "spec-: extract" 12 | @echo "spec-: compose" 13 | 14 | .PHONY: spec-extract 15 | spec-extract: build-linux build-musl 16 | $(call racer_spec,$@) 17 | 18 | .PHONY: spec-compose 19 | spec-compose: spec-extract 20 | $(call racer_spec,$@) -------------------------------------------------------------------------------- /script/spec.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | import sys 4 | import logging 5 | 6 | from argparse import ArgumentParser 7 | 8 | from spec_extract import Extractor 9 | from spec_factory import Spec 10 | 11 | from util import enable_coloring_in_logging 12 | 13 | 14 | def main(argv: List[str]) -> int: 15 | # setup argument parser 16 | parser = ArgumentParser() 17 | 18 | # logging configs 19 | parser.add_argument( 20 | '-v', '--verbose', action='count', default=1, 21 | help='Verbosity level, can be specified multiple times, default to 1', 22 | ) 23 | 24 | # override flag 25 | parser.add_argument( 26 | '-c', '--clean', action='store_true', 27 | help='Clean existing files', 28 | ) 29 | 30 | # action selection 31 | subs = parser.add_subparsers(dest='cmd') 32 | subs.add_parser( 33 | 'extract', 34 | help='Extract information', 35 | ) 36 | 37 | sub_compose = subs.add_parser( 38 | 'compose', 39 | help='Compose the specification', 40 | ) 41 | sub_compose.add_argument( 42 | '-s', '--show', action='store_true', 43 | help='Show the composed specification in text' 44 | ) 45 | 46 | # parse 47 | args = parser.parse_args(argv) 48 | 49 | # prepare logs 50 | enable_coloring_in_logging() 51 | logging.basicConfig( 52 | format='%(asctime)s %(levelname)s %(message)s', 53 | level=logging.WARNING - (logging.DEBUG - logging.NOTSET) * args.verbose 54 | ) 55 | 56 | # construct the instance 57 | if args.cmd == 'extract': 58 | extractor = Extractor() 59 | extractor.extract(args.clean) 60 | 61 | elif args.cmd == 'compose': 62 | composer = Spec.formulate() 63 | if args.show: 64 | for syscall in composer.Syscalls: 65 | assert syscall.base is not None 66 | print('[{}]'.format(syscall.base.name)) 67 | 68 | total_weight = sum(syscall.opts.values()) 69 | for option, weight in syscall.opts.items(): 70 | if weight == 0: 71 | continue 72 | print(' {:2.0f}%% - {}'.format( 73 | weight / total_weight * 10000, option.dump() 74 | )) 75 | 76 | else: 77 | parser.print_help() 78 | return -1 79 | 80 | return 0 81 | 82 | 83 | if __name__ == '__main__': 84 | sys.exit(main(sys.argv[1:])) 85 | -------------------------------------------------------------------------------- /script/spec_const.py: -------------------------------------------------------------------------------- 1 | # distribution 2 | SPEC_SYSCALL_GROUP_WEIGHT_TOTAL = 10000 3 | 4 | # sizes 5 | SPEC_PTR_SIZE = 8 6 | SPEC_PAGE_SIZE = 4096 7 | 8 | # path limits 9 | SPEC_LINK_MAX = 127 10 | SPEC_NAME_MAX = 255 11 | SPEC_PATH_MAX = 4096 12 | 13 | SPEC_XATTR_NAME_MAX = 255 14 | SPEC_XATTR_SIZE_MAX = 65536 15 | SPEC_XATTR_LIST_MAX = 65536 16 | 17 | SPEC_AT_FDCWD = -100 18 | SPEC_FD_LIMIT_MIN = 3 19 | SPEC_FD_LIMIT_MAX = 200 20 | 21 | # buffer limits 22 | SPEC_RAND_SIZE_MAX = int(SPEC_PAGE_SIZE * 1.5) 23 | SPEC_RAND_COUNT_MAX = 8 24 | SPEC_RAND_OFFSET_MIN = -SPEC_RAND_SIZE_MAX 25 | SPEC_RAND_OFFSET_MAX = SPEC_RAND_SIZE_MAX * 6 26 | SPEC_RAND_PATH_SEG_MAX = 16 27 | 28 | # charset and bufset 29 | SPEC_CHARSET = [chr(i) for i in range(1, 256)] 30 | SPEC_BYTESET = [chr(i).encode('charmap') for i in range(0, 256)] 31 | 32 | # integer constants 33 | SPEC_ERR_CODE_MIN = -4096 34 | SPEC_ERR_CODE_MAX = -1 35 | 36 | # programming 37 | SPEC_PROG_HEAP_OFFSET = 64 38 | 39 | # execution 40 | SPEC_EXEC_TRIAL_PER_SYSCALL = 50 41 | -------------------------------------------------------------------------------- /script/spec_lego_struct.py: -------------------------------------------------------------------------------- 1 | from typing import cast, List, Dict, Set, Optional 2 | 3 | from spec_random import SPEC_RANDOM 4 | from spec_basis import Rand, Kobj, Lego, Field, Syscall, Program, Executable 5 | from util_bean import Bean 6 | 7 | 8 | class RandStruct(Rand): 9 | pass 10 | 11 | 12 | class KobjStruct(Kobj): 13 | pass 14 | 15 | 16 | class LegoStruct(Lego[RandStruct, KobjStruct]): 17 | size: int 18 | fields: List[Field] 19 | 20 | # bean 21 | def validate(self) -> None: 22 | assert self.size != 0 23 | 24 | names = set() # type: Set[str] 25 | sizes = 0 26 | has_send = self.fields[0].lego.has_info_send() 27 | 28 | for field in self.fields: 29 | # for duplication check 30 | names.add(field.name) 31 | 32 | # for size check 33 | sizes += field.size 34 | 35 | # for flow check 36 | assert has_send == field.lego.has_info_send() 37 | 38 | assert len(names) == len(self.fields) 39 | assert self.size == sizes 40 | 41 | # debug 42 | def note(self) -> str: 43 | return ', '.join([i.dump() for i in self.fields]) 44 | 45 | # chain 46 | def link_impl(self, ctxt: Syscall) -> None: 47 | for field in self.fields: 48 | field.lego.link(self, ctxt) 49 | 50 | # memory 51 | def length(self) -> Optional[int]: 52 | return self.size 53 | 54 | # input/output 55 | def has_info_send(self) -> bool: 56 | # given all fields are sync-ed in send, pick first one 57 | return self.fields[0].lego.has_info_send() 58 | 59 | def has_info_recv(self) -> bool: 60 | # mark the struct as recv only if all fields are recv 61 | for field in self.fields: 62 | if not field.lego.has_info_recv(): 63 | return False 64 | 65 | return True 66 | 67 | # builders 68 | def _mk_rand_impl(self) -> RandStruct: 69 | return RandStruct() 70 | 71 | def _mk_kobj_impl(self) -> KobjStruct: 72 | return KobjStruct() 73 | 74 | # operations: engage 75 | def engage_rand_impl(self, prog: Program) -> None: 76 | # prep 77 | for field in self.fields: 78 | field.lego.engage(prog) 79 | 80 | def engage_kobj_impl(self, prog: Program) -> None: 81 | # prep 82 | for field in self.fields: 83 | field.lego.engage(prog) 84 | 85 | # operations: remove 86 | def remove_rand_impl(self, prog: Program) -> None: 87 | # un-prep 88 | for field in self.fields: 89 | field.lego.remove(prog) 90 | 91 | def remove_kobj_impl(self, prog: Program) -> None: 92 | # un-prep 93 | for field in self.fields: 94 | field.lego.remove(prog) 95 | 96 | # operations: mutate and puzzle 97 | def mutate_rand_impl(self, prog: Program) -> None: 98 | p = SPEC_RANDOM.random() 99 | 100 | if p < 0.8: 101 | # [TOSS] change only one field 102 | SPEC_RANDOM.choice(self.fields).lego.mutate_rand(prog) 103 | 104 | else: 105 | # [TOSS] change multiple fields at once 106 | num = SPEC_RANDOM.randint(1, len(self.fields)) 107 | for item in SPEC_RANDOM.sample(self.fields, num): 108 | item.lego.mutate_rand(prog) 109 | 110 | def puzzle_rand_impl(self, prog: Program) -> None: 111 | p = SPEC_RANDOM.random() 112 | 113 | if p < 0.8: 114 | # [DRAG] change only one field 115 | SPEC_RANDOM.choice(self.fields).lego.puzzle_rand(prog) 116 | 117 | else: 118 | # [DRAG] change multiple fields at once 119 | num = SPEC_RANDOM.randint(1, len(self.fields)) 120 | for item in SPEC_RANDOM.sample(self.fields, num): 121 | item.lego.puzzle_rand(prog) 122 | 123 | # operations: update 124 | def update_rand_impl(self, prog: Program) -> None: 125 | for field in self.fields: 126 | field.lego.update_rand(prog) 127 | 128 | # operations: migrate 129 | def migrate_impl( 130 | self, other: Lego, ctxt: Dict[Bean, Bean], hist: Set[Lego] 131 | ) -> None: 132 | lego = cast(LegoStruct, other) 133 | for f1, f2 in zip(self.fields, lego.fields): 134 | f1.lego.migrate(f2.lego, ctxt, hist) 135 | 136 | # show 137 | def expo(self) -> str: 138 | caps = 4 139 | subs = [] # type: List[str] 140 | 141 | for field in self.fields: 142 | if caps == 0: 143 | subs.append('...') 144 | break 145 | 146 | subs.append('{}={}'.format(field.name, field.lego.show())) 147 | caps -= 1 148 | 149 | return '[{}]'.format(', '.join(subs)) 150 | 151 | # blob 152 | def blob_size(self) -> int: 153 | size = 0 154 | 155 | for field in self.fields: 156 | size += field.lego.blob_size() 157 | 158 | return size 159 | 160 | def blob_hole_impl(self, inst: Executable) -> None: 161 | for field in self.fields: 162 | field.lego.blob_hole(self, inst) 163 | 164 | def blob_data(self, inst: Executable) -> bytes: 165 | data = b'' 166 | 167 | for field in self.fields: 168 | data += field.lego.blob_data(inst) 169 | 170 | return data 171 | 172 | def blob_fill_impl(self, inst: Executable) -> None: 173 | for field in self.fields: 174 | field.lego.blob_fill(inst) 175 | 176 | # relationship 177 | def rely_on(self, prog: Program) -> Set[int]: 178 | deps = set() # type: Set[int] 179 | for field in self.fields: 180 | deps.update(field.lego.rely_on(prog)) 181 | 182 | return deps 183 | -------------------------------------------------------------------------------- /script/spec_pack.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | from spec_const import SPEC_PTR_SIZE 4 | 5 | 6 | # int 7 | def _get_int_pack_format(bits: int, signed: bool) -> str: 8 | if (bits, signed) == (8, False): 9 | return 'B' 10 | if (bits, signed) == (8, True): 11 | return 'b' 12 | if (bits, signed) == (16, False): 13 | return 'H' 14 | if (bits, signed) == (16, True): 15 | return 'h' 16 | if (bits, signed) == (32, False): 17 | return 'I' 18 | if (bits, signed) == (32, True): 19 | return 'i' 20 | if (bits, signed) == (64, False): 21 | return 'Q' 22 | if (bits, signed) == (64, True): 23 | return 'q' 24 | raise RuntimeError('Invalid bits') 25 | 26 | 27 | def pack_int(val: int, bits: int, signed: bool = True) -> bytes: 28 | return struct.pack(_get_int_pack_format(bits, signed), val) 29 | 30 | 31 | # ptr 32 | def pack_ptr(val: int) -> bytes: 33 | return pack_int(val, SPEC_PTR_SIZE * 8, False) 34 | 35 | 36 | # str 37 | def pack_str(val: str) -> bytes: 38 | return struct.pack('{}s'.format(len(val) + 1), val.encode('charmap')) 39 | -------------------------------------------------------------------------------- /script/spec_random.py: -------------------------------------------------------------------------------- 1 | from random import Random 2 | 3 | SPEC_RANDOM = Random() 4 | -------------------------------------------------------------------------------- /script/spec_type_len.py: -------------------------------------------------------------------------------- 1 | from typing import cast, Dict, Set, Optional, Union 2 | 3 | from spec_random import SPEC_RANDOM 4 | from spec_basis import Rand, Kobj, KindSend, Lego, Syscall, Program, Executable 5 | from spec_pack import pack_int 6 | from spec_lego_simple import LegoSimple 7 | from spec_lego_pointer import LegoPointer 8 | from spec_lego_vector import RandVector 9 | from spec_type_str import RandStr 10 | from spec_type_buf import RandBuf 11 | from util_bean import Bean, BeanRef 12 | 13 | 14 | class RandLen(Rand): 15 | offset: Union[int, float] # offset to the actual length 16 | 17 | 18 | class KobjLen(Kobj): 19 | pass 20 | 21 | 22 | class KindSendLen(KindSend[RandLen]): 23 | bits: int 24 | ptr: BeanRef[LegoPointer] 25 | 26 | # bean 27 | def validate(self) -> None: 28 | assert self.bits in {8, 16, 32, 64} 29 | 30 | # debug 31 | def note(self) -> str: 32 | return self.ptr.bean.dump() 33 | 34 | # chain 35 | def link(self, ctxt: Syscall) -> None: 36 | # use None as the root so we do not associate that lego with anything 37 | self.ptr.bean.link(None, ctxt) 38 | 39 | # memory 40 | def length(self) -> Optional[int]: 41 | return self.bits // 8 42 | 43 | # builder 44 | def mk_rand(self) -> RandLen: 45 | return RandLen() 46 | 47 | # operations: engage and remove 48 | def engage_rand(self, rand: RandLen, prog: Program) -> None: 49 | # prep 50 | self.ptr.bean.engage(prog) 51 | self.ptr.bean.add_rdep_rand(self.lego.bean) 52 | 53 | # init 54 | rand.offset = 0 55 | 56 | def remove_rand(self, rand: RandLen, prog: Program) -> None: 57 | # un-prep 58 | self.ptr.bean.del_rdep_rand(self.lego.bean) 59 | self.ptr.bean.remove(prog) 60 | 61 | # operations: mutate and puzzle 62 | def mutate_rand(self, rand: RandLen, prog: Program) -> None: 63 | # [TOSS] change the underlying pointer 64 | self.ptr.bean.mutate_rand(prog) 65 | 66 | def puzzle_rand(self, rand: RandLen, prog: Program) -> None: 67 | p = SPEC_RANDOM.random() 68 | 69 | if p < 0.1: 70 | # [DRAG] add an offset (absolute) to the length 71 | rand.offset = SPEC_RANDOM.choice([ 72 | 1, 8, 64, 512, 4096 73 | ]) 74 | 75 | elif p < 0.2: 76 | # [DRAG] add an offset (relative) to the length 77 | rand.offset = SPEC_RANDOM.choice([ 78 | 0.1, 0.5, 0.9, 1.0, 79 | ]) 80 | 81 | else: 82 | # [DRAG] change the underlying pointer 83 | self.ptr.bean.puzzle_rand(prog) 84 | 85 | # operations: update 86 | def update_rand(self, rand: RandLen, prog: Program) -> None: 87 | assert self.ptr.bean.rand is not None 88 | 89 | # operations: migrate 90 | def migrate_rand( 91 | self, 92 | rand: RandLen, orig: RandLen, 93 | ctxt: Dict[Bean, Bean], hist: Set['Lego'] 94 | ) -> None: 95 | # first migrate the ptr 96 | self.ptr.bean.migrate( 97 | cast(KindSendLen, 98 | cast(LegoSimple, orig.lego.bean).kind_send).ptr.bean, 99 | ctxt, hist 100 | ) 101 | 102 | # then migrate the rand value 103 | rand.offset = orig.offset 104 | 105 | # utils 106 | def _measure(self, rand: RandLen) -> int: 107 | ptr = self.ptr.bean.rand 108 | assert ptr is not None 109 | 110 | # get the object size 111 | if not ptr.pick: 112 | # null pointer gets size 0 113 | return 0 114 | 115 | mem = cast(BeanRef[Lego], self.ptr.bean.memv) 116 | obj = mem.bean.rand 117 | 118 | if isinstance(obj, RandStr): 119 | size = len(obj.data) + 1 120 | elif isinstance(obj, RandBuf): 121 | size = len(obj.data) 122 | elif isinstance(obj, RandVector): 123 | size = len(obj.meta) 124 | else: 125 | raise RuntimeError('Invalid type for length measurement') 126 | 127 | # adjust for offset (only substraction allowed, stopped at 0) 128 | if isinstance(rand.offset, int): 129 | if size >= rand.offset: 130 | size -= rand.offset 131 | elif isinstance(rand.offset, float): 132 | size = int(size * (1 - rand.offset)) 133 | else: 134 | raise RuntimeError('Invalid type for length offset') 135 | 136 | return size 137 | 138 | # expo 139 | def expo_rand(self, rand: RandLen) -> str: 140 | return str(self._measure(rand)) 141 | 142 | # blob 143 | def blob_size_rand(self, rand: RandLen) -> int: 144 | return cast(int, self.length()) 145 | 146 | def blob_hole_rand(self, rand: RandLen, inst: Executable) -> None: 147 | # although KindSendLen requires a ptr lego, it does not require 148 | # that the lego to be on heap (although the lego is indeed on 149 | # heap in almost all cases) 150 | pass 151 | 152 | def blob_data_rand(self, rand: RandLen, inst: Executable) -> bytes: 153 | return pack_int(self._measure(rand), self.bits) 154 | 155 | def blob_fill_rand(self, rand: RandLen, inst: Executable) -> None: 156 | # similar to the logic in blob_hole_rand(), the ptr lego may not 157 | # necessarily be on heap, therefore, do not call fill on it 158 | pass 159 | 160 | # relationship 161 | def rely_on_rand(self, rand: RandLen, prog: Program) -> Set[int]: 162 | return set() 163 | -------------------------------------------------------------------------------- /script/work.mk: -------------------------------------------------------------------------------- 1 | define racer_work 2 | $(eval goal := $(patsubst work-%,%,$1)) 3 | $(eval args := $(subst -, ,$(goal))) 4 | $(eval opts := $(if $(findstring $1,$(MAKECMDGOALS)),$(EXTRA),)) 5 | $(eval vals := $(if $(findstring $1,$(MAKECMDGOALS)),$(VALUE),)) 6 | python3 script/work.py $(opts) $(args) $(vals) 7 | endef 8 | 9 | .PHONY: work-help 10 | work-help: 11 | @echo "work-: prep" 12 | 13 | .PHONY: work-prep 14 | work-prep: build-qemu build-linux build-initramfs 15 | $(call racer_work,$@) -------------------------------------------------------------------------------- /script/work.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | import sys 4 | import logging 5 | 6 | from argparse import ArgumentParser 7 | 8 | from fs import FSWorker 9 | from fs_ext4 import FS_CONFIGS_EXT4, FSWorker_EXT4 10 | from fs_btrfs import FS_CONFIGS_BTRFS, FSWorker_BTRFS 11 | from fs_xfs import FS_CONFIGS_XFS, FSWorker_XFS 12 | 13 | from util import enable_coloring_in_logging 14 | 15 | import config 16 | 17 | 18 | def main(argv: List[str]) -> int: 19 | # setup argument parser 20 | parser = ArgumentParser() 21 | 22 | # logging configs 23 | parser.add_argument( 24 | '-v', '--verbose', action='count', default=1, 25 | help='Verbosity level, can be specified multiple times, default to 1', 26 | ) 27 | 28 | # override flag 29 | parser.add_argument( 30 | '-c', '--clean', action='store_true', 31 | help='Clean existing files', 32 | ) 33 | 34 | # tag selection 35 | parser.add_argument( 36 | '-t', '--tag', 37 | default='000', 38 | help='Tag of the filesystem configuration (default to 000)', 39 | ) 40 | 41 | # action selection 42 | subs = parser.add_subparsers(dest='cmd') 43 | subs.add_parser( 44 | 'prep', 45 | help='Prepare samples', 46 | ) 47 | 48 | # parse 49 | args = parser.parse_args(argv) 50 | 51 | # prepare logs 52 | enable_coloring_in_logging() 53 | logging.basicConfig( 54 | format='%(asctime)s %(levelname)s %(message)s', 55 | level=logging.WARNING - (logging.DEBUG - logging.NOTSET) * args.verbose 56 | ) 57 | 58 | # prepare options 59 | cmd = args.cmd 60 | config.OPTION().action = '-'.join(['work', cmd]) 61 | 62 | # construct the instance 63 | fswork = None # type: Optional[FSWorker] 64 | 65 | fsname = config.OPTION().flavor 66 | if fsname == 'ext4': 67 | fswork = FSWorker_EXT4(FS_CONFIGS_EXT4[args.tag]) 68 | 69 | elif fsname == 'btrfs': 70 | fswork = FSWorker_BTRFS(FS_CONFIGS_BTRFS[args.tag]) 71 | 72 | elif fsname == 'xfs': 73 | fswork = FSWorker_XFS(FS_CONFIGS_XFS[args.tag]) 74 | 75 | else: 76 | parser.print_help() 77 | return -1 78 | 79 | try: 80 | if cmd == 'prep': 81 | fswork.prep(args.clean) 82 | 83 | except Exception as ex: 84 | logging.error('Unexpected error: {}'.format(ex)) 85 | return -2 86 | 87 | return 0 88 | 89 | 90 | if __name__ == '__main__': 91 | sys.exit(main(sys.argv[1:])) 92 | --------------------------------------------------------------------------------