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