/* -*- 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 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 (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_domain (const char *, va_list *);
static void parse_socktype (const char *, va_list *);
static void parse_futexop (const char *, va_list *);
static void parse_ioctlop (const char *, va_list *);
static void parse_fcntlop (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[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 = 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 = { &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, .stop = 3, /* socketpair */
.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, .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, &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 } }, /* 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")
|| 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)
{
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] =
{
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 (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));
else
PRINTF("[SIG %d]", 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)}",
__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 (const char * type, 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 (const char * type, 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 (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_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 (const char * type, 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 (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;
}
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 (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");
}