http://sourceware.org/ml/systemtap/2008-q2/msg00266.htmlHere's a utrace probe example. This shows the promise (and the current limitations) of utrace probes. It acts as a "mini" strace - "mini" because it can only decode arguments for 3 system calls: open(), read(), and close(). It does print the name (but not the arguments) of every other system call. Currently it handles i686 and x86_64 (32-bit executables or 64-bit executables). Right now it is set up to probe /bin/cat. -- David Smith dsm...@redhat.com Red Hat http://www.redhat.com 256.217.0141 (direct) 256.837.0057 (fax) %{ #include <linux/unistd.h> /* Only works for x86/x86_64 */ static inline long *user_syscall_arg(struct task_struct *task, struct pt_regs *regs, int n) { #ifdef CONFIG_X86_32 BUG_ON(n > 5); # if defined (STAPCONF_X86_UNIREGS) return ®s->bx + n; # else return ®s->ebx + n; # endif /* STAPCONF_X86_UNIREGS */ #else # ifdef CONFIG_IA32_EMULATION if (test_tsk_thread_flag(task, TIF_IA32)) switch (n) { # if defined (STAPCONF_X86_UNIREGS) case 0: return ®s->bx; case 1: return ®s->cx; case 2: return ®s->dx; case 3: return ®s->si; case 4: return ®s->di; case 5: return ®s->bp; # else case 0: return ®s->rbx; case 1: return ®s->rcx; case 2: return ®s->rdx; case 3: return ®s->rsi; case 4: return ®s->rdi; case 5: return ®s->rbp; # endif /* STAPCONF_X86_UNIREGS */ default: BUG(); } # endif /* CONFIG_IA32_EMULATION */ switch (n) { # if defined (STAPCONF_X86_UNIREGS) case 0: return ®s->di; case 1: return ®s->si; case 2: return ®s->dx; case 3: return ®s->r10; case 4: return ®s->r8; case 5: return ®s->r9; # else case 0: return ®s->rdi; case 1: return ®s->rsi; case 2: return ®s->rdx; case 3: return ®s->r10; case 4: return ®s->r8; case 5: return ®s->r9; # endif /* STAPCONF_X86_UNIREGS */ default: BUG(); } #endif /* CONFIG_X86_32 */ return NULL; } /* Only works for x86/x86_64 */ static inline long *user_syscall_return_value(struct task_struct *task, struct pt_regs *regs) { #ifdef CONFIG_X86_32 # if defined (STAPCONF_X86_UNIREGS) return ®s->ax; # else return ®s->eax; # endif /* STAPCONF_X86_UNIREGS */ #else # ifdef CONFIG_IA32_EMULATION if (test_tsk_thread_flag(task, TIF_IA32)) /* * Sign-extend the value so (int)-EFOO becomes (long)-EFOO * and will match correctly in comparisons. */ # if defined (STAPCONF_X86_UNIREGS) regs->ax = (long) (int) regs->ax; # else regs->rax = (long) (int) regs->rax; # endif /* STAPCONF_X86_UNIREGS */ # endif /* CONFIG_IA32_EMULATION */ # if defined (STAPCONF_X86_UNIREGS) return ®s->ax; # else return ®s->rax; # endif /* STAPCONF_X86_UNIREGS */ #endif /* CONFIG_X86_32 */ } %} function get_syscall_arg:long(n:long) %{ /* pure */ if (THIS->n > 5 || THIS->n < 0) { snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "invalid getn_syscall_arg requested of %lld", THIS->n); CONTEXT->last_error = CONTEXT->error_buffer; return; } THIS->__retvalue = (int64_t) (long) \ kread(user_syscall_arg(current, CONTEXT->regs, THIS->n)); CATCH_DEREF_FAULT(); %} function get_syscall_return_value:long() %{ /* pure */ THIS->__retvalue = (int64_t) (long) \ kread(user_syscall_return_value(current, CONTEXT->regs)); CATCH_DEREF_FAULT(); %} function syscall_decode:string(syscall:long) %{ /* pure */ char *name; #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) const char * const x86_32[] = { /* 0 */ "restart_syscall", "_exit", "fork", "read", "write", /* 5 */ "open", "close", "waitpid", "creat", "link", /* 10 */ "unlink", "execve", "chdir", "time", "mknod", /* 15 */ "chmod", "lchown", "break", "oldstat", "lseek", /* 20 */ "getpid", "mount", "oldumount", "setuid", "getuid", /* 25 */ "stime", "ptrace", "alarm", "oldfstat", "pause", /* 30 */ "utime", "stty", "gtty", "access", "nice", /* 35 */ "ftime", "sync", "kill", "rename", "mkdir", /* 40 */ "rmdir", "dup", "pipe", "times", "prof", /* 45 */ "brk", "setgid", "getgid", "signal", "geteuid", /* 50 */ "getegid", "acct", "umount", "lock", "ioctl", /* 55 */ "fcntl", "mpx", "setpgid", "ulimit", "oldolduname", /* 60 */ "umask", "chroot", "ustat", "dup2", "getppid", /* 65 */ "getpgrp", "setsid", "sigaction", "siggetmask", "sigsetmask", /* 70 */ "setreuid", "setregid", "sigsuspend", "sigpending", "sethostname", /* 75 */ "setrlimit", "old_getrlimit", "getrusage", "gettimeofday", "settimeofday", /* 80 */ "getgroups", "setgroups", "oldselect", "symlink", "oldlstat", /* 85 */ "readlink", "uselib", "swapon", "reboot", "readdir", /* 90 */ "old_mmap", "munmap", "truncate", "ftruncate", "fchmod", /* 95 */ "fchown", "getpriority", "setpriority", "profil", "statfs", /* 100 */ "fstatfs", "ioperm", "socketcall", "syslog", "setitimer", /* 105 */ "getitimer", "stat", "lstat", "fstat", "olduname", /* 110 */ "iopl", "vhangup", "idle", "vm86old", "wait4", /* 115 */ "swapoff", "sysinfo", "ipc", "fsync", "sigreturn", /* 120 */ "clone", "setdomainname", "uname", "modify_ldt", "adjtimex", /* 125 */ "mprotect", "sigprocmask", "create_module", "init_module", "delete_module", /* 130 */ "get_kernel_syms", "quotactl", "getpgid", "fchdir", "bdflush", /* 135 */ "sysfs", "personality", "afs_syscall", "setfsuid", "setfsgid", /* 140 */ "_llseek", "getdents", "select", "flock", "msync", /* 145 */ "readv", "writev", "getsid", "fdatasync", "_sysctl", /* 150 */ "mlock", "munlock", "mlockall", "munlockall", "sched_setparam", /* 155 */ "sched_getparam", "sched_setscheduler", "sched_getscheduler", "sched_yield", "sched_get_priority_max", /* 160 */ "sched_get_priority_min", "sched_rr_get_interval", "nanosleep", "mremap", "setresuid", /* 165 */ "getresuid", "vm86", "query_module", "poll", "nfsservctl", /* 170 */ "setresgid", "getresgid", "prctl", "rt_sigreturn", "rt_sigaction", /* 175 */ "rt_sigprocmask", "rt_sigpending", "rt_sigtimedwait", "rt_sigqueueinfo", "rt_sigsuspend", /* 180 */ "pread64", "pwrite64", "chown", "getcwd", "capget", /* 185 */ "capset", "sigaltstack", "sendfile", "getpmsg", "putpmsg", /* 190 */ "vfork", "getrlimit", "mmap2", "truncate64", "ftruncate64", /* 195 */ "stat64", "lstat64", "fstat64", "lchown32", "getuid32", /* 200 */ "getgid32", "geteuid32", "getegid32", "setreuid32", "setregid32", /* 205 */ "getgroups32", "setgroups32", "fchown32", "setresuid32", "getresuid32", /* 210 */ "setresgid32", "getresgid32", "chown32", "setuid32", "setgid32", /* 215 */ "setfsuid32", "setfsgid32", "pivot_root", "mincore", "madvise", /* 220 */ "getdents64", "fcntl64", "SYS_222", "security", "gettid", /* 225 */ "readahead", "setxattr", "lsetxattr", "fsetxattr", "getxattr", /* 230 */ "lgetxattr", "fgetxattr", "listxattr", "llistxattr", "flistxattr", /* 235 */ "removexattr", "lremovexattr", "fremovexattr", "tkill", "sendfile64", /* 240 */ "futex", "sched_setaffinity", "sched_getaffinity", "set_thread_area", "get_thread_area", /* 245 */ "io_setup", "io_destroy", "io_getevents", "io_submit", "io_cancel", /* 250 */ "fadvise64", "SYS_251", "exit_group", "lookup_dcookie", "epoll_create", /* 255 */ "epoll_ctl", "epoll_wait", "remap_file_pages", "set_tid_address", "timer_create", /* 260 */ "timer_settime", "timer_gettime", "timer_getoverrun", "timer_delete", "clock_settime", /* 265 */ "clock_gettime", "clock_getres", "clock_nanosleep", "statfs64", "fstatfs64", /* 270 */ "tgkill", "utimes", "fadvise64_64", "vserver", "mbind", /* 275 */ "get_mempolicy", "set_mempolicy", "mq_open", "mq_unlink", "mq_timedsend", /* 280 */ "mq_timedreceive", "mq_notify", "mq_getsetattr", "sys_kexec_load", "waitid", /* 285 */ "SYS_285", "add_key", "request_key", "keyctl", "ioprio_set", /* 290 */ "ioprio_get", "inotify_init", "inotify_add_watch", "inotify_rm_watch", "migrate_pages", /* 295 */ "openat", "mkdirat", "mknodat", "fchownat", "futimesat", /* 300 */ "fstatat64", "unlinkat", "renameat", "linkat", "symlinkat", /* 305 */ "readlinkat", "fchmodat", "faccessat", "pselect6", "ppoll", /* 310 */ "unshare", "set_robust_list", "get_robust_list", "splice", "sync_file_range", /* 315 */ "tee", "vmsplice", "move_pages", "getcpu", "epoll_pwait", /* 320 */ "utimensat", "signalfd", "timerfd", "eventfd", "SYS_324", /* 325 */ "SYS_325", "SYS_326", "SYS_327", "SYS_328", "SYS_329", /* 330 */ "SYS_330", "SYS_331", "SYS_332", "SYS_333", "SYS_334", /* 335 */ "SYS_335", "SYS_336", "SYS_337", "SYS_338", "SYS_339", /* 340 */ "SYS_340", "SYS_341", "SYS_342", "SYS_343", "SYS_344", /* 345 */ "SYS_345", "SYS_346", "SYS_347", "SYS_348", "SYS_349", /* 350 */ "SYS_350", "SYS_351", "SYS_352", "SYS_353", "SYS_354", /* 355 */ "SYS_355", "SYS_356", "SYS_357", "SYS_358", "SYS_359", /* 360 */ "SYS_360", "SYS_361", "SYS_362", "SYS_363", "SYS_364", /* 365 */ "SYS_365", "SYS_366", "SYS_367", "SYS_368", "SYS_369", /* 370 */ "SYS_370", "SYS_371", "SYS_372", "SYS_373", "SYS_374", /* 375 */ "SYS_375", "SYS_376", "SYS_377", "SYS_378", "SYS_379", /* 380 */ "SYS_380", "SYS_381", "SYS_382", "SYS_383", "SYS_384", /* 385 */ "SYS_385", "SYS_386", "SYS_387", "SYS_388", "SYS_389", /* 390 */ "SYS_390", "SYS_391", "SYS_392", "SYS_393", "SYS_394", /* 395 */ "SYS_395", "SYS_396", "SYS_397", "SYS_398", "SYS_399", /* 400 */ "socket_subcall", "socket", "bind", "connect", "listen", /* 405 */ "accept", "getsockname", "getpeername", "socketpair", "send", /* 410 */ "recv", "sendto", "recvfrom", "shutdown", "setsockopt", /* 415 */ "getsockopt", "sendmsg", "recvmsg", "ipc_subcall", "semop", /* 420 */ "semget", "semctl", "semtimedop", "ipc_subcall", "ipc_subcall", /* 425 */ "ipc_subcall", "ipc_subcall", "ipc_subcall", "ipc_subcall", "msgsnd", /* 430 */ "msgrcv", "msgget", "msgctl", "ipc_subcall", "ipc_subcall", /* 435 */ "ipc_subcall", "ipc_subcall", "ipc_subcall", "ipc_subcall", "shmat", /* 440 */ "shmdt", "shmget", "shmctl", }; #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ #ifdef CONFIG_X86_64 const char * const x86_64[] = { /* 0 */ "read", "write", "open", "close", "stat", /* 5 */ "fstat", "lstat", "poll", "lseek", "mmap", /* 10 */ "mprotect", "munmap", "brk", "rt_sigaction", "rt_sigprocmask", /* 15 */ "rt_sigreturn", "ioctl", "pread", "pwrite", "readv", /* 20 */ "writev", "access", "pipe", "select", "sched_yield", /* 25 */ "mremap", "msync", "mincore", "madvise", "shmget", /* 30 */ "shmat", "shmctl", "dup", "dup2", "pause", /* 35 */ "nanosleep", "getitimer", "alarm", "setitimer", "getpid", /* 40 */ "sendfile", "socket", "connect", "accept", "sendto", /* 45 */ "recvfrom", "sendmsg", "recvmsg", "shutdown", "bind", /* 50 */ "listen", "getsockname", "getpeername", "socketpair", "setsockopt", /* 55 */ "getsockopt", "clone", "fork", "vfork", "execve", /* 60 */ "_exit", "wait4", "kill", "uname", "semget", /* 65 */ "semop", "semctl", "shmdt", "msgget", "msgsnd", /* 70 */ "msgrcv", "msgctl", "fcntl", "flock", "fsync", /* 75 */ "fdatasync", "truncate", "ftruncate", "getdents", "getcwd", /* 80 */ "chdir", "fchdir", "rename", "mkdir", "rmdir", /* 85 */ "creat", "link", "unlink", "symlink", "readlink", /* 90 */ "chmod", "fchmod", "chown", "fchown", "lchown", /* 95 */ "umask", "gettimeofday", "getrlimit", "getrusage", "sysinfo", /* 100 */ "times", "ptrace", "getuid", "syslog", "getgid", /* 105 */ "setuid", "setgid", "geteuid", "getegid", "setpgid", /* 110 */ "getppid", "getpgrp", "setsid", "setreuid", "setregid", /* 115 */ "getgroups", "setgroups", "setresuid", "getresuid", "setresgid", /* 120 */ "getresgid", "getpgid", "setfsuid", "setfsgid", "getsid", /* 125 */ "capget", "capset", "rt_sigpending", "rt_sigtimedwait", "rt_sigqueueinfo", /* 130 */ "rt_sigsuspend", "sigaltstack", "utime", "mknod", "uselib", /* 135 */ "personality", "ustat", "statfs", "fstatfs", "sysfs", /* 140 */ "getpriority", "setpriority", "sched_setparam", "sched_getparam", "sched_setscheduler", /* 145 */ "sched_getscheduler", "sched_get_priority_max", "sched_get_priority_min", "sched_rr_get_interval", "mlock", /* 150 */ "munlock", "mlockall", "munlockall", "vhangup", "modify_ldt", /* 155 */ "pivot_root", "_sysctl", "prctl", "arch_prctl", "adjtimex", /* 160 */ "setrlimit", "chroot", "sync", "acct", "settimeofday", /* 165 */ "mount", "umount", "swapon", "swapoff", "reboot", /* 170 */ "sethostname", "setdomainname", "iopl", "ioperm", "create_module", /* 175 */ "init_module", "delete_module", "get_kernel_syms", "query_module", "quotactl", /* 180 */ "nfsservctl", "getpmsg", "putpmsg", "afs_syscall", "tuxcall", /* 185 */ "security", "gettid", "readahead", "setxattr", "lsetxattr", /* 190 */ "fsetxattr", "getxattr", "lgetxattr", "fgetxattr", "listxattr", /* 195 */ "llistxattr", "flistxattr", "removexattr", "lremovexattr", "fremovexattr", /* 200 */ "tkill", "time", "futex", "sched_setaffinity", "sched_getaffinity", /* 205 */ "set_thread_area", "io_setup", "io_destroy", "io_getevents", "io_submit", /* 210 */ "io_cancel", "get_thread_area", "lookup_dcookie", "epoll_create", "epoll_ctl_old", /* 215 */ "epoll_wait_old", "remap_file_pages", "getdents64", "set_tid_address", "restart_syscall", /* 220 */ "semtimedop", "fadvise64", "timer_create", "timer_settime", "timer_gettime", /* 225 */ "timer_getoverrun", "timer_delete", "clock_settime", "clock_gettime", "clock_getres", /* 230 */ "clock_nanosleep", "exit_group", "epoll_wait", "epoll_ctl", "tgkill", /* 235 */ "utimes", "vserver", "mbind", "set_mempolicy", "get_mempolicy", /* 240 */ "mq_open", "mq_unlink", "mq_timedsend", "mq_timedreceive", "mq_notify", /* 245 */ "mq_getsetattr", "kexec_load", "waitid", "add_key", "request_key", /* 250 */ "keyctl", "ioprio_set", "ioprio_get", "inotify_init", "inotify_add_watch", /* 255 */ "inotify_rm_watch", "migrate_pages", "openat", "mkdirat", "mknodat", /* 260 */ "fchownat", "futimesat", "newfstatat", "unlinkat", "renameat", /* 265 */ "linkat", "symlinkat", "readlinkat", "fchmodat", "faccessat", /* 270 */ "pselect6", "ppoll", "unshare", "set_robust_list", "get_robust_list", /* 275 */ "splice", "sync_file_range", "tee", "vmsplice", "move_pages", /* 280 */ "utimensat", "epoll_pwait", "signalfd", "timerfd", "eventfd", }; #endif /* CONFIG_X86_64 */ #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) # if defined(CONFIG_IA32_EMULATION) if (test_tsk_thread_flag(current, TIF_IA32)) { # endif /* CONFIG_IA32_EMULATION */ if (THIS->syscall < 0 || THIS->syscall > (sizeof(x86_32)/sizeof(x86_32[0]))) { snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "invalid syscall number %lld", THIS->syscall); CONTEXT->last_error = CONTEXT->error_buffer; } else { strlcpy(THIS->__retvalue, x86_32[THIS->syscall], MAXSTRINGLEN); } # if defined(CONFIG_IA32_EMULATION) return; } # endif /* CONFIG_IA32_EMULATION */ #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ #ifdef CONFIG_X86_64 if (THIS->syscall < 0 || THIS->syscall > (sizeof(x86_64)/sizeof(x86_64[0]))) { snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "invalid syscall number %lld", THIS->syscall); CONTEXT->last_error = CONTEXT->error_buffer; } else { strlcpy(THIS->__retvalue, x86_64[THIS->syscall], MAXSTRINGLEN); } #endif %} function open_parse_flags_and_mode:string(flags:long, mode:long) %{ /* pure */ #define HANDLE_FLAG(flag) \ if ((THIS->flags & (flag)) == (flag)) { \ if (strlen(THIS->__retvalue) > 0) \ strlcat(THIS->__retvalue, "|" #flag, MAXSTRINGLEN); \ else \ strlcat(THIS->__retvalue, #flag, MAXSTRINGLEN); \ } strlcpy(THIS->__retvalue, "", MAXSTRINGLEN); HANDLE_FLAG(O_RDONLY); HANDLE_FLAG(O_WRONLY); HANDLE_FLAG(O_RDWR); #ifdef O_ACCMODE HANDLE_FLAG(O_ACCMODE); #endif HANDLE_FLAG(O_CREAT); HANDLE_FLAG(O_EXCL); HANDLE_FLAG(O_NOCTTY); HANDLE_FLAG(O_TRUNC); HANDLE_FLAG(O_APPEND); HANDLE_FLAG(O_NONBLOCK); #ifdef O_SYNC HANDLE_FLAG(O_SYNC); #endif #ifdef O_ASYNC HANDLE_FLAG(O_ASYNC); #endif #ifdef O_DSYNC HANDLE_FLAG(O_DSYNC); #endif #ifdef O_RSYNC HANDLE_FLAG(O_RSYNC); #endif #ifdef O_NDELAY HANDLE_FLAG(O_NDELAY); #endif #ifdef O_PRIV HANDLE_FLAG(O_PRIV); #endif #ifdef O_DIRECT HANDLE_FLAG(O_DIRECT); #endif #ifdef O_LARGEFILE HANDLE_FLAG(O_LARGEFILE); #endif #ifdef O_DIRECTORY HANDLE_FLAG(O_DIRECTORY); #endif #ifdef O_NOFOLLOW HANDLE_FLAG(O_NOFOLLOW); #endif #ifdef O_NOATIME HANDLE_FLAG(O_NOATIME); #endif #ifdef FNDELAY HANDLE_FLAG(FNDELAY); #endif #ifdef FAPPEND HANDLE_FLAG(FAPPEND); #endif #ifdef FMARK HANDLE_FLAG(FMARK); #endif #ifdef FDEFER HANDLE_FLAG(FDEFER); #endif #ifdef FASYNC HANDLE_FLAG(FASYNC); #endif #ifdef FSHLOCK HANDLE_FLAG(FSHLOCK); #endif #ifdef FEXLOCK HANDLE_FLAG(FEXLOCK); #endif #ifdef FCREAT HANDLE_FLAG(FCREAT); #endif #ifdef FTRUNC HANDLE_FLAG(FTRUNC); #endif #ifdef FEXCL HANDLE_FLAG(FEXCL); #endif #ifdef FNBIO HANDLE_FLAG(FNBIO); #endif #ifdef FSYNC HANDLE_FLAG(FSYNC); #endif #ifdef FNOCTTY HANDLE_FLAG(FNOCTTY); #endif #ifdef O_SHLOCK HANDLE_FLAG(O_SHLOCK); #endif #ifdef O_EXLOCK HANDLE_FLAG(O_EXLOCK); #endif #undef HANDLE_FLAG // If O_CREAT was specified, handle mode if ((THIS->flags & O_CREAT) == O_CREAT) { char modebuf[100]; snprintf(modebuf, sizeof(modebuf), ", %#lo", (unsigned long)THIS->mode); strlcat(THIS->__retvalue, modebuf, MAXSTRINGLEN); } %} %(arch == "x86_64" %? function ia32:long() %{ /* pure */ if (test_tsk_thread_flag(current, TIF_IA32)) THIS->__retvalue = 1; else THIS->__retvalue = 0; %} %) global output probe process("/bin/cat").exec { printf("cat starting...\n") } probe process("/bin/cat").syscall { output = 1 # __NR_read: %( arch == "i686" %? if ($syscall == 3) %: %( arch == "x86_64" %? if ((ia32() && $syscall == 3) || (!ia32() && $syscall == 0)) %) %) { printf("read(%d, %p, %d)", get_syscall_arg(0), get_syscall_arg(1), get_syscall_arg(2)) output = 2 } # __NR_open: %(arch == "i686" %? else if ($syscall == 5) %: %(arch == "x86_64" %? else if ((ia32() && $syscall == 5) || (!ia32() && $syscall == 2)) %) %) { printf("open(\"%s\", %s)", user_string(get_syscall_arg(0)), open_parse_flags_and_mode(get_syscall_arg(1), get_syscall_arg(2))) output = 2 } # __NR_close: %(arch == "i686" %? else if ($syscall == 6) %: %(arch == "x86_64" %? else if ((ia32() && $syscall == 6) || (!ia32() && $syscall == 3)) %) %) { printf("close(%d)", get_syscall_arg(0)) output = 2 } # default else { printf("syscall %d: %s(?)", $syscall, syscall_decode($syscall)) } } probe process("/bin/cat").syscall.return { if (output == 1) printf(" = %#x\n", get_syscall_return_value()) else printf(" = %d\n", get_syscall_return_value()) } probe process("/bin/cat").death { printf("done...\n") exit() } |