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