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