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