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