/* Copyright (C) 2014 Stony Brook University This file is part of Graphene Library OS. Graphene Library OS is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Graphene Library OS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* * shim_parser.c * * This file contains codes for parsing system call arguements for debug * purpose. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void parse_open_flags(va_list); static void parse_open_mode(va_list); static void parse_access_mode(va_list); static void parse_clone_flags(va_list); static void parse_mmap_prot(va_list); static void parse_mmap_flags(va_list); static void parse_exec_args(va_list); static void parse_exec_envp(va_list); static void parse_pipe_fds(va_list); static void parse_signum(va_list); static void parse_sigmask(va_list); static void parse_sigprocmask_how(va_list); static void parse_timespec(va_list); static void parse_sockaddr(va_list); static void parse_domain(va_list); static void parse_socktype(va_list); static void parse_futexop(va_list); static void parse_ioctlop(va_list); static void parse_fcntlop(va_list); static void parse_seek(va_list); static void parse_at_fdcwd(va_list); static void parse_wait_option(va_list); struct parser_table { int slow; int stop; void (*parser[6])(va_list); } syscall_parser_table[LIBOS_SYSCALL_BOUND] = { {.slow = 1, .parser = {NULL}}, /* read */ {.slow = 1, .parser = {NULL}}, /* write */ {.slow = 1, /* open */ .parser = {NULL, &parse_open_flags, &parse_open_mode}}, {.slow = 0, .parser = {NULL}}, /* close */ {.slow = 0, .parser = {NULL}}, /* stat */ {.slow = 0, .parser = {NULL}}, /* fstat */ {.slow = 0, .parser = {NULL}}, /* lstat */ {.slow = 1, .parser = {NULL}}, /* poll */ {.slow = 0, .parser = {NULL, NULL, &parse_seek}}, /* lseek */ {.slow = 1, /* mmap */ .parser = {NULL, NULL, &parse_mmap_prot, &parse_mmap_flags}}, {.slow = 1, /* mprotect */ .parser = {NULL, NULL, &parse_mmap_prot}}, {.slow = 1, .parser = {NULL}}, /* munmap */ {.slow = 0, .parser = {NULL}}, /* brk */ {.slow = 0, .parser = {&parse_signum}}, /* rt_sigaction */ {.slow = 0, /* rt_sigprocmask */ .parser = {&parse_sigprocmask_how, &parse_sigmask, &parse_sigmask}}, {.slow = 0, .parser = {NULL}}, /* rt_sigreturn */ {.slow = 1, .parser = {NULL, &parse_ioctlop}}, /* ioctl */ {.slow = 1, .parser = {NULL}}, /* pread64 */ {.slow = 0, .parser = {NULL}}, /* pwrite64 */ {.slow = 1, .parser = {NULL}}, /* readv */ {.slow = 0, .parser = {NULL}}, /* writev */ {.slow = 0, /* access */ .parser = {NULL, &parse_access_mode}}, {.slow = 0, /* pipe */ .parser = {&parse_pipe_fds}}, {.slow = 0, .parser = {NULL}}, /* select */ {.slow = 0, .parser = {NULL}}, /* sched_yield */ {.slow = 0, .parser = {NULL}}, /* mremap */ {.slow = 0, .parser = {NULL}}, /* msync */ {.slow = 0, .parser = {NULL}}, /* mincore */ {.slow = 0, .parser = {NULL}}, /* madvise */ {.slow = 0, .parser = {NULL}}, /* shmget */ {.slow = 0, .parser = {NULL}}, /* shmat */ {.slow = 0, .parser = {NULL}}, /* shmctl */ {.slow = 0, .parser = {NULL}}, /* dup */ {.slow = 0, .parser = {NULL}}, /* dup2 */ {.slow = 1, .parser = {NULL}}, /* pause */ {.slow = 1, .parser = {&parse_timespec}}, /* nanosleep */ {.slow = 0, .parser = {NULL}}, /* getitimer */ {.slow = 0, .parser = {NULL}}, /* alarm */ {.slow = 0, .parser = {NULL}}, /* setitimer */ {.slow = 0, .parser = {NULL}}, /* getpid */ {.slow = 0, .parser = {NULL}}, /* sendfile */ {.slow = 0, .parser = {&parse_domain, &parse_socktype}}, /* socket */ {.slow = 1, .parser = {NULL, &parse_sockaddr}}, /* connect */ {.slow = 1, .parser = {NULL}}, /* accept */ {.slow = 0, .parser = {NULL}}, /* sendto */ {.slow = 0, .parser = {NULL}}, /* recvfrom */ {.slow = 0, .parser = {NULL}}, /* sendmsg */ {.slow = 1, .parser = {NULL}}, /* recvmsg */ {.slow = 0, .parser = {NULL}}, /* shutdown */ {.slow = 0, .parser = {NULL}}, /* bind */ {.slow = 0, .parser = {NULL}}, /* listen */ {.slow = 0, .parser = {NULL}}, /* getsockname */ {.slow = 0, .parser = {NULL}}, /* getpeername */ {.slow = 0, /* socketpair */ .stop = 3, .parser = {&parse_domain, &parse_socktype, NULL, &parse_pipe_fds}}, {.slow = 0, .parser = {NULL}}, /* setsockopt */ {.slow = 0, .parser = {NULL}}, /* getsockopt */ {.slow = 1, .parser = {&parse_clone_flags}}, /* clone */ {.slow = 1, .parser = {NULL}}, /* fork */ {.slow = 1, .parser = {NULL}}, /* vfork */ {.slow = 1, /* execve */ .parser = {NULL, &parse_exec_args, &parse_exec_envp}}, {.slow = 0, .parser = {NULL}}, /* exit */ {.slow = 1, .parser = {NULL, NULL, &parse_wait_option, NULL}}, /* wait4 */ {.slow = 0, /* kill */ .parser = {NULL, &parse_signum, }}, {.slow = 0, .parser = {NULL}}, /* uname */ {.slow = 0, .parser = {NULL}}, /* semget */ {.slow = 1, .parser = {NULL}}, /* semop */ {.slow = 0, .parser = {NULL}}, /* semctl */ {.slow = 0, .parser = {NULL}}, /* shmdt */ {.slow = 1, .parser = {NULL}}, /* msgget */ {.slow = 1, .parser = {NULL}}, /* msgsnd */ {.slow = 1, .parser = {NULL}}, /* msgrcv */ {.slow = 1, .parser = {NULL}}, /* msgctl */ {.slow = 0, .parser = {NULL, &parse_fcntlop}}, /* fcntl */ {.slow = 0, .parser = {NULL}}, /* flock */ {.slow = 0, .parser = {NULL}}, /* fsync */ {.slow = 0, .parser = {NULL}}, /* fdatasync */ {.slow = 0, .parser = {NULL}}, /* truncate */ {.slow = 0, .parser = {NULL}}, /* ftruncate */ {.slow = 0, .parser = {NULL}}, /* getdents */ {.slow = 0, .parser = {NULL}}, /* getcwd */ {.slow = 0, .parser = {NULL}}, /* chdir */ {.slow = 0, .parser = {NULL}}, /* fchdir */ {.slow = 0, .parser = {NULL}}, /* rename */ {.slow = 0, .parser = {NULL}}, /* mkdir */ {.slow = 0, .parser = {NULL}}, /* rmdir */ {.slow = 0, .parser = {NULL, &parse_open_mode}}, /* creat */ {.slow = 0, .parser = {NULL}}, /* link */ {.slow = 0, .parser = {NULL}}, /* unlink */ {.slow = 0, .parser = {NULL}}, /* symlink */ {.slow = 0, .parser = {NULL}}, /* readlink */ {.slow = 0, .parser = {NULL}}, /* chmod */ {.slow = 0, .parser = {NULL}}, /* fchmod */ {.slow = 0, .parser = {NULL}}, /* chown */ {.slow = 0, .parser = {NULL}}, /* fchown */ {.slow = 0, .parser = {NULL}}, /* lchown */ {.slow = 0, .parser = {NULL}}, /* umask */ {.slow = 0, .parser = {NULL}}, /* gettimeofday */ {.slow = 0, .parser = {NULL}}, /* getrlimit */ {.slow = 0, .parser = {NULL}}, /* getrusage */ {.slow = 0, .parser = {NULL}}, /* sysinfo */ {.slow = 0, .parser = {NULL}}, /* times */ {.slow = 0, .parser = {NULL}}, /* ptrace */ {.slow = 0, .parser = {NULL}}, /* getuid */ {.slow = 0, .parser = {NULL}}, /* syslog */ {.slow = 0, .parser = {NULL}}, /* getgid */ {.slow = 0, .parser = {NULL}}, /* setuid */ {.slow = 0, .parser = {NULL}}, /* setgid */ {.slow = 0, .parser = {NULL}}, /* geteuid */ {.slow = 0, .parser = {NULL}}, /* getegid */ {.slow = 0, .parser = {NULL}}, /* setpgid */ {.slow = 0, .parser = {NULL}}, /* getppid */ {.slow = 0, .parser = {NULL}}, /* getpgrp */ {.slow = 0, .parser = {NULL}}, /* setsid */ {.slow = 0, .parser = {NULL}}, /* setreuid */ {.slow = 0, .parser = {NULL}}, /* setregid */ {.slow = 0, .parser = {NULL}}, /* getgroups */ {.slow = 0, .parser = {NULL}}, /* setgroups */ {.slow = 0, .parser = {NULL}}, /* setresuid */ {.slow = 0, .parser = {NULL}}, /* getresuid */ {.slow = 0, .parser = {NULL}}, /* setresgid */ {.slow = 0, .parser = {NULL}}, /* getresgid */ {.slow = 0, .parser = {NULL}}, /* getpgid */ {.slow = 0, .parser = {NULL}}, /* setfsuid */ {.slow = 0, .parser = {NULL}}, /* setfsgid */ {.slow = 0, .parser = {NULL}}, /* getsid */ {.slow = 0, .parser = {NULL}}, /* capget */ {.slow = 0, .parser = {NULL}}, /* capset */ {.slow = 0, .parser = {NULL}}, /* rt_sigpending */ {.slow = 0, .parser = {NULL}}, /* rt_sigtimedwait */ {.slow = 0, .parser = {NULL}}, /* rt_sigqueueinfo */ {.slow = 1, .parser = {NULL}}, /* rt_sigsuspend */ {.slow = 0, .parser = {NULL}}, /* sigaltstack */ {.slow = 0, .parser = {NULL}}, /* utime */ {.slow = 0, .parser = {NULL}}, /* mknod */ {.slow = 0, .parser = {NULL}}, /* uselib */ {.slow = 0, .parser = {NULL}}, /* personality */ {.slow = 0, .parser = {NULL}}, /* ustat */ {.slow = 0, .parser = {NULL}}, /* statfs */ {.slow = 0, .parser = {NULL}}, /* fstatfs */ {.slow = 0, .parser = {NULL}}, /* sysfs */ {.slow = 0, .parser = {NULL}}, /* getpriority */ {.slow = 0, .parser = {NULL}}, /* setpriority */ {.slow = 0, .parser = {NULL}}, /* sched_setparam */ {.slow = 0, .parser = {NULL}}, /* sched_getparam */ {.slow = 0, .parser = {NULL}}, /* sched_setscheduler */ {.slow = 0, .parser = {NULL}}, /* sched_getscheduler */ {.slow = 0, .parser = {NULL}}, /* sched_get_priority_max */ {.slow = 0, .parser = {NULL}}, /* sched_get_priority_min */ {.slow = 0, .parser = {NULL}}, /* sched_rr_get_interval */ {.slow = 0, .parser = {NULL}}, /* mlock */ {.slow = 0, .parser = {NULL}}, /* munlock */ {.slow = 0, .parser = {NULL}}, /* mlockall */ {.slow = 0, .parser = {NULL}}, /* munlockall */ {.slow = 0, .parser = {NULL}}, /* vhangup */ {.slow = 0, .parser = {NULL}}, /* modify_ldt */ {.slow = 0, .parser = {NULL}}, /* pivot_root */ {.slow = 0, .parser = {NULL}}, /* _sysctl */ {.slow = 0, .parser = {NULL}}, /* prctl */ {.slow = 0, .parser = {NULL}}, /* arch_prctl */ {.slow = 0, .parser = {NULL}}, /* adjtimex */ {.slow = 0, .parser = {NULL}}, /* setrlimit */ {.slow = 0, .parser = {NULL}}, /* chroot */ {.slow = 0, .parser = {NULL}}, /* sync */ {.slow = 0, .parser = {NULL}}, /* acct */ {.slow = 0, .parser = {NULL}}, /* settimeofday */ {.slow = 0, .parser = {NULL}}, /* mount */ {.slow = 0, .parser = {NULL}}, /* umount2 */ {.slow = 0, .parser = {NULL}}, /* swapon */ {.slow = 0, .parser = {NULL}}, /* swapoff */ {.slow = 0, .parser = {NULL}}, /* reboot */ {.slow = 0, .parser = {NULL}}, /* sethostname */ {.slow = 0, .parser = {NULL}}, /* setdomainname */ {.slow = 0, .parser = {NULL}}, /* iopl */ {.slow = 0, .parser = {NULL}}, /* ioperm */ {.slow = 0, .parser = {NULL}}, /* create_module */ {.slow = 0, .parser = {NULL}}, /* init_module */ {.slow = 0, .parser = {NULL}}, /* delete_module */ {.slow = 0, .parser = {NULL}}, /* get_kernel_syms */ {.slow = 0, .parser = {NULL}}, /* query_module */ {.slow = 0, .parser = {NULL}}, /* quotactl */ {.slow = 0, .parser = {NULL}}, /* nfsservctl */ {.slow = 0, .parser = {NULL}}, /* getpmsg */ {.slow = 0, .parser = {NULL}}, /* putpmsg */ {.slow = 0, .parser = {NULL}}, /* afs_syscall */ {.slow = 0, .parser = {NULL}}, /* tuxcall */ {.slow = 0, .parser = {NULL}}, /* security */ {.slow = 0, .parser = {NULL}}, /* gettid */ {.slow = 0, .parser = {NULL}}, /* readahead */ {.slow = 0, .parser = {NULL}}, /* setxattr */ {.slow = 0, .parser = {NULL}}, /* lsetxattr */ {.slow = 0, .parser = {NULL}}, /* fsetxattr */ {.slow = 0, .parser = {NULL}}, /* getxattr */ {.slow = 0, .parser = {NULL}}, /* lgetxattr */ {.slow = 0, .parser = {NULL}}, /* fgetxattr */ {.slow = 0, .parser = {NULL}}, /* listxattr */ {.slow = 0, .parser = {NULL}}, /* llistxattr */ {.slow = 0, .parser = {NULL}}, /* flistxattr */ {.slow = 0, .parser = {NULL}}, /* removexattr */ {.slow = 0, .parser = {NULL}}, /* lremovexattr */ {.slow = 0, .parser = {NULL}}, /* fremovexattr */ {.slow = 0, .parser = {NULL, &parse_signum}}, /* tkill */ {.slow = 0, .parser = {NULL}}, /* time */ {.slow = 1, .parser = {NULL, &parse_futexop}}, /* futex */ {.slow = 0, .parser = {NULL}}, /* sched_setaffinity */ {.slow = 0, .parser = {NULL}}, /* sched_getaffinity */ {.slow = 0, .parser = {NULL}}, /* set_thread_area */ {.slow = 0, .parser = {NULL}}, /* io_setup */ {.slow = 0, .parser = {NULL}}, /* io_destroy */ {.slow = 0, .parser = {NULL}}, /* io_getevents */ {.slow = 0, .parser = {NULL}}, /* io_submit */ {.slow = 0, .parser = {NULL}}, /* io_cancel */ {.slow = 0, .parser = {NULL}}, /* get_thread_area */ {.slow = 0, .parser = {NULL}}, /* lookup_dcookie */ {.slow = 0, .parser = {NULL}}, /* epoll_create */ {.slow = 0, .parser = {NULL}}, /* epoll_ctl_old */ {.slow = 0, .parser = {NULL}}, /* epoll_wait_old */ {.slow = 0, .parser = {NULL}}, /* remap_file_pages */ {.slow = 0, .parser = {NULL}}, /* getdents64 */ {.slow = 0, .parser = {NULL}}, /* set_tid_address */ {.slow = 0, .parser = {NULL}}, /* restart_syscall */ {.slow = 0, .parser = {NULL}}, /* semtimedop */ {.slow = 0, .parser = {NULL}}, /* fadvise64 */ {.slow = 0, .parser = {NULL}}, /* timer_create */ {.slow = 0, .parser = {NULL}}, /* timer_settime */ {.slow = 0, .parser = {NULL}}, /* timer_gettime */ {.slow = 0, .parser = {NULL}}, /* timer_getoverrun */ {.slow = 0, .parser = {NULL}}, /* timer_delete */ {.slow = 0, .parser = {NULL}}, /* clock_settime */ {.slow = 0, .parser = {NULL}}, /* clock_gettime */ {.slow = 0, .parser = {NULL}}, /* clock_getres */ {.slow = 0, .parser = {NULL}}, /* clock_nanosleep */ {.slow = 0, .parser = {NULL}}, /* exit_group */ {.slow = 1, .parser = {NULL}}, /* epoll_wait */ {.slow = 0, .parser = {NULL}}, /* epoll_ctl */ {.slow = 0, .parser = {NULL, NULL, &parse_signum}}, /* tgkill */ {.slow = 0, .parser = {NULL}}, /* utimes */ {.slow = 0, .parser = {NULL}}, /* vserver */ {.slow = 0, .parser = {NULL}}, /* mbind */ {.slow = 0, .parser = {NULL}}, /* set_mempolicy */ {.slow = 0, .parser = {NULL}}, /* get_mempolicy */ {.slow = 0, .parser = {NULL}}, /* mq_open */ {.slow = 0, .parser = {NULL}}, /* mq_unlink */ {.slow = 0, .parser = {NULL}}, /* mq_timedsend */ {.slow = 0, .parser = {NULL}}, /* mq_timedreceive */ {.slow = 0, .parser = {NULL}}, /* mq_notify */ {.slow = 0, .parser = {NULL}}, /* mq_getsetattr */ {.slow = 0, .parser = {NULL}}, /* kexec_load */ {.slow = 1, .parser = {NULL}}, /* waitid */ {.slow = 0, .parser = {NULL}}, /* add_key */ {.slow = 0, .parser = {NULL}}, /* request_key */ {.slow = 0, .parser = {NULL}}, /* keyctl */ {.slow = 0, .parser = {NULL}}, /* ioprio_set */ {.slow = 0, .parser = {NULL}}, /* ioprio_get */ {.slow = 0, .parser = {NULL}}, /* inotify_init */ {.slow = 0, .parser = {NULL}}, /* inotify_add_watch */ {.slow = 0, .parser = {NULL}}, /* inotify_rm_watch */ {.slow = 0, .parser = {NULL}}, /* migrate_pages */ {.slow = 0, .parser = {&parse_at_fdcwd, NULL, &parse_open_flags, &parse_open_mode}}, /* openat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* mkdirat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* mknodat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* fchownat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* futimesat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* newfstatat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* unlinkat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* renameat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* linkat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* symlinkat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* readlinkat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* fchmodat */ {.slow = 0, .parser = {&parse_at_fdcwd}}, /* faccessat */ {.slow = 0, .parser = {NULL}}, /* pselect6 */ {.slow = 1, .parser = {NULL}}, /* ppoll */ {.slow = 0, .parser = {NULL}}, /* unshare */ {.slow = 0, .parser = {NULL}}, /* set_robust_list */ {.slow = 0, .parser = {NULL}}, /* get_robust_list */ {.slow = 0, .parser = {NULL}}, /* splice */ {.slow = 0, .parser = {NULL}}, /* tee */ {.slow = 0, .parser = {NULL}}, /* sync_file_range */ {.slow = 0, .parser = {NULL}}, /* vmsplice */ {.slow = 0, .parser = {NULL}}, /* move_pages */ {.slow = 0, .parser = {NULL}}, /* utimensat */ {.slow = 1, .parser = {NULL}}, /* epoll_pwait */ {.slow = 0, .parser = {NULL}}, /* signalfd */ {.slow = 0, .parser = {NULL}}, /* timerfd_create */ {.slow = 0, .parser = {NULL}}, /* eventfd */ {.slow = 0, .parser = {NULL}}, /* fallocate */ {.slow = 0, .parser = {NULL}}, /* timerfd_settime */ {.slow = 0, .parser = {NULL}}, /* timerfd_gettime */ {.slow = 1, .parser = {NULL}}, /* accept4 */ {.slow = 0, .parser = {NULL}}, /* signalfd4 */ {.slow = 0, .parser = {NULL}}, /* eventfd2 */ {.slow = 0, .parser = {NULL}}, /* epoll_create1 */ {.slow = 0, .parser = {NULL}}, /* dup3 */ {.slow = 0, .parser = {NULL}}, /* pipe2 */ {.slow = 0, .parser = {NULL}}, /* inotify_init1 */ {.slow = 0, .parser = {NULL}}, /* preadv */ {.slow = 0, .parser = {NULL}}, /* pwritev */ {.slow = 0, .parser = {NULL}}, /* rt_tgsigqueueinfo */ {.slow = 0, .parser = {NULL}}, /* perf_event_open */ {.slow = 0, .parser = {NULL}}, /* recvmmsg */ [LIBOS_SYSCALL_BASE] = {.slow = 0, .parser = {NULL}}, {.slow = 1, .parser = {NULL}}, /* checkpoint */ {.slow = 1, .parser = {NULL}}, /* restore */ {.slow = 1, .parser = {NULL}}, /* msgpersist */ {.slow = 1, .parser = {NULL}}, /* benchmark_ipc */ {.slow = 1, .parser = {NULL}}, /* send_rpc */ {.slow = 1, .parser = {NULL}}, /* recv_rpc */ }; static inline int is_pointer(const char* type) { return type[strlen(type) - 1] == '*' || !strcmp_static(type, "long") || !strcmp_static(type, "unsigned long"); } #define PRINTF(fmt, ...) \ do { \ debug_printf(fmt, __VA_ARGS__); \ } while (0) #define PUTS(str) \ do { \ debug_puts(str); \ } while (0) #define PUTCH(ch) \ do { \ debug_putch(ch); \ } while (0) #define VPRINTF(fmt, ap) \ do { \ debug_vprintf(fmt, ap); \ } while (0) static inline void parse_string_arg(va_list ap) { va_list ap_test_arg; va_copy(ap_test_arg, ap); const char* test_arg = va_arg(ap_test_arg, const char*); if (!test_user_string(test_arg)) { VPRINTF("\"%s\"", ap); } else { /* invalid memory region, print arg as ptr not string */ VPRINTF("\"(invalid-addr %p)\"", ap); } va_end(ap_test_arg); } static inline void parse_pointer_arg(va_list ap) { VPRINTF("%p", ap); } static inline void parse_integer_arg(va_list ap) { VPRINTF("%d", ap); } static inline void parse_syscall_args(va_list ap) { const char* arg_type = va_arg(ap, const char*); if (!strcmp_static(arg_type, "const char *") || !strcmp_static(arg_type, "const char*")) parse_string_arg(ap); else if (is_pointer(arg_type)) parse_pointer_arg(ap); else parse_integer_arg(ap); } static inline void skip_syscall_args(va_list ap) { const char* arg_type = va_arg(ap, const char*); if (!strcmp_static(arg_type, "const char *") || !strcmp_static(arg_type, "const char*")) va_arg(ap, const char*); else if (is_pointer(arg_type)) va_arg(ap, void*); else va_arg(ap, int); } void sysparser_printf(const char* fmt, ...) { va_list ap; va_start(ap, fmt); VPRINTF(fmt, ap); va_end(ap); } void parse_syscall_before(int sysno, const char* name, int nr, ...) { if (!debug_handle) return; struct parser_table* parser = &syscall_parser_table[sysno]; if (!parser->slow && !parser->stop) return; va_list ap; va_start(ap, nr); PRINTF("---- shim_%s(", name); for (int i = 0; i < nr; i++) { if (parser->stop && parser->stop == i) goto dotdotdot; if (i) PUTCH(','); if (parser->parser[i]) { const char* type = va_arg(ap, const char*); __UNUSED(type); // type not needed on this path (*parser->parser[i])(ap); } else parse_syscall_args(ap); } PUTCH(')'); dotdotdot: PRINTF(" ... %s\n", name); va_end(ap); } void parse_syscall_after(int sysno, const char* name, int nr, ...) { if (!debug_handle) return; struct parser_table* parser = &syscall_parser_table[sysno]; va_list ap; va_start(ap, nr); const char* ret_type = va_arg(ap, const char*); if (parser->slow || parser->stop) PRINTF("---- return from shim_%s(...", name); else PRINTF("---- shim_%s(", name); unsigned long ret_ptr = 0; int ret_val = 0; if (is_pointer(ret_type)) ret_ptr = (unsigned long)va_arg(ap, void*); else ret_val = va_arg(ap, int); if (!parser->slow || parser->stop) for (int i = 0; i < nr; i++) { if (parser->stop && i < parser->stop) { skip_syscall_args(ap); continue; } if (i) PUTCH(','); if (parser->parser[i]) { const char* type = va_arg(ap, const char*); __UNUSED(type); // type not needed on this path (*parser->parser[i])(ap); } else parse_syscall_args(ap); } if (is_pointer(ret_type)) { if ((uint64_t)ret_ptr < (uint64_t)-4095L) PRINTF(") = 0x%08lx\n", ret_ptr); else PRINTF(") = %ld\n", (long)ret_ptr); } else { PRINTF(") = %d\n", ret_val); } va_end(ap); } static void parse_open_flags(va_list ap) { int flags = va_arg(ap, int); if (flags & O_WRONLY) { PUTS("O_WRONLY"); flags &= ~O_WRONLY; } else if (flags & O_RDWR) { PUTS("O_RDWR"); flags &= ~O_RDWR; } else PUTS("O_RDONLY"); if (flags & O_APPEND) { PUTS("|O_APPEND"); flags &= ~O_APPEND; } if (flags & O_CREAT) { PUTS("|O_CREAT"); flags &= ~O_CREAT; } if (flags & O_TRUNC) { PUTS("|O_TRUNC"); flags &= ~O_TRUNC; } if (flags & O_EXCL) { PUTS("|O_EXCL"); flags &= ~O_EXCL; } if (flags) PRINTF("|%o", flags); } static void parse_open_mode(va_list ap) { VPRINTF("%04o", ap); } static void parse_access_mode(va_list ap) { int mode = va_arg(ap, int); PUTS("F_OK"); if (mode) { if (mode & R_OK) PUTS("|R_OK"); if (mode & W_OK) PUTS("|W_OK"); if (mode & X_OK) PUTS("|X_OK"); } } static void parse_clone_flags(va_list ap) { int flags = va_arg(ap, int); #define FLG(n) \ { "CLONE_" #n, CLONE_##n, } const struct { const char* name; int flag; } all_flags[] = { FLG(VM), FLG(FS), FLG(FILES), FLG(SIGHAND), FLG(PTRACE), FLG(VFORK), FLG(PARENT), FLG(THREAD), FLG(NEWNS), FLG(SYSVSEM), FLG(SETTLS), FLG(PARENT_SETTID), FLG(CHILD_CLEARTID), FLG(DETACHED), FLG(UNTRACED), FLG(CHILD_SETTID), FLG(NEWUTS), FLG(NEWIPC), FLG(NEWUSER), FLG(NEWPID), FLG(NEWNET), FLG(IO), }; #undef FLG bool printed = false; for (size_t i = 0; i < ARRAY_SIZE(all_flags); i++) if (flags & all_flags[i].flag) { if (printed) PUTCH('|'); else printed = true; PUTS(all_flags[i].name); flags &= ~all_flags[i].flag; } #define CLONE_SIGNAL_MASK 0xff int exit_signal = flags & CLONE_SIGNAL_MASK; flags &= ~CLONE_SIGNAL_MASK; if (exit_signal) { if (exit_signal >= 0 && exit_signal <= NUM_KNOWN_SIGS) PRINTF("|%s", signal_name(exit_signal)); else PRINTF("|[SIG %d]", exit_signal); } if (flags) PRINTF("|0x%x", flags); } static void parse_mmap_prot(va_list ap) { int prot = va_arg(ap, int); int nflags = 0; if (prot == PROT_NONE) { PUTS("PROT_NONE"); return; } if (prot & PROT_READ) { if (nflags++) PUTS("|"); PUTS("PROT_READ"); } if (prot & PROT_WRITE) { if (nflags++) PUTS("|"); PUTS("PROT_WRITE"); } if (prot & PROT_EXEC) { if (nflags++) PUTS("|"); PUTS("PROT_EXEC"); } } static void parse_mmap_flags(va_list ap) { int flags = va_arg(ap, int); if (flags & MAP_SHARED) { PUTS("MAP_SHARED"); flags &= ~MAP_SHARED; } if (flags & MAP_PRIVATE) { PUTS("MAP_PRIVATE"); flags &= ~MAP_PRIVATE; } if (flags & MAP_ANONYMOUS) { PUTS("|MAP_ANON"); flags &= ~MAP_ANONYMOUS; } if (flags & MAP_FILE) { PUTS("|MAP_FILE"); flags &= ~MAP_FILE; } if (flags & MAP_FIXED) { PUTS("|MAP_FIXED"); flags &= ~MAP_FIXED; } #ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED if (flags & MAP_UNINITIALIZED) { PUTS("|MAP_UNINITIALIZED"); flags &= ~MAP_UNINITIALIZED; } #endif if (flags) PRINTF("|0x%x", flags); } static void parse_exec_args(va_list ap) { const char** args = va_arg(ap, const char**); PUTS("["); for (;; args++) { if (test_user_memory(args, sizeof(*args), false)) { PRINTF("(invalid-argv %p)", args); break; } if (*args == NULL) break; if (test_user_string(*args)) { PRINTF("(invalid-addr %p),", *args); continue; } PUTS(*args); PUTS(","); } PUTS("]"); } static void parse_exec_envp(va_list ap) { const char** envp = va_arg(ap, const char**); if (!envp) { PUTS("NULL"); return; } PUTS("["); int cnt = 0; for (; cnt < 2; cnt++, envp++) { if (test_user_memory(envp, sizeof(*envp), false)) { PRINTF("(invalid-envp %p)", envp); break; } if (*envp == NULL) break; if (test_user_string(*envp)) { PRINTF("(invalid-addr %p),", *envp); continue; } PUTS(*envp); PUTS(","); } if (cnt > 2) PRINTF("(%d more)", cnt); PUTS("]"); } static void parse_pipe_fds(va_list ap) { int* fds = va_arg(ap, int*); PRINTF("[%d, %d]", fds[0], fds[1]); } #define S(sig) #sig const char* const siglist[NUM_KNOWN_SIGS + 1] = { S(SIGUNUSED), S(SIGHUP), S(SIGINT), S(SIGQUIT), S(SIGILL), S(SIGTRAP), S(SIGABRT), S(SIGBUS), S(SIGFPE), S(SIGKILL), S(SIGUSR1), S(SIGSEGV), S(SIGUSR2), S(SIGPIPE), S(SIGALRM), S(SIGTERM), S(SIGSTKFLT), S(SIGCHLD), S(SIGCONT), S(SIGSTOP), S(SIGTSTP), S(SIGTTIN), S(SIGTTOU), S(SIGURG), S(SIGXCPU), S(SIGXFSZ), S(SIGVTALRM), S(SIGPROF), S(SIGWINCH), S(SIGIO), S(SIGPWR), S(SIGSYS), S(SIGRTMIN), }; static void parse_signum(va_list ap) { int signum = va_arg(ap, int); if (signum >= 0 && signum <= NUM_KNOWN_SIGS) PUTS(signal_name(signum)); else PRINTF("[SIG %d]", signum); } static void parse_sigmask(va_list ap) { __sigset_t* sigset = va_arg(ap, __sigset_t*); if (!sigset) { PUTS("NULL"); return; } if (test_user_memory(sigset, sizeof(*sigset), false)) { PRINTF("(invalid-addr %p)", sigset); return; } PUTS("["); for (size_t signum = 1; signum <= sizeof(sigset) * 8; signum++) if (__sigismember(sigset, signum)) { PUTS(signal_name(signum)); PUTS(","); } PUTS("]"); } static void parse_sigprocmask_how(va_list ap) { int how = va_arg(ap, int); switch (how) { case SIG_BLOCK: PUTS("BLOCK"); break; case SIG_UNBLOCK: PUTS("UNBLOCK"); break; case SIG_SETMASK: PUTS("SETMASK"); break; default: PUTS(""); break; } } static void parse_timespec(va_list ap) { const struct timespec* tv = va_arg(ap, const struct timespec*); if (!tv) { PUTS("NULL"); return; } if (test_user_memory((void*)tv, sizeof(*tv), false)) { PRINTF("(invalid-addr %p)", tv); return; } PRINTF("[%ld,%ld]", tv->tv_sec, tv->tv_nsec); } static void parse_sockaddr(va_list ap) { const struct sockaddr* addr = va_arg(ap, const struct sockaddr*); if (!addr) { PUTS("NULL"); return; } if (test_user_memory((void*)addr, sizeof(*addr), false)) { PRINTF("(invalid-addr %p)", addr); return; } switch (addr->sa_family) { case AF_INET: { struct sockaddr_in* a = (void*)addr; unsigned char* ip = (void*)&a->sin_addr.s_addr; PRINTF("{family=INET,ip=%u.%u.%u.%u,port=htons(%u)}", ip[0], ip[1], ip[2], ip[3], __ntohs(a->sin_port)); break; } case AF_INET6: { struct sockaddr_in6* a = (void*)addr; unsigned short* ip = (void*)&a->sin6_addr.s6_addr; PRINTF( "{family=INET,ip=[%x:%x:%x:%x:%x:%x:%x:%x]," "port=htons(%u)}", __ntohs(ip[0]), __ntohs(ip[1]), __ntohs(ip[2]), __ntohs(ip[3]), __ntohs(ip[4]), __ntohs(ip[5]), __ntohs(ip[6]), __ntohs(ip[7]), __ntohs(a->sin6_port)); break; } case AF_UNIX: { struct sockaddr_un* a = (void*)addr; PRINTF("{family=UNIX,path=%s}", a->sun_path); break; } default: PUTS("UNKNOWN"); break; } } static void parse_domain(va_list ap) { int domain = va_arg(ap, int); #define PF_UNSPEC 0 /* Unspecified. */ #define PF_INET 2 /* IP protocol family. */ #define PF_AX25 3 /* Amateur Radio AX.25. */ #define PF_IPX 4 /* Novell Internet Protocol. */ #define PF_APPLETALK 5 /* Appletalk DDP. */ #define PF_ATMPVC 8 /* ATM PVCs. */ #define PF_X25 9 /* Reserved for X.25 project. */ #define PF_INET6 10 /* IP version 6. */ #define PF_NETLINK 16 #define PF_PACKET 17 /* Packet family. */ switch (domain) { case PF_UNSPEC: PUTS("UNSPEC"); break; case PF_UNIX: PUTS("UNIX"); break; case PF_INET: PUTS("INET"); break; case PF_INET6: PUTS("INET6"); break; case PF_IPX: PUTS("IPX"); break; case PF_NETLINK: PUTS("NETLINK"); break; case PF_X25: PUTS("X25"); break; case PF_AX25: PUTS("AX25"); break; case PF_ATMPVC: PUTS("ATMPVC"); break; case PF_APPLETALK: PUTS("APPLETALK"); break; case PF_PACKET: PUTS("PACKET"); break; default: PUTS("UNKNOWN"); break; } } static void parse_socktype(va_list ap) { int socktype = va_arg(ap, int); if (socktype & SOCK_NONBLOCK) { socktype &= ~SOCK_NONBLOCK; PUTS("SOCK_NONBLOCK|"); } if (socktype & SOCK_CLOEXEC) { socktype &= ~SOCK_CLOEXEC; PUTS("SOCK_CLOEXEC|"); } #define SOCK_RAW 3 /* Raw protocol interface. */ #define SOCK_RDM 4 /* Reliably-delivered messages. */ #define SOCK_SEQPACKET 5 /* Sequenced, reliable, connection-based, */ #define SOCK_DCCP 6 /* Datagram Congestion Control Protocol. */ #define SOCK_PACKET 10 /* Linux specific way of getting packets */ switch (socktype) { case SOCK_STREAM: PUTS("STREAM"); break; case SOCK_DGRAM: PUTS("DGRAM"); break; case SOCK_SEQPACKET: PUTS("SEQPACKET"); break; case SOCK_RAW: PUTS("RAW"); break; case SOCK_RDM: PUTS("RDM"); break; case SOCK_PACKET: PUTS("PACKET"); break; default: PUTS("UNKNOWN"); break; } } static void parse_futexop(va_list ap) { int op = va_arg(ap, int); #ifdef FUTEX_PRIVATE_FLAG if (op & FUTEX_PRIVATE_FLAG) { PUTS("FUTEX_PRIVATE|"); op &= ~FUTEX_PRIVATE_FLAG; } #endif #ifdef FUTEX_CLOCK_REALTIME if (op & FUTEX_CLOCK_REALTIME) { PUTS("FUTEX_CLOCK_REALTIME|"); op &= ~FUTEX_CLOCK_REALTIME; } #endif op &= FUTEX_CMD_MASK; switch (op) { case FUTEX_WAIT: PUTS("FUTEX_WAIT"); break; case FUTEX_WAIT_BITSET: PUTS("FUTEX_WAIT_BITSET"); break; case FUTEX_WAKE: PUTS("FUTEX_WAKE"); break; case FUTEX_WAKE_BITSET: PUTS("FUTEX_WAKE_BITSET"); break; case FUTEX_FD: PUTS("FUTEX_FD"); break; case FUTEX_REQUEUE: PUTS("FUTEX_REQUEUE"); break; case FUTEX_CMP_REQUEUE: PUTS("FUTEX_CMP_REQUEUE"); break; case FUTEX_WAKE_OP: PUTS("FUTEX_WAKE_OP"); break; default: PRINTF("OP %d", op); break; } } static void parse_fcntlop(va_list ap) { int op = va_arg(ap, int); switch (op) { case F_DUPFD: PUTS("F_DUPFD"); break; case F_GETFD: PUTS("F_GETFD"); break; case F_SETFD: PUTS("F_SETFD"); break; case F_GETFL: PUTS("F_GETFL"); break; case F_SETFL: PUTS("F_SETFL"); break; case F_GETLK: PUTS("F_GETLK"); break; case F_SETLK: PUTS("F_SETLK"); break; case F_SETLKW: PUTS("F_SETLKW"); break; case F_SETOWN: PUTS("F_SETOWN"); break; case F_GETOWN: PUTS("F_GETOWN"); break; case F_SETSIG: PUTS("F_SETSIG"); break; case F_GETSIG: PUTS("F_GETSIG"); break; case F_GETLK64: PUTS("F_GETLK64"); break; case F_SETLK64: PUTS("F_SETLK64"); break; case F_SETLKW64: PUTS("F_SETLKW64"); break; case F_SETOWN_EX: PUTS("F_SETOWN_EX"); break; case F_GETOWN_EX: PUTS("F_GETOWN_EX"); break; case F_GETOWNER_UIDS: PUTS("F_GETOWNER_UIDS"); break; default: PRINTF("OP %d", op); break; } } static void parse_ioctlop(va_list ap) { int op = va_arg(ap, int); if (op >= TCGETS && op <= TIOCVHANGUP) { const char* opnames[] = { "TCGETS", /* 0x5401 */ "TCSETS", /* 0x5402 */ "TCSETSW", /* 0x5403 */ "TCSETSF", /* 0x5404 */ "TCGETA", /* 0x5405 */ "TCSETA", /* 0x5406 */ "TCSETAW", /* 0x5407 */ "TCSETAF", /* 0x5408 */ "TCSBRK", /* 0x5409 */ "TCXONC", /* 0x540A */ "TCFLSH", /* 0x540B */ "TIOCEXCL", /* 0x540C */ "TIOCNXCL", /* 0x540D */ "TIOCSCTTY", /* 0x540E */ "TIOCGPGRP", /* 0x540F */ "TIOCSPGRP", /* 0x5410 */ "TIOCOUTQ", /* 0x5411 */ "TIOCSTI", /* 0x5412 */ "TIOCGWINSZ", /* 0x5413 */ "TIOCSWINSZ", /* 0x5414 */ "TIOCMGET", /* 0x5415 */ "TIOCMBIS", /* 0x5416 */ "TIOCMBIC", /* 0x5417 */ "TIOCMSET", /* 0x5418 */ "TIOCGSOFTCAR", /* 0x5419 */ "TIOCSSOFTCAR", /* 0x541A */ "FIONREAD", /* 0x541B */ "TIOCLINUX", /* 0x541C */ "TIOCCONS", /* 0x541D */ "TIOCGSERIAL", /* 0x541E */ "TIOCSSERIAL", /* 0x541F */ "TIOCPKT", /* 0x5420 */ "FIONBIO", /* 0x5421 */ "TIOCNOTTY", /* 0x5422 */ "TIOCSETD", /* 0x5423 */ "TIOCGETD", /* 0x5424 */ "TCSBRKP", /* 0x5425 */ "", "TIOCSBRK", /* 0x5427 */ "TIOCCBRK", /* 0x5428 */ "TIOCGSID", /* 0x5429 */ "TCGETS2", /* 0x542A */ "TCSETS2", /* 0x542B */ "TCSETSW2", /* 0x542C */ "TCSETSF2", /* 0x542D */ "TIOCGRS485", /* 0x542E */ "TIOCSRS485", /* 0x542F */ "TIOCGPTN", /* 0x5430 */ "TIOCSPTLCK", /* 0x5431 */ "TCGETX", /* 0x5432 */ "TCSETX", /* 0x5433 */ "TCSETXF", /* 0x5434 */ "TCSETXW", /* 0x5435 */ "TIOCSIG", /* 0x5436 */ "TIOCVHANGUP", /* 0x5437 */ }; PUTS(opnames[op - TCGETS]); return; } if (op >= FIONCLEX && op <= TIOCSERSETMULTI) { const char* opnames[] = { "FIONCLEX", /* 0x5450 */ "FIOCLEX", /* 0x5451 */ "FIOASYNC", /* 0x5452 */ "TIOCSERCONFIG", /* 0x5453 */ "TIOCSERGWILD", /* 0x5454 */ "TIOCSERSWILD", /* 0x5455 */ "TIOCGLCKTRMIOS", /* 0x5456 */ "TIOCSLCKTRMIOS", /* 0x5457 */ "TIOCSERGSTRUCT", /* 0x5458 */ "TIOCSERGETLSR", /* 0x5459 */ "TIOCSERGETMULTI", /* 0x545A */ "TIOCSERSETMULTI", /* 0x545B */ }; PUTS(opnames[op - FIONCLEX]); return; } #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port __inline__ interrupt counts */ PRINTF("OP 0x%04x", op); } static void parse_seek(va_list ap) { int seek = va_arg(ap, int); switch (seek) { case SEEK_CUR: PUTS("SEEK_CUR"); break; case SEEK_SET: PUTS("SEEK_SET"); break; case SEEK_END: PUTS("SEEK_END"); break; default: PRINTF("%d", seek); break; } } static void parse_at_fdcwd(va_list ap) { int fd = va_arg(ap, int); switch (fd) { case AT_FDCWD: PUTS("AT_FDCWD"); break; default: PRINTF("%d", fd); break; } } static void parse_wait_option(va_list ap) { int option = va_arg(ap, int); if (option & WNOHANG) PUTS("WNOHANG"); }