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