cosmopolitan/tool/build/strace.c

1199 lines
54 KiB
C
Raw Normal View History

2022-03-24 15:00:21 +00:00
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
2022-03-24 15:00:21 +00:00
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/user_regs_struct.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
2022-09-06 18:22:08 +00:00
#include "libc/intrin/bits.h"
2022-03-24 15:00:21 +00:00
#include "libc/intrin/kprintf.h"
#include "libc/intrin/nomultics.internal.h"
2022-03-24 15:00:21 +00:00
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/append.h"
2022-03-24 15:00:21 +00:00
#include "libc/str/str.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/ptrace.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/w.h"
/**
* @fileoverview ptrace() tutorial
*/
#define PROLOGUE "%r%8d %'18T "
#undef __NR_execve
#define __WALL 0x40000000
#define PTR 0
#define ULONG 0
#define INT 1
#define LONG 2
#define STR 3
#define BUF 4
#define IOV 5
#define STRLIST 6
#define INTPTR 7
#define STAT 8
#define SIG 9
#define SIGSET 10
2022-04-06 16:12:05 +00:00
#define PIPE 11
2022-03-24 15:00:21 +00:00
#define OCTAL 0x80
2022-04-06 16:12:05 +00:00
static const long __NR_brk = 12;
static const long __NR_sigreturn = 15;
2022-03-24 15:00:21 +00:00
static const struct Syscall {
long *number;
const char *name;
2022-04-06 16:12:05 +00:00
char arity;
char eager;
2022-03-24 15:00:21 +00:00
unsigned char ret;
unsigned char arg[6];
} kSyscalls[] = {
// clang-format off
2022-04-06 16:12:05 +00:00
{&__NR_exit, "exit", 1, 1, INT, {INT}},
{&__NR_exit_group, "exit_group", 1, 1, INT, {INT}},
{&__NR_read, "read", 3, 1, LONG, {INT, BUF, ULONG}},
{&__NR_write, "write", 3, 3, LONG, {INT, BUF, ULONG}},
{&__NR_open, "open", 3, 3, INT, {STR, INT, OCTAL|INT}},
{&__NR_close, "close", 1, 1, INT, {INT}},
{&__NR_brk, "brk", 1, 1, ULONG, {ULONG}},
{&__NR_stat, "stat", 2, 1, INT, {STR, STAT}},
{&__NR_fstat, "fstat", 2, 1, INT, {INT, STAT}},
{&__NR_lstat, "lstat", 2, 1, INT, {INT, STAT}},
{&__NR_poll, "poll", 3, 3, INT, {PTR, INT, INT}},
{&__NR_ppoll, "ppoll", 4, 4, INT},
{&__NR_lseek, "lseek", 3, 3, LONG, {INT, LONG, INT}},
{&__NR_mmap, "mmap", 6, 6, ULONG, {PTR, ULONG, INT, INT, INT, ULONG}},
{&__NR_msync, "msync", 3, 3, INT, {PTR, ULONG, INT}},
{&__NR_mprotect, "mprotect", 3, 3, INT, {PTR, ULONG, INT}},
{&__NR_munmap, "munmap", 2, 2, INT, {PTR, ULONG}},
{&__NR_sigreturn, "rt_sigreturn", 6, 6, LONG},
{&__NR_sigaction, "rt_sigaction", 4, 4, INT, {SIG}},
{&__NR_sigprocmask, "rt_sigprocmask", 4, 4, INT, {INT, SIGSET, SIGSET, LONG}},
{&__NR_sigpending, "rt_sigpending", 2, 2, INT, {SIGSET, LONG}},
{&__NR_sigsuspend, "rt_sigsuspend", 2, 2, INT, {SIGSET, LONG}},
{&__NR_sigqueueinfo, "rt_sigqueueinfo", 6, 6},
2022-04-06 16:12:05 +00:00
{&__NR_ioctl, "ioctl", 3, 3, INT, {INT, ULONG, ULONG}},
{&__NR_pread, "pread64", 4, 1, LONG, {INT, BUF, ULONG, ULONG}},
{&__NR_pwrite, "pwrite64", 4, 4, LONG, {INT, BUF, ULONG, ULONG}},
{&__NR_readv, "readv", 3, 1, LONG, {INT, IOV, INT}},
{&__NR_writev, "writev", 3, 3, LONG, {INT, IOV, INT}},
{&__NR_access, "access", 2, 2, INT, {STR, OCTAL|INT}},
{&__NR_pipe, "pipe", 1, 0, INT, {PIPE}},
{&__NR_pipe2, "pipe2", 2, 0, INT, {PIPE, INT}},
{&__NR_select, "select", 5, 5},
{&__NR_pselect, "pselect", 6, 6},
{&__NR_pselect6, "pselect6", 6, 6},
{&__NR_sched_yield, "sched_yield", 0, 0, INT},
{&__NR_mremap, "mremap", 5, 5},
{&__NR_mincore, "mincore", 6, 6},
{&__NR_madvise, "madvise", 6, 6},
{&__NR_shmget, "shmget", 6, 6},
{&__NR_shmat, "shmat", 6, 6},
{&__NR_shmctl, "shmctl", 6, 6},
{&__NR_dup, "dup", 1, 1, INT, {INT}},
{&__NR_dup2, "dup2", 2, 2, INT, {INT, INT}},
{&__NR_pause, "pause", 0, 0, INT},
{&__NR_nanosleep, "nanosleep", 2, 1},
{&__NR_getitimer, "getitimer", 2, 2},
{&__NR_setitimer, "setitimer", 3, 3},
{&__NR_alarm, "alarm", 1, 1},
{&__NR_getpid, "getpid", 0, 0, INT},
{&__NR_sendfile, "sendfile", 6, 6},
{&__NR_socket, "socket", 3, 3, INT, {INT, INT, INT}},
{&__NR_connect, "connect", 3, 3},
{&__NR_accept, "accept", 3, 3},
{&__NR_sendto, "sendto", 6, 6},
{&__NR_recvfrom, "recvfrom", 6, 6},
{&__NR_sendmsg, "sendmsg", 6, 6},
{&__NR_recvmsg, "recvmsg", 6, 6},
{&__NR_shutdown, "shutdown", 6, 6},
{&__NR_bind, "bind", 6, 6},
{&__NR_listen, "listen", 6, 6},
{&__NR_getsockname, "getsockname", 6, 6},
{&__NR_getpeername, "getpeername", 6, 6},
{&__NR_socketpair, "socketpair", 6, 6},
{&__NR_setsockopt, "setsockopt", 6, 6},
{&__NR_getsockopt, "getsockopt", 6, 6},
{&__NR_fork, "fork", 0, 0, INT},
{&__NR_vfork, "vfork", 0, 0, INT},
{&__NR_posix_spawn, "posix_spawn", 6, 6},
{&__NR_execve, "execve", 3, 3, INT, {STR, STRLIST, STRLIST}},
{&__NR_wait4, "wait4", 4, 4, INT, {INT, INTPTR, INT, PTR}},
{&__NR_kill, "kill", 2, 2, INT, {INT, SIG}},
{&__NR_killpg, "killpg", 2, 2, INT, {INT, SIG}},
{&__NR_clone, "clone", 5, 5, INT, {PTR, PTR, INTPTR, INTPTR, ULONG}},
{&__NR_tkill, "tkill", 2, 2, INT, {INT, SIG}},
{&__NR_futex, "futex", 6, 6},
{&__NR_set_robust_list, "set_robust_list", 6, 6},
{&__NR_get_robust_list, "get_robust_list", 6, 6},
{&__NR_uname, "uname", 6, 6},
{&__NR_semget, "semget", 6, 6},
{&__NR_semop, "semop", 6, 6},
{&__NR_semctl, "semctl", 6, 6},
{&__NR_shmdt, "shmdt", 6, 6},
{&__NR_msgget, "msgget", 6, 6},
{&__NR_msgsnd, "msgsnd", 6, 6},
{&__NR_msgrcv, "msgrcv", 6, 6},
{&__NR_msgctl, "msgctl", 6, 6},
{&__NR_fcntl, "fcntl", 3, 3, INT, {INT, INT, ULONG}},
{&__NR_flock, "flock", 6, 6},
{&__NR_fsync, "fsync", 6, 6},
{&__NR_fdatasync, "fdatasync", 6, 6},
{&__NR_truncate, "truncate", 2, 2, INT, {STR, ULONG}},
{&__NR_ftruncate, "ftruncate", 6, 6, INT, {INT, ULONG}},
{&__NR_getcwd, "getcwd", 2, 2, INT, {BUF, ULONG}},
{&__NR_chdir, "chdir", 1, 1, INT, {STR}},
{&__NR_fchdir, "fchdir", 1, 1, INT, {INT}},
{&__NR_rename, "rename", 2, 2, INT, {STR, STR}},
{&__NR_mkdir, "mkdir", 2, 2, INT, {STR, OCTAL|INT}},
{&__NR_rmdir, "rmdir", 1, 1, INT, {STR}},
{&__NR_creat, "creat", 2, 2, INT, {STR, OCTAL|INT}},
{&__NR_link, "link", 2, 2, INT, {STR, STR}},
{&__NR_unlink, "unlink", 1, 1, INT, {STR}},
{&__NR_symlink, "symlink", 6, 6},
{&__NR_readlink, "readlink", 3, 1, INT, {STR, BUF, ULONG}},
{&__NR_chmod, "chmod", 6, 6},
{&__NR_fchmod, "fchmod", 6, 6},
{&__NR_chown, "chown", 6, 6},
{&__NR_fchown, "fchown", 6, 6},
{&__NR_lchown, "lchown", 6, 6},
{&__NR_umask, "umask", 1, 1, OCTAL|INT, {OCTAL|INT}},
{&__NR_gettimeofday, "gettimeofday", 6, 6},
{&__NR_getrlimit, "getrlimit", 6, 6},
{&__NR_getrusage, "getrusage", 6, 6},
{&__NR_sysinfo, "sysinfo", 6, 6},
{&__NR_times, "times", 6, 6},
{&__NR_ptrace, "ptrace", 6, 6},
{&__NR_syslog, "syslog", 6, 6},
{&__NR_getuid, "getuid", 0, 0, INT},
{&__NR_getgid, "getgid", 0, 0, INT},
{&__NR_getppid, "getppid", 0, 0, INT},
{&__NR_getpgrp, "getpgrp", 0, 0, INT},
{&__NR_setsid, "setsid", 1, 1, INT, {INT}},
{&__NR_getsid, "getsid", 0, 0, INT},
{&__NR_getpgid, "getpgid", 0, 0, INT},
{&__NR_setpgid, "setpgid", 2, 2, INT, {INT, INT}},
{&__NR_geteuid, "geteuid", 0, 0, INT},
{&__NR_getegid, "getegid", 0, 0, INT},
{&__NR_getgroups, "getgroups", 6, 6},
{&__NR_setgroups, "setgroups", 6, 6},
{&__NR_setreuid, "setreuid", 6, 6},
{&__NR_setregid, "setregid", 6, 6},
{&__NR_setuid, "setuid", 1, 1, INT, {INT}},
{&__NR_setgid, "setgid", 1, 1, INT, {INT}},
{&__NR_setresuid, "setresuid", 6, 6},
{&__NR_setresgid, "setresgid", 6, 6},
{&__NR_getresuid, "getresuid", 6, 6},
{&__NR_getresgid, "getresgid", 6, 6},
{&__NR_sigaltstack, "sigaltstack", 6, 6},
{&__NR_mknod, "mknod", 6, 6},
{&__NR_mknodat, "mknodat", 6, 6},
{&__NR_mkfifo, "mkfifo", 6, 6},
{&__NR_mkfifoat, "mkfifoat", 6, 6},
{&__NR_statfs, "statfs", 6, 6},
{&__NR_fstatfs, "fstatfs", 6, 6},
{&__NR_getpriority, "getpriority", 6, 6},
{&__NR_setpriority, "setpriority", 6, 6},
{&__NR_mlock, "mlock", 6, 6},
{&__NR_munlock, "munlock", 6, 6},
{&__NR_mlockall, "mlockall", 6, 6},
{&__NR_munlockall, "munlockall", 6, 6},
{&__NR_setrlimit, "setrlimit", 6, 6},
{&__NR_chroot, "chroot", 6, 6},
{&__NR_sync, "sync", 6, 6},
{&__NR_acct, "acct", 6, 6},
{&__NR_settimeofday, "settimeofday", 6, 6},
{&__NR_mount, "mount", 6, 6},
{&__NR_reboot, "reboot", 6, 6},
{&__NR_quotactl, "quotactl", 6, 6},
{&__NR_setfsuid, "setfsuid", 6, 6},
{&__NR_setfsgid, "setfsgid", 6, 6},
{&__NR_capget, "capget", 6, 6},
{&__NR_capset, "capset", 6, 6},
{&__NR_sigtimedwait, "sigtimedwait", 6, 6},
{&__NR_personality, "personality", 6, 6},
{&__NR_ustat, "ustat", 6, 6},
{&__NR_sysfs, "sysfs", 6, 6},
{&__NR_sched_setparam, "sched_setparam", 6, 6},
{&__NR_sched_getparam, "sched_getparam", 6, 6},
{&__NR_sched_setscheduler, "sched_setscheduler", 6, 6},
{&__NR_sched_getscheduler, "sched_getscheduler", 6, 6},
{&__NR_sched_get_priority_max, "sched_get_priority_max", 6, 6},
{&__NR_sched_get_priority_min, "sched_get_priority_min", 6, 6},
{&__NR_sched_rr_get_interval, "sched_rr_get_interval", 6, 6},
{&__NR_vhangup, "vhangup", 6, 6},
{&__NR_modify_ldt, "modify_ldt", 6, 6},
{&__NR_pivot_root, "pivot_root", 6, 6},
{&__NR__sysctl, "_sysctl", 6, 6},
{&__NR_prctl, "prctl", 6, 6},
{&__NR_arch_prctl, "arch_prctl", 2, 2, INT, {INT, ULONG}},
{&__NR_adjtimex, "adjtimex", 6, 6},
{&__NR_umount2, "umount2", 6, 6},
{&__NR_swapon, "swapon", 6, 6},
{&__NR_swapoff, "swapoff", 6, 6},
{&__NR_sethostname, "sethostname", 6, 6},
{&__NR_setdomainname, "setdomainname", 6, 6},
{&__NR_iopl, "iopl", 6, 6},
{&__NR_ioperm, "ioperm", 6, 6},
{&__NR_init_module, "init_module", 6, 6},
{&__NR_delete_module, "delete_module", 6, 6},
{&__NR_gettid, "gettid", 6, 6},
{&__NR_readahead, "readahead", 6, 6},
{&__NR_setxattr, "setxattr", 6, 6},
{&__NR_fsetxattr, "fsetxattr", 6, 6},
{&__NR_getxattr, "getxattr", 6, 6},
{&__NR_fgetxattr, "fgetxattr", 6, 6},
{&__NR_listxattr, "listxattr", 6, 6},
{&__NR_flistxattr, "flistxattr", 6, 6},
{&__NR_removexattr, "removexattr", 6, 6},
{&__NR_fremovexattr, "fremovexattr", 6, 6},
{&__NR_lsetxattr, "lsetxattr", 6, 6},
{&__NR_lgetxattr, "lgetxattr", 6, 6},
{&__NR_llistxattr, "llistxattr", 6, 6},
{&__NR_lremovexattr, "lremovexattr", 6, 6},
{&__NR_sched_setaffinity, "sched_setaffinity", 6, 6},
{&__NR_sched_getaffinity, "sched_getaffinity", 6, 6},
{&__NR_cpuset_getaffinity, "cpuset_getaffinity", 6, 6},
{&__NR_cpuset_setaffinity, "cpuset_setaffinity", 6, 6},
{&__NR_io_setup, "io_setup", 6, 6},
{&__NR_io_destroy, "io_destroy", 6, 6},
{&__NR_io_getevents, "io_getevents", 6, 6},
{&__NR_io_submit, "io_submit", 6, 6},
{&__NR_io_cancel, "io_cancel", 6, 6},
{&__NR_lookup_dcookie, "lookup_dcookie", 6, 6},
{&__NR_epoll_create, "epoll_create", 6, 6},
{&__NR_epoll_wait, "epoll_wait", 6, 6},
{&__NR_epoll_ctl, "epoll_ctl", 6, 6},
{&__NR_getdents, "getdents64", 6, 6},
{&__NR_set_tid_address, "set_tid_address", 1, 1},
{&__NR_restart_syscall, "restart_syscall", 6, 6},
{&__NR_semtimedop, "semtimedop", 6, 6},
{&__NR_fadvise, "fadvise", 6, 6},
{&__NR_timer_create, "timer_create", 6, 6},
{&__NR_timer_settime, "timer_settime", 6, 6},
{&__NR_timer_gettime, "timer_gettime", 6, 6},
{&__NR_timer_getoverrun, "timer_getoverrun", 6, 6},
{&__NR_timer_delete, "timer_delete", 6, 6},
{&__NR_clock_settime, "clock_settime", 6, 6},
{&__NR_clock_gettime, "clock_gettime", 6, 6},
{&__NR_clock_getres, "clock_getres", 6, 6},
{&__NR_clock_nanosleep, "clock_nanosleep", 6, 6},
{&__NR_tgkill, "tgkill", 6, 6},
{&__NR_mbind, "mbind", 6, 6},
{&__NR_set_mempolicy, "set_mempolicy", 6, 6},
{&__NR_get_mempolicy, "get_mempolicy", 6, 6},
{&__NR_mq_open, "mq_open", 6, 6},
{&__NR_mq_unlink, "mq_unlink", 6, 6},
{&__NR_mq_timedsend, "mq_timedsend", 6, 6},
{&__NR_mq_timedreceive, "mq_timedreceive", 6, 6},
{&__NR_mq_notify, "mq_notify", 6, 6},
{&__NR_mq_getsetattr, "mq_getsetattr", 6, 6},
{&__NR_kexec_load, "kexec_load", 6, 6},
{&__NR_waitid, "waitid", 6, 6},
{&__NR_add_key, "add_key", 6, 6},
{&__NR_request_key, "request_key", 6, 6},
{&__NR_keyctl, "keyctl", 6, 6},
{&__NR_ioprio_set, "ioprio_set", 6, 6},
{&__NR_ioprio_get, "ioprio_get", 6, 6},
{&__NR_inotify_init, "inotify_init", 6, 6},
{&__NR_inotify_add_watch, "inotify_add_watch", 6, 6},
{&__NR_inotify_rm_watch, "inotify_rm_watch", 6, 6},
{&__NR_openat, "openat", 4, 4, INT, {INT, STR, INT, OCTAL|INT}},
{&__NR_mkdirat, "mkdirat", 3, 3, INT, {INT, STR, OCTAL|INT}},
{&__NR_fchownat, "fchownat", 6, 6},
{&__NR_utime, "utime", 6, 6},
{&__NR_utimes, "utimes", 6, 6},
{&__NR_futimesat, "futimesat", 6, 6},
{&__NR_futimes, "futimes", 6, 6},
{&__NR_futimens, "futimens", 6, 6},
{&__NR_fstatat, "newfstatat", 4, 2, INT, {INT, STR, STAT, INT}},
{&__NR_unlinkat, "unlinkat", 3, 3, INT, {INT, STR, INT}},
{&__NR_renameat, "renameat", 4, 4, INT, {INT, STR, INT, STR}},
{&__NR_linkat, "linkat", 6, 6},
{&__NR_symlinkat, "symlinkat", 6, 6},
{&__NR_readlinkat, "readlinkat", 6, 6},
{&__NR_fchmodat, "fchmodat", 6, 6},
{&__NR_faccessat, "faccessat", 4, 4, INT, {INT, STR, INT, INT}},
{&__NR_unshare, "unshare", 6, 6},
{&__NR_splice, "splice", 6, 6},
{&__NR_tee, "tee", 6, 6},
{&__NR_sync_file_range, "sync_file_range", 4, 4},
{&__NR_vmsplice, "vmsplice", 6, 6},
{&__NR_migrate_pages, "migrate_pages", 6, 6},
{&__NR_move_pages, "move_pages", 6, 6},
{&__NR_preadv, "preadv", 4, 1, LONG, {INT, IOV, ULONG, ULONG}},
{&__NR_pwritev, "pwritev", 6, 6, LONG, {INT, IOV, ULONG, ULONG}},
{&__NR_utimensat, "utimensat", 6, 6},
{&__NR_fallocate, "fallocate", 6, 6},
{&__NR_posix_fallocate, "posix_fallocate", 6, 6},
{&__NR_accept4, "accept4", 4, 4},
{&__NR_dup3, "dup3", 3, 3, INT},
{&__NR_epoll_pwait, "epoll_pwait", 6, 6},
{&__NR_epoll_create1, "epoll_create1", 6, 6},
{&__NR_perf_event_open, "perf_event_open", 6, 6},
{&__NR_inotify_init1, "inotify_init1", 6, 6},
{&__NR_tgsigqueueinfo, "rt_tgsigqueueinfo", 6, 6},
2022-04-06 16:12:05 +00:00
{&__NR_signalfd, "signalfd", 6, 6},
{&__NR_signalfd4, "signalfd4", 6, 6},
{&__NR_eventfd, "eventfd", 6, 6},
{&__NR_eventfd2, "eventfd2", 6, 6},
{&__NR_timerfd_create, "timerfd_create", 6, 6},
{&__NR_timerfd_settime, "timerfd_settime", 6, 6},
{&__NR_timerfd_gettime, "timerfd_gettime", 6, 6},
{&__NR_recvmmsg, "recvmmsg", 6, 6},
{&__NR_fanotify_init, "fanotify_init", 6, 6},
{&__NR_fanotify_mark, "fanotify_mark", 6, 6},
{&__NR_prlimit, "prlimit", 6, 6},
{&__NR_name_to_handle_at, "name_to_handle_at", 6, 6},
{&__NR_open_by_handle_at, "open_by_handle_at", 6, 6},
{&__NR_clock_adjtime, "clock_adjtime", 6, 6},
{&__NR_syncfs, "syncfs", 6, 6},
{&__NR_sendmmsg, "sendmmsg", 6, 6},
{&__NR_setns, "setns", 6, 6},
{&__NR_getcpu, "getcpu", 6, 6},
{&__NR_process_vm_readv, "process_vm_readv", 6, 6},
{&__NR_process_vm_writev, "process_vm_writev", 6, 6},
{&__NR_kcmp, "kcmp", 6, 6},
{&__NR_finit_module, "finit_module", 6, 6},
{&__NR_sched_setattr, "sched_setattr", 6, 6},
{&__NR_sched_getattr, "sched_getattr", 6, 6},
{&__NR_renameat2, "renameat2", 6, 6},
{&__NR_seccomp, "seccomp", 6, 6},
{&__NR_getrandom, "getrandom", 6, 6},
{&__NR_memfd_create, "memfd_create", 6, 6},
{&__NR_kexec_file_load, "kexec_file_load", 6, 6},
{&__NR_bpf, "bpf", 6, 6},
{&__NR_execveat, "execveat", 6, 6},
{&__NR_userfaultfd, "userfaultfd", 6, 6},
{&__NR_membarrier, "membarrier", 6, 6},
{&__NR_mlock2, "mlock2", 6, 6},
{&__NR_copy_file_range, "copy_file_range", 6, 6},
{&__NR_preadv2, "preadv2", 6, 6},
{&__NR_pwritev2, "pwritev2", 6, 6},
{&__NR_pkey_mprotect, "pkey_mprotect", 6, 6},
{&__NR_pkey_alloc, "pkey_alloc", 6, 6},
{&__NR_pkey_free, "pkey_free", 6, 6},
{&__NR_statx, "statx", 6, 6},
{&__NR_io_pgetevents, "io_pgetevents", 6, 6},
{&__NR_rseq, "rseq", 6, 6},
{&__NR_pidfd_send_signal, "pidfd_send_signal", 6, 6},
{&__NR_io_uring_setup, "io_uring_setup", 6, 6},
{&__NR_io_uring_enter, "io_uring_enter", 6, 6},
{&__NR_io_uring_register, "io_uring_register", 6, 6},
2022-03-24 15:00:21 +00:00
// clang-format on
};
static const struct Errno {
errno_t *number;
2022-03-24 15:00:21 +00:00
const char *name;
} kErrnos[] = {
{&ENOSYS, "ENOSYS"}, //
{&EPERM, "EPERM"}, //
{&ENOENT, "ENOENT"}, //
{&ESRCH, "ESRCH"}, //
{&EINTR, "EINTR"}, //
{&EIO, "EIO"}, //
{&ENXIO, "ENXIO"}, //
{&E2BIG, "E2BIG"}, //
{&ENOEXEC, "ENOEXEC"}, //
{&EBADF, "EBADF"}, //
{&ECHILD, "ECHILD"}, //
{&EAGAIN, "EAGAIN"}, //
{&ENOMEM, "ENOMEM"}, //
{&EACCES, "EACCES"}, //
{&EFAULT, "EFAULT"}, //
{&ENOTBLK, "ENOTBLK"}, //
{&EBUSY, "EBUSY"}, //
{&EEXIST, "EEXIST"}, //
{&EXDEV, "EXDEV"}, //
{&ENODEV, "ENODEV"}, //
{&ENOTDIR, "ENOTDIR"}, //
{&EISDIR, "EISDIR"}, //
{&EINVAL, "EINVAL"}, //
{&ENFILE, "ENFILE"}, //
{&EMFILE, "EMFILE"}, //
{&ENOTTY, "ENOTTY"}, //
{&ETXTBSY, "ETXTBSY"}, //
{&EFBIG, "EFBIG"}, //
{&ENOSPC, "ENOSPC"}, //
{&EDQUOT, "EDQUOT"}, //
{&ESPIPE, "ESPIPE"}, //
{&EROFS, "EROFS"}, //
{&EMLINK, "EMLINK"}, //
{&EPIPE, "EPIPE"}, //
{&EDOM, "EDOM"}, //
{&ERANGE, "ERANGE"}, //
{&EDEADLK, "EDEADLK"}, //
{&ENAMETOOLONG, "ENAMETOOLONG"}, //
{&ENOLCK, "ENOLCK"}, //
{&ENOTEMPTY, "ENOTEMPTY"}, //
{&ELOOP, "ELOOP"}, //
{&ENOMSG, "ENOMSG"}, //
{&EIDRM, "EIDRM"}, //
{&ETIME, "ETIME"}, //
{&EPROTO, "EPROTO"}, //
{&EOVERFLOW, "EOVERFLOW"}, //
{&EILSEQ, "EILSEQ"}, //
{&EUSERS, "EUSERS"}, //
{&ENOTSOCK, "ENOTSOCK"}, //
{&EDESTADDRREQ, "EDESTADDRREQ"}, //
{&EMSGSIZE, "EMSGSIZE"}, //
{&EPROTOTYPE, "EPROTOTYPE"}, //
{&ENOPROTOOPT, "ENOPROTOOPT"}, //
{&EPROTONOSUPPORT, "EPROTONOSUPPORT"}, //
{&ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT"}, //
{&ENOTSUP, "ENOTSUP"}, //
{&EOPNOTSUPP, "EOPNOTSUPP"}, //
{&EPFNOSUPPORT, "EPFNOSUPPORT"}, //
{&EAFNOSUPPORT, "EAFNOSUPPORT"}, //
{&EADDRINUSE, "EADDRINUSE"}, //
{&EADDRNOTAVAIL, "EADDRNOTAVAIL"}, //
{&ENETDOWN, "ENETDOWN"}, //
{&ENETUNREACH, "ENETUNREACH"}, //
{&ENETRESET, "ENETRESET"}, //
{&ECONNABORTED, "ECONNABORTED"}, //
{&ECONNRESET, "ECONNRESET"}, //
{&ENOBUFS, "ENOBUFS"}, //
{&EISCONN, "EISCONN"}, //
{&ENOTCONN, "ENOTCONN"}, //
{&ESHUTDOWN, "ESHUTDOWN"}, //
{&ETOOMANYREFS, "ETOOMANYREFS"}, //
{&ETIMEDOUT, "ETIMEDOUT"}, //
{&ECONNREFUSED, "ECONNREFUSED"}, //
{&EHOSTDOWN, "EHOSTDOWN"}, //
{&EHOSTUNREACH, "EHOSTUNREACH"}, //
{&EALREADY, "EALREADY"}, //
{&EINPROGRESS, "EINPROGRESS"}, //
{&ESTALE, "ESTALE"}, //
{&EREMOTE, "EREMOTE"}, //
{&EBADRPC, "EBADRPC"}, //
{&ERPCMISMATCH, "ERPCMISMATCH"}, //
{&EPROGUNAVAIL, "EPROGUNAVAIL"}, //
{&EPROGMISMATCH, "EPROGMISMATCH"}, //
{&EPROCUNAVAIL, "EPROCUNAVAIL"}, //
{&EFTYPE, "EFTYPE"}, //
{&EAUTH, "EAUTH"}, //
{&ENEEDAUTH, "ENEEDAUTH"}, //
{&EPROCLIM, "EPROCLIM"}, //
{&ENOATTR, "ENOATTR"}, //
{&EPWROFF, "EPWROFF"}, //
{&EDEVERR, "EDEVERR"}, //
{&EBADEXEC, "EBADEXEC"}, //
{&EBADARCH, "EBADARCH"}, //
{&ESHLIBVERS, "ESHLIBVERS"}, //
{&EBADMACHO, "EBADMACHO"}, //
{&ENOPOLICY, "ENOPOLICY"}, //
{&EBADMSG, "EBADMSG"}, //
{&ECANCELED, "ECANCELED"}, //
{&EOWNERDEAD, "EOWNERDEAD"}, //
{&ENOTRECOVERABLE, "ENOTRECOVERABLE"}, //
{&ENONET, "ENONET"}, //
{&ERESTART, "ERESTART"}, //
{&ENOSR, "ENOSR"}, //
{&ENOSTR, "ENOSTR"}, //
{&ENODATA, "ENODATA"}, //
{&EMULTIHOP, "EMULTIHOP"}, //
{&ENOLINK, "ENOLINK"}, //
{&ENOMEDIUM, "ENOMEDIUM"}, //
{&EMEDIUMTYPE, "EMEDIUMTYPE"}, //
{&EWOULDBLOCK, "EWOULDBLOCK"}, //
};
struct Pid {
int pid;
2022-04-06 19:32:43 +00:00
uint32_t hash;
2022-03-24 15:00:21 +00:00
bool insyscall;
struct Syscall *call;
2022-04-06 16:12:05 +00:00
struct Syscall fakecall;
2022-03-24 15:00:21 +00:00
struct user_regs_struct args;
2022-04-06 16:12:05 +00:00
char fakename[12];
};
struct PidList {
2022-04-06 19:32:43 +00:00
uint32_t i, n;
struct Pid *p;
2022-03-24 15:00:21 +00:00
};
char *ob; // output buffer
struct Pid *sp; // active subprocess
2022-04-06 19:32:43 +00:00
static uint32_t Hash(uint64_t pid) {
uint32_t hash;
hash = (pid * 6364136223846793005 + 1442695040888963407) >> 32;
if (!hash) hash = 1;
return hash;
}
2022-04-06 16:12:05 +00:00
static struct Pid *GetPid(struct PidList *list, int pid) {
2022-04-06 19:32:43 +00:00
uint32_t i, hash, step;
DCHECK_NE(0, pid);
DCHECK_LE(list->i, list->n >> 1);
if (list->n) {
i = 0;
step = 0;
hash = Hash(pid);
do {
i = (hash + step * (step + 1) / 2) & (list->n - 1);
if (list->p[i].pid == pid) {
return list->p + i;
}
step++;
} while (list->p[i].hash);
2022-04-06 16:12:05 +00:00
}
return 0;
}
2022-04-06 19:32:43 +00:00
static void ReservePid(struct PidList *list, int count) {
size_t i, j, step;
struct PidList old;
DCHECK_LE(list->i, list->n >> 1);
while (list->i + count >= (list->n >> 1)) {
memcpy(&old, list, sizeof(*list));
list->n = list->n ? list->n << 1 : 16;
list->p = calloc(list->n, sizeof(*list->p));
for (i = 0; i < old.n; ++i) {
if (!old.p[i].hash) continue;
step = 0;
do {
j = (old.p[i].hash + step * (step + 1) / 2) & (list->n - 1);
step++;
} while (list->p[j].hash);
list->p[j] = old.p[i];
}
free(old.p);
}
}
2022-04-06 16:12:05 +00:00
static struct Pid *AddPid(struct PidList *list, int pid) {
struct Pid *item;
2022-04-06 19:32:43 +00:00
uint32_t i, hash, step;
DCHECK_NE(0, pid);
DCHECK_LE(list->i, list->n >> 1);
2022-04-06 16:12:05 +00:00
if (!(item = GetPid(list, pid))) {
2022-04-06 19:32:43 +00:00
ReservePid(list, 1);
hash = Hash(pid);
++list->i;
i = 0;
step = 0;
do {
i = (hash + step * (step + 1) / 2) & (list->n - 1);
step++;
} while (list->p[i].hash);
list->p[i].hash = hash;
list->p[i].pid = pid;
item = list->p + i;
2022-04-06 16:12:05 +00:00
}
return item;
}
2022-04-06 19:32:43 +00:00
static void RemovePid(struct PidList *list, int pid) {
uint32_t i, hash, step;
DCHECK_NE(0, pid);
DCHECK_LE(list->i, list->n >> 1);
if (list->n) {
i = 0;
step = 0;
hash = Hash(pid);
do {
i = (hash + step * (step + 1) / 2) & (list->n - 1);
if (list->p[i].pid == pid) {
bzero(list->p + i, sizeof(*list->p));
list->i--;
assert(list->i < 99999);
return;
}
step++;
} while (list->p[i].hash);
}
2022-04-06 16:12:05 +00:00
}
2022-03-24 15:00:21 +00:00
static ssize_t WriteAll(int fd, const char *p, size_t n) {
ssize_t rc;
size_t i, got;
for (i = 0; i < n;) {
rc = write(fd, p + i, n - i);
if (rc != -1) {
got = rc;
i += got;
} else if (errno != EINTR) {
return -1;
}
}
return i;
}
static void Flush(void) {
WriteAll(2, ob, appendz(ob).i);
appendr(&ob, 0);
}
static const char *GetErrnoName(int x) {
2022-04-06 16:12:05 +00:00
const char *s;
2022-03-24 15:00:21 +00:00
static char buf[16];
if ((s = _strerrno(x))) return s;
FormatInt64(buf, x);
2022-03-24 15:00:21 +00:00
return buf;
}
static struct Syscall *GetSyscall(int x) {
int i;
2022-04-06 16:12:05 +00:00
if (x >= 0) {
2022-03-24 15:00:21 +00:00
for (i = 0; i < ARRAYLEN(kSyscalls); ++i) {
if (x == *kSyscalls[i].number) {
return kSyscalls + i;
}
}
}
return NULL;
}
static char *PeekString(unsigned long x) {
union {
char buf[8];
long word;
} u;
char *p;
unsigned offset;
unsigned long addr, i, n;
if (!x) return NULL;
addr = ROUNDDOWN(x, 8);
offset = x - addr;
2022-04-06 16:12:05 +00:00
errno = 0;
2022-03-24 15:00:21 +00:00
u.word = ptrace(PTRACE_PEEKTEXT, sp->pid, addr);
2022-04-06 16:12:05 +00:00
if (errno) return 0;
2022-03-24 15:00:21 +00:00
n = strnlen(u.buf + offset, 8 - offset);
2022-04-06 16:12:05 +00:00
p = calloc(1, n);
2022-03-24 15:00:21 +00:00
memcpy(p, u.buf + offset, n);
if (n == 8 - offset) {
do {
addr += 8;
2022-04-06 16:12:05 +00:00
errno = 0;
2022-03-24 15:00:21 +00:00
u.word = ptrace(PTRACE_PEEKDATA, sp->pid, addr);
2022-04-06 16:12:05 +00:00
if (errno) break;
2022-03-24 15:00:21 +00:00
i = strnlen(u.buf, 8);
p = realloc(p, n + i);
memcpy(p + n, u.buf, i);
n += i;
} while (i == 8);
}
p = realloc(p, n + 1);
p[n] = 0;
return p;
}
static char *PrintString(char *s) {
kappendf(&ob, "%#s", s);
return s;
}
static void *PeekData(unsigned long x, size_t size) {
2022-03-24 15:00:21 +00:00
union {
char buf[8];
long word;
} u;
char *p;
unsigned offset;
unsigned long addr, i, n;
if (!x) return NULL;
addr = ROUNDDOWN(x, 8);
offset = x - addr;
2022-04-06 16:12:05 +00:00
errno = 0;
2022-03-24 15:00:21 +00:00
u.word = ptrace(PTRACE_PEEKTEXT, sp->pid, addr);
2022-04-06 16:12:05 +00:00
if (errno) return 0;
p = calloc(1, size);
2022-04-06 19:32:43 +00:00
memcpy(p, u.buf + offset, MIN(size, 8 - offset));
2022-03-24 15:00:21 +00:00
for (i = 8 - offset; i < size; i += MIN(8, size - i)) {
addr += 8;
2022-04-06 16:12:05 +00:00
errno = 0;
2022-03-24 15:00:21 +00:00
u.word = ptrace(PTRACE_PEEKDATA, sp->pid, addr);
2022-04-06 16:12:05 +00:00
if (errno) break;
2022-03-24 15:00:21 +00:00
memcpy(p + i, u.buf, MIN(8, size - i));
}
return p;
}
static char *PrintData(char *data, size_t size) {
kappendf(&ob, "%#.*hhs%s", MIN(40, size), data, size > 40 ? "..." : "", data);
return data;
}
static struct iovec *PeekIov(unsigned long addr, int len) {
int i;
char *p;
long word;
struct iovec *iov;
if (!addr) return NULL;
2022-04-06 16:12:05 +00:00
p = calloc(1, len * 16);
2022-03-24 15:00:21 +00:00
for (i = 0; i < len * 2; ++i, addr += sizeof(word)) {
2022-04-06 16:12:05 +00:00
errno = 0;
2022-03-24 15:00:21 +00:00
word = ptrace(PTRACE_PEEKTEXT, sp->pid, addr);
2022-04-06 16:12:05 +00:00
if (errno) break;
2022-03-24 15:00:21 +00:00
memcpy(p + i * sizeof(word), &word, sizeof(word));
}
iov = (struct iovec *)p;
for (i = 0; i < len; ++i) {
2022-04-06 16:12:05 +00:00
errno = 0;
2022-03-24 15:00:21 +00:00
iov[i].iov_base = PeekData((long)iov[i].iov_base, iov[i].iov_len);
2022-04-06 16:12:05 +00:00
if (errno) break;
2022-03-24 15:00:21 +00:00
}
return iov;
}
static struct iovec *PrintIov(struct iovec *iov, int iovlen) {
int i;
if (iov) {
appendw(&ob, '{');
for (i = 0; i < iovlen; ++i) {
if (i) appendw(&ob, READ16LE(", "));
appendw(&ob, '{');
PrintData(iov[i].iov_base, iov[i].iov_len);
kappendf(&ob, ", %#lx}", iov[i].iov_len);
}
appendw(&ob, '}');
} else {
appendw(&ob, READ32LE("NULL"));
}
return iov;
}
static void FreeIov(struct iovec *iov, int iovlen) {
int i;
if (iov) {
for (i = 0; i < iovlen; ++i) {
free(iov[i].iov_base);
}
free(iov);
}
}
static char **PeekStringList(unsigned long addr) {
char *p;
long word;
size_t i, n;
char **list;
if (!addr) return NULL;
for (p = NULL, n = 0;; ++n) {
p = realloc(p, (n + 1) * sizeof(word));
word = ptrace(PTRACE_PEEKTEXT, sp->pid, addr + n * sizeof(word));
memcpy(p + n * sizeof(word), &word, sizeof(word));
if (!word) break;
}
list = (char **)p;
for (i = 0; i < n; ++i) {
list[i] = PeekString((long)list[i]);
}
return list;
}
static char **PrintStringList(char **list) {
int i;
if (list) {
appendw(&ob, '{');
for (i = 0;; ++i) {
if (i) appendw(&ob, READ16LE(", "));
PrintString(list[i]);
if (!list[i]) break;
}
appendw(&ob, '}');
} else {
appendw(&ob, READ32LE("NULL"));
}
return list;
}
static void FreeStringList(char **list) {
int i;
if (list) {
for (i = 0; list[i]; ++i) {
free(list[i]);
}
free(list);
}
}
2022-04-06 16:12:05 +00:00
static void PrintPipe(unsigned long addr) {
unsigned long word;
word = ptrace(PTRACE_PEEKDATA, sp->pid, addr);
kappendf(&ob, "[{%d, %d}]", (int)word, (int)(word >> 32));
}
2022-03-24 15:00:21 +00:00
static struct stat *PeekStat(unsigned long addr) {
int i;
char *p;
long word;
if (!addr) return NULL;
2022-04-06 16:12:05 +00:00
p = calloc(1, sizeof(struct stat));
2022-03-24 15:00:21 +00:00
for (i = 0; i < sizeof(struct stat); i += sizeof(word)) {
2022-04-06 16:12:05 +00:00
errno = 0;
2022-03-24 15:00:21 +00:00
word = ptrace(PTRACE_PEEKTEXT, sp->pid, addr + i);
2022-04-06 16:12:05 +00:00
if (errno) break;
2022-03-24 15:00:21 +00:00
memcpy(p + i, &word, sizeof(word));
}
return (struct stat *)p;
}
static struct stat *PrintStat(struct stat *st) {
bool printed;
printed = false;
appendw(&ob, '{');
if (st->st_size) {
kappendf(&ob, ".st_size = %#lx", st->st_size);
printed = true;
}
if (st->st_mode) {
if (printed) appendw(&ob, READ16LE(", "));
kappendf(&ob, ".st_mode = %#o", st->st_mode);
printed = true;
}
appendw(&ob, '}');
return st;
}
static void PrintSigset(unsigned long p) {
kappendf(&ob, "{%#lx}", ptrace(PTRACE_PEEKTEXT, sp->pid, p));
}
2022-03-24 15:00:21 +00:00
static void PrintSyscallArg(int type, unsigned long x, unsigned long y) {
char *s;
switch (type & 31) {
case ULONG:
kappendf(&ob, "%#lx", x);
break;
case INT:
if (type & OCTAL) {
kappendf(&ob, "%#o", x);
} else {
kappendf(&ob, "%d", x);
}
break;
case LONG:
kappendf(&ob, "%ld", x);
break;
case STR:
free(PrintString(PeekString(x)));
break;
case BUF:
2022-04-06 16:12:05 +00:00
free(PrintData(PeekData(x, MIN(32, y)), MIN(32, y)));
2022-03-24 15:00:21 +00:00
break;
case IOV:
FreeIov(PrintIov(PeekIov(x, y), y), y);
break;
case STAT:
free(PrintStat(PeekStat(x)));
break;
2022-04-06 16:12:05 +00:00
case PIPE:
PrintPipe(x);
break;
2022-03-24 15:00:21 +00:00
case SIG:
appends(&ob, strsignal(x));
break;
case SIGSET:
PrintSigset(x);
break;
2022-03-24 15:00:21 +00:00
case STRLIST:
FreeStringList(PrintStringList(PeekStringList(x)));
break;
case INTPTR:
if (x) {
s = PeekData(x, 4);
kappendf(&ob, "{%d}", READ32LE(s));
free(s);
}
break;
default:
kappendf(&ob, "wut[%'ld]", x);
break;
}
}
2022-04-06 16:12:05 +00:00
static void PrintSyscall(bool issecond) {
int a, b, eager, arity;
bool gotsome, isresuming, isunfinished;
gotsome = false;
if (issecond) {
if (!sp->call) {
return;
}
} else {
if (!(sp->call = GetSyscall(sp->args.orig_rax))) {
ksnprintf(sp->fakename, sizeof(sp->fakename), "%d", sp->args.orig_rax);
bzero(&sp->fakecall, sizeof(sp->fakecall));
sp->call = &sp->fakecall;
sp->call->name = sp->fakename;
sp->call->arity = 6;
sp->call->eager = 6;
}
if (sp->args.orig_rax == __NR_execve) {
if (sp->args.rax == -ENOSYS) {
sp->args.rax = 0;
2022-03-24 15:00:21 +00:00
}
2022-04-06 16:12:05 +00:00
} else if (sp->args.rax == -ENOSYS) {
return;
2022-03-24 15:00:21 +00:00
}
}
2022-04-06 16:12:05 +00:00
isresuming = false;
isunfinished = false;
if (!isunfinished) {
a = 0;
b = sp->call->arity;
} else if (!isresuming) {
a = 0;
b = sp->call->eager;
} else {
a = sp->call->eager;
b = sp->call->arity;
}
kappendf(&ob, PROLOGUE " %s%s(", sp->pid, isresuming ? "<resuming> " : "",
sp->call->name);
if (a <= 0 && 0 < b) {
if (gotsome) appendw(&ob, READ16LE(", "));
PrintSyscallArg(sp->call->arg[0], sp->args.rdi, sp->args.rsi);
gotsome = true;
}
if (a <= 1 && 1 < b) {
if (gotsome) appendw(&ob, READ16LE(", "));
PrintSyscallArg(sp->call->arg[1], sp->args.rsi, sp->args.rdx);
gotsome = true;
}
if (a <= 2 && 2 < b) {
if (gotsome) appendw(&ob, READ16LE(", "));
PrintSyscallArg(sp->call->arg[2], sp->args.rdx, sp->args.r10);
gotsome = true;
}
if (a <= 3 && 3 < b) {
if (gotsome) appendw(&ob, READ16LE(", "));
PrintSyscallArg(sp->call->arg[3], sp->args.r10, sp->args.r8);
gotsome = true;
}
if (a <= 4 && 4 < b) {
if (gotsome) appendw(&ob, READ16LE(", "));
PrintSyscallArg(sp->call->arg[4], sp->args.r8, sp->args.r9);
gotsome = true;
}
if (a <= 5 && 5 < b) {
if (gotsome) appendw(&ob, READ16LE(", "));
PrintSyscallArg(sp->call->arg[5], sp->args.r9, 0);
gotsome = true;
}
if (isunfinished) {
appends(&ob, ") → <unfinished>");
} else {
appends(&ob, ") → ");
if (sp->args.rax > (unsigned long)-4096) {
kappendf(&ob, "-1 %s", GetErrnoName(-sp->args.rax));
2022-03-24 15:00:21 +00:00
} else {
2022-04-06 16:12:05 +00:00
PrintSyscallArg(sp->call->ret, sp->args.rax, 0);
2022-03-24 15:00:21 +00:00
}
}
2022-04-06 16:12:05 +00:00
kappendf(&ob, "%n");
Flush();
sp->call = 0;
2022-03-24 15:00:21 +00:00
}
wontreturn void PropagateExit(int wstatus) {
exit(WEXITSTATUS(wstatus));
}
wontreturn void PropagateTermination(int wstatus) {
sigset_t mask;
// if signal that terminated program was sent to our whole
// process group, then that signal should be delivered and kill
// this process the moment it's unblocked here. we only unblock
// here because if the child process ignores the signal and does
// exit(0) then we want to propagate that intent too.
sigemptyset(&mask);
sigaddset(&mask, WTERMSIG(wstatus));
sigprocmask(SIG_UNBLOCK, &mask, 0);
// otherwise we can propagate it by the exit code convention
// commonly used with shell scripts
exit(128 + WTERMSIG(wstatus));
}
wontreturn void StraceMain(int argc, char *argv[]) {
unsigned long msg;
struct siginfo si;
2022-04-06 16:12:05 +00:00
struct Pid *s, *child;
struct PidList pidlist;
sigset_t mask, origmask;
2022-04-06 16:12:05 +00:00
int i, sig, evpid, root, wstatus, signal;
struct sigaction sigign, saveint, savequit;
2022-03-24 15:00:21 +00:00
if (!IsLinux()) {
kprintf("error: ptrace() is only supported on linux right now%n");
exit(1);
}
if (IsModeDbg()) ShowCrashReports();
if (argc < 2) {
kprintf("Usage: %s PROGRAM [ARGS...]%n", argv[0]);
exit(1);
}
2022-04-06 19:32:43 +00:00
pidlist.i = 0;
pidlist.n = 0;
pidlist.p = 0;
2022-03-24 15:00:21 +00:00
sigign.sa_flags = 0;
sigign.sa_handler = SIG_IGN;
sigemptyset(&sigign.sa_mask);
sigaction(SIGINT, &sigign, &saveint);
sigaction(SIGQUIT, &sigign, &savequit);
2022-03-24 15:00:21 +00:00
sigemptyset(&mask);
/* sigaddset(&mask, SIGCHLD); */
sigprocmask(SIG_BLOCK, &mask, &origmask);
2022-03-24 15:00:21 +00:00
CHECK_NE(-1, (root = fork()));
2022-04-06 16:12:05 +00:00
if (!root) {
sigaction(SIGINT, &saveint, 0);
sigaction(SIGQUIT, &savequit, 0);
sigprocmask(SIG_SETMASK, &origmask, 0);
2022-03-24 15:00:21 +00:00
ptrace(PTRACE_TRACEME);
execvp(argv[1], argv + 1);
_Exit(127);
}
2022-04-06 16:12:05 +00:00
sp = AddPid(&pidlist, root);
2022-03-24 15:00:21 +00:00
// wait for ptrace(PTRACE_TRACEME) to be called
CHECK_EQ(sp->pid, waitpid(sp->pid, &wstatus, 0));
// configure linux process tracing
CHECK_NE(-1, ptrace(PTRACE_SETOPTIONS, sp->pid, 0,
2022-04-06 16:12:05 +00:00
(PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK |
PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC |
PTRACE_O_TRACEEXIT | PTRACE_O_TRACESYSGOOD)));
2022-03-24 15:00:21 +00:00
// continue child process setting breakpoint at next system call
CHECK_NE(-1, ptrace(PTRACE_SYSCALL, sp->pid, 0, 0));
for (;;) {
2022-04-06 16:12:05 +00:00
CHECK_NE(-1, (evpid = waitpid(-1, &wstatus, __WALL)));
2022-03-24 15:00:21 +00:00
2022-04-06 19:32:43 +00:00
// prevent rehash in second addpid call
ReservePid(&pidlist, 2);
2022-04-06 16:12:05 +00:00
// we can get wait notifications before fork/vfork/etc. events
sp = AddPid(&pidlist, evpid);
2022-03-24 15:00:21 +00:00
// handle actual exit
if (WIFEXITED(wstatus)) {
kprintf(PROLOGUE " exited with %d%n", sp->pid, WEXITSTATUS(wstatus));
2022-04-06 19:32:43 +00:00
RemovePid(&pidlist, sp->pid);
2022-03-24 15:00:21 +00:00
sp = 0;
// we exit when the last process being monitored exits
2022-04-06 19:32:43 +00:00
if (!pidlist.i) {
2022-03-24 15:00:21 +00:00
PropagateExit(wstatus);
} else {
continue;
}
}
// handle actual kill
if (WIFSIGNALED(wstatus)) {
kprintf(PROLOGUE " exited with signal %G%n", sp->pid, WTERMSIG(wstatus));
RemovePid(&pidlist, sp->pid);
sp = 0;
// we die when the last process being monitored dies
if (!pidlist.i) {
PropagateTermination(wstatus);
} else {
continue;
}
}
// handle core dump
if (WCOREDUMP(wstatus)) {
kprintf(PROLOGUE " exited with core%n", sp->pid);
2022-04-06 19:32:43 +00:00
RemovePid(&pidlist, sp->pid);
2022-03-24 15:00:21 +00:00
sp = 0;
// we die when the last process being monitored dies
2022-04-06 19:32:43 +00:00
if (!pidlist.i) {
2022-03-24 15:00:21 +00:00
PropagateTermination(wstatus);
} else {
continue;
}
}
// handle trace events
2022-04-06 16:12:05 +00:00
sig = 0;
2022-03-24 15:00:21 +00:00
signal = (wstatus >> 8) & 0xffff;
2022-04-06 16:12:05 +00:00
assert(WIFSTOPPED(wstatus));
if (signal == SIGTRAP | PTRACE_EVENT_STOP) {
CHECK_NE(-1, ptrace(PTRACE_GETSIGINFO, sp->pid, 0, &si));
if (si.si_code == SIGTRAP || si.si_code == SIGTRAP | 0x80) {
CHECK_NE(-1, ptrace(PTRACE_GETREGS, sp->pid, 0, &sp->args));
PrintSyscall(sp->insyscall);
sp->insyscall = !sp->insyscall;
ptrace(PTRACE_SYSCALL, sp->pid, 0, 0);
} else {
sig = signal & 127;
kappendf(&ob, PROLOGUE " got signal %G%n", sp->pid, sig);
Flush();
ptrace(PTRACE_SYSCALL, sp->pid, 0, sig);
}
2022-04-06 16:12:05 +00:00
} else if (signal == (SIGTRAP | (PTRACE_EVENT_EXIT << 8))) {
2022-03-24 15:00:21 +00:00
CHECK_NE(-1, ptrace(PTRACE_GETEVENTMSG, sp->pid, 0, &msg));
2022-04-06 16:12:05 +00:00
sig = WSTOPSIG(wstatus);
ptrace(PTRACE_SYSCALL, sp->pid, 0, 0);
2022-04-06 16:12:05 +00:00
} else if (signal == (SIGTRAP | (PTRACE_EVENT_EXEC << 8))) {
CHECK_NE(-1, ptrace(PTRACE_GETEVENTMSG, sp->pid, 0, &msg));
ptrace(PTRACE_SYSCALL, sp->pid, 0, 0);
} else if (signal == (SIGTRAP | (PTRACE_EVENT_FORK << 8)) ||
signal == (SIGTRAP | (PTRACE_EVENT_VFORK << 8)) ||
signal == (SIGTRAP | (PTRACE_EVENT_CLONE << 8))) {
2022-04-06 16:12:05 +00:00
CHECK_NE(-1, ptrace(PTRACE_GETEVENTMSG, evpid, 0, &msg));
child = AddPid(&pidlist, msg);
child->pid = msg;
2022-03-24 15:00:21 +00:00
if (signal == (SIGTRAP | (PTRACE_EVENT_FORK << 8))) {
2022-04-06 16:12:05 +00:00
kappendf(&ob, PROLOGUE " fork() → %d%n", sp->pid, child->pid);
2022-03-24 15:00:21 +00:00
} else if (signal == (SIGTRAP | (PTRACE_EVENT_VFORK << 8))) {
2022-04-06 16:12:05 +00:00
kappendf(&ob, PROLOGUE " vfork() → %d%n", sp->pid, child->pid);
2022-03-24 15:00:21 +00:00
} else {
2022-04-06 16:12:05 +00:00
kappendf(&ob, PROLOGUE " clone() → %d%n", sp->pid, child->pid);
2022-03-24 15:00:21 +00:00
}
Flush();
2022-04-06 16:12:05 +00:00
ptrace(PTRACE_SYSCALL, child->pid, 0, 0);
ptrace(PTRACE_SYSCALL, sp->pid, 0, 0);
2022-03-24 15:00:21 +00:00
} else {
kappendf(&ob, PROLOGUE " gottish signal %G%n", sp->pid, sig);
Flush();
ptrace(PTRACE_SYSCALL, sp->pid, 0, signal & 127);
2022-03-24 15:00:21 +00:00
}
}
}
int main(int argc, char *argv[]) {
StraceMain(argc, argv);
}