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