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