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