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