10f66f451Sopenharmony_ci/* strace.c - Trace system calls. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2020 The Android Open Source Project 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * See https://man7.org/linux/man-pages/man2/syscall.2.html 60f66f451Sopenharmony_ci 70f66f451Sopenharmony_ciUSE_STRACE(NEWTOY(strace, "^p#s#v", TOYFLAG_USR|TOYFLAG_SBIN)) 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ciconfig STRACE 100f66f451Sopenharmony_ci bool "strace" 110f66f451Sopenharmony_ci default n 120f66f451Sopenharmony_ci help 130f66f451Sopenharmony_ci usage: strace [-fv] [-p PID] [-s NUM] COMMAND [ARGS...] 140f66f451Sopenharmony_ci 150f66f451Sopenharmony_ci Trace systems calls made by a process. 160f66f451Sopenharmony_ci 170f66f451Sopenharmony_ci -s String length limit. 180f66f451Sopenharmony_ci -v Dump all of large structs/arrays. 190f66f451Sopenharmony_ci*/ 200f66f451Sopenharmony_ci 210f66f451Sopenharmony_ci#include <sys/ptrace.h> 220f66f451Sopenharmony_ci#include <sys/syscall.h> 230f66f451Sopenharmony_ci#include <sys/user.h> 240f66f451Sopenharmony_ci 250f66f451Sopenharmony_ci#define FOR_strace 260f66f451Sopenharmony_ci#include "toys.h" 270f66f451Sopenharmony_ci 280f66f451Sopenharmony_ciGLOBALS( 290f66f451Sopenharmony_ci long s, p; 300f66f451Sopenharmony_ci 310f66f451Sopenharmony_ci char ioctl[32], *fmt; 320f66f451Sopenharmony_ci long regs[256/sizeof(long)], syscall; 330f66f451Sopenharmony_ci pid_t pid; 340f66f451Sopenharmony_ci int arg; 350f66f451Sopenharmony_ci) 360f66f451Sopenharmony_ci 370f66f451Sopenharmony_ci struct user_regs_struct regs; 380f66f451Sopenharmony_ci 390f66f451Sopenharmony_ci 400f66f451Sopenharmony_ci// Syscall args from https://man7.org/linux/man-pages/man2/syscall.2.html 410f66f451Sopenharmony_ci// REG_ORDER is args 0-6, SYSCALL, RESULT 420f66f451Sopenharmony_ci#if defined(__ARM_EABI__) 430f66f451Sopenharmony_cistatic const char REG_ORDER[] = {0,1,2,3,4,5,7,0}; 440f66f451Sopenharmony_ci#elif defined(__ARM_ARCH) && __ARM_ARCH == 8 450f66f451Sopenharmony_cistatic const char REG_ORDER[] = {0,1,2,3,4,5,8,0}; 460f66f451Sopenharmony_ci#elif defined(__i386__) 470f66f451Sopenharmony_ci// ebx,ecx,edx,esi,edi,ebp,orig_eax,eax 480f66f451Sopenharmony_cistatic const char REG_ORDER[] = {0,1,2,3,4,5,11,6}; 490f66f451Sopenharmony_ci#elif defined(__m68k__) 500f66f451Sopenharmony_ci// d1,d2,d3,d4,d5,a0,orig_d0,d0 510f66f451Sopenharmony_cistatic const char REG_ORDER[] = {0,1,2,3,4,7,16,14); 520f66f451Sopenharmony_ci#elif defined(__PPC__) || defined(__PPC64__) 530f66f451Sopenharmony_cistatic const char REG_ORDER[] = {3,4,5,6,7,8,0,3}; 540f66f451Sopenharmony_ci#elif defined(__s390__) // also covers s390x 550f66f451Sopenharmony_ci// r2,r3,r4,r5,r6,r7,r1,r2 but mask+addr before r0 so +2 560f66f451Sopenharmony_cistatic const char REG_ORDER[] = {4,5,6,7,8,9,3,4}; 570f66f451Sopenharmony_ci#elif defined(__sh__) 580f66f451Sopenharmony_cistatic const char REG_ORDER[] = {4,5,6,7,0,1,3,0}; 590f66f451Sopenharmony_ci#elif defined(__x86_64__) 600f66f451Sopenharmony_ci// rdi,rsi,rdx,r10,r8,r9,orig_rax,rax 610f66f451Sopenharmony_cistatic const char REG_ORDER[] = {14,13,12,7,9,8,15,10}; 620f66f451Sopenharmony_ci#else 630f66f451Sopenharmony_ci#error unsupported architecture 640f66f451Sopenharmony_ci#endif 650f66f451Sopenharmony_ci 660f66f451Sopenharmony_ci#define C(x) case x: return #x 670f66f451Sopenharmony_ci 680f66f451Sopenharmony_ci#define FS_IOC_FSGETXATTR 0x801c581f 690f66f451Sopenharmony_ci#define FS_IOC_FSSETXATTR 0x401c5820 700f66f451Sopenharmony_ci#define FS_IOC_GETFLAGS 0x80086601 710f66f451Sopenharmony_ci#define FS_IOC_SETFLAGS 0x40086602 720f66f451Sopenharmony_ci#define FS_IOC_GETVERSION 0x80087601 730f66f451Sopenharmony_ci#define FS_IOC_SETVERSION 0x40047602 740f66f451Sopenharmony_cistruct fsxattr { 750f66f451Sopenharmony_ci unsigned fsx_xflags; 760f66f451Sopenharmony_ci unsigned fsx_extsize; 770f66f451Sopenharmony_ci unsigned fsx_nextents; 780f66f451Sopenharmony_ci unsigned fsx_projid; 790f66f451Sopenharmony_ci unsigned fsx_cowextsize; 800f66f451Sopenharmony_ci char fsx_pad[8]; 810f66f451Sopenharmony_ci}; 820f66f451Sopenharmony_ci 830f66f451Sopenharmony_cistatic char *strioctl(int i) 840f66f451Sopenharmony_ci{ 850f66f451Sopenharmony_ci switch (i) { 860f66f451Sopenharmony_ci C(FS_IOC_FSGETXATTR); 870f66f451Sopenharmony_ci C(FS_IOC_FSSETXATTR); 880f66f451Sopenharmony_ci C(FS_IOC_GETFLAGS); 890f66f451Sopenharmony_ci C(FS_IOC_GETVERSION); 900f66f451Sopenharmony_ci C(FS_IOC_SETFLAGS); 910f66f451Sopenharmony_ci C(FS_IOC_SETVERSION); 920f66f451Sopenharmony_ci C(SIOCGIFADDR); 930f66f451Sopenharmony_ci C(SIOCGIFBRDADDR); 940f66f451Sopenharmony_ci C(SIOCGIFCONF); 950f66f451Sopenharmony_ci C(SIOCGIFDSTADDR); 960f66f451Sopenharmony_ci C(SIOCGIFFLAGS); 970f66f451Sopenharmony_ci C(SIOCGIFHWADDR); 980f66f451Sopenharmony_ci C(SIOCGIFMAP); 990f66f451Sopenharmony_ci C(SIOCGIFMTU); 1000f66f451Sopenharmony_ci C(SIOCGIFNETMASK); 1010f66f451Sopenharmony_ci C(SIOCGIFTXQLEN); 1020f66f451Sopenharmony_ci C(TCGETS); 1030f66f451Sopenharmony_ci C(TCSETS); 1040f66f451Sopenharmony_ci C(TIOCGWINSZ); 1050f66f451Sopenharmony_ci C(TIOCSWINSZ); 1060f66f451Sopenharmony_ci } 1070f66f451Sopenharmony_ci sprintf(toybuf, "%#x", i); 1080f66f451Sopenharmony_ci return toybuf; 1090f66f451Sopenharmony_ci} 1100f66f451Sopenharmony_ci 1110f66f451Sopenharmony_ci// TODO: move to lib, implement errno(1)? 1120f66f451Sopenharmony_cistatic char *strerrno(int e) 1130f66f451Sopenharmony_ci{ 1140f66f451Sopenharmony_ci switch (e) { 1150f66f451Sopenharmony_ci // uapi errno-base.h 1160f66f451Sopenharmony_ci C(EPERM); 1170f66f451Sopenharmony_ci C(ENOENT); 1180f66f451Sopenharmony_ci C(ESRCH); 1190f66f451Sopenharmony_ci C(EINTR); 1200f66f451Sopenharmony_ci C(EIO); 1210f66f451Sopenharmony_ci C(ENXIO); 1220f66f451Sopenharmony_ci C(E2BIG); 1230f66f451Sopenharmony_ci C(ENOEXEC); 1240f66f451Sopenharmony_ci C(EBADF); 1250f66f451Sopenharmony_ci C(ECHILD); 1260f66f451Sopenharmony_ci C(EAGAIN); 1270f66f451Sopenharmony_ci C(ENOMEM); 1280f66f451Sopenharmony_ci C(EACCES); 1290f66f451Sopenharmony_ci C(EFAULT); 1300f66f451Sopenharmony_ci C(ENOTBLK); 1310f66f451Sopenharmony_ci C(EBUSY); 1320f66f451Sopenharmony_ci C(EEXIST); 1330f66f451Sopenharmony_ci C(EXDEV); 1340f66f451Sopenharmony_ci C(ENODEV); 1350f66f451Sopenharmony_ci C(ENOTDIR); 1360f66f451Sopenharmony_ci C(EISDIR); 1370f66f451Sopenharmony_ci C(EINVAL); 1380f66f451Sopenharmony_ci C(ENFILE); 1390f66f451Sopenharmony_ci C(EMFILE); 1400f66f451Sopenharmony_ci C(ENOTTY); 1410f66f451Sopenharmony_ci C(ETXTBSY); 1420f66f451Sopenharmony_ci C(EFBIG); 1430f66f451Sopenharmony_ci C(ENOSPC); 1440f66f451Sopenharmony_ci C(ESPIPE); 1450f66f451Sopenharmony_ci C(EROFS); 1460f66f451Sopenharmony_ci C(EMLINK); 1470f66f451Sopenharmony_ci C(EPIPE); 1480f66f451Sopenharmony_ci C(EDOM); 1490f66f451Sopenharmony_ci C(ERANGE); 1500f66f451Sopenharmony_ci // uapi errno.h 1510f66f451Sopenharmony_ci C(EDEADLK); 1520f66f451Sopenharmony_ci C(ENAMETOOLONG); 1530f66f451Sopenharmony_ci C(ENOLCK); 1540f66f451Sopenharmony_ci C(ENOSYS); 1550f66f451Sopenharmony_ci C(ENOTEMPTY); 1560f66f451Sopenharmony_ci C(ELOOP); 1570f66f451Sopenharmony_ci C(ENOMSG); 1580f66f451Sopenharmony_ci // ...etc; fill in as we see them in practice? 1590f66f451Sopenharmony_ci } 1600f66f451Sopenharmony_ci sprintf(toybuf, "%d", e); 1610f66f451Sopenharmony_ci return toybuf; 1620f66f451Sopenharmony_ci} 1630f66f451Sopenharmony_ci 1640f66f451Sopenharmony_ci#undef C 1650f66f451Sopenharmony_ci 1660f66f451Sopenharmony_cistatic void xptrace(int req, pid_t pid, void *addr, void *data) 1670f66f451Sopenharmony_ci{ 1680f66f451Sopenharmony_ci if (ptrace(req, pid, addr, data)) perror_exit("ptrace pid %d", pid); 1690f66f451Sopenharmony_ci} 1700f66f451Sopenharmony_ci 1710f66f451Sopenharmony_cistatic void get_regs() 1720f66f451Sopenharmony_ci{ 1730f66f451Sopenharmony_ci xptrace(PTRACE_GETREGS, TT.pid, 0, TT.regs); 1740f66f451Sopenharmony_ci} 1750f66f451Sopenharmony_ci 1760f66f451Sopenharmony_cistatic void ptrace_struct(long addr, void *dst, size_t bytes) 1770f66f451Sopenharmony_ci{ 1780f66f451Sopenharmony_ci int offset = 0, i; 1790f66f451Sopenharmony_ci long v; 1800f66f451Sopenharmony_ci 1810f66f451Sopenharmony_ci for (i=0; i<bytes; i+=sizeof(long)) { 1820f66f451Sopenharmony_ci errno = 0; 1830f66f451Sopenharmony_ci v = ptrace(PTRACE_PEEKDATA, TT.pid, addr + offset); 1840f66f451Sopenharmony_ci if (errno) perror_exit("PTRACE_PEEKDATA failed"); 1850f66f451Sopenharmony_ci memcpy(dst + offset, &v, sizeof(v)); 1860f66f451Sopenharmony_ci offset += sizeof(long); 1870f66f451Sopenharmony_ci } 1880f66f451Sopenharmony_ci} 1890f66f451Sopenharmony_ci 1900f66f451Sopenharmony_ci// TODO: this all relies on having the libc structs match the kernel structs, 1910f66f451Sopenharmony_ci// which isn't always true for glibc... 1920f66f451Sopenharmony_cistatic void print_struct(long addr) 1930f66f451Sopenharmony_ci{ 1940f66f451Sopenharmony_ci if (!addr) { // All NULLs look the same... 1950f66f451Sopenharmony_ci fprintf(stderr, "NULL"); 1960f66f451Sopenharmony_ci while (*TT.fmt != '}') ++TT.fmt; 1970f66f451Sopenharmony_ci ++TT.fmt; 1980f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "ifreq}")) { 1990f66f451Sopenharmony_ci struct ifreq ir; 2000f66f451Sopenharmony_ci 2010f66f451Sopenharmony_ci ptrace_struct(addr, &ir, sizeof(ir)); 2020f66f451Sopenharmony_ci // TODO: is this always an ioctl? use TT.regs[REG_ORDER[1]] to work out what to show. 2030f66f451Sopenharmony_ci fprintf(stderr, "{...}"); 2040f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "fsxattr}")) { 2050f66f451Sopenharmony_ci struct fsxattr fx; 2060f66f451Sopenharmony_ci 2070f66f451Sopenharmony_ci ptrace_struct(addr, &fx, sizeof(fx)); 2080f66f451Sopenharmony_ci fprintf(stderr, "{fsx_xflags=%#x, fsx_extsize=%d, fsx_nextents=%d, " 2090f66f451Sopenharmony_ci "fsx_projid=%d, fsx_cowextsize=%d}", fx.fsx_xflags, fx.fsx_extsize, 2100f66f451Sopenharmony_ci fx.fsx_nextents, fx.fsx_projid, fx.fsx_cowextsize); 2110f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "long}")) { 2120f66f451Sopenharmony_ci long l; 2130f66f451Sopenharmony_ci 2140f66f451Sopenharmony_ci ptrace_struct(addr, &l, sizeof(l)); 2150f66f451Sopenharmony_ci fprintf(stderr, "%ld", l); 2160f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "longx}")) { 2170f66f451Sopenharmony_ci long l; 2180f66f451Sopenharmony_ci 2190f66f451Sopenharmony_ci ptrace_struct(addr, &l, sizeof(l)); 2200f66f451Sopenharmony_ci fprintf(stderr, "%#lx", l); 2210f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "rlimit}")) { 2220f66f451Sopenharmony_ci struct rlimit rl; 2230f66f451Sopenharmony_ci 2240f66f451Sopenharmony_ci ptrace_struct(addr, &rl, sizeof(rl)); 2250f66f451Sopenharmony_ci fprintf(stderr, "{rlim_cur=%lld, rlim_max=%lld}", 2260f66f451Sopenharmony_ci (long long)rl.rlim_cur, (long long)rl.rlim_max); 2270f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "sigset}")) { 2280f66f451Sopenharmony_ci long long ss; 2290f66f451Sopenharmony_ci int i; 2300f66f451Sopenharmony_ci 2310f66f451Sopenharmony_ci ptrace_struct(addr, &ss, sizeof(ss)); 2320f66f451Sopenharmony_ci fprintf(stderr, "["); 2330f66f451Sopenharmony_ci for (i=0; i<64;++i) { 2340f66f451Sopenharmony_ci // TODO: use signal names, fix spacing 2350f66f451Sopenharmony_ci if (ss & (1ULL<<i)) fprintf(stderr, "%d ", i); 2360f66f451Sopenharmony_ci } 2370f66f451Sopenharmony_ci fprintf(stderr, "]"); 2380f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "stat}")) { 2390f66f451Sopenharmony_ci struct stat sb; 2400f66f451Sopenharmony_ci 2410f66f451Sopenharmony_ci ptrace_struct(addr, &sb, sizeof(sb)); 2420f66f451Sopenharmony_ci // TODO: decode IFMT bits in st_mode 2430f66f451Sopenharmony_ci if (FLAG(v)) { 2440f66f451Sopenharmony_ci // TODO: full atime/mtime/ctime dump. 2450f66f451Sopenharmony_ci fprintf(stderr, "{st_dev=makedev(%#x, %#x), st_ino=%ld, st_mode=%o, " 2460f66f451Sopenharmony_ci "st_nlink=%ld, st_uid=%d, st_gid=%d, st_blksize=%ld, st_blocks=%ld, " 2470f66f451Sopenharmony_ci "st_size=%lld, st_atime=%ld, st_mtime=%ld, st_ctime=%ld}", 2480f66f451Sopenharmony_ci dev_major(sb.st_dev), dev_minor(sb.st_dev), sb.st_ino, sb.st_mode, 2490f66f451Sopenharmony_ci sb.st_nlink, sb.st_uid, sb.st_gid, sb.st_blksize, sb.st_blocks, 2500f66f451Sopenharmony_ci (long long)sb.st_size, sb.st_atime, sb.st_mtime, sb.st_ctime); 2510f66f451Sopenharmony_ci } else { 2520f66f451Sopenharmony_ci fprintf(stderr, "{st_mode=%o, st_size=%lld, ...}", sb.st_mode, 2530f66f451Sopenharmony_ci (long long)sb.st_size); 2540f66f451Sopenharmony_ci } 2550f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "termios}")) { 2560f66f451Sopenharmony_ci struct termios to; 2570f66f451Sopenharmony_ci 2580f66f451Sopenharmony_ci ptrace_struct(addr, &to, sizeof(to)); 2590f66f451Sopenharmony_ci fprintf(stderr, "{c_iflag=%#lx, c_oflag=%#lx, c_cflag=%#lx, c_lflag=%#lx}", 2600f66f451Sopenharmony_ci (long)to.c_iflag, (long)to.c_oflag, (long)to.c_cflag, (long)to.c_lflag); 2610f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "timespec}")) { 2620f66f451Sopenharmony_ci struct timespec ts; 2630f66f451Sopenharmony_ci 2640f66f451Sopenharmony_ci ptrace_struct(addr, &ts, sizeof(ts)); 2650f66f451Sopenharmony_ci fprintf(stderr, "{tv_sec=%lld, tv_nsec=%lld}", 2660f66f451Sopenharmony_ci (long long)ts.tv_sec, (long long)ts.tv_nsec); 2670f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "winsize}")) { 2680f66f451Sopenharmony_ci struct winsize ws; 2690f66f451Sopenharmony_ci 2700f66f451Sopenharmony_ci ptrace_struct(addr, &ws, sizeof(ws)); 2710f66f451Sopenharmony_ci fprintf(stderr, "{ws_row=%hu, ws_col=%hu, ws_xpixel=%hu, ws_ypixel=%hu}", 2720f66f451Sopenharmony_ci ws.ws_row, ws.ws_col, ws.ws_xpixel, ws.ws_ypixel); 2730f66f451Sopenharmony_ci } else abort(); 2740f66f451Sopenharmony_ci} 2750f66f451Sopenharmony_ci 2760f66f451Sopenharmony_cistatic void print_ptr(long addr) 2770f66f451Sopenharmony_ci{ 2780f66f451Sopenharmony_ci if (!addr) fprintf(stderr, "NULL"); 2790f66f451Sopenharmony_ci else fprintf(stderr, "0x%lx", addr); 2800f66f451Sopenharmony_ci} 2810f66f451Sopenharmony_ci 2820f66f451Sopenharmony_cistatic void print_string(long addr) 2830f66f451Sopenharmony_ci{ 2840f66f451Sopenharmony_ci long offset = 0, total = 0; 2850f66f451Sopenharmony_ci int done = 0, i; 2860f66f451Sopenharmony_ci 2870f66f451Sopenharmony_ci fputc('"', stderr); 2880f66f451Sopenharmony_ci while (!done) { 2890f66f451Sopenharmony_ci errno = 0; 2900f66f451Sopenharmony_ci long v = ptrace(PTRACE_PEEKDATA, TT.pid, addr + offset); 2910f66f451Sopenharmony_ci if (errno) return; 2920f66f451Sopenharmony_ci memcpy(toybuf, &v, sizeof(v)); 2930f66f451Sopenharmony_ci for (i=0; i<sizeof(v); ++i) { 2940f66f451Sopenharmony_ci if (!toybuf[i]) { 2950f66f451Sopenharmony_ci // TODO: handle the case of dumping n bytes (e.g. read()/write()), not 2960f66f451Sopenharmony_ci // just NUL-terminated strings. 2970f66f451Sopenharmony_ci done = 1; 2980f66f451Sopenharmony_ci break; 2990f66f451Sopenharmony_ci } 3000f66f451Sopenharmony_ci if (isprint(toybuf[i])) fputc(toybuf[i], stderr); 3010f66f451Sopenharmony_ci else { 3020f66f451Sopenharmony_ci // TODO: reuse an existing escape function. 3030f66f451Sopenharmony_ci fputc('\\', stderr); 3040f66f451Sopenharmony_ci if (toybuf[i] == '\n') fputc('n', stderr); 3050f66f451Sopenharmony_ci else if (toybuf[i] == '\r') fputc('r', stderr); 3060f66f451Sopenharmony_ci else if (toybuf[i] == '\t') fputc('t', stderr); 3070f66f451Sopenharmony_ci else fprintf(stderr, "x%2.2x", toybuf[i]); 3080f66f451Sopenharmony_ci } 3090f66f451Sopenharmony_ci if (++total >= TT.s) { 3100f66f451Sopenharmony_ci done = 1; 3110f66f451Sopenharmony_ci break; 3120f66f451Sopenharmony_ci } 3130f66f451Sopenharmony_ci } 3140f66f451Sopenharmony_ci offset += sizeof(v); 3150f66f451Sopenharmony_ci } 3160f66f451Sopenharmony_ci fputc('"', stderr); 3170f66f451Sopenharmony_ci} 3180f66f451Sopenharmony_ci 3190f66f451Sopenharmony_cistatic void print_bitmask(int bitmask, long v, char *zero, ...) 3200f66f451Sopenharmony_ci{ 3210f66f451Sopenharmony_ci va_list ap; 3220f66f451Sopenharmony_ci int first = 1; 3230f66f451Sopenharmony_ci 3240f66f451Sopenharmony_ci if (!v && zero) { 3250f66f451Sopenharmony_ci fprintf(stderr, "%s", zero); 3260f66f451Sopenharmony_ci return; 3270f66f451Sopenharmony_ci } 3280f66f451Sopenharmony_ci 3290f66f451Sopenharmony_ci va_start(ap, zero); 3300f66f451Sopenharmony_ci for (;;) { 3310f66f451Sopenharmony_ci int this = va_arg(ap, int); 3320f66f451Sopenharmony_ci char *name; 3330f66f451Sopenharmony_ci 3340f66f451Sopenharmony_ci if (!this) break; 3350f66f451Sopenharmony_ci name = va_arg(ap, char*); 3360f66f451Sopenharmony_ci if (bitmask) { 3370f66f451Sopenharmony_ci if (v & this) { 3380f66f451Sopenharmony_ci fprintf(stderr, "%s%s", first?"":"|", name); 3390f66f451Sopenharmony_ci first = 0; 3400f66f451Sopenharmony_ci v &= ~this; 3410f66f451Sopenharmony_ci } 3420f66f451Sopenharmony_ci } else { 3430f66f451Sopenharmony_ci if (v == this) { 3440f66f451Sopenharmony_ci fprintf(stderr, "%s", name); 3450f66f451Sopenharmony_ci v = 0; 3460f66f451Sopenharmony_ci break; 3470f66f451Sopenharmony_ci } 3480f66f451Sopenharmony_ci } 3490f66f451Sopenharmony_ci } 3500f66f451Sopenharmony_ci va_end(ap); 3510f66f451Sopenharmony_ci if (v) fprintf(stderr, "%s%#lx", first?"":"|", v); 3520f66f451Sopenharmony_ci} 3530f66f451Sopenharmony_ci 3540f66f451Sopenharmony_cistatic void print_flags(long v) 3550f66f451Sopenharmony_ci{ 3560f66f451Sopenharmony_ci#define C(n) n, #n 3570f66f451Sopenharmony_ci if (strstart(&TT.fmt, "access|")) { 3580f66f451Sopenharmony_ci print_bitmask(1, v, "F_OK", C(R_OK), C(W_OK), C(X_OK), 0); 3590f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "mmap|")) { 3600f66f451Sopenharmony_ci print_bitmask(1, v, 0, C(MAP_SHARED), C(MAP_PRIVATE), C(MAP_32BIT), 3610f66f451Sopenharmony_ci C(MAP_ANONYMOUS), C(MAP_FIXED), C(MAP_GROWSDOWN), C(MAP_HUGETLB), 3620f66f451Sopenharmony_ci C(MAP_DENYWRITE), 0); 3630f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "open|")) { 3640f66f451Sopenharmony_ci print_bitmask(1, v, "O_RDONLY", C(O_WRONLY), C(O_RDWR), C(O_CLOEXEC), 3650f66f451Sopenharmony_ci C(O_CREAT), C(O_DIRECTORY), C(O_EXCL), C(O_NOCTTY), C(O_NOFOLLOW), 3660f66f451Sopenharmony_ci C(O_TRUNC), C(O_ASYNC), C(O_APPEND), C(O_DSYNC), C(O_EXCL), 3670f66f451Sopenharmony_ci C(O_NOATIME), C(O_NONBLOCK), C(O_PATH), C(O_SYNC), 3680f66f451Sopenharmony_ci 0x4000, "O_DIRECT", 0x8000, "O_LARGEFILE", 0x410000, "O_TMPFILE", 0); 3690f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "prot|")) { 3700f66f451Sopenharmony_ci print_bitmask(1,v,"PROT_NONE",C(PROT_READ),C(PROT_WRITE),C(PROT_EXEC),0); 3710f66f451Sopenharmony_ci } else abort(); 3720f66f451Sopenharmony_ci} 3730f66f451Sopenharmony_ci 3740f66f451Sopenharmony_cistatic void print_alternatives(long v) 3750f66f451Sopenharmony_ci{ 3760f66f451Sopenharmony_ci if (strstart(&TT.fmt, "rlimit^")) { 3770f66f451Sopenharmony_ci print_bitmask(0, v, "RLIMIT_CPU", C(RLIMIT_FSIZE), C(RLIMIT_DATA), 3780f66f451Sopenharmony_ci C(RLIMIT_STACK), C(RLIMIT_CORE), C(RLIMIT_RSS), C(RLIMIT_NPROC), 3790f66f451Sopenharmony_ci C(RLIMIT_NOFILE), C(RLIMIT_MEMLOCK), C(RLIMIT_AS), C(RLIMIT_LOCKS), 3800f66f451Sopenharmony_ci C(RLIMIT_SIGPENDING), C(RLIMIT_MSGQUEUE), C(RLIMIT_NICE), 3810f66f451Sopenharmony_ci C(RLIMIT_RTPRIO), C(RLIMIT_RTTIME), 0); 3820f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "seek^")) { 3830f66f451Sopenharmony_ci print_bitmask(0, v, "SEEK_SET", C(SEEK_CUR), C(SEEK_END), C(SEEK_DATA), 3840f66f451Sopenharmony_ci C(SEEK_HOLE), 0); 3850f66f451Sopenharmony_ci } else if (strstart(&TT.fmt, "sig^")) { 3860f66f451Sopenharmony_ci print_bitmask(0, v, "SIG_BLOCK", C(SIG_UNBLOCK), C(SIG_SETMASK), 0); 3870f66f451Sopenharmony_ci } else abort(); 3880f66f451Sopenharmony_ci} 3890f66f451Sopenharmony_ci 3900f66f451Sopenharmony_cistatic void print_args() 3910f66f451Sopenharmony_ci{ 3920f66f451Sopenharmony_ci int i; 3930f66f451Sopenharmony_ci 3940f66f451Sopenharmony_ci // Loop through arguments and print according to format string 3950f66f451Sopenharmony_ci for (i = 0; *TT.fmt; i++, TT.arg++) { 3960f66f451Sopenharmony_ci long v = TT.regs[REG_ORDER[TT.arg]]; 3970f66f451Sopenharmony_ci char *s, ch; 3980f66f451Sopenharmony_ci 3990f66f451Sopenharmony_ci if (i) fprintf(stderr, ", "); 4000f66f451Sopenharmony_ci switch (ch = *TT.fmt++) { 4010f66f451Sopenharmony_ci case 'd': fprintf(stderr, "%ld", v); break; // decimal 4020f66f451Sopenharmony_ci case 'f': if ((int) v == AT_FDCWD) fprintf(stderr, "AT_FDCWD"); 4030f66f451Sopenharmony_ci else fprintf(stderr, "%ld", v); 4040f66f451Sopenharmony_ci break; 4050f66f451Sopenharmony_ci case 'i': fprintf(stderr, "%s", strioctl(v)); break; // decimal 4060f66f451Sopenharmony_ci case 'm': fprintf(stderr, "%03o", (unsigned) v); break; // mode for open() 4070f66f451Sopenharmony_ci case 'o': fprintf(stderr, "%ld", v); break; // off_t 4080f66f451Sopenharmony_ci case 'p': print_ptr(v); break; 4090f66f451Sopenharmony_ci case 's': print_string(v); break; 4100f66f451Sopenharmony_ci case 'S': // The libc-reserved signals aren't known to num_to_sig(). 4110f66f451Sopenharmony_ci // TODO: use an strace-only routine for >= 32? 4120f66f451Sopenharmony_ci if (!(s = num_to_sig(v))) fprintf(stderr, "%ld", v); 4130f66f451Sopenharmony_ci else fprintf(stderr, "SIG%s", s); 4140f66f451Sopenharmony_ci break; 4150f66f451Sopenharmony_ci case 'z': fprintf(stderr, "%zd", v); break; // size_t 4160f66f451Sopenharmony_ci case 'x': fprintf(stderr, "%lx", v); break; // hex 4170f66f451Sopenharmony_ci 4180f66f451Sopenharmony_ci case '{': print_struct(v); break; 4190f66f451Sopenharmony_ci case '|': print_flags(v); break; 4200f66f451Sopenharmony_ci case '^': print_alternatives(v); break; 4210f66f451Sopenharmony_ci 4220f66f451Sopenharmony_ci case '/': return; // Separates "enter" and "exit" arguments. 4230f66f451Sopenharmony_ci 4240f66f451Sopenharmony_ci default: fprintf(stderr, "?%c<0x%lx>", ch, v); break; 4250f66f451Sopenharmony_ci } 4260f66f451Sopenharmony_ci } 4270f66f451Sopenharmony_ci} 4280f66f451Sopenharmony_ci 4290f66f451Sopenharmony_cistatic void print_enter(void) 4300f66f451Sopenharmony_ci{ 4310f66f451Sopenharmony_ci char *name; 4320f66f451Sopenharmony_ci 4330f66f451Sopenharmony_ci get_regs(); 4340f66f451Sopenharmony_ci TT.syscall = TT.regs[REG_ORDER[6]]; 4350f66f451Sopenharmony_ci if (TT.syscall == __NR_ioctl) { 4360f66f451Sopenharmony_ci name = "ioctl"; 4370f66f451Sopenharmony_ci switch (TT.regs[REG_ORDER[1]]) { 4380f66f451Sopenharmony_ci case FS_IOC_FSGETXATTR: TT.fmt = "fi/{fsxattr}"; break; 4390f66f451Sopenharmony_ci case FS_IOC_FSSETXATTR: TT.fmt = "fi{fsxattr}"; break; 4400f66f451Sopenharmony_ci case FS_IOC_GETFLAGS: TT.fmt = "fi/{longx}"; break; 4410f66f451Sopenharmony_ci case FS_IOC_GETVERSION: TT.fmt = "fi/{long}"; break; 4420f66f451Sopenharmony_ci case FS_IOC_SETFLAGS: TT.fmt = "fi{long}"; break; 4430f66f451Sopenharmony_ci case FS_IOC_SETVERSION: TT.fmt = "fi{long}"; break; 4440f66f451Sopenharmony_ci //case SIOCGIFCONF: struct ifconf 4450f66f451Sopenharmony_ci case SIOCGIFADDR: 4460f66f451Sopenharmony_ci case SIOCGIFBRDADDR: 4470f66f451Sopenharmony_ci case SIOCGIFDSTADDR: 4480f66f451Sopenharmony_ci case SIOCGIFFLAGS: 4490f66f451Sopenharmony_ci case SIOCGIFHWADDR: 4500f66f451Sopenharmony_ci case SIOCGIFMAP: 4510f66f451Sopenharmony_ci case SIOCGIFMTU: 4520f66f451Sopenharmony_ci case SIOCGIFNETMASK: 4530f66f451Sopenharmony_ci case SIOCGIFTXQLEN: TT.fmt = "fi/{ifreq}"; break; 4540f66f451Sopenharmony_ci case SIOCSIFADDR: 4550f66f451Sopenharmony_ci case SIOCSIFBRDADDR: 4560f66f451Sopenharmony_ci case SIOCSIFDSTADDR: 4570f66f451Sopenharmony_ci case SIOCSIFFLAGS: 4580f66f451Sopenharmony_ci case SIOCSIFHWADDR: 4590f66f451Sopenharmony_ci case SIOCSIFMAP: 4600f66f451Sopenharmony_ci case SIOCSIFMTU: 4610f66f451Sopenharmony_ci case SIOCSIFNETMASK: 4620f66f451Sopenharmony_ci case SIOCSIFTXQLEN: TT.fmt = "fi{ifreq}"; break; 4630f66f451Sopenharmony_ci case TCGETS: TT.fmt = "fi/{termios}"; break; 4640f66f451Sopenharmony_ci case TCSETS: TT.fmt = "fi{termios}"; break; 4650f66f451Sopenharmony_ci case TIOCGWINSZ: TT.fmt = "fi/{winsize}"; break; 4660f66f451Sopenharmony_ci case TIOCSWINSZ: TT.fmt = "fi{winsize}"; break; 4670f66f451Sopenharmony_ci default: 4680f66f451Sopenharmony_ci TT.fmt = (TT.regs[REG_ORDER[0]]&1) ? "fip" : "fi/p"; 4690f66f451Sopenharmony_ci break; 4700f66f451Sopenharmony_ci } 4710f66f451Sopenharmony_ci } else switch (TT.syscall) { 4720f66f451Sopenharmony_ci#define SC(n,f) case __NR_ ## n: name = #n; TT.fmt = f; break 4730f66f451Sopenharmony_ci SC(access, "s|access|"); 4740f66f451Sopenharmony_ci SC(arch_prctl, "dp"); 4750f66f451Sopenharmony_ci SC(brk, "p"); 4760f66f451Sopenharmony_ci SC(close, "d"); 4770f66f451Sopenharmony_ci SC(connect, "fpd"); // TODO: sockaddr 4780f66f451Sopenharmony_ci SC(dup, "f"); 4790f66f451Sopenharmony_ci SC(dup2, "ff"); 4800f66f451Sopenharmony_ci SC(dup3, "ff|open|"); 4810f66f451Sopenharmony_ci SC(execve, "spp"); 4820f66f451Sopenharmony_ci SC(exit_group, "d"); 4830f66f451Sopenharmony_ci SC(fcntl, "fdp"); // TODO: probably needs special case 4840f66f451Sopenharmony_ci SC(fstat, "f/{stat}"); 4850f66f451Sopenharmony_ci SC(futex, "pdxppx"); 4860f66f451Sopenharmony_ci SC(getdents64, "dpz"); 4870f66f451Sopenharmony_ci SC(geteuid, ""); 4880f66f451Sopenharmony_ci SC(getuid, ""); 4890f66f451Sopenharmony_ci 4900f66f451Sopenharmony_ci SC(getxattr, "sspz"); 4910f66f451Sopenharmony_ci SC(lgetxattr, "sspz"); 4920f66f451Sopenharmony_ci SC(fgetxattr, "fspz"); 4930f66f451Sopenharmony_ci 4940f66f451Sopenharmony_ci SC(lseek, "fo^seek^"); 4950f66f451Sopenharmony_ci SC(lstat, "s/{stat}"); 4960f66f451Sopenharmony_ci SC(mmap, "pz|prot||mmap|fx"); 4970f66f451Sopenharmony_ci SC(mprotect, "pz|prot|"); 4980f66f451Sopenharmony_ci SC(mremap, "pzzdp"); // TODO: flags 4990f66f451Sopenharmony_ci SC(munmap, "pz"); 5000f66f451Sopenharmony_ci SC(nanosleep, "{timespec}/{timespec}"); 5010f66f451Sopenharmony_ci SC(newfstatat, "fs/{stat}d"); 5020f66f451Sopenharmony_ci SC(open, "sd|open|m"); 5030f66f451Sopenharmony_ci SC(openat, "fs|open|m"); 5040f66f451Sopenharmony_ci SC(poll, "pdd"); 5050f66f451Sopenharmony_ci SC(prlimit64, "d^rlimit^{rlimit}/{rlimit}"); 5060f66f451Sopenharmony_ci SC(read, "d/sz"); 5070f66f451Sopenharmony_ci SC(readlinkat, "s/sz"); 5080f66f451Sopenharmony_ci SC(rt_sigaction, "Sppz"); 5090f66f451Sopenharmony_ci SC(rt_sigprocmask, "^sig^{sigset}/{sigset}z"); 5100f66f451Sopenharmony_ci SC(set_robust_list, "pd"); 5110f66f451Sopenharmony_ci SC(set_tid_address, "p"); 5120f66f451Sopenharmony_ci SC(socket, "ddd"); // TODO: flags 5130f66f451Sopenharmony_ci SC(stat, "s/{stat}"); 5140f66f451Sopenharmony_ci SC(statfs, "sp"); 5150f66f451Sopenharmony_ci SC(sysinfo, "p"); 5160f66f451Sopenharmony_ci SC(umask, "m"); 5170f66f451Sopenharmony_ci SC(uname, "p"); 5180f66f451Sopenharmony_ci SC(write, "dsz"); 5190f66f451Sopenharmony_ci default: 5200f66f451Sopenharmony_ci sprintf(name = toybuf, "SYS_%ld", TT.syscall); 5210f66f451Sopenharmony_ci TT.fmt = "pppppp"; 5220f66f451Sopenharmony_ci break; 5230f66f451Sopenharmony_ci } 5240f66f451Sopenharmony_ci 5250f66f451Sopenharmony_ci fprintf(stderr, "%s(", name); 5260f66f451Sopenharmony_ci TT.arg = 0; 5270f66f451Sopenharmony_ci print_args(); 5280f66f451Sopenharmony_ci} 5290f66f451Sopenharmony_ci 5300f66f451Sopenharmony_cistatic void print_exit(void) 5310f66f451Sopenharmony_ci{ 5320f66f451Sopenharmony_ci long result; 5330f66f451Sopenharmony_ci 5340f66f451Sopenharmony_ci get_regs(); 5350f66f451Sopenharmony_ci result = TT.regs[REG_ORDER[7]]; 5360f66f451Sopenharmony_ci if (*TT.fmt) print_args(); 5370f66f451Sopenharmony_ci fprintf(stderr, ") = "); 5380f66f451Sopenharmony_ci if (result >= -4095UL) 5390f66f451Sopenharmony_ci fprintf(stderr, "-1 %s (%s)", strerrno(-result), strerror(-result)); 5400f66f451Sopenharmony_ci else if (TT.syscall==__NR_mmap || TT.syscall==__NR_brk) print_ptr(result); 5410f66f451Sopenharmony_ci else fprintf(stderr, "%ld", result); 5420f66f451Sopenharmony_ci fputc('\n', stderr); 5430f66f451Sopenharmony_ci} 5440f66f451Sopenharmony_ci 5450f66f451Sopenharmony_cistatic int next(void) 5460f66f451Sopenharmony_ci{ 5470f66f451Sopenharmony_ci int status; 5480f66f451Sopenharmony_ci 5490f66f451Sopenharmony_ci for (;;) { 5500f66f451Sopenharmony_ci ptrace(PTRACE_SYSCALL, TT.pid, 0, 0); 5510f66f451Sopenharmony_ci waitpid(TT.pid, &status, 0); 5520f66f451Sopenharmony_ci // PTRACE_O_TRACESYSGOOD sets bit 7 to indicate a syscall. 5530f66f451Sopenharmony_ci if (WIFSTOPPED(status) && WSTOPSIG(status) & 0x80) return 1; 5540f66f451Sopenharmony_ci if (WIFEXITED(status)) return 0; 5550f66f451Sopenharmony_ci fprintf(stderr, "[stopped %d (%x)]\n", status, WSTOPSIG(status)); 5560f66f451Sopenharmony_ci } 5570f66f451Sopenharmony_ci} 5580f66f451Sopenharmony_ci 5590f66f451Sopenharmony_cistatic void strace_detach(int s) 5600f66f451Sopenharmony_ci{ 5610f66f451Sopenharmony_ci xptrace(PTRACE_DETACH, TT.pid, 0, 0); 5620f66f451Sopenharmony_ci exit(1); 5630f66f451Sopenharmony_ci} 5640f66f451Sopenharmony_ci 5650f66f451Sopenharmony_civoid strace_main(void) 5660f66f451Sopenharmony_ci{ 5670f66f451Sopenharmony_ci int status; 5680f66f451Sopenharmony_ci 5690f66f451Sopenharmony_ci if (!FLAG(s)) TT.s = 32; 5700f66f451Sopenharmony_ci 5710f66f451Sopenharmony_ci if (FLAG(p)) { 5720f66f451Sopenharmony_ci if (*toys.optargs) help_exit("No arguments with -p"); 5730f66f451Sopenharmony_ci TT.pid = TT.p; 5740f66f451Sopenharmony_ci signal(SIGINT, strace_detach); 5750f66f451Sopenharmony_ci // TODO: PTRACE_SEIZE instead? 5760f66f451Sopenharmony_ci xptrace(PTRACE_ATTACH, TT.pid, 0, 0); 5770f66f451Sopenharmony_ci } else { 5780f66f451Sopenharmony_ci if (!*toys.optargs) help_exit("Needs 1 argument"); 5790f66f451Sopenharmony_ci TT.pid = xfork(); 5800f66f451Sopenharmony_ci if (!TT.pid) { 5810f66f451Sopenharmony_ci errno = 0; 5820f66f451Sopenharmony_ci ptrace(PTRACE_TRACEME); 5830f66f451Sopenharmony_ci if (errno) perror_exit("PTRACE_TRACEME failed"); 5840f66f451Sopenharmony_ci raise(SIGSTOP); 5850f66f451Sopenharmony_ci toys.stacktop = 0; 5860f66f451Sopenharmony_ci xexec(toys.optargs); 5870f66f451Sopenharmony_ci } 5880f66f451Sopenharmony_ci } 5890f66f451Sopenharmony_ci 5900f66f451Sopenharmony_ci do { 5910f66f451Sopenharmony_ci waitpid(TT.pid, &status, 0); 5920f66f451Sopenharmony_ci } while (!WIFSTOPPED(status)); 5930f66f451Sopenharmony_ci 5940f66f451Sopenharmony_ci // TODO: PTRACE_O_TRACEEXIT 5950f66f451Sopenharmony_ci // TODO: PTRACE_O_TRACEFORK/PTRACE_O_TRACEVFORK/PTRACE_O_TRACECLONE for -f. 5960f66f451Sopenharmony_ci errno = 0; 5970f66f451Sopenharmony_ci ptrace(PTRACE_SETOPTIONS, TT.pid, 0, PTRACE_O_TRACESYSGOOD); 5980f66f451Sopenharmony_ci if (errno) perror_exit("PTRACE_SETOPTIONS PTRACE_O_TRACESYSGOOD failed"); 5990f66f451Sopenharmony_ci 6000f66f451Sopenharmony_ci // TODO: real strace swallows the failed execve()s if it started the child 6010f66f451Sopenharmony_ci 6020f66f451Sopenharmony_ci for (;;) { 6030f66f451Sopenharmony_ci if (!next()) break; 6040f66f451Sopenharmony_ci print_enter(); 6050f66f451Sopenharmony_ci if (!next()) break; 6060f66f451Sopenharmony_ci print_exit(); 6070f66f451Sopenharmony_ci } 6080f66f451Sopenharmony_ci 6090f66f451Sopenharmony_ci // TODO: support -f and keep track of children. 6100f66f451Sopenharmony_ci waitpid(TT.pid, &status, 0); 6110f66f451Sopenharmony_ci if (WIFEXITED(status)) 6120f66f451Sopenharmony_ci fprintf(stderr, "+++ exited with %d +++\n", WEXITSTATUS(status)); 6130f66f451Sopenharmony_ci if (WIFSTOPPED(status)) 6140f66f451Sopenharmony_ci fprintf(stderr, "+++ stopped with %d +++\n", WSTOPSIG(status)); 6150f66f451Sopenharmony_ci} 616