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