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