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