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