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