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