├── .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 |
--------------------------------------------------------------------------------