/* 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");
}