1 /* 2 * Copyright 1997 Sean Eric Fagan 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by Sean Eric Fagan 15 * 4. Neither the name of the author may be used to endorse or promote 16 * products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 /* 36 * This file has routines used to print out system calls and their 37 * arguments. 38 */ 39 40 #include <sys/types.h> 41 #include <sys/event.h> 42 #include <sys/ioccom.h> 43 #include <sys/mount.h> 44 #include <sys/ptrace.h> 45 #include <sys/resource.h> 46 #include <sys/socket.h> 47 #include <sys/stat.h> 48 #include <sys/un.h> 49 #include <sys/wait.h> 50 #include <machine/sysarch.h> 51 #include <netinet/in.h> 52 #include <arpa/inet.h> 53 54 #include <assert.h> 55 #include <ctype.h> 56 #include <err.h> 57 #include <fcntl.h> 58 #include <poll.h> 59 #include <signal.h> 60 #include <stdbool.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 #include <sysdecode.h> 65 #include <unistd.h> 66 #include <vis.h> 67 68 #include <contrib/cloudabi/cloudabi_types_common.h> 69 70 #include "truss.h" 71 #include "extern.h" 72 #include "syscall.h" 73 74 /* 75 * This should probably be in its own file, sorted alphabetically. 76 */ 77 static struct syscall decoded_syscalls[] = { 78 /* Native ABI */ 79 { .name = "__getcwd", .ret_type = 1, .nargs = 2, 80 .args = { { Name | OUT, 0 }, { Int, 1 } } }, 81 { .name = "_umtx_op", .ret_type = 1, .nargs = 5, 82 .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 }, 83 { Ptr, 4 } } }, 84 { .name = "accept", .ret_type = 1, .nargs = 3, 85 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 86 { .name = "access", .ret_type = 1, .nargs = 2, 87 .args = { { Name | IN, 0 }, { Accessmode, 1 } } }, 88 { .name = "bind", .ret_type = 1, .nargs = 3, 89 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 90 { .name = "bindat", .ret_type = 1, .nargs = 4, 91 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 }, 92 { Int, 3 } } }, 93 { .name = "break", .ret_type = 1, .nargs = 1, 94 .args = { { Ptr, 0 } } }, 95 { .name = "cap_fcntls_get", .ret_type = 1, .nargs = 2, 96 .args = { { Int, 0 }, { CapFcntlRights | OUT, 1 } } }, 97 { .name = "cap_fcntls_limit", .ret_type = 1, .nargs = 2, 98 .args = { { Int, 0 }, { CapFcntlRights, 1 } } }, 99 { .name = "chdir", .ret_type = 1, .nargs = 1, 100 .args = { { Name, 0 } } }, 101 { .name = "chflags", .ret_type = 1, .nargs = 2, 102 .args = { { Name | IN, 0 }, { FileFlags, 1 } } }, 103 { .name = "chflagsat", .ret_type = 1, .nargs = 4, 104 .args = { { Atfd, 0 }, { Name | IN, 1 }, { FileFlags, 2 }, 105 { Atflags, 3 } } }, 106 { .name = "chmod", .ret_type = 1, .nargs = 2, 107 .args = { { Name, 0 }, { Octal, 1 } } }, 108 { .name = "chown", .ret_type = 1, .nargs = 3, 109 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } }, 110 { .name = "chroot", .ret_type = 1, .nargs = 1, 111 .args = { { Name, 0 } } }, 112 { .name = "clock_gettime", .ret_type = 1, .nargs = 2, 113 .args = { { Int, 0 }, { Timespec | OUT, 1 } } }, 114 { .name = "close", .ret_type = 1, .nargs = 1, 115 .args = { { Int, 0 } } }, 116 { .name = "connect", .ret_type = 1, .nargs = 3, 117 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 118 { .name = "connectat", .ret_type = 1, .nargs = 4, 119 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 }, 120 { Int, 3 } } }, 121 { .name = "eaccess", .ret_type = 1, .nargs = 2, 122 .args = { { Name | IN, 0 }, { Accessmode, 1 } } }, 123 { .name = "execve", .ret_type = 1, .nargs = 3, 124 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 }, 125 { ExecEnv | IN, 2 } } }, 126 { .name = "exit", .ret_type = 0, .nargs = 1, 127 .args = { { Hex, 0 } } }, 128 { .name = "faccessat", .ret_type = 1, .nargs = 4, 129 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 }, 130 { Atflags, 3 } } }, 131 { .name = "fchflags", .ret_type = 1, .nargs = 2, 132 .args = { { Int, 0 }, { FileFlags, 1 } } }, 133 { .name = "fchmod", .ret_type = 1, .nargs = 2, 134 .args = { { Int, 0 }, { Octal, 1 } } }, 135 { .name = "fchmodat", .ret_type = 1, .nargs = 4, 136 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } }, 137 { .name = "fchown", .ret_type = 1, .nargs = 3, 138 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } }, 139 { .name = "fchownat", .ret_type = 1, .nargs = 5, 140 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 }, 141 { Atflags, 4 } } }, 142 { .name = "fcntl", .ret_type = 1, .nargs = 3, 143 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } }, 144 { .name = "flock", .ret_type = 1, .nargs = 2, 145 .args = { { Int, 0 }, { Flockop, 1 } } }, 146 { .name = "fstat", .ret_type = 1, .nargs = 2, 147 .args = { { Int, 0 }, { Stat | OUT, 1 } } }, 148 { .name = "fstatat", .ret_type = 1, .nargs = 4, 149 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 }, 150 { Atflags, 3 } } }, 151 { .name = "fstatfs", .ret_type = 1, .nargs = 2, 152 .args = { { Int, 0 }, { StatFs | OUT, 1 } } }, 153 { .name = "ftruncate", .ret_type = 1, .nargs = 2, 154 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } }, 155 { .name = "futimens", .ret_type = 1, .nargs = 2, 156 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } }, 157 { .name = "futimes", .ret_type = 1, .nargs = 2, 158 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } }, 159 { .name = "futimesat", .ret_type = 1, .nargs = 3, 160 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } }, 161 { .name = "getfsstat", .ret_type = 1, .nargs = 3, 162 .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } }, 163 { .name = "getitimer", .ret_type = 1, .nargs = 2, 164 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } }, 165 { .name = "getpeername", .ret_type = 1, .nargs = 3, 166 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 167 { .name = "getpgid", .ret_type = 1, .nargs = 1, 168 .args = { { Int, 0 } } }, 169 { .name = "getrlimit", .ret_type = 1, .nargs = 2, 170 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } }, 171 { .name = "getrusage", .ret_type = 1, .nargs = 2, 172 .args = { { Int, 0 }, { Rusage | OUT, 1 } } }, 173 { .name = "getsid", .ret_type = 1, .nargs = 1, 174 .args = { { Int, 0 } } }, 175 { .name = "getsockname", .ret_type = 1, .nargs = 3, 176 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 177 { .name = "gettimeofday", .ret_type = 1, .nargs = 2, 178 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } }, 179 { .name = "ioctl", .ret_type = 1, .nargs = 3, 180 .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } }, 181 { .name = "kevent", .ret_type = 1, .nargs = 6, 182 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, 183 { Int, 4 }, { Timespec, 5 } } }, 184 { .name = "kill", .ret_type = 1, .nargs = 2, 185 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } }, 186 { .name = "kldfind", .ret_type = 1, .nargs = 1, 187 .args = { { Name | IN, 0 } } }, 188 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1, 189 .args = { { Int, 0 } } }, 190 { .name = "kldload", .ret_type = 1, .nargs = 1, 191 .args = { { Name | IN, 0 } } }, 192 { .name = "kldnext", .ret_type = 1, .nargs = 1, 193 .args = { { Int, 0 } } }, 194 { .name = "kldstat", .ret_type = 1, .nargs = 2, 195 .args = { { Int, 0 }, { Ptr, 1 } } }, 196 { .name = "kldsym", .ret_type = 1, .nargs = 3, 197 .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } }, 198 { .name = "kldunload", .ret_type = 1, .nargs = 1, 199 .args = { { Int, 0 } } }, 200 { .name = "kldunloadf", .ret_type = 1, .nargs = 2, 201 .args = { { Int, 0 }, { Kldunloadflags, 1 } } }, 202 { .name = "kse_release", .ret_type = 0, .nargs = 1, 203 .args = { { Timespec, 0 } } }, 204 { .name = "lchflags", .ret_type = 1, .nargs = 2, 205 .args = { { Name | IN, 0 }, { FileFlags, 1 } } }, 206 { .name = "lchmod", .ret_type = 1, .nargs = 2, 207 .args = { { Name, 0 }, { Octal, 1 } } }, 208 { .name = "lchown", .ret_type = 1, .nargs = 3, 209 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } }, 210 { .name = "link", .ret_type = 1, .nargs = 2, 211 .args = { { Name, 0 }, { Name, 1 } } }, 212 { .name = "linkat", .ret_type = 1, .nargs = 5, 213 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 }, 214 { Atflags, 4 } } }, 215 { .name = "lseek", .ret_type = 2, .nargs = 3, 216 .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } }, 217 { .name = "lstat", .ret_type = 1, .nargs = 2, 218 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, 219 { .name = "lutimes", .ret_type = 1, .nargs = 2, 220 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, 221 { .name = "madvise", .ret_type = 1, .nargs = 3, 222 .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } }, 223 { .name = "mkdir", .ret_type = 1, .nargs = 2, 224 .args = { { Name, 0 }, { Octal, 1 } } }, 225 { .name = "mkdirat", .ret_type = 1, .nargs = 3, 226 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } }, 227 { .name = "mkfifo", .ret_type = 1, .nargs = 2, 228 .args = { { Name, 0 }, { Octal, 1 } } }, 229 { .name = "mkfifoat", .ret_type = 1, .nargs = 3, 230 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } }, 231 { .name = "mknod", .ret_type = 1, .nargs = 3, 232 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } }, 233 { .name = "mknodat", .ret_type = 1, .nargs = 4, 234 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } }, 235 { .name = "mmap", .ret_type = 1, .nargs = 6, 236 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 }, 237 { Int, 4 }, { QuadHex, 5 } } }, 238 { .name = "modfind", .ret_type = 1, .nargs = 1, 239 .args = { { Name | IN, 0 } } }, 240 { .name = "mount", .ret_type = 1, .nargs = 4, 241 .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } }, 242 { .name = "mprotect", .ret_type = 1, .nargs = 3, 243 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } }, 244 { .name = "munmap", .ret_type = 1, .nargs = 2, 245 .args = { { Ptr, 0 }, { Sizet, 1 } } }, 246 { .name = "nanosleep", .ret_type = 1, .nargs = 1, 247 .args = { { Timespec, 0 } } }, 248 { .name = "open", .ret_type = 1, .nargs = 3, 249 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } }, 250 { .name = "openat", .ret_type = 1, .nargs = 4, 251 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 }, 252 { Octal, 3 } } }, 253 { .name = "pathconf", .ret_type = 1, .nargs = 2, 254 .args = { { Name | IN, 0 }, { Pathconf, 1 } } }, 255 { .name = "pipe", .ret_type = 1, .nargs = 1, 256 .args = { { PipeFds | OUT, 0 } } }, 257 { .name = "pipe2", .ret_type = 1, .nargs = 2, 258 .args = { { Ptr, 0 }, { Pipe2, 1 } } }, 259 { .name = "poll", .ret_type = 1, .nargs = 3, 260 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } }, 261 { .name = "posix_fadvise", .ret_type = 1, .nargs = 4, 262 .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 }, 263 { Fadvice, 3 } } }, 264 { .name = "posix_openpt", .ret_type = 1, .nargs = 1, 265 .args = { { Open, 0 } } }, 266 { .name = "procctl", .ret_type = 1, .nargs = 4, 267 .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } }, 268 { .name = "read", .ret_type = 1, .nargs = 3, 269 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } }, 270 { .name = "readlink", .ret_type = 1, .nargs = 3, 271 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } }, 272 { .name = "readlinkat", .ret_type = 1, .nargs = 4, 273 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 }, 274 { Sizet, 3 } } }, 275 { .name = "recvfrom", .ret_type = 1, .nargs = 6, 276 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 }, { Hex, 3 }, 277 { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } }, 278 { .name = "rename", .ret_type = 1, .nargs = 2, 279 .args = { { Name, 0 }, { Name, 1 } } }, 280 { .name = "renameat", .ret_type = 1, .nargs = 4, 281 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } }, 282 { .name = "rfork", .ret_type = 1, .nargs = 1, 283 .args = { { Rforkflags, 0 } } }, 284 { .name = "rmdir", .ret_type = 1, .nargs = 1, 285 .args = { { Name, 0 } } }, 286 { .name = "select", .ret_type = 1, .nargs = 5, 287 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, 288 { Timeval, 4 } } }, 289 { .name = "sendto", .ret_type = 1, .nargs = 6, 290 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 }, { Hex, 3 }, 291 { Sockaddr | IN, 4 }, { Int | IN, 5 } } }, 292 { .name = "setitimer", .ret_type = 1, .nargs = 3, 293 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } }, 294 { .name = "setrlimit", .ret_type = 1, .nargs = 2, 295 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } }, 296 { .name = "shutdown", .ret_type = 1, .nargs = 2, 297 .args = { { Int, 0 }, { Shutdown, 1 } } }, 298 { .name = "sigaction", .ret_type = 1, .nargs = 3, 299 .args = { { Signal, 0 }, { Sigaction | IN, 1 }, 300 { Sigaction | OUT, 2 } } }, 301 { .name = "sigpending", .ret_type = 1, .nargs = 1, 302 .args = { { Sigset | OUT, 0 } } }, 303 { .name = "sigprocmask", .ret_type = 1, .nargs = 3, 304 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } }, 305 { .name = "sigqueue", .ret_type = 1, .nargs = 3, 306 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } }, 307 { .name = "sigreturn", .ret_type = 1, .nargs = 1, 308 .args = { { Ptr, 0 } } }, 309 { .name = "sigsuspend", .ret_type = 1, .nargs = 1, 310 .args = { { Sigset | IN, 0 } } }, 311 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3, 312 .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } }, 313 { .name = "sigwait", .ret_type = 1, .nargs = 2, 314 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } }, 315 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2, 316 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } }, 317 { .name = "socket", .ret_type = 1, .nargs = 3, 318 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } }, 319 { .name = "stat", .ret_type = 1, .nargs = 2, 320 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, 321 { .name = "statfs", .ret_type = 1, .nargs = 2, 322 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } }, 323 { .name = "symlink", .ret_type = 1, .nargs = 2, 324 .args = { { Name, 0 }, { Name, 1 } } }, 325 { .name = "symlinkat", .ret_type = 1, .nargs = 3, 326 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } }, 327 { .name = "sysarch", .ret_type = 1, .nargs = 2, 328 .args = { { Sysarch, 0 }, { Ptr, 1 } } }, 329 { .name = "thr_kill", .ret_type = 1, .nargs = 2, 330 .args = { { Long, 0 }, { Signal, 1 } } }, 331 { .name = "thr_self", .ret_type = 1, .nargs = 1, 332 .args = { { Ptr, 0 } } }, 333 { .name = "truncate", .ret_type = 1, .nargs = 2, 334 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } }, 335 #if 0 336 /* Does not exist */ 337 { .name = "umount", .ret_type = 1, .nargs = 2, 338 .args = { { Name, 0 }, { Int, 2 } } }, 339 #endif 340 { .name = "unlink", .ret_type = 1, .nargs = 1, 341 .args = { { Name, 0 } } }, 342 { .name = "unlinkat", .ret_type = 1, .nargs = 3, 343 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } }, 344 { .name = "unmount", .ret_type = 1, .nargs = 2, 345 .args = { { Name, 0 }, { Int, 1 } } }, 346 { .name = "utimensat", .ret_type = 1, .nargs = 4, 347 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 }, 348 { Atflags, 3 } } }, 349 { .name = "utimes", .ret_type = 1, .nargs = 2, 350 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, 351 { .name = "utrace", .ret_type = 1, .nargs = 1, 352 .args = { { Utrace, 0 } } }, 353 { .name = "wait4", .ret_type = 1, .nargs = 4, 354 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 }, 355 { Rusage | OUT, 3 } } }, 356 { .name = "wait6", .ret_type = 1, .nargs = 6, 357 .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 }, 358 { Waitoptions, 3 }, { Rusage | OUT, 4 }, { Ptr, 5 } } }, 359 { .name = "write", .ret_type = 1, .nargs = 3, 360 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } }, 361 362 /* Linux ABI */ 363 { .name = "linux_access", .ret_type = 1, .nargs = 2, 364 .args = { { Name, 0 }, { Accessmode, 1 } } }, 365 { .name = "linux_execve", .ret_type = 1, .nargs = 3, 366 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 }, 367 { ExecEnv | IN, 2 } } }, 368 { .name = "linux_lseek", .ret_type = 2, .nargs = 3, 369 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } }, 370 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2, 371 .args = { { Name | IN, 0 }, { Int, 1 } } }, 372 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2, 373 .args = { { Int, 0 }, { Ptr | OUT, 1 } } }, 374 { .name = "linux_newstat", .ret_type = 1, .nargs = 2, 375 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } }, 376 { .name = "linux_open", .ret_type = 1, .nargs = 3, 377 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } }, 378 { .name = "linux_readlink", .ret_type = 1, .nargs = 3, 379 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } }, 380 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2, 381 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } }, 382 { .name = "linux_stat64", .ret_type = 1, .nargs = 2, 383 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } }, 384 385 /* CloudABI system calls. */ 386 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1, 387 .args = { { CloudABIClockID, 0 } } }, 388 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2, 389 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } }, 390 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3, 391 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } }, 392 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1, 393 .args = { { Int, 0 } } }, 394 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1, 395 .args = { { CloudABIFileType, 0 } } }, 396 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2, 397 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } }, 398 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1, 399 .args = { { Int, 0 } } }, 400 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1, 401 .args = { { Int, 0 } } }, 402 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2, 403 .args = { { Int, 0 }, { Int, 1 } } }, 404 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3, 405 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } }, 406 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2, 407 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } }, 408 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3, 409 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 }, 410 { ClouduABIFDSFlags, 2 } } }, 411 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1, 412 .args = { { Int, 0 } } }, 413 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4, 414 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 }, 415 { CloudABIAdvice, 3 } } }, 416 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3, 417 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } }, 418 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3, 419 .args = { { Int, 0 }, { BinString | IN, 1 }, 420 { CloudABIFileType, 3 } } }, 421 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4, 422 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 }, 423 { Int, 3 }, { BinString | IN, 4 } } }, 424 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4, 425 .args = { { Int, 0 }, { BinString | IN, 1 }, 426 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } }, 427 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4, 428 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, 429 { Int, 3 } } }, 430 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4, 431 .args = { { Int, 0 }, { BinString | IN, 1 }, 432 { BinString | OUT, 3 }, { Int, 4 } } }, 433 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4, 434 .args = { { Int, 0 }, { BinString | IN, 1 }, 435 { Int, 3 }, { BinString | IN, 4 } } }, 436 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2, 437 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } }, 438 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3, 439 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 }, 440 { CloudABIFSFlags, 2 } } }, 441 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3, 442 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 }, 443 { CloudABIFileStat | OUT, 3 } } }, 444 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4, 445 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 }, 446 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } }, 447 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3, 448 .args = { { BinString | IN, 0 }, 449 { Int, 2 }, { BinString | IN, 3 } } }, 450 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3, 451 .args = { { Int, 0 }, { BinString | IN, 1 }, 452 { CloudABIULFlags, 3 } } }, 453 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2, 454 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } }, 455 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3, 456 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } }, 457 { .name = "cloudabi_sys_mem_lock", .ret_type = 1, .nargs = 2, 458 .args = { { Ptr, 0 }, { Int, 1 } } }, 459 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6, 460 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 }, 461 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } }, 462 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3, 463 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } }, 464 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3, 465 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } }, 466 { .name = "cloudabi_sys_mem_unlock", .ret_type = 1, .nargs = 2, 467 .args = { { Ptr, 0 }, { Int, 1 } } }, 468 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2, 469 .args = { { Ptr, 0 }, { Int, 1 } } }, 470 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5, 471 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, 472 { IntArray, 3 }, { Int, 4 } } }, 473 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1, 474 .args = { { Int, 0 } } }, 475 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 }, 476 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1, 477 .args = { { CloudABISignal, 0 } } }, 478 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2, 479 .args = { { BinString | OUT, 0 }, { Int, 1 } } }, 480 { .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2, 481 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } }, 482 { .name = "cloudabi_sys_sock_bind", .ret_type = 1, .nargs = 3, 483 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } }, 484 { .name = "cloudabi_sys_sock_connect", .ret_type = 1, .nargs = 3, 485 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } }, 486 { .name = "cloudabi_sys_sock_listen", .ret_type = 1, .nargs = 2, 487 .args = { { Int, 0 }, { Int, 1 } } }, 488 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2, 489 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } }, 490 { .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3, 491 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 }, 492 { CloudABISSFlags, 2 } } }, 493 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2, 494 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } }, 495 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 }, 496 497 { .name = 0 }, 498 }; 499 static STAILQ_HEAD(, syscall) syscalls; 500 501 /* Xlat idea taken from strace */ 502 struct xlat { 503 int val; 504 const char *str; 505 }; 506 507 #define X(a) { a, #a }, 508 #define XEND { 0, NULL } 509 510 static struct xlat kevent_filters[] = { 511 X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE) 512 X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER) 513 X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER) 514 X(EVFILT_SENDFILE) XEND 515 }; 516 517 static struct xlat kevent_flags[] = { 518 X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT) 519 X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT) 520 X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND 521 }; 522 523 static struct xlat kevent_user_ffctrl[] = { 524 X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY) 525 XEND 526 }; 527 528 static struct xlat kevent_rdwr_fflags[] = { 529 X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND 530 }; 531 532 static struct xlat kevent_vnode_fflags[] = { 533 X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB) 534 X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND 535 }; 536 537 static struct xlat kevent_proc_fflags[] = { 538 X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR) 539 X(NOTE_CHILD) XEND 540 }; 541 542 static struct xlat kevent_timer_fflags[] = { 543 X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS) 544 XEND 545 }; 546 547 static struct xlat poll_flags[] = { 548 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR) 549 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND) 550 X(POLLWRBAND) X(POLLINIGNEOF) XEND 551 }; 552 553 static struct xlat sigaction_flags[] = { 554 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP) 555 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND 556 }; 557 558 static struct xlat pathconf_arg[] = { 559 X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT) 560 X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF) 561 X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE) 562 X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO) 563 X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS) 564 X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE) 565 X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN) 566 X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX) 567 X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT) 568 X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND 569 }; 570 571 static struct xlat at_flags[] = { 572 X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW) 573 X(AT_REMOVEDIR) XEND 574 }; 575 576 static struct xlat sysarch_ops[] = { 577 #if defined(__i386__) || defined(__amd64__) 578 X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM) 579 X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE) 580 X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE) 581 X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE) 582 X(AMD64_GET_XFPUSTATE) 583 #endif 584 XEND 585 }; 586 587 static struct xlat linux_socketcall_ops[] = { 588 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN) 589 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME) 590 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO) 591 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT) 592 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG) 593 XEND 594 }; 595 596 #undef X 597 #define X(a) { CLOUDABI_##a, #a }, 598 599 static struct xlat cloudabi_advice[] = { 600 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL) 601 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED) 602 XEND 603 }; 604 605 static struct xlat cloudabi_clockid[] = { 606 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID) 607 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID) 608 XEND 609 }; 610 611 static struct xlat cloudabi_errno[] = { 612 X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL) 613 X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG) 614 X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED) 615 X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT) 616 X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ) 617 X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR) 618 X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP) 619 X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH) 620 X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK) 621 X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC) 622 X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE) 623 X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW) 624 X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT) 625 X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE) 626 X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE) 627 XEND 628 }; 629 630 static struct xlat cloudabi_fdflags[] = { 631 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK) 632 X(FDFLAG_RSYNC) X(FDFLAG_SYNC) 633 XEND 634 }; 635 636 static struct xlat cloudabi_fdsflags[] = { 637 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS) 638 XEND 639 }; 640 641 static struct xlat cloudabi_filetype[] = { 642 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE) 643 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY) 644 X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS) 645 X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY) 646 X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_SEQPACKET) 647 X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK) 648 XEND 649 }; 650 651 static struct xlat cloudabi_fsflags[] = { 652 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM) 653 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE) 654 XEND 655 }; 656 657 static struct xlat cloudabi_mflags[] = { 658 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED) 659 XEND 660 }; 661 662 static struct xlat cloudabi_mprot[] = { 663 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ) 664 XEND 665 }; 666 667 static struct xlat cloudabi_msflags[] = { 668 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC) 669 XEND 670 }; 671 672 static struct xlat cloudabi_oflags[] = { 673 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC) 674 XEND 675 }; 676 677 static struct xlat cloudabi_sa_family[] = { 678 X(AF_UNSPEC) X(AF_INET) X(AF_INET6) X(AF_UNIX) 679 XEND 680 }; 681 682 static struct xlat cloudabi_sdflags[] = { 683 X(SHUT_RD) X(SHUT_WR) 684 XEND 685 }; 686 687 static struct xlat cloudabi_signal[] = { 688 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE) 689 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT) 690 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP) 691 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2) 692 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ) 693 XEND 694 }; 695 696 static struct xlat cloudabi_ssflags[] = { 697 X(SOCKSTAT_CLEAR_ERROR) 698 XEND 699 }; 700 701 static struct xlat cloudabi_ssstate[] = { 702 X(SOCKSTATE_ACCEPTCONN) 703 XEND 704 }; 705 706 static struct xlat cloudabi_ulflags[] = { 707 X(UNLINK_REMOVEDIR) 708 XEND 709 }; 710 711 static struct xlat cloudabi_whence[] = { 712 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET) 713 XEND 714 }; 715 716 #undef X 717 #undef XEND 718 719 /* 720 * Searches an xlat array for a value, and returns it if found. Otherwise 721 * return a string representation. 722 */ 723 static const char * 724 lookup(struct xlat *xlat, int val, int base) 725 { 726 static char tmp[16]; 727 728 for (; xlat->str != NULL; xlat++) 729 if (xlat->val == val) 730 return (xlat->str); 731 switch (base) { 732 case 8: 733 sprintf(tmp, "0%o", val); 734 break; 735 case 16: 736 sprintf(tmp, "0x%x", val); 737 break; 738 case 10: 739 sprintf(tmp, "%u", val); 740 break; 741 default: 742 errx(1,"Unknown lookup base"); 743 break; 744 } 745 return (tmp); 746 } 747 748 static const char * 749 xlookup(struct xlat *xlat, int val) 750 { 751 752 return (lookup(xlat, val, 16)); 753 } 754 755 /* 756 * Searches an xlat array containing bitfield values. Remaining bits 757 * set after removing the known ones are printed at the end: 758 * IN|0x400. 759 */ 760 static char * 761 xlookup_bits(struct xlat *xlat, int val) 762 { 763 int len, rem; 764 static char str[512]; 765 766 len = 0; 767 rem = val; 768 for (; xlat->str != NULL; xlat++) { 769 if ((xlat->val & rem) == xlat->val) { 770 /* 771 * Don't print the "all-bits-zero" string unless all 772 * bits are really zero. 773 */ 774 if (xlat->val == 0 && val != 0) 775 continue; 776 len += sprintf(str + len, "%s|", xlat->str); 777 rem &= ~(xlat->val); 778 } 779 } 780 781 /* 782 * If we have leftover bits or didn't match anything, print 783 * the remainder. 784 */ 785 if (rem || len == 0) 786 len += sprintf(str + len, "0x%x", rem); 787 if (len && str[len - 1] == '|') 788 len--; 789 str[len] = 0; 790 return (str); 791 } 792 793 static void 794 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value) 795 { 796 const char *str; 797 798 str = decoder(value); 799 if (str != NULL) 800 fputs(str, fp); 801 else 802 fprintf(fp, "%d", value); 803 } 804 805 static void 806 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value) 807 { 808 int rem; 809 810 if (!decoder(fp, value, &rem)) 811 fprintf(fp, "0x%x", rem); 812 else if (rem != 0) 813 fprintf(fp, "|0x%x", rem); 814 } 815 816 static void 817 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp, 818 uint32_t value) 819 { 820 uint32_t rem; 821 822 if (!decoder(fp, value, &rem)) 823 fprintf(fp, "0x%x", rem); 824 else if (rem != 0) 825 fprintf(fp, "|0x%x", rem); 826 } 827 828 #ifndef __LP64__ 829 /* 830 * Add argument padding to subsequent system calls afater a Quad 831 * syscall arguments as needed. This used to be done by hand in the 832 * decoded_syscalls table which was ugly and error prone. It is 833 * simpler to do the fixup of offsets at initalization time than when 834 * decoding arguments. 835 */ 836 static void 837 quad_fixup(struct syscall *sc) 838 { 839 int offset, prev; 840 u_int i; 841 842 offset = 0; 843 prev = -1; 844 for (i = 0; i < sc->nargs; i++) { 845 /* This arg type is a dummy that doesn't use offset. */ 846 if ((sc->args[i].type & ARG_MASK) == PipeFds) 847 continue; 848 849 assert(prev < sc->args[i].offset); 850 prev = sc->args[i].offset; 851 sc->args[i].offset += offset; 852 switch (sc->args[i].type & ARG_MASK) { 853 case Quad: 854 case QuadHex: 855 #ifdef __powerpc__ 856 /* 857 * 64-bit arguments on 32-bit powerpc must be 858 * 64-bit aligned. If the current offset is 859 * not aligned, the calling convention inserts 860 * a 32-bit pad argument that should be skipped. 861 */ 862 if (sc->args[i].offset % 2 == 1) { 863 sc->args[i].offset++; 864 offset++; 865 } 866 #endif 867 offset++; 868 default: 869 break; 870 } 871 } 872 } 873 #endif 874 875 void 876 init_syscalls(void) 877 { 878 struct syscall *sc; 879 880 STAILQ_INIT(&syscalls); 881 for (sc = decoded_syscalls; sc->name != NULL; sc++) { 882 #ifndef __LP64__ 883 quad_fixup(sc); 884 #endif 885 STAILQ_INSERT_HEAD(&syscalls, sc, entries); 886 } 887 } 888 889 static struct syscall * 890 find_syscall(struct procabi *abi, u_int number) 891 { 892 struct extra_syscall *es; 893 894 if (number < nitems(abi->syscalls)) 895 return (abi->syscalls[number]); 896 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) { 897 if (es->number == number) 898 return (es->sc); 899 } 900 return (NULL); 901 } 902 903 static void 904 add_syscall(struct procabi *abi, u_int number, struct syscall *sc) 905 { 906 struct extra_syscall *es; 907 908 if (number < nitems(abi->syscalls)) { 909 assert(abi->syscalls[number] == NULL); 910 abi->syscalls[number] = sc; 911 } else { 912 es = malloc(sizeof(*es)); 913 es->sc = sc; 914 es->number = number; 915 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries); 916 } 917 } 918 919 /* 920 * If/when the list gets big, it might be desirable to do it 921 * as a hash table or binary search. 922 */ 923 struct syscall * 924 get_syscall(struct threadinfo *t, u_int number, u_int nargs) 925 { 926 struct syscall *sc; 927 const char *name; 928 char *new_name; 929 u_int i; 930 931 sc = find_syscall(t->proc->abi, number); 932 if (sc != NULL) 933 return (sc); 934 935 name = sysdecode_syscallname(t->proc->abi->abi, number); 936 if (name == NULL) { 937 asprintf(&new_name, "#%d", number); 938 name = new_name; 939 } else 940 new_name = NULL; 941 STAILQ_FOREACH(sc, &syscalls, entries) { 942 if (strcmp(name, sc->name) == 0) { 943 add_syscall(t->proc->abi, number, sc); 944 free(new_name); 945 return (sc); 946 } 947 } 948 949 /* It is unknown. Add it into the list. */ 950 #if DEBUG 951 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name, 952 nargs); 953 #endif 954 955 sc = calloc(1, sizeof(struct syscall)); 956 sc->name = name; 957 if (new_name != NULL) 958 sc->unknown = true; 959 sc->ret_type = 1; 960 sc->nargs = nargs; 961 for (i = 0; i < nargs; i++) { 962 sc->args[i].offset = i; 963 /* Treat all unknown arguments as LongHex. */ 964 sc->args[i].type = LongHex; 965 } 966 STAILQ_INSERT_HEAD(&syscalls, sc, entries); 967 add_syscall(t->proc->abi, number, sc); 968 969 return (sc); 970 } 971 972 /* 973 * Copy a fixed amount of bytes from the process. 974 */ 975 static int 976 get_struct(pid_t pid, void *offset, void *buf, int len) 977 { 978 struct ptrace_io_desc iorequest; 979 980 iorequest.piod_op = PIOD_READ_D; 981 iorequest.piod_offs = offset; 982 iorequest.piod_addr = buf; 983 iorequest.piod_len = len; 984 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) 985 return (-1); 986 return (0); 987 } 988 989 #define MAXSIZE 4096 990 991 /* 992 * Copy a string from the process. Note that it is 993 * expected to be a C string, but if max is set, it will 994 * only get that much. 995 */ 996 static char * 997 get_string(pid_t pid, void *addr, int max) 998 { 999 struct ptrace_io_desc iorequest; 1000 char *buf, *nbuf; 1001 size_t offset, size, totalsize; 1002 1003 offset = 0; 1004 if (max) 1005 size = max + 1; 1006 else { 1007 /* Read up to the end of the current page. */ 1008 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE); 1009 if (size > MAXSIZE) 1010 size = MAXSIZE; 1011 } 1012 totalsize = size; 1013 buf = malloc(totalsize); 1014 if (buf == NULL) 1015 return (NULL); 1016 for (;;) { 1017 iorequest.piod_op = PIOD_READ_D; 1018 iorequest.piod_offs = (char *)addr + offset; 1019 iorequest.piod_addr = buf + offset; 1020 iorequest.piod_len = size; 1021 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) { 1022 free(buf); 1023 return (NULL); 1024 } 1025 if (memchr(buf + offset, '\0', size) != NULL) 1026 return (buf); 1027 offset += size; 1028 if (totalsize < MAXSIZE && max == 0) { 1029 size = MAXSIZE - totalsize; 1030 if (size > PAGE_SIZE) 1031 size = PAGE_SIZE; 1032 nbuf = realloc(buf, totalsize + size); 1033 if (nbuf == NULL) { 1034 buf[totalsize - 1] = '\0'; 1035 return (buf); 1036 } 1037 buf = nbuf; 1038 totalsize += size; 1039 } else { 1040 buf[totalsize - 1] = '\0'; 1041 return (buf); 1042 } 1043 } 1044 } 1045 1046 static const char * 1047 strsig2(int sig) 1048 { 1049 static char tmp[32]; 1050 const char *signame; 1051 1052 signame = sysdecode_signal(sig); 1053 if (signame == NULL) { 1054 snprintf(tmp, sizeof(tmp), "%d", sig); 1055 signame = tmp; 1056 } 1057 return (signame); 1058 } 1059 1060 static void 1061 print_kevent(FILE *fp, struct kevent *ke, int input) 1062 { 1063 1064 switch (ke->filter) { 1065 case EVFILT_READ: 1066 case EVFILT_WRITE: 1067 case EVFILT_VNODE: 1068 case EVFILT_PROC: 1069 case EVFILT_TIMER: 1070 case EVFILT_PROCDESC: 1071 fprintf(fp, "%ju", (uintmax_t)ke->ident); 1072 break; 1073 case EVFILT_SIGNAL: 1074 fputs(strsig2(ke->ident), fp); 1075 break; 1076 default: 1077 fprintf(fp, "%p", (void *)ke->ident); 1078 } 1079 fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter), 1080 xlookup_bits(kevent_flags, ke->flags)); 1081 switch (ke->filter) { 1082 case EVFILT_READ: 1083 case EVFILT_WRITE: 1084 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp); 1085 break; 1086 case EVFILT_VNODE: 1087 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp); 1088 break; 1089 case EVFILT_PROC: 1090 case EVFILT_PROCDESC: 1091 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp); 1092 break; 1093 case EVFILT_TIMER: 1094 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp); 1095 break; 1096 case EVFILT_USER: { 1097 int ctrl, data; 1098 1099 ctrl = ke->fflags & NOTE_FFCTRLMASK; 1100 data = ke->fflags & NOTE_FFLAGSMASK; 1101 if (input) { 1102 fputs(xlookup(kevent_user_ffctrl, ctrl), fp); 1103 if (ke->fflags & NOTE_TRIGGER) 1104 fputs("|NOTE_TRIGGER", fp); 1105 if (data != 0) 1106 fprintf(fp, "|%#x", data); 1107 } else { 1108 fprintf(fp, "%#x", data); 1109 } 1110 break; 1111 } 1112 default: 1113 fprintf(fp, "%#x", ke->fflags); 1114 } 1115 fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata); 1116 } 1117 1118 static void 1119 print_utrace(FILE *fp, void *utrace_addr, size_t len) 1120 { 1121 unsigned char *utrace_buffer; 1122 1123 fprintf(fp, "{ "); 1124 if (sysdecode_utrace(fp, utrace_addr, len)) { 1125 fprintf(fp, " }"); 1126 return; 1127 } 1128 1129 utrace_buffer = utrace_addr; 1130 fprintf(fp, "%zu:", len); 1131 while (len--) 1132 fprintf(fp, " %02x", *utrace_buffer++); 1133 fprintf(fp, " }"); 1134 } 1135 1136 /* 1137 * Converts a syscall argument into a string. Said string is 1138 * allocated via malloc(), so needs to be free()'d. sc is 1139 * a pointer to the syscall description (see above); args is 1140 * an array of all of the system call arguments. 1141 */ 1142 char * 1143 print_arg(struct syscall_args *sc, unsigned long *args, long *retval, 1144 struct trussinfo *trussinfo) 1145 { 1146 FILE *fp; 1147 char *tmp; 1148 size_t tmplen; 1149 pid_t pid; 1150 1151 fp = open_memstream(&tmp, &tmplen); 1152 pid = trussinfo->curthread->proc->pid; 1153 switch (sc->type & ARG_MASK) { 1154 case Hex: 1155 fprintf(fp, "0x%x", (int)args[sc->offset]); 1156 break; 1157 case Octal: 1158 fprintf(fp, "0%o", (int)args[sc->offset]); 1159 break; 1160 case Int: 1161 fprintf(fp, "%d", (int)args[sc->offset]); 1162 break; 1163 case UInt: 1164 fprintf(fp, "%u", (unsigned int)args[sc->offset]); 1165 break; 1166 case LongHex: 1167 fprintf(fp, "0x%lx", args[sc->offset]); 1168 break; 1169 case Long: 1170 fprintf(fp, "%ld", args[sc->offset]); 1171 break; 1172 case Sizet: 1173 fprintf(fp, "%zu", (size_t)args[sc->offset]); 1174 break; 1175 case Name: { 1176 /* NULL-terminated string. */ 1177 char *tmp2; 1178 1179 tmp2 = get_string(pid, (void*)args[sc->offset], 0); 1180 fprintf(fp, "\"%s\"", tmp2); 1181 free(tmp2); 1182 break; 1183 } 1184 case BinString: { 1185 /* 1186 * Binary block of data that might have printable characters. 1187 * XXX If type|OUT, assume that the length is the syscall's 1188 * return value. Otherwise, assume that the length of the block 1189 * is in the next syscall argument. 1190 */ 1191 int max_string = trussinfo->strsize; 1192 char tmp2[max_string + 1], *tmp3; 1193 int len; 1194 int truncated = 0; 1195 1196 if (sc->type & OUT) 1197 len = retval[0]; 1198 else 1199 len = args[sc->offset + 1]; 1200 1201 /* 1202 * Don't print more than max_string characters, to avoid word 1203 * wrap. If we have to truncate put some ... after the string. 1204 */ 1205 if (len > max_string) { 1206 len = max_string; 1207 truncated = 1; 1208 } 1209 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) 1210 != -1) { 1211 tmp3 = malloc(len * 4 + 1); 1212 while (len) { 1213 if (strvisx(tmp3, tmp2, len, 1214 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) 1215 break; 1216 len--; 1217 truncated = 1; 1218 } 1219 fprintf(fp, "\"%s\"%s", tmp3, truncated ? 1220 "..." : ""); 1221 free(tmp3); 1222 } else { 1223 fprintf(fp, "0x%lx", args[sc->offset]); 1224 } 1225 break; 1226 } 1227 case ExecArgs: 1228 case ExecEnv: 1229 case StringArray: { 1230 uintptr_t addr; 1231 union { 1232 char *strarray[0]; 1233 char buf[PAGE_SIZE]; 1234 } u; 1235 char *string; 1236 size_t len; 1237 u_int first, i; 1238 1239 /* 1240 * Only parse argv[] and environment arrays from exec calls 1241 * if requested. 1242 */ 1243 if (((sc->type & ARG_MASK) == ExecArgs && 1244 (trussinfo->flags & EXECVEARGS) == 0) || 1245 ((sc->type & ARG_MASK) == ExecEnv && 1246 (trussinfo->flags & EXECVEENVS) == 0)) { 1247 fprintf(fp, "0x%lx", args[sc->offset]); 1248 break; 1249 } 1250 1251 /* 1252 * Read a page of pointers at a time. Punt if the top-level 1253 * pointer is not aligned. Note that the first read is of 1254 * a partial page. 1255 */ 1256 addr = args[sc->offset]; 1257 if (addr % sizeof(char *) != 0) { 1258 fprintf(fp, "0x%lx", args[sc->offset]); 1259 break; 1260 } 1261 1262 len = PAGE_SIZE - (addr & PAGE_MASK); 1263 if (get_struct(pid, (void *)addr, u.buf, len) == -1) { 1264 fprintf(fp, "0x%lx", args[sc->offset]); 1265 break; 1266 } 1267 1268 fputc('[', fp); 1269 first = 1; 1270 i = 0; 1271 while (u.strarray[i] != NULL) { 1272 string = get_string(pid, u.strarray[i], 0); 1273 fprintf(fp, "%s \"%s\"", first ? "" : ",", string); 1274 free(string); 1275 first = 0; 1276 1277 i++; 1278 if (i == len / sizeof(char *)) { 1279 addr += len; 1280 len = PAGE_SIZE; 1281 if (get_struct(pid, (void *)addr, u.buf, len) == 1282 -1) { 1283 fprintf(fp, ", <inval>"); 1284 break; 1285 } 1286 i = 0; 1287 } 1288 } 1289 fputs(" ]", fp); 1290 break; 1291 } 1292 #ifdef __LP64__ 1293 case Quad: 1294 fprintf(fp, "%ld", args[sc->offset]); 1295 break; 1296 case QuadHex: 1297 fprintf(fp, "0x%lx", args[sc->offset]); 1298 break; 1299 #else 1300 case Quad: 1301 case QuadHex: { 1302 unsigned long long ll; 1303 1304 #if _BYTE_ORDER == _LITTLE_ENDIAN 1305 ll = (unsigned long long)args[sc->offset + 1] << 32 | 1306 args[sc->offset]; 1307 #else 1308 ll = (unsigned long long)args[sc->offset] << 32 | 1309 args[sc->offset + 1]; 1310 #endif 1311 if ((sc->type & ARG_MASK) == Quad) 1312 fprintf(fp, "%lld", ll); 1313 else 1314 fprintf(fp, "0x%llx", ll); 1315 break; 1316 } 1317 #endif 1318 case Ptr: 1319 fprintf(fp, "0x%lx", args[sc->offset]); 1320 break; 1321 case Readlinkres: { 1322 char *tmp2; 1323 1324 if (retval[0] == -1) 1325 break; 1326 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]); 1327 fprintf(fp, "\"%s\"", tmp2); 1328 free(tmp2); 1329 break; 1330 } 1331 case Ioctl: { 1332 const char *temp; 1333 unsigned long cmd; 1334 1335 cmd = args[sc->offset]; 1336 temp = sysdecode_ioctlname(cmd); 1337 if (temp) 1338 fputs(temp, fp); 1339 else { 1340 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }", 1341 cmd, cmd & IOC_OUT ? "R" : "", 1342 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd), 1343 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?', 1344 cmd & 0xFF, IOCPARM_LEN(cmd)); 1345 } 1346 break; 1347 } 1348 case Timespec: { 1349 struct timespec ts; 1350 1351 if (get_struct(pid, (void *)args[sc->offset], &ts, 1352 sizeof(ts)) != -1) 1353 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec, 1354 ts.tv_nsec); 1355 else 1356 fprintf(fp, "0x%lx", args[sc->offset]); 1357 break; 1358 } 1359 case Timespec2: { 1360 struct timespec ts[2]; 1361 const char *sep; 1362 unsigned int i; 1363 1364 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts)) 1365 != -1) { 1366 fputs("{ ", fp); 1367 sep = ""; 1368 for (i = 0; i < nitems(ts); i++) { 1369 fputs(sep, fp); 1370 sep = ", "; 1371 switch (ts[i].tv_nsec) { 1372 case UTIME_NOW: 1373 fprintf(fp, "UTIME_NOW"); 1374 break; 1375 case UTIME_OMIT: 1376 fprintf(fp, "UTIME_OMIT"); 1377 break; 1378 default: 1379 fprintf(fp, "%jd.%09ld", 1380 (intmax_t)ts[i].tv_sec, 1381 ts[i].tv_nsec); 1382 break; 1383 } 1384 } 1385 fputs(" }", fp); 1386 } else 1387 fprintf(fp, "0x%lx", args[sc->offset]); 1388 break; 1389 } 1390 case Timeval: { 1391 struct timeval tv; 1392 1393 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 1394 != -1) 1395 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec, 1396 tv.tv_usec); 1397 else 1398 fprintf(fp, "0x%lx", args[sc->offset]); 1399 break; 1400 } 1401 case Timeval2: { 1402 struct timeval tv[2]; 1403 1404 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 1405 != -1) 1406 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1407 (intmax_t)tv[0].tv_sec, tv[0].tv_usec, 1408 (intmax_t)tv[1].tv_sec, tv[1].tv_usec); 1409 else 1410 fprintf(fp, "0x%lx", args[sc->offset]); 1411 break; 1412 } 1413 case Itimerval: { 1414 struct itimerval itv; 1415 1416 if (get_struct(pid, (void *)args[sc->offset], &itv, 1417 sizeof(itv)) != -1) 1418 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1419 (intmax_t)itv.it_interval.tv_sec, 1420 itv.it_interval.tv_usec, 1421 (intmax_t)itv.it_value.tv_sec, 1422 itv.it_value.tv_usec); 1423 else 1424 fprintf(fp, "0x%lx", args[sc->offset]); 1425 break; 1426 } 1427 case LinuxSockArgs: 1428 { 1429 struct linux_socketcall_args largs; 1430 1431 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs, 1432 sizeof(largs)) != -1) 1433 fprintf(fp, "{ %s, 0x%lx }", 1434 lookup(linux_socketcall_ops, largs.what, 10), 1435 (long unsigned int)largs.args); 1436 else 1437 fprintf(fp, "0x%lx", args[sc->offset]); 1438 break; 1439 } 1440 case Pollfd: { 1441 /* 1442 * XXX: A Pollfd argument expects the /next/ syscall argument 1443 * to be the number of fds in the array. This matches the poll 1444 * syscall. 1445 */ 1446 struct pollfd *pfd; 1447 int numfds = args[sc->offset + 1]; 1448 size_t bytes = sizeof(struct pollfd) * numfds; 1449 int i; 1450 1451 if ((pfd = malloc(bytes)) == NULL) 1452 err(1, "Cannot malloc %zu bytes for pollfd array", 1453 bytes); 1454 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) 1455 != -1) { 1456 fputs("{", fp); 1457 for (i = 0; i < numfds; i++) { 1458 fprintf(fp, " %d/%s", pfd[i].fd, 1459 xlookup_bits(poll_flags, pfd[i].events)); 1460 } 1461 fputs(" }", fp); 1462 } else { 1463 fprintf(fp, "0x%lx", args[sc->offset]); 1464 } 1465 free(pfd); 1466 break; 1467 } 1468 case Fd_set: { 1469 /* 1470 * XXX: A Fd_set argument expects the /first/ syscall argument 1471 * to be the number of fds in the array. This matches the 1472 * select syscall. 1473 */ 1474 fd_set *fds; 1475 int numfds = args[0]; 1476 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 1477 int i; 1478 1479 if ((fds = malloc(bytes)) == NULL) 1480 err(1, "Cannot malloc %zu bytes for fd_set array", 1481 bytes); 1482 if (get_struct(pid, (void *)args[sc->offset], fds, bytes) 1483 != -1) { 1484 fputs("{", fp); 1485 for (i = 0; i < numfds; i++) { 1486 if (FD_ISSET(i, fds)) 1487 fprintf(fp, " %d", i); 1488 } 1489 fputs(" }", fp); 1490 } else 1491 fprintf(fp, "0x%lx", args[sc->offset]); 1492 free(fds); 1493 break; 1494 } 1495 case Signal: 1496 fputs(strsig2(args[sc->offset]), fp); 1497 break; 1498 case Sigset: { 1499 long sig; 1500 sigset_t ss; 1501 int i, first; 1502 1503 sig = args[sc->offset]; 1504 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 1505 sizeof(ss)) == -1) { 1506 fprintf(fp, "0x%lx", args[sc->offset]); 1507 break; 1508 } 1509 fputs("{ ", fp); 1510 first = 1; 1511 for (i = 1; i < sys_nsig; i++) { 1512 if (sigismember(&ss, i)) { 1513 fprintf(fp, "%s%s", !first ? "|" : "", 1514 strsig2(i)); 1515 first = 0; 1516 } 1517 } 1518 if (!first) 1519 fputc(' ', fp); 1520 fputc('}', fp); 1521 break; 1522 } 1523 case Sigprocmask: 1524 print_integer_arg(sysdecode_sigprocmask_how, fp, 1525 args[sc->offset]); 1526 break; 1527 case Fcntlflag: 1528 /* XXX: Output depends on the value of the previous argument. */ 1529 if (sysdecode_fcntl_arg_p(args[sc->offset - 1])) 1530 sysdecode_fcntl_arg(fp, args[sc->offset - 1], 1531 args[sc->offset], 16); 1532 break; 1533 case Open: 1534 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]); 1535 break; 1536 case Fcntl: 1537 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]); 1538 break; 1539 case Mprot: 1540 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]); 1541 break; 1542 case Mmapflags: 1543 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]); 1544 break; 1545 case Whence: 1546 print_integer_arg(sysdecode_whence, fp, args[sc->offset]); 1547 break; 1548 case Sockdomain: 1549 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]); 1550 break; 1551 case Socktype: 1552 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]); 1553 break; 1554 case Shutdown: 1555 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]); 1556 break; 1557 case Resource: 1558 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]); 1559 break; 1560 case Pathconf: 1561 fputs(xlookup(pathconf_arg, args[sc->offset]), fp); 1562 break; 1563 case Rforkflags: 1564 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]); 1565 break; 1566 case Sockaddr: { 1567 char addr[64]; 1568 struct sockaddr_in *lsin; 1569 struct sockaddr_in6 *lsin6; 1570 struct sockaddr_un *sun; 1571 struct sockaddr *sa; 1572 socklen_t len; 1573 u_char *q; 1574 1575 if (args[sc->offset] == 0) { 1576 fputs("NULL", fp); 1577 break; 1578 } 1579 1580 /* 1581 * Extract the address length from the next argument. If 1582 * this is an output sockaddr (OUT is set), then the 1583 * next argument is a pointer to a socklen_t. Otherwise 1584 * the next argument contains a socklen_t by value. 1585 */ 1586 if (sc->type & OUT) { 1587 if (get_struct(pid, (void *)args[sc->offset + 1], 1588 &len, sizeof(len)) == -1) { 1589 fprintf(fp, "0x%lx", args[sc->offset]); 1590 break; 1591 } 1592 } else 1593 len = args[sc->offset + 1]; 1594 1595 /* If the length is too small, just bail. */ 1596 if (len < sizeof(*sa)) { 1597 fprintf(fp, "0x%lx", args[sc->offset]); 1598 break; 1599 } 1600 1601 sa = calloc(1, len); 1602 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) { 1603 free(sa); 1604 fprintf(fp, "0x%lx", args[sc->offset]); 1605 break; 1606 } 1607 1608 switch (sa->sa_family) { 1609 case AF_INET: 1610 if (len < sizeof(*lsin)) 1611 goto sockaddr_short; 1612 lsin = (struct sockaddr_in *)(void *)sa; 1613 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr)); 1614 fprintf(fp, "{ AF_INET %s:%d }", addr, 1615 htons(lsin->sin_port)); 1616 break; 1617 case AF_INET6: 1618 if (len < sizeof(*lsin6)) 1619 goto sockaddr_short; 1620 lsin6 = (struct sockaddr_in6 *)(void *)sa; 1621 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, 1622 sizeof(addr)); 1623 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr, 1624 htons(lsin6->sin6_port)); 1625 break; 1626 case AF_UNIX: 1627 sun = (struct sockaddr_un *)sa; 1628 fprintf(fp, "{ AF_UNIX \"%.*s\" }", 1629 (int)(len - offsetof(struct sockaddr_un, sun_path)), 1630 sun->sun_path); 1631 break; 1632 default: 1633 sockaddr_short: 1634 fprintf(fp, 1635 "{ sa_len = %d, sa_family = %d, sa_data = {", 1636 (int)sa->sa_len, (int)sa->sa_family); 1637 for (q = (u_char *)sa->sa_data; 1638 q < (u_char *)sa + len; q++) 1639 fprintf(fp, "%s 0x%02x", 1640 q == (u_char *)sa->sa_data ? "" : ",", 1641 *q); 1642 fputs(" } }", fp); 1643 } 1644 free(sa); 1645 break; 1646 } 1647 case Sigaction: { 1648 struct sigaction sa; 1649 1650 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa)) 1651 != -1) { 1652 fputs("{ ", fp); 1653 if (sa.sa_handler == SIG_DFL) 1654 fputs("SIG_DFL", fp); 1655 else if (sa.sa_handler == SIG_IGN) 1656 fputs("SIG_IGN", fp); 1657 else 1658 fprintf(fp, "%p", sa.sa_handler); 1659 fprintf(fp, " %s ss_t }", 1660 xlookup_bits(sigaction_flags, sa.sa_flags)); 1661 } else 1662 fprintf(fp, "0x%lx", args[sc->offset]); 1663 break; 1664 } 1665 case Kevent: { 1666 /* 1667 * XXX XXX: The size of the array is determined by either the 1668 * next syscall argument, or by the syscall return value, 1669 * depending on which argument number we are. This matches the 1670 * kevent syscall, but luckily that's the only syscall that uses 1671 * them. 1672 */ 1673 struct kevent *ke; 1674 int numevents = -1; 1675 size_t bytes; 1676 int i; 1677 1678 if (sc->offset == 1) 1679 numevents = args[sc->offset+1]; 1680 else if (sc->offset == 3 && retval[0] != -1) 1681 numevents = retval[0]; 1682 1683 if (numevents >= 0) { 1684 bytes = sizeof(struct kevent) * numevents; 1685 if ((ke = malloc(bytes)) == NULL) 1686 err(1, 1687 "Cannot malloc %zu bytes for kevent array", 1688 bytes); 1689 } else 1690 ke = NULL; 1691 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], 1692 ke, bytes) != -1) { 1693 fputc('{', fp); 1694 for (i = 0; i < numevents; i++) { 1695 fputc(' ', fp); 1696 print_kevent(fp, &ke[i], sc->offset == 1); 1697 } 1698 fputs(" }", fp); 1699 } else { 1700 fprintf(fp, "0x%lx", args[sc->offset]); 1701 } 1702 free(ke); 1703 break; 1704 } 1705 case Stat: { 1706 struct stat st; 1707 1708 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) 1709 != -1) { 1710 char mode[12]; 1711 1712 strmode(st.st_mode, mode); 1713 fprintf(fp, 1714 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode, 1715 (uintmax_t)st.st_ino, (intmax_t)st.st_size, 1716 (long)st.st_blksize); 1717 } else { 1718 fprintf(fp, "0x%lx", args[sc->offset]); 1719 } 1720 break; 1721 } 1722 case StatFs: { 1723 unsigned int i; 1724 struct statfs buf; 1725 1726 if (get_struct(pid, (void *)args[sc->offset], &buf, 1727 sizeof(buf)) != -1) { 1728 char fsid[17]; 1729 1730 bzero(fsid, sizeof(fsid)); 1731 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) { 1732 for (i = 0; i < sizeof(buf.f_fsid); i++) 1733 snprintf(&fsid[i*2], 1734 sizeof(fsid) - (i*2), "%02x", 1735 ((u_char *)&buf.f_fsid)[i]); 1736 } 1737 fprintf(fp, 1738 "{ fstypename=%s,mntonname=%s,mntfromname=%s," 1739 "fsid=%s }", buf.f_fstypename, buf.f_mntonname, 1740 buf.f_mntfromname, fsid); 1741 } else 1742 fprintf(fp, "0x%lx", args[sc->offset]); 1743 break; 1744 } 1745 1746 case Rusage: { 1747 struct rusage ru; 1748 1749 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru)) 1750 != -1) { 1751 fprintf(fp, 1752 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }", 1753 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, 1754 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, 1755 ru.ru_inblock, ru.ru_oublock); 1756 } else 1757 fprintf(fp, "0x%lx", args[sc->offset]); 1758 break; 1759 } 1760 case Rlimit: { 1761 struct rlimit rl; 1762 1763 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl)) 1764 != -1) { 1765 fprintf(fp, "{ cur=%ju,max=%ju }", 1766 rl.rlim_cur, rl.rlim_max); 1767 } else 1768 fprintf(fp, "0x%lx", args[sc->offset]); 1769 break; 1770 } 1771 case ExitStatus: { 1772 int status; 1773 1774 if (get_struct(pid, (void *)args[sc->offset], &status, 1775 sizeof(status)) != -1) { 1776 fputs("{ ", fp); 1777 if (WIFCONTINUED(status)) 1778 fputs("CONTINUED", fp); 1779 else if (WIFEXITED(status)) 1780 fprintf(fp, "EXITED,val=%d", 1781 WEXITSTATUS(status)); 1782 else if (WIFSIGNALED(status)) 1783 fprintf(fp, "SIGNALED,sig=%s%s", 1784 strsig2(WTERMSIG(status)), 1785 WCOREDUMP(status) ? ",cored" : ""); 1786 else 1787 fprintf(fp, "STOPPED,sig=%s", 1788 strsig2(WTERMSIG(status))); 1789 fputs(" }", fp); 1790 } else 1791 fprintf(fp, "0x%lx", args[sc->offset]); 1792 break; 1793 } 1794 case Waitoptions: 1795 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]); 1796 break; 1797 case Idtype: 1798 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]); 1799 break; 1800 case Procctl: 1801 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]); 1802 break; 1803 case Umtxop: 1804 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]); 1805 break; 1806 case Atfd: 1807 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]); 1808 break; 1809 case Atflags: 1810 fputs(xlookup_bits(at_flags, args[sc->offset]), fp); 1811 break; 1812 case Accessmode: 1813 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]); 1814 break; 1815 case Sysarch: 1816 fputs(xlookup(sysarch_ops, args[sc->offset]), fp); 1817 break; 1818 case PipeFds: 1819 /* 1820 * The pipe() system call in the kernel returns its 1821 * two file descriptors via return values. However, 1822 * the interface exposed by libc is that pipe() 1823 * accepts a pointer to an array of descriptors. 1824 * Format the output to match the libc API by printing 1825 * the returned file descriptors as a fake argument. 1826 * 1827 * Overwrite the first retval to signal a successful 1828 * return as well. 1829 */ 1830 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]); 1831 retval[0] = 0; 1832 break; 1833 case Utrace: { 1834 size_t len; 1835 void *utrace_addr; 1836 1837 len = args[sc->offset + 1]; 1838 utrace_addr = calloc(1, len); 1839 if (get_struct(pid, (void *)args[sc->offset], 1840 (void *)utrace_addr, len) != -1) 1841 print_utrace(fp, utrace_addr, len); 1842 else 1843 fprintf(fp, "0x%lx", args[sc->offset]); 1844 free(utrace_addr); 1845 break; 1846 } 1847 case IntArray: { 1848 int descriptors[16]; 1849 unsigned long i, ndescriptors; 1850 bool truncated; 1851 1852 ndescriptors = args[sc->offset + 1]; 1853 truncated = false; 1854 if (ndescriptors > nitems(descriptors)) { 1855 ndescriptors = nitems(descriptors); 1856 truncated = true; 1857 } 1858 if (get_struct(pid, (void *)args[sc->offset], 1859 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) { 1860 fprintf(fp, "{"); 1861 for (i = 0; i < ndescriptors; i++) 1862 fprintf(fp, i == 0 ? " %d" : ", %d", 1863 descriptors[i]); 1864 fprintf(fp, truncated ? ", ... }" : " }"); 1865 } else 1866 fprintf(fp, "0x%lx", args[sc->offset]); 1867 break; 1868 } 1869 case Pipe2: 1870 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]); 1871 break; 1872 case CapFcntlRights: { 1873 uint32_t rights; 1874 1875 if (sc->type & OUT) { 1876 if (get_struct(pid, (void *)args[sc->offset], &rights, 1877 sizeof(rights)) == -1) { 1878 fprintf(fp, "0x%lx", args[sc->offset]); 1879 break; 1880 } 1881 } else 1882 rights = args[sc->offset]; 1883 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights); 1884 break; 1885 } 1886 case Fadvice: 1887 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]); 1888 break; 1889 case FileFlags: { 1890 fflags_t rem; 1891 1892 if (!sysdecode_fileflags(fp, args[sc->offset], &rem)) 1893 fprintf(fp, "0x%x", rem); 1894 else if (rem != 0) 1895 fprintf(fp, "|0x%x", rem); 1896 break; 1897 } 1898 case Flockop: 1899 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]); 1900 break; 1901 case Getfsstatmode: 1902 print_integer_arg(sysdecode_getfsstat_mode, fp, 1903 args[sc->offset]); 1904 break; 1905 case Kldsymcmd: 1906 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]); 1907 break; 1908 case Kldunloadflags: 1909 print_integer_arg(sysdecode_kldunload_flags, fp, 1910 args[sc->offset]); 1911 break; 1912 case Madvice: 1913 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]); 1914 break; 1915 1916 case CloudABIAdvice: 1917 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp); 1918 break; 1919 case CloudABIClockID: 1920 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp); 1921 break; 1922 case ClouduABIFDSFlags: 1923 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp); 1924 break; 1925 case CloudABIFDStat: { 1926 cloudabi_fdstat_t fds; 1927 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds)) 1928 != -1) { 1929 fprintf(fp, "{ %s, ", 1930 xlookup(cloudabi_filetype, fds.fs_filetype)); 1931 fprintf(fp, "%s, ... }", 1932 xlookup_bits(cloudabi_fdflags, fds.fs_flags)); 1933 } else 1934 fprintf(fp, "0x%lx", args[sc->offset]); 1935 break; 1936 } 1937 case CloudABIFileStat: { 1938 cloudabi_filestat_t fsb; 1939 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb)) 1940 != -1) 1941 fprintf(fp, "{ %s, %ju }", 1942 xlookup(cloudabi_filetype, fsb.st_filetype), 1943 (uintmax_t)fsb.st_size); 1944 else 1945 fprintf(fp, "0x%lx", args[sc->offset]); 1946 break; 1947 } 1948 case CloudABIFileType: 1949 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp); 1950 break; 1951 case CloudABIFSFlags: 1952 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp); 1953 break; 1954 case CloudABILookup: 1955 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0) 1956 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW", 1957 (int)args[sc->offset]); 1958 else 1959 fprintf(fp, "%d", (int)args[sc->offset]); 1960 break; 1961 case CloudABIMFlags: 1962 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp); 1963 break; 1964 case CloudABIMProt: 1965 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp); 1966 break; 1967 case CloudABIMSFlags: 1968 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp); 1969 break; 1970 case CloudABIOFlags: 1971 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp); 1972 break; 1973 case CloudABISDFlags: 1974 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp); 1975 break; 1976 case CloudABISignal: 1977 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp); 1978 break; 1979 case CloudABISockStat: { 1980 cloudabi_sockstat_t ss; 1981 if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss)) 1982 != -1) { 1983 fprintf(fp, "{ %s, ", xlookup( 1984 cloudabi_sa_family, ss.ss_sockname.sa_family)); 1985 fprintf(fp, "%s, ", xlookup( 1986 cloudabi_sa_family, ss.ss_peername.sa_family)); 1987 fprintf(fp, "%s, ", xlookup( 1988 cloudabi_errno, ss.ss_error)); 1989 fprintf(fp, "%s }", xlookup_bits( 1990 cloudabi_ssstate, ss.ss_state)); 1991 } else 1992 fprintf(fp, "0x%lx", args[sc->offset]); 1993 break; 1994 } 1995 case CloudABISSFlags: 1996 fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp); 1997 break; 1998 case CloudABITimestamp: 1999 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000, 2000 args[sc->offset] % 1000000000); 2001 break; 2002 case CloudABIULFlags: 2003 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp); 2004 break; 2005 case CloudABIWhence: 2006 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp); 2007 break; 2008 2009 default: 2010 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); 2011 } 2012 fclose(fp); 2013 return (tmp); 2014 } 2015 2016 /* 2017 * Print (to outfile) the system call and its arguments. 2018 */ 2019 void 2020 print_syscall(struct trussinfo *trussinfo) 2021 { 2022 struct threadinfo *t; 2023 const char *name; 2024 char **s_args; 2025 int i, len, nargs; 2026 2027 t = trussinfo->curthread; 2028 2029 name = t->cs.sc->name; 2030 nargs = t->cs.nargs; 2031 s_args = t->cs.s_args; 2032 2033 len = print_line_prefix(trussinfo); 2034 len += fprintf(trussinfo->outfile, "%s(", name); 2035 2036 for (i = 0; i < nargs; i++) { 2037 if (s_args[i] != NULL) 2038 len += fprintf(trussinfo->outfile, "%s", s_args[i]); 2039 else 2040 len += fprintf(trussinfo->outfile, 2041 "<missing argument>"); 2042 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? 2043 "," : ""); 2044 } 2045 len += fprintf(trussinfo->outfile, ")"); 2046 for (i = 0; i < 6 - (len / 8); i++) 2047 fprintf(trussinfo->outfile, "\t"); 2048 } 2049 2050 void 2051 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval) 2052 { 2053 struct timespec timediff; 2054 struct threadinfo *t; 2055 struct syscall *sc; 2056 int error; 2057 2058 t = trussinfo->curthread; 2059 sc = t->cs.sc; 2060 if (trussinfo->flags & COUNTONLY) { 2061 timespecsubt(&t->after, &t->before, &timediff); 2062 timespecadd(&sc->time, &timediff, &sc->time); 2063 sc->ncalls++; 2064 if (errorp) 2065 sc->nerror++; 2066 return; 2067 } 2068 2069 print_syscall(trussinfo); 2070 fflush(trussinfo->outfile); 2071 2072 if (retval == NULL) { 2073 /* 2074 * This system call resulted in the current thread's exit, 2075 * so there is no return value or error to display. 2076 */ 2077 fprintf(trussinfo->outfile, "\n"); 2078 return; 2079 } 2080 2081 if (errorp) { 2082 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi, 2083 retval[0]); 2084 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0], 2085 error == INT_MAX ? "Unknown error" : strerror(error)); 2086 } 2087 #ifndef __LP64__ 2088 else if (sc->ret_type == 2) { 2089 off_t off; 2090 2091 #if _BYTE_ORDER == _LITTLE_ENDIAN 2092 off = (off_t)retval[1] << 32 | retval[0]; 2093 #else 2094 off = (off_t)retval[0] << 32 | retval[1]; 2095 #endif 2096 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off, 2097 (intmax_t)off); 2098 } 2099 #endif 2100 else 2101 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0], 2102 retval[0]); 2103 } 2104 2105 void 2106 print_summary(struct trussinfo *trussinfo) 2107 { 2108 struct timespec total = {0, 0}; 2109 struct syscall *sc; 2110 int ncall, nerror; 2111 2112 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n", 2113 "syscall", "seconds", "calls", "errors"); 2114 ncall = nerror = 0; 2115 STAILQ_FOREACH(sc, &syscalls, entries) 2116 if (sc->ncalls) { 2117 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 2118 sc->name, (intmax_t)sc->time.tv_sec, 2119 sc->time.tv_nsec, sc->ncalls, sc->nerror); 2120 timespecadd(&total, &sc->time, &total); 2121 ncall += sc->ncalls; 2122 nerror += sc->nerror; 2123 } 2124 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n", 2125 "", "-------------", "-------", "-------"); 2126 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 2127 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror); 2128 } 2129