/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */ /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */ /* Copyright (C) 2014 OSCAR lab, 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 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 General Public License for more details. You should have received a copy of the GNU 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 (const char *, va_list *); static void parse_open_mode (const char *, va_list *); static void parse_access_mode (const char *, va_list *); static void parse_clone_flags (const char *, va_list *); static void parse_mmap_prot (const char *, va_list *); static void parse_mmap_flags (const char *, va_list *); static void parse_exec_args (const char *, va_list *); static void parse_exec_envp (const char *, va_list *); static void parse_pipe_fds (const char *, va_list *); static void parse_signum (const char *, va_list *); static void parse_sigmask (const char *, va_list *); static void parse_sigprocmask_how (const char *, va_list *); static void parse_timespec (const char *, va_list *); static void parse_sockaddr (const char *, va_list *); static void parse_futexop (const char *, va_list *); static void parse_ioctlop (const char *, va_list *); static void parse_seek (const char *, va_list *); static void parse_at_fdcwd (const char *, va_list *); static void parse_wait_option (const char *, va_list *); struct parser_table { int slow; int stop; void (*parser[6]) (const char *, va_list *); } syscall_parser_table[SHIM_NSYSCALLS] = { { .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 = 0, .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 = { NULL } }, /* 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, .stop = 3, /* socketpair */ .parser = { NULL, NULL, 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, .parser = { NULL, &parse_signum, } }, /* kill */ { .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 } }, /* 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 = 0, .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 */ { .slow = 0, .parser = { NULL } }, { .slow = 1, .parser = { NULL } }, /* checkpoint */ { .slow = 1, .parser = { NULL } }, /* restore */ { .slow = 1, .parser = { NULL } }, /* sandbox_create */ { .slow = 0, .parser = { NULL } }, /* sandbox_attach */ { .slow = 0, .parser = { NULL } }, /* sandbox_current */ { .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"); } #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) { VPRINTF("\"%s\"", ap); } 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 *")) 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 *")) 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 *); (*parser->parser[i])(type, &ap); } else parse_syscall_args(&ap); } PUTCH(')'); dotdotdot: PRINTF(" ...\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; int ret_val; 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 *); (*parser->parser[i])(type, &ap); } else parse_syscall_args(&ap); } if (is_pointer(ret_type)) { if (ret_ptr < -4095L) PRINTF(") = %p\n", ret_ptr); else PRINTF(") = %ld\n", (long) ret_ptr); } else { if (ret_val >= 0) PRINTF(") = %d\n", ret_val); else PRINTF(") = %d\n", ret_val); } va_end (ap); } static void parse_open_flags (const char * type, 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 (const char * type, va_list * ap) { VPRINTF("%04o", ap); } static void parse_access_mode (const char * type, 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 (const char * type, 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 (int i = 0 ; i < sizeof(all_flags) / sizeof(all_flags[0]) ; i++) if (flags & all_flags[i].flag) { if (printed) PUTCH('|'); else printed = true; PUTS(all_flags[i].name); flags &= ~all_flags[i].flag; } if (flags) PRINTF("|0x%x", flags); } static void parse_mmap_prot (const char * type, 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 (const char * type, 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 (const char * type, va_list * ap) { const char ** args = va_arg(*ap, const char **); PUTS("["); for (; *args ; args++) { PUTS(*args); PUTS(","); } PUTS("]"); } static void parse_exec_envp (const char * type, va_list * ap) { const char ** envp = va_arg(*ap, const char **); if (!envp) { PUTS("NULL"); return; } int cnt = 0; PUTS("["); for (; *envp ; envp++) if (cnt++ < 2) { PUTS(*envp); PUTS(","); } if (cnt > 2) PRINTF("(%d more)", cnt); PUTS("]"); } static void parse_pipe_fds (const char * type, 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] = { NULL, 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), }; static void parse_signum (const char * type, va_list * ap) { unsigned int signum = va_arg(*ap, unsigned int); if (signum > 0 && signum <= NUM_KNOWN_SIGS) PUTS(signal_name(signum)); } static void parse_sigmask (const char * type, va_list * ap) { __sigset_t * sigset = va_arg(*ap, __sigset_t *); if (!sigset) { PUTS("NULL"); return; } PUTS("["); for (int signum = 1 ; signum <= sizeof(sigset) * 8 ; signum++) if (__sigismember(sigset, signum)) { PUTS(signal_name(signum)); PUTS(","); } PUTS("]"); } static void parse_sigprocmask_how (const char * type, 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 (const char * type, va_list * ap) { const struct timespec * tv = va_arg(*ap, const struct timespec *); if (!tv) { PUTS("NULL"); return; } PRINTF("[%ld,%lld]", tv->tv_sec, tv->tv_nsec); } static void parse_sockaddr (const char * type, va_list *ap) { const struct sockaddr *addr = va_arg(*ap, const struct sockaddr *); if (!addr) { PUTS("NULL"); 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)}", ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], 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_futexop (const char * type, 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_WAKE: PUTS("FUTEX_WAKE"); 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_ioctlop (const char * type, 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; } PRINTF("OP 0x%04u", op); } static void parse_seek (const char * type, 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 (const char * type, 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 (const char * type, va_list * ap) { int option = va_arg(*ap, int); if (option & WNOHANG) PUTS("WNOHANG"); }