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