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, void *offset, void *buf, int len) 1055 { 1056 struct ptrace_io_desc iorequest; 1057 1058 iorequest.piod_op = PIOD_READ_D; 1059 iorequest.piod_offs = 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, void *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 = (char *)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_sockaddr(FILE *fp, struct trussinfo *trussinfo, void *arg, socklen_t len) 1187 { 1188 char addr[64]; 1189 struct sockaddr_in *lsin; 1190 struct sockaddr_in6 *lsin6; 1191 struct sockaddr_un *sun; 1192 struct sockaddr *sa; 1193 u_char *q; 1194 pid_t pid = trussinfo->curthread->proc->pid; 1195 1196 if (arg == NULL) { 1197 fputs("NULL", fp); 1198 return; 1199 } 1200 /* If the length is too small, just bail. */ 1201 if (len < sizeof(*sa)) { 1202 fprintf(fp, "%p", arg); 1203 return; 1204 } 1205 1206 sa = calloc(1, len); 1207 if (get_struct(pid, arg, sa, len) == -1) { 1208 free(sa); 1209 fprintf(fp, "%p", arg); 1210 return; 1211 } 1212 1213 switch (sa->sa_family) { 1214 case AF_INET: 1215 if (len < sizeof(*lsin)) 1216 goto sockaddr_short; 1217 lsin = (struct sockaddr_in *)(void *)sa; 1218 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr)); 1219 fprintf(fp, "{ AF_INET %s:%d }", addr, 1220 htons(lsin->sin_port)); 1221 break; 1222 case AF_INET6: 1223 if (len < sizeof(*lsin6)) 1224 goto sockaddr_short; 1225 lsin6 = (struct sockaddr_in6 *)(void *)sa; 1226 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, 1227 sizeof(addr)); 1228 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr, 1229 htons(lsin6->sin6_port)); 1230 break; 1231 case AF_UNIX: 1232 sun = (struct sockaddr_un *)sa; 1233 fprintf(fp, "{ AF_UNIX \"%.*s\" }", 1234 (int)(len - offsetof(struct sockaddr_un, sun_path)), 1235 sun->sun_path); 1236 break; 1237 default: 1238 sockaddr_short: 1239 fprintf(fp, 1240 "{ sa_len = %d, sa_family = %d, sa_data = {", 1241 (int)sa->sa_len, (int)sa->sa_family); 1242 for (q = (u_char *)sa->sa_data; 1243 q < (u_char *)sa + len; q++) 1244 fprintf(fp, "%s 0x%02x", 1245 q == (u_char *)sa->sa_data ? "" : ",", 1246 *q); 1247 fputs(" } }", fp); 1248 } 1249 free(sa); 1250 } 1251 1252 #define IOV_LIMIT 16 1253 1254 static void 1255 print_iovec(FILE *fp, struct trussinfo *trussinfo, void *arg, int iovcnt) 1256 { 1257 struct iovec iov[IOV_LIMIT]; 1258 size_t max_string = trussinfo->strsize; 1259 char tmp2[max_string + 1], *tmp3; 1260 size_t len; 1261 pid_t pid = trussinfo->curthread->proc->pid; 1262 int i; 1263 bool buf_truncated, iov_truncated; 1264 1265 if (iovcnt <= 0) { 1266 fprintf(fp, "%p", arg); 1267 return; 1268 } 1269 if (iovcnt > IOV_LIMIT) { 1270 iovcnt = IOV_LIMIT; 1271 iov_truncated = true; 1272 } else { 1273 iov_truncated = false; 1274 } 1275 if (get_struct(pid, arg, &iov, iovcnt * sizeof(struct iovec)) == -1) { 1276 fprintf(fp, "%p", arg); 1277 return; 1278 } 1279 1280 fputs("[", fp); 1281 for (i = 0; i < iovcnt; i++) { 1282 len = iov[i].iov_len; 1283 if (len > max_string) { 1284 len = max_string; 1285 buf_truncated = true; 1286 } else { 1287 buf_truncated = false; 1288 } 1289 fprintf(fp, "%s{", (i > 0) ? "," : ""); 1290 if (len && get_struct(pid, iov[i].iov_base, &tmp2, len) != -1) { 1291 tmp3 = malloc(len * 4 + 1); 1292 while (len) { 1293 if (strvisx(tmp3, tmp2, len, 1294 VIS_CSTYLE|VIS_TAB|VIS_NL) <= 1295 (int)max_string) 1296 break; 1297 len--; 1298 buf_truncated = true; 1299 } 1300 fprintf(fp, "\"%s\"%s", tmp3, 1301 buf_truncated ? "..." : ""); 1302 free(tmp3); 1303 } else { 1304 fprintf(fp, "%p", iov[i].iov_base); 1305 } 1306 fprintf(fp, ",%zu}", iov[i].iov_len); 1307 } 1308 fprintf(fp, "%s%s", iov_truncated ? ",..." : "", "]"); 1309 } 1310 1311 static void 1312 print_gen_cmsg(FILE *fp, struct cmsghdr *cmsghdr) 1313 { 1314 u_char *q; 1315 1316 fputs("{", fp); 1317 for (q = CMSG_DATA(cmsghdr); 1318 q < (u_char *)cmsghdr + cmsghdr->cmsg_len; q++) { 1319 fprintf(fp, "%s0x%02x", q == CMSG_DATA(cmsghdr) ? "" : ",", *q); 1320 } 1321 fputs("}", fp); 1322 } 1323 1324 static void 1325 print_sctp_initmsg(FILE *fp, struct sctp_initmsg *init) 1326 { 1327 fprintf(fp, "{out=%u,", init->sinit_num_ostreams); 1328 fprintf(fp, "in=%u,", init->sinit_max_instreams); 1329 fprintf(fp, "max_rtx=%u,", init->sinit_max_attempts); 1330 fprintf(fp, "max_rto=%u}", init->sinit_max_init_timeo); 1331 } 1332 1333 static void 1334 print_sctp_sndrcvinfo(FILE *fp, bool receive, struct sctp_sndrcvinfo *info) 1335 { 1336 fprintf(fp, "{sid=%u,", info->sinfo_stream); 1337 if (receive) { 1338 fprintf(fp, "ssn=%u,", info->sinfo_ssn); 1339 } 1340 fputs("flgs=", fp); 1341 sysdecode_sctp_sinfo_flags(fp, info->sinfo_flags); 1342 fprintf(fp, ",ppid=%u,", ntohl(info->sinfo_ppid)); 1343 if (!receive) { 1344 fprintf(fp, "ctx=%u,", info->sinfo_context); 1345 fprintf(fp, "ttl=%u,", info->sinfo_timetolive); 1346 } 1347 if (receive) { 1348 fprintf(fp, "tsn=%u,", info->sinfo_tsn); 1349 fprintf(fp, "cumtsn=%u,", info->sinfo_cumtsn); 1350 } 1351 fprintf(fp, "id=%u}", info->sinfo_assoc_id); 1352 } 1353 1354 static void 1355 print_sctp_sndinfo(FILE *fp, struct sctp_sndinfo *info) 1356 { 1357 fprintf(fp, "{sid=%u,", info->snd_sid); 1358 fputs("flgs=", fp); 1359 print_mask_arg(sysdecode_sctp_snd_flags, fp, info->snd_flags); 1360 fprintf(fp, ",ppid=%u,", ntohl(info->snd_ppid)); 1361 fprintf(fp, "ctx=%u,", info->snd_context); 1362 fprintf(fp, "id=%u}", info->snd_assoc_id); 1363 } 1364 1365 static void 1366 print_sctp_rcvinfo(FILE *fp, struct sctp_rcvinfo *info) 1367 { 1368 fprintf(fp, "{sid=%u,", info->rcv_sid); 1369 fprintf(fp, "ssn=%u,", info->rcv_ssn); 1370 fputs("flgs=", fp); 1371 print_mask_arg(sysdecode_sctp_rcv_flags, fp, info->rcv_flags); 1372 fprintf(fp, ",ppid=%u,", ntohl(info->rcv_ppid)); 1373 fprintf(fp, "tsn=%u,", info->rcv_tsn); 1374 fprintf(fp, "cumtsn=%u,", info->rcv_cumtsn); 1375 fprintf(fp, "ctx=%u,", info->rcv_context); 1376 fprintf(fp, "id=%u}", info->rcv_assoc_id); 1377 } 1378 1379 static void 1380 print_sctp_nxtinfo(FILE *fp, struct sctp_nxtinfo *info) 1381 { 1382 fprintf(fp, "{sid=%u,", info->nxt_sid); 1383 fputs("flgs=", fp); 1384 print_mask_arg(sysdecode_sctp_nxt_flags, fp, info->nxt_flags); 1385 fprintf(fp, ",ppid=%u,", ntohl(info->nxt_ppid)); 1386 fprintf(fp, "len=%u,", info->nxt_length); 1387 fprintf(fp, "id=%u}", info->nxt_assoc_id); 1388 } 1389 1390 static void 1391 print_sctp_prinfo(FILE *fp, struct sctp_prinfo *info) 1392 { 1393 fputs("{pol=", fp); 1394 print_integer_arg(sysdecode_sctp_pr_policy, fp, info->pr_policy); 1395 fprintf(fp, ",val=%u}", info->pr_value); 1396 } 1397 1398 static void 1399 print_sctp_authinfo(FILE *fp, struct sctp_authinfo *info) 1400 { 1401 fprintf(fp, "{num=%u}", info->auth_keynumber); 1402 } 1403 1404 static void 1405 print_sctp_ipv4_addr(FILE *fp, struct in_addr *addr) 1406 { 1407 char buf[INET_ADDRSTRLEN]; 1408 const char *s; 1409 1410 s = inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN); 1411 if (s != NULL) 1412 fprintf(fp, "{addr=%s}", s); 1413 else 1414 fputs("{addr=???}", fp); 1415 } 1416 1417 static void 1418 print_sctp_ipv6_addr(FILE *fp, struct in6_addr *addr) 1419 { 1420 char buf[INET6_ADDRSTRLEN]; 1421 const char *s; 1422 1423 s = inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN); 1424 if (s != NULL) 1425 fprintf(fp, "{addr=%s}", s); 1426 else 1427 fputs("{addr=???}", fp); 1428 } 1429 1430 static void 1431 print_sctp_cmsg(FILE *fp, bool receive, struct cmsghdr *cmsghdr) 1432 { 1433 void *data; 1434 socklen_t len; 1435 1436 len = cmsghdr->cmsg_len; 1437 data = CMSG_DATA(cmsghdr); 1438 switch (cmsghdr->cmsg_type) { 1439 case SCTP_INIT: 1440 if (len == CMSG_LEN(sizeof(struct sctp_initmsg))) 1441 print_sctp_initmsg(fp, (struct sctp_initmsg *)data); 1442 else 1443 print_gen_cmsg(fp, cmsghdr); 1444 break; 1445 case SCTP_SNDRCV: 1446 if (len == CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) 1447 print_sctp_sndrcvinfo(fp, receive, 1448 (struct sctp_sndrcvinfo *)data); 1449 else 1450 print_gen_cmsg(fp, cmsghdr); 1451 break; 1452 #if 0 1453 case SCTP_EXTRCV: 1454 if (len == CMSG_LEN(sizeof(struct sctp_extrcvinfo))) 1455 print_sctp_extrcvinfo(fp, 1456 (struct sctp_extrcvinfo *)data); 1457 else 1458 print_gen_cmsg(fp, cmsghdr); 1459 break; 1460 #endif 1461 case SCTP_SNDINFO: 1462 if (len == CMSG_LEN(sizeof(struct sctp_sndinfo))) 1463 print_sctp_sndinfo(fp, (struct sctp_sndinfo *)data); 1464 else 1465 print_gen_cmsg(fp, cmsghdr); 1466 break; 1467 case SCTP_RCVINFO: 1468 if (len == CMSG_LEN(sizeof(struct sctp_rcvinfo))) 1469 print_sctp_rcvinfo(fp, (struct sctp_rcvinfo *)data); 1470 else 1471 print_gen_cmsg(fp, cmsghdr); 1472 break; 1473 case SCTP_NXTINFO: 1474 if (len == CMSG_LEN(sizeof(struct sctp_nxtinfo))) 1475 print_sctp_nxtinfo(fp, (struct sctp_nxtinfo *)data); 1476 else 1477 print_gen_cmsg(fp, cmsghdr); 1478 break; 1479 case SCTP_PRINFO: 1480 if (len == CMSG_LEN(sizeof(struct sctp_prinfo))) 1481 print_sctp_prinfo(fp, (struct sctp_prinfo *)data); 1482 else 1483 print_gen_cmsg(fp, cmsghdr); 1484 break; 1485 case SCTP_AUTHINFO: 1486 if (len == CMSG_LEN(sizeof(struct sctp_authinfo))) 1487 print_sctp_authinfo(fp, (struct sctp_authinfo *)data); 1488 else 1489 print_gen_cmsg(fp, cmsghdr); 1490 break; 1491 case SCTP_DSTADDRV4: 1492 if (len == CMSG_LEN(sizeof(struct in_addr))) 1493 print_sctp_ipv4_addr(fp, (struct in_addr *)data); 1494 else 1495 print_gen_cmsg(fp, cmsghdr); 1496 break; 1497 case SCTP_DSTADDRV6: 1498 if (len == CMSG_LEN(sizeof(struct in6_addr))) 1499 print_sctp_ipv6_addr(fp, (struct in6_addr *)data); 1500 else 1501 print_gen_cmsg(fp, cmsghdr); 1502 break; 1503 default: 1504 print_gen_cmsg(fp, cmsghdr); 1505 } 1506 } 1507 1508 static void 1509 print_cmsgs(FILE *fp, pid_t pid, bool receive, struct msghdr *msghdr) 1510 { 1511 struct cmsghdr *cmsghdr; 1512 char *cmsgbuf; 1513 const char *temp; 1514 socklen_t len; 1515 int level, type; 1516 bool first; 1517 1518 len = msghdr->msg_controllen; 1519 if (len == 0) { 1520 fputs("{}", fp); 1521 return; 1522 } 1523 cmsgbuf = calloc(1, len); 1524 if (get_struct(pid, msghdr->msg_control, cmsgbuf, len) == -1) { 1525 fprintf(fp, "%p", msghdr->msg_control); 1526 free(cmsgbuf); 1527 return; 1528 } 1529 msghdr->msg_control = cmsgbuf; 1530 first = true; 1531 fputs("{", fp); 1532 for (cmsghdr = CMSG_FIRSTHDR(msghdr); 1533 cmsghdr != NULL; 1534 cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr)) { 1535 level = cmsghdr->cmsg_level; 1536 type = cmsghdr->cmsg_type; 1537 len = cmsghdr->cmsg_len; 1538 fprintf(fp, "%s{level=", first ? "" : ","); 1539 print_integer_arg(sysdecode_sockopt_level, fp, level); 1540 fputs(",type=", fp); 1541 temp = sysdecode_cmsg_type(level, type); 1542 if (temp) { 1543 fputs(temp, fp); 1544 } else { 1545 fprintf(fp, "%d", type); 1546 } 1547 fputs(",data=", fp); 1548 switch (level) { 1549 case IPPROTO_SCTP: 1550 print_sctp_cmsg(fp, receive, cmsghdr); 1551 break; 1552 default: 1553 print_gen_cmsg(fp, cmsghdr); 1554 break; 1555 } 1556 fputs("}", fp); 1557 first = false; 1558 } 1559 fputs("}", fp); 1560 free(cmsgbuf); 1561 } 1562 1563 static void 1564 print_sysctl_oid(FILE *fp, int *oid, int len) 1565 { 1566 int i; 1567 1568 for (i = 0; i < len; i++) 1569 fprintf(fp, ".%d", oid[i]); 1570 } 1571 1572 /* 1573 * Converts a syscall argument into a string. Said string is 1574 * allocated via malloc(), so needs to be free()'d. sc is 1575 * a pointer to the syscall description (see above); args is 1576 * an array of all of the system call arguments. 1577 */ 1578 char * 1579 print_arg(struct syscall_args *sc, unsigned long *args, register_t *retval, 1580 struct trussinfo *trussinfo) 1581 { 1582 FILE *fp; 1583 char *tmp; 1584 size_t tmplen; 1585 pid_t pid; 1586 1587 fp = open_memstream(&tmp, &tmplen); 1588 pid = trussinfo->curthread->proc->pid; 1589 switch (sc->type & ARG_MASK) { 1590 case Hex: 1591 fprintf(fp, "0x%x", (int)args[sc->offset]); 1592 break; 1593 case Octal: 1594 fprintf(fp, "0%o", (int)args[sc->offset]); 1595 break; 1596 case Int: 1597 fprintf(fp, "%d", (int)args[sc->offset]); 1598 break; 1599 case UInt: 1600 fprintf(fp, "%u", (unsigned int)args[sc->offset]); 1601 break; 1602 case PUInt: { 1603 unsigned int val; 1604 1605 if (get_struct(pid, (void *)args[sc->offset], &val, 1606 sizeof(val)) == 0) 1607 fprintf(fp, "{ %u }", val); 1608 else 1609 fprintf(fp, "0x%lx", args[sc->offset]); 1610 break; 1611 } 1612 case LongHex: 1613 fprintf(fp, "0x%lx", args[sc->offset]); 1614 break; 1615 case Long: 1616 fprintf(fp, "%ld", args[sc->offset]); 1617 break; 1618 case Sizet: 1619 fprintf(fp, "%zu", (size_t)args[sc->offset]); 1620 break; 1621 case ShmName: 1622 /* Handle special SHM_ANON value. */ 1623 if ((char *)args[sc->offset] == SHM_ANON) { 1624 fprintf(fp, "SHM_ANON"); 1625 break; 1626 } 1627 /* FALLTHROUGH */ 1628 case Name: { 1629 /* NULL-terminated string. */ 1630 char *tmp2; 1631 1632 tmp2 = get_string(pid, (void*)args[sc->offset], 0); 1633 fprintf(fp, "\"%s\"", tmp2); 1634 free(tmp2); 1635 break; 1636 } 1637 case BinString: { 1638 /* 1639 * Binary block of data that might have printable characters. 1640 * XXX If type|OUT, assume that the length is the syscall's 1641 * return value. Otherwise, assume that the length of the block 1642 * is in the next syscall argument. 1643 */ 1644 int max_string = trussinfo->strsize; 1645 char tmp2[max_string + 1], *tmp3; 1646 int len; 1647 int truncated = 0; 1648 1649 if (sc->type & OUT) 1650 len = retval[0]; 1651 else 1652 len = args[sc->offset + 1]; 1653 1654 /* 1655 * Don't print more than max_string characters, to avoid word 1656 * wrap. If we have to truncate put some ... after the string. 1657 */ 1658 if (len > max_string) { 1659 len = max_string; 1660 truncated = 1; 1661 } 1662 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) 1663 != -1) { 1664 tmp3 = malloc(len * 4 + 1); 1665 while (len) { 1666 if (strvisx(tmp3, tmp2, len, 1667 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) 1668 break; 1669 len--; 1670 truncated = 1; 1671 } 1672 fprintf(fp, "\"%s\"%s", tmp3, truncated ? 1673 "..." : ""); 1674 free(tmp3); 1675 } else { 1676 fprintf(fp, "0x%lx", args[sc->offset]); 1677 } 1678 break; 1679 } 1680 case ExecArgs: 1681 case ExecEnv: 1682 case StringArray: { 1683 uintptr_t addr; 1684 union { 1685 char *strarray[0]; 1686 char buf[PAGE_SIZE]; 1687 } u; 1688 char *string; 1689 size_t len; 1690 u_int first, i; 1691 1692 /* 1693 * Only parse argv[] and environment arrays from exec calls 1694 * if requested. 1695 */ 1696 if (((sc->type & ARG_MASK) == ExecArgs && 1697 (trussinfo->flags & EXECVEARGS) == 0) || 1698 ((sc->type & ARG_MASK) == ExecEnv && 1699 (trussinfo->flags & EXECVEENVS) == 0)) { 1700 fprintf(fp, "0x%lx", args[sc->offset]); 1701 break; 1702 } 1703 1704 /* 1705 * Read a page of pointers at a time. Punt if the top-level 1706 * pointer is not aligned. Note that the first read is of 1707 * a partial page. 1708 */ 1709 addr = args[sc->offset]; 1710 if (addr % sizeof(char *) != 0) { 1711 fprintf(fp, "0x%lx", args[sc->offset]); 1712 break; 1713 } 1714 1715 len = PAGE_SIZE - (addr & PAGE_MASK); 1716 if (get_struct(pid, (void *)addr, u.buf, len) == -1) { 1717 fprintf(fp, "0x%lx", args[sc->offset]); 1718 break; 1719 } 1720 1721 fputc('[', fp); 1722 first = 1; 1723 i = 0; 1724 while (u.strarray[i] != NULL) { 1725 string = get_string(pid, u.strarray[i], 0); 1726 fprintf(fp, "%s \"%s\"", first ? "" : ",", string); 1727 free(string); 1728 first = 0; 1729 1730 i++; 1731 if (i == len / sizeof(char *)) { 1732 addr += len; 1733 len = PAGE_SIZE; 1734 if (get_struct(pid, (void *)addr, u.buf, len) == 1735 -1) { 1736 fprintf(fp, ", <inval>"); 1737 break; 1738 } 1739 i = 0; 1740 } 1741 } 1742 fputs(" ]", fp); 1743 break; 1744 } 1745 #ifdef __LP64__ 1746 case Quad: 1747 fprintf(fp, "%ld", args[sc->offset]); 1748 break; 1749 case QuadHex: 1750 fprintf(fp, "0x%lx", args[sc->offset]); 1751 break; 1752 #else 1753 case Quad: 1754 case QuadHex: { 1755 unsigned long long ll; 1756 1757 #if _BYTE_ORDER == _LITTLE_ENDIAN 1758 ll = (unsigned long long)args[sc->offset + 1] << 32 | 1759 args[sc->offset]; 1760 #else 1761 ll = (unsigned long long)args[sc->offset] << 32 | 1762 args[sc->offset + 1]; 1763 #endif 1764 if ((sc->type & ARG_MASK) == Quad) 1765 fprintf(fp, "%lld", ll); 1766 else 1767 fprintf(fp, "0x%llx", ll); 1768 break; 1769 } 1770 #endif 1771 case PQuadHex: { 1772 uint64_t val; 1773 1774 if (get_struct(pid, (void *)args[sc->offset], &val, 1775 sizeof(val)) == 0) 1776 fprintf(fp, "{ 0x%jx }", (uintmax_t)val); 1777 else 1778 fprintf(fp, "0x%lx", args[sc->offset]); 1779 break; 1780 } 1781 case Ptr: 1782 fprintf(fp, "0x%lx", args[sc->offset]); 1783 break; 1784 case Readlinkres: { 1785 char *tmp2; 1786 1787 if (retval[0] == -1) 1788 break; 1789 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]); 1790 fprintf(fp, "\"%s\"", tmp2); 1791 free(tmp2); 1792 break; 1793 } 1794 case Ioctl: { 1795 const char *temp; 1796 unsigned long cmd; 1797 1798 cmd = args[sc->offset]; 1799 temp = sysdecode_ioctlname(cmd); 1800 if (temp) 1801 fputs(temp, fp); 1802 else { 1803 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }", 1804 cmd, cmd & IOC_OUT ? "R" : "", 1805 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd), 1806 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?', 1807 cmd & 0xFF, IOCPARM_LEN(cmd)); 1808 } 1809 break; 1810 } 1811 case Timespec: { 1812 struct timespec ts; 1813 1814 if (get_struct(pid, (void *)args[sc->offset], &ts, 1815 sizeof(ts)) != -1) 1816 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec, 1817 ts.tv_nsec); 1818 else 1819 fprintf(fp, "0x%lx", args[sc->offset]); 1820 break; 1821 } 1822 case Timespec2: { 1823 struct timespec ts[2]; 1824 const char *sep; 1825 unsigned int i; 1826 1827 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts)) 1828 != -1) { 1829 fputs("{ ", fp); 1830 sep = ""; 1831 for (i = 0; i < nitems(ts); i++) { 1832 fputs(sep, fp); 1833 sep = ", "; 1834 switch (ts[i].tv_nsec) { 1835 case UTIME_NOW: 1836 fprintf(fp, "UTIME_NOW"); 1837 break; 1838 case UTIME_OMIT: 1839 fprintf(fp, "UTIME_OMIT"); 1840 break; 1841 default: 1842 fprintf(fp, "%jd.%09ld", 1843 (intmax_t)ts[i].tv_sec, 1844 ts[i].tv_nsec); 1845 break; 1846 } 1847 } 1848 fputs(" }", fp); 1849 } else 1850 fprintf(fp, "0x%lx", args[sc->offset]); 1851 break; 1852 } 1853 case Timeval: { 1854 struct timeval tv; 1855 1856 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 1857 != -1) 1858 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec, 1859 tv.tv_usec); 1860 else 1861 fprintf(fp, "0x%lx", args[sc->offset]); 1862 break; 1863 } 1864 case Timeval2: { 1865 struct timeval tv[2]; 1866 1867 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 1868 != -1) 1869 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1870 (intmax_t)tv[0].tv_sec, tv[0].tv_usec, 1871 (intmax_t)tv[1].tv_sec, tv[1].tv_usec); 1872 else 1873 fprintf(fp, "0x%lx", args[sc->offset]); 1874 break; 1875 } 1876 case Itimerval: { 1877 struct itimerval itv; 1878 1879 if (get_struct(pid, (void *)args[sc->offset], &itv, 1880 sizeof(itv)) != -1) 1881 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1882 (intmax_t)itv.it_interval.tv_sec, 1883 itv.it_interval.tv_usec, 1884 (intmax_t)itv.it_value.tv_sec, 1885 itv.it_value.tv_usec); 1886 else 1887 fprintf(fp, "0x%lx", args[sc->offset]); 1888 break; 1889 } 1890 case LinuxSockArgs: 1891 { 1892 struct linux_socketcall_args largs; 1893 1894 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs, 1895 sizeof(largs)) != -1) 1896 fprintf(fp, "{ %s, 0x%lx }", 1897 lookup(linux_socketcall_ops, largs.what, 10), 1898 (long unsigned int)largs.args); 1899 else 1900 fprintf(fp, "0x%lx", args[sc->offset]); 1901 break; 1902 } 1903 case Pollfd: { 1904 /* 1905 * XXX: A Pollfd argument expects the /next/ syscall argument 1906 * to be the number of fds in the array. This matches the poll 1907 * syscall. 1908 */ 1909 struct pollfd *pfd; 1910 int numfds = args[sc->offset + 1]; 1911 size_t bytes = sizeof(struct pollfd) * numfds; 1912 int i; 1913 1914 if ((pfd = malloc(bytes)) == NULL) 1915 err(1, "Cannot malloc %zu bytes for pollfd array", 1916 bytes); 1917 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) 1918 != -1) { 1919 fputs("{", fp); 1920 for (i = 0; i < numfds; i++) { 1921 fprintf(fp, " %d/%s", pfd[i].fd, 1922 xlookup_bits(poll_flags, pfd[i].events)); 1923 } 1924 fputs(" }", fp); 1925 } else { 1926 fprintf(fp, "0x%lx", args[sc->offset]); 1927 } 1928 free(pfd); 1929 break; 1930 } 1931 case Fd_set: { 1932 /* 1933 * XXX: A Fd_set argument expects the /first/ syscall argument 1934 * to be the number of fds in the array. This matches the 1935 * select syscall. 1936 */ 1937 fd_set *fds; 1938 int numfds = args[0]; 1939 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 1940 int i; 1941 1942 if ((fds = malloc(bytes)) == NULL) 1943 err(1, "Cannot malloc %zu bytes for fd_set array", 1944 bytes); 1945 if (get_struct(pid, (void *)args[sc->offset], fds, bytes) 1946 != -1) { 1947 fputs("{", fp); 1948 for (i = 0; i < numfds; i++) { 1949 if (FD_ISSET(i, fds)) 1950 fprintf(fp, " %d", i); 1951 } 1952 fputs(" }", fp); 1953 } else 1954 fprintf(fp, "0x%lx", args[sc->offset]); 1955 free(fds); 1956 break; 1957 } 1958 case Signal: 1959 fputs(strsig2(args[sc->offset]), fp); 1960 break; 1961 case Sigset: { 1962 long sig; 1963 sigset_t ss; 1964 int i, first; 1965 1966 sig = args[sc->offset]; 1967 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 1968 sizeof(ss)) == -1) { 1969 fprintf(fp, "0x%lx", args[sc->offset]); 1970 break; 1971 } 1972 fputs("{ ", fp); 1973 first = 1; 1974 for (i = 1; i < sys_nsig; i++) { 1975 if (sigismember(&ss, i)) { 1976 fprintf(fp, "%s%s", !first ? "|" : "", 1977 strsig2(i)); 1978 first = 0; 1979 } 1980 } 1981 if (!first) 1982 fputc(' ', fp); 1983 fputc('}', fp); 1984 break; 1985 } 1986 case Sigprocmask: 1987 print_integer_arg(sysdecode_sigprocmask_how, fp, 1988 args[sc->offset]); 1989 break; 1990 case Fcntlflag: 1991 /* XXX: Output depends on the value of the previous argument. */ 1992 if (sysdecode_fcntl_arg_p(args[sc->offset - 1])) 1993 sysdecode_fcntl_arg(fp, args[sc->offset - 1], 1994 args[sc->offset], 16); 1995 break; 1996 case Open: 1997 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]); 1998 break; 1999 case Fcntl: 2000 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]); 2001 break; 2002 case Mprot: 2003 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]); 2004 break; 2005 case Mmapflags: 2006 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]); 2007 break; 2008 case Whence: 2009 print_integer_arg(sysdecode_whence, fp, args[sc->offset]); 2010 break; 2011 case Sockdomain: 2012 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]); 2013 break; 2014 case Socktype: 2015 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]); 2016 break; 2017 case Shutdown: 2018 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]); 2019 break; 2020 case Resource: 2021 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]); 2022 break; 2023 case RusageWho: 2024 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]); 2025 break; 2026 case Pathconf: 2027 print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]); 2028 break; 2029 case Rforkflags: 2030 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]); 2031 break; 2032 case Sockaddr: { 2033 socklen_t len; 2034 2035 if (args[sc->offset] == 0) { 2036 fputs("NULL", fp); 2037 break; 2038 } 2039 2040 /* 2041 * Extract the address length from the next argument. If 2042 * this is an output sockaddr (OUT is set), then the 2043 * next argument is a pointer to a socklen_t. Otherwise 2044 * the next argument contains a socklen_t by value. 2045 */ 2046 if (sc->type & OUT) { 2047 if (get_struct(pid, (void *)args[sc->offset + 1], 2048 &len, sizeof(len)) == -1) { 2049 fprintf(fp, "0x%lx", args[sc->offset]); 2050 break; 2051 } 2052 } else 2053 len = args[sc->offset + 1]; 2054 2055 print_sockaddr(fp, trussinfo, (void *)args[sc->offset], len); 2056 break; 2057 } 2058 case Sigaction: { 2059 struct sigaction sa; 2060 2061 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa)) 2062 != -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 fprintf(fp, "0x%lx", 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, (void *)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 fprintf(fp, "0x%lx", 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, (void *)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 fprintf(fp, "0x%lx", args[sc->offset]); 2153 } 2154 free(ke11); 2155 break; 2156 } 2157 case Stat: { 2158 struct stat st; 2159 2160 if (get_struct(pid, (void *)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 fprintf(fp, "0x%lx", args[sc->offset]); 2171 } 2172 break; 2173 } 2174 case Stat11: { 2175 struct freebsd11_stat st; 2176 2177 if (get_struct(pid, (void *)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 fprintf(fp, "0x%lx", args[sc->offset]); 2188 } 2189 break; 2190 } 2191 case StatFs: { 2192 unsigned int i; 2193 struct statfs buf; 2194 2195 if (get_struct(pid, (void *)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 fprintf(fp, "0x%lx", args[sc->offset]); 2212 break; 2213 } 2214 2215 case Rusage: { 2216 struct rusage ru; 2217 2218 if (get_struct(pid, (void *)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 fprintf(fp, "0x%lx", args[sc->offset]); 2227 break; 2228 } 2229 case Rlimit: { 2230 struct rlimit rl; 2231 2232 if (get_struct(pid, (void *)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 fprintf(fp, "0x%lx", args[sc->offset]); 2238 break; 2239 } 2240 case ExitStatus: { 2241 int status; 2242 2243 if (get_struct(pid, (void *)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 fprintf(fp, "0x%lx", 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, (void *)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, (void *)args[sc->offset], 2366 (void *)utrace_addr, len) != -1) 2367 print_utrace(fp, utrace_addr, len); 2368 else 2369 fprintf(fp, "0x%lx", 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, (void *)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 fprintf(fp, "0x%lx", 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, (void *)args[sc->offset], &rights, 2403 sizeof(rights)) == -1) { 2404 fprintf(fp, "0x%lx", 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, (void *)args[sc->offset], &rights, 2487 sizeof(rights)) != -1) { 2488 fputs("{ ", fp); 2489 sysdecode_cap_rights(fp, &rights); 2490 fputs(" }", fp); 2491 } else 2492 fprintf(fp, "0x%lx", 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, (void *)args[sc->offset], &sp, 2541 sizeof(sp)) != -1) 2542 fprintf(fp, "{ %d }", sp.sched_priority); 2543 else 2544 fprintf(fp, "0x%lx", args[sc->offset]); 2545 break; 2546 } 2547 case PSig: { 2548 int sig; 2549 2550 if (get_struct(pid, (void *)args[sc->offset], &sig, 2551 sizeof(sig)) == 0) 2552 fprintf(fp, "{ %s }", strsig2(sig)); 2553 else 2554 fprintf(fp, "0x%lx", args[sc->offset]); 2555 break; 2556 } 2557 case Siginfo: { 2558 siginfo_t si; 2559 2560 if (get_struct(pid, (void *)args[sc->offset], &si, 2561 sizeof(si)) != -1) { 2562 fprintf(fp, "{ signo=%s", strsig2(si.si_signo)); 2563 decode_siginfo(fp, &si); 2564 fprintf(fp, " }"); 2565 } else 2566 fprintf(fp, "0x%lx", args[sc->offset]); 2567 break; 2568 } 2569 case Iovec: 2570 /* 2571 * Print argument as an array of struct iovec, where the next 2572 * syscall argument is the number of elements of the array. 2573 */ 2574 2575 print_iovec(fp, trussinfo, (void *)args[sc->offset], 2576 (int)args[sc->offset + 1]); 2577 break; 2578 case Sctpsndrcvinfo: { 2579 struct sctp_sndrcvinfo info; 2580 2581 if (get_struct(pid, (void *)args[sc->offset], 2582 &info, sizeof(struct sctp_sndrcvinfo)) == -1) { 2583 fprintf(fp, "0x%lx", args[sc->offset]); 2584 break; 2585 } 2586 print_sctp_sndrcvinfo(fp, sc->type & OUT, &info); 2587 break; 2588 } 2589 case Msghdr: { 2590 struct msghdr msghdr; 2591 2592 if (get_struct(pid, (void *)args[sc->offset], 2593 &msghdr, sizeof(struct msghdr)) == -1) { 2594 fprintf(fp, "0x%lx", args[sc->offset]); 2595 break; 2596 } 2597 fputs("{", fp); 2598 print_sockaddr(fp, trussinfo, msghdr.msg_name, msghdr.msg_namelen); 2599 fprintf(fp, ",%d,", msghdr.msg_namelen); 2600 print_iovec(fp, trussinfo, msghdr.msg_iov, msghdr.msg_iovlen); 2601 fprintf(fp, ",%d,", msghdr.msg_iovlen); 2602 print_cmsgs(fp, pid, sc->type & OUT, &msghdr); 2603 fprintf(fp, ",%u,", msghdr.msg_controllen); 2604 print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags); 2605 fputs("}", fp); 2606 break; 2607 } 2608 2609 case CloudABIAdvice: 2610 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp); 2611 break; 2612 case CloudABIClockID: 2613 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp); 2614 break; 2615 case CloudABIFDSFlags: 2616 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp); 2617 break; 2618 case CloudABIFDStat: { 2619 cloudabi_fdstat_t fds; 2620 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds)) 2621 != -1) { 2622 fprintf(fp, "{ %s, ", 2623 xlookup(cloudabi_filetype, fds.fs_filetype)); 2624 fprintf(fp, "%s, ... }", 2625 xlookup_bits(cloudabi_fdflags, fds.fs_flags)); 2626 } else 2627 fprintf(fp, "0x%lx", args[sc->offset]); 2628 break; 2629 } 2630 case CloudABIFileStat: { 2631 cloudabi_filestat_t fsb; 2632 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb)) 2633 != -1) 2634 fprintf(fp, "{ %s, %ju }", 2635 xlookup(cloudabi_filetype, fsb.st_filetype), 2636 (uintmax_t)fsb.st_size); 2637 else 2638 fprintf(fp, "0x%lx", args[sc->offset]); 2639 break; 2640 } 2641 case CloudABIFileType: 2642 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp); 2643 break; 2644 case CloudABIFSFlags: 2645 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp); 2646 break; 2647 case CloudABILookup: 2648 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0) 2649 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW", 2650 (int)args[sc->offset]); 2651 else 2652 fprintf(fp, "%d", (int)args[sc->offset]); 2653 break; 2654 case CloudABIMFlags: 2655 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp); 2656 break; 2657 case CloudABIMProt: 2658 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp); 2659 break; 2660 case CloudABIMSFlags: 2661 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp); 2662 break; 2663 case CloudABIOFlags: 2664 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp); 2665 break; 2666 case CloudABISDFlags: 2667 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp); 2668 break; 2669 case CloudABISignal: 2670 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp); 2671 break; 2672 case CloudABITimestamp: 2673 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000, 2674 args[sc->offset] % 1000000000); 2675 break; 2676 case CloudABIULFlags: 2677 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp); 2678 break; 2679 case CloudABIWhence: 2680 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp); 2681 break; 2682 2683 default: 2684 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); 2685 } 2686 fclose(fp); 2687 return (tmp); 2688 } 2689 2690 /* 2691 * Print (to outfile) the system call and its arguments. 2692 */ 2693 void 2694 print_syscall(struct trussinfo *trussinfo) 2695 { 2696 struct threadinfo *t; 2697 const char *name; 2698 char **s_args; 2699 int i, len, nargs; 2700 2701 t = trussinfo->curthread; 2702 2703 name = t->cs.sc->name; 2704 nargs = t->cs.nargs; 2705 s_args = t->cs.s_args; 2706 2707 len = print_line_prefix(trussinfo); 2708 len += fprintf(trussinfo->outfile, "%s(", name); 2709 2710 for (i = 0; i < nargs; i++) { 2711 if (s_args[i] != NULL) 2712 len += fprintf(trussinfo->outfile, "%s", s_args[i]); 2713 else 2714 len += fprintf(trussinfo->outfile, 2715 "<missing argument>"); 2716 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? 2717 "," : ""); 2718 } 2719 len += fprintf(trussinfo->outfile, ")"); 2720 for (i = 0; i < 6 - (len / 8); i++) 2721 fprintf(trussinfo->outfile, "\t"); 2722 } 2723 2724 void 2725 print_syscall_ret(struct trussinfo *trussinfo, int error, register_t *retval) 2726 { 2727 struct timespec timediff; 2728 struct threadinfo *t; 2729 struct syscall *sc; 2730 2731 t = trussinfo->curthread; 2732 sc = t->cs.sc; 2733 if (trussinfo->flags & COUNTONLY) { 2734 timespecsub(&t->after, &t->before, &timediff); 2735 timespecadd(&sc->time, &timediff, &sc->time); 2736 sc->ncalls++; 2737 if (error != 0) 2738 sc->nerror++; 2739 return; 2740 } 2741 2742 print_syscall(trussinfo); 2743 fflush(trussinfo->outfile); 2744 2745 if (retval == NULL) { 2746 /* 2747 * This system call resulted in the current thread's exit, 2748 * so there is no return value or error to display. 2749 */ 2750 fprintf(trussinfo->outfile, "\n"); 2751 return; 2752 } 2753 2754 if (error == ERESTART) 2755 fprintf(trussinfo->outfile, " ERESTART\n"); 2756 else if (error == EJUSTRETURN) 2757 fprintf(trussinfo->outfile, " EJUSTRETURN\n"); 2758 else if (error != 0) { 2759 fprintf(trussinfo->outfile, " ERR#%d '%s'\n", 2760 sysdecode_freebsd_to_abi_errno(t->proc->abi->abi, error), 2761 strerror(error)); 2762 } 2763 #ifndef __LP64__ 2764 else if (sc->ret_type == 2) { 2765 off_t off; 2766 2767 #if _BYTE_ORDER == _LITTLE_ENDIAN 2768 off = (off_t)retval[1] << 32 | retval[0]; 2769 #else 2770 off = (off_t)retval[0] << 32 | retval[1]; 2771 #endif 2772 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off, 2773 (intmax_t)off); 2774 } 2775 #endif 2776 else 2777 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", 2778 (intmax_t)retval[0], (intmax_t)retval[0]); 2779 } 2780 2781 void 2782 print_summary(struct trussinfo *trussinfo) 2783 { 2784 struct timespec total = {0, 0}; 2785 struct syscall *sc; 2786 int ncall, nerror; 2787 2788 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n", 2789 "syscall", "seconds", "calls", "errors"); 2790 ncall = nerror = 0; 2791 STAILQ_FOREACH(sc, &syscalls, entries) 2792 if (sc->ncalls) { 2793 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 2794 sc->name, (intmax_t)sc->time.tv_sec, 2795 sc->time.tv_nsec, sc->ncalls, sc->nerror); 2796 timespecadd(&total, &sc->time, &total); 2797 ncall += sc->ncalls; 2798 nerror += sc->nerror; 2799 } 2800 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n", 2801 "", "-------------", "-------", "-------"); 2802 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 2803 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror); 2804 } 2805