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, size_t len) 1581 { 1582 size_t i; 1583 bool first; 1584 1585 first = true; 1586 fprintf(fp, "{ "); 1587 for (i = 0; i < len; i++) { 1588 fprintf(fp, "%s%d", first ? "" : ".", oid[i]); 1589 first = false; 1590 } 1591 fprintf(fp, " }"); 1592 } 1593 1594 static void 1595 print_sysctl(FILE *fp, int *oid, size_t len) 1596 { 1597 char name[BUFSIZ]; 1598 int qoid[CTL_MAXNAME + 2]; 1599 size_t i; 1600 1601 qoid[0] = CTL_SYSCTL; 1602 qoid[1] = CTL_SYSCTL_NAME; 1603 memcpy(qoid + 2, oid, len * sizeof(int)); 1604 i = sizeof(name); 1605 if (sysctl(qoid, len + 2, name, &i, 0, 0) == -1) 1606 print_sysctl_oid(fp, oid, len); 1607 else 1608 fprintf(fp, "%s", name); 1609 } 1610 1611 /* 1612 * Converts a syscall argument into a string. Said string is 1613 * allocated via malloc(), so needs to be free()'d. sc is 1614 * a pointer to the syscall description (see above); args is 1615 * an array of all of the system call arguments. 1616 */ 1617 char * 1618 print_arg(struct syscall_args *sc, unsigned long *args, register_t *retval, 1619 struct trussinfo *trussinfo) 1620 { 1621 FILE *fp; 1622 char *tmp; 1623 size_t tmplen; 1624 pid_t pid; 1625 1626 fp = open_memstream(&tmp, &tmplen); 1627 pid = trussinfo->curthread->proc->pid; 1628 switch (sc->type & ARG_MASK) { 1629 case Hex: 1630 fprintf(fp, "0x%x", (int)args[sc->offset]); 1631 break; 1632 case Octal: 1633 fprintf(fp, "0%o", (int)args[sc->offset]); 1634 break; 1635 case Int: 1636 fprintf(fp, "%d", (int)args[sc->offset]); 1637 break; 1638 case UInt: 1639 fprintf(fp, "%u", (unsigned int)args[sc->offset]); 1640 break; 1641 case PUInt: { 1642 unsigned int val; 1643 1644 if (get_struct(pid, args[sc->offset], &val, 1645 sizeof(val)) == 0) 1646 fprintf(fp, "{ %u }", val); 1647 else 1648 print_pointer(fp, args[sc->offset]); 1649 break; 1650 } 1651 case LongHex: 1652 fprintf(fp, "0x%lx", args[sc->offset]); 1653 break; 1654 case Long: 1655 fprintf(fp, "%ld", args[sc->offset]); 1656 break; 1657 case Sizet: 1658 fprintf(fp, "%zu", (size_t)args[sc->offset]); 1659 break; 1660 case ShmName: 1661 /* Handle special SHM_ANON value. */ 1662 if ((char *)args[sc->offset] == SHM_ANON) { 1663 fprintf(fp, "SHM_ANON"); 1664 break; 1665 } 1666 /* FALLTHROUGH */ 1667 case Name: { 1668 /* NULL-terminated string. */ 1669 char *tmp2; 1670 1671 tmp2 = get_string(pid, args[sc->offset], 0); 1672 fprintf(fp, "\"%s\"", tmp2); 1673 free(tmp2); 1674 break; 1675 } 1676 case BinString: { 1677 /* 1678 * Binary block of data that might have printable characters. 1679 * XXX If type|OUT, assume that the length is the syscall's 1680 * return value. Otherwise, assume that the length of the block 1681 * is in the next syscall argument. 1682 */ 1683 int max_string = trussinfo->strsize; 1684 char tmp2[max_string + 1], *tmp3; 1685 int len; 1686 int truncated = 0; 1687 1688 if (sc->type & OUT) 1689 len = retval[0]; 1690 else 1691 len = args[sc->offset + 1]; 1692 1693 /* 1694 * Don't print more than max_string characters, to avoid word 1695 * wrap. If we have to truncate put some ... after the string. 1696 */ 1697 if (len > max_string) { 1698 len = max_string; 1699 truncated = 1; 1700 } 1701 if (len && get_struct(pid, args[sc->offset], &tmp2, len) 1702 != -1) { 1703 tmp3 = malloc(len * 4 + 1); 1704 while (len) { 1705 if (strvisx(tmp3, tmp2, len, 1706 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) 1707 break; 1708 len--; 1709 truncated = 1; 1710 } 1711 fprintf(fp, "\"%s\"%s", tmp3, truncated ? 1712 "..." : ""); 1713 free(tmp3); 1714 } else { 1715 print_pointer(fp, args[sc->offset]); 1716 } 1717 break; 1718 } 1719 case ExecArgs: 1720 case ExecEnv: 1721 case StringArray: { 1722 uintptr_t addr; 1723 union { 1724 char *strarray[0]; 1725 char buf[PAGE_SIZE]; 1726 } u; 1727 char *string; 1728 size_t len; 1729 u_int first, i; 1730 1731 /* 1732 * Only parse argv[] and environment arrays from exec calls 1733 * if requested. 1734 */ 1735 if (((sc->type & ARG_MASK) == ExecArgs && 1736 (trussinfo->flags & EXECVEARGS) == 0) || 1737 ((sc->type & ARG_MASK) == ExecEnv && 1738 (trussinfo->flags & EXECVEENVS) == 0)) { 1739 print_pointer(fp, args[sc->offset]); 1740 break; 1741 } 1742 1743 /* 1744 * Read a page of pointers at a time. Punt if the top-level 1745 * pointer is not aligned. Note that the first read is of 1746 * a partial page. 1747 */ 1748 addr = args[sc->offset]; 1749 if (addr % sizeof(char *) != 0) { 1750 print_pointer(fp, args[sc->offset]); 1751 break; 1752 } 1753 1754 len = PAGE_SIZE - (addr & PAGE_MASK); 1755 if (get_struct(pid, addr, u.buf, len) == -1) { 1756 print_pointer(fp, args[sc->offset]); 1757 break; 1758 } 1759 1760 fputc('[', fp); 1761 first = 1; 1762 i = 0; 1763 while (u.strarray[i] != NULL) { 1764 string = get_string(pid, (uintptr_t)u.strarray[i], 0); 1765 fprintf(fp, "%s \"%s\"", first ? "" : ",", string); 1766 free(string); 1767 first = 0; 1768 1769 i++; 1770 if (i == len / sizeof(char *)) { 1771 addr += len; 1772 len = PAGE_SIZE; 1773 if (get_struct(pid, addr, u.buf, len) == 1774 -1) { 1775 fprintf(fp, ", <inval>"); 1776 break; 1777 } 1778 i = 0; 1779 } 1780 } 1781 fputs(" ]", fp); 1782 break; 1783 } 1784 #ifdef __LP64__ 1785 case Quad: 1786 fprintf(fp, "%ld", args[sc->offset]); 1787 break; 1788 case QuadHex: 1789 fprintf(fp, "0x%lx", args[sc->offset]); 1790 break; 1791 #else 1792 case Quad: 1793 case QuadHex: { 1794 unsigned long long ll; 1795 1796 #if _BYTE_ORDER == _LITTLE_ENDIAN 1797 ll = (unsigned long long)args[sc->offset + 1] << 32 | 1798 args[sc->offset]; 1799 #else 1800 ll = (unsigned long long)args[sc->offset] << 32 | 1801 args[sc->offset + 1]; 1802 #endif 1803 if ((sc->type & ARG_MASK) == Quad) 1804 fprintf(fp, "%lld", ll); 1805 else 1806 fprintf(fp, "0x%llx", ll); 1807 break; 1808 } 1809 #endif 1810 case PQuadHex: { 1811 uint64_t val; 1812 1813 if (get_struct(pid, args[sc->offset], &val, 1814 sizeof(val)) == 0) 1815 fprintf(fp, "{ 0x%jx }", (uintmax_t)val); 1816 else 1817 print_pointer(fp, args[sc->offset]); 1818 break; 1819 } 1820 case Ptr: 1821 print_pointer(fp, args[sc->offset]); 1822 break; 1823 case Readlinkres: { 1824 char *tmp2; 1825 1826 if (retval[0] == -1) 1827 break; 1828 tmp2 = get_string(pid, args[sc->offset], retval[0]); 1829 fprintf(fp, "\"%s\"", tmp2); 1830 free(tmp2); 1831 break; 1832 } 1833 case Ioctl: { 1834 const char *temp; 1835 unsigned long cmd; 1836 1837 cmd = args[sc->offset]; 1838 temp = sysdecode_ioctlname(cmd); 1839 if (temp) 1840 fputs(temp, fp); 1841 else { 1842 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }", 1843 cmd, cmd & IOC_OUT ? "R" : "", 1844 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd), 1845 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?', 1846 cmd & 0xFF, IOCPARM_LEN(cmd)); 1847 } 1848 break; 1849 } 1850 case Timespec: { 1851 struct timespec ts; 1852 1853 if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1) 1854 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec, 1855 ts.tv_nsec); 1856 else 1857 print_pointer(fp, args[sc->offset]); 1858 break; 1859 } 1860 case Timespec2: { 1861 struct timespec ts[2]; 1862 const char *sep; 1863 unsigned int i; 1864 1865 if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1) { 1866 fputs("{ ", fp); 1867 sep = ""; 1868 for (i = 0; i < nitems(ts); i++) { 1869 fputs(sep, fp); 1870 sep = ", "; 1871 switch (ts[i].tv_nsec) { 1872 case UTIME_NOW: 1873 fprintf(fp, "UTIME_NOW"); 1874 break; 1875 case UTIME_OMIT: 1876 fprintf(fp, "UTIME_OMIT"); 1877 break; 1878 default: 1879 fprintf(fp, "%jd.%09ld", 1880 (intmax_t)ts[i].tv_sec, 1881 ts[i].tv_nsec); 1882 break; 1883 } 1884 } 1885 fputs(" }", fp); 1886 } else 1887 print_pointer(fp, args[sc->offset]); 1888 break; 1889 } 1890 case Timeval: { 1891 struct timeval tv; 1892 1893 if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1) 1894 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec, 1895 tv.tv_usec); 1896 else 1897 print_pointer(fp, args[sc->offset]); 1898 break; 1899 } 1900 case Timeval2: { 1901 struct timeval tv[2]; 1902 1903 if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1) 1904 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1905 (intmax_t)tv[0].tv_sec, tv[0].tv_usec, 1906 (intmax_t)tv[1].tv_sec, tv[1].tv_usec); 1907 else 1908 print_pointer(fp, args[sc->offset]); 1909 break; 1910 } 1911 case Itimerval: { 1912 struct itimerval itv; 1913 1914 if (get_struct(pid, args[sc->offset], &itv, sizeof(itv)) != -1) 1915 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1916 (intmax_t)itv.it_interval.tv_sec, 1917 itv.it_interval.tv_usec, 1918 (intmax_t)itv.it_value.tv_sec, 1919 itv.it_value.tv_usec); 1920 else 1921 print_pointer(fp, args[sc->offset]); 1922 break; 1923 } 1924 case LinuxSockArgs: 1925 { 1926 struct linux_socketcall_args largs; 1927 1928 if (get_struct(pid, args[sc->offset], (void *)&largs, 1929 sizeof(largs)) != -1) 1930 fprintf(fp, "{ %s, 0x%lx }", 1931 lookup(linux_socketcall_ops, largs.what, 10), 1932 (long unsigned int)largs.args); 1933 else 1934 print_pointer(fp, args[sc->offset]); 1935 break; 1936 } 1937 case Pollfd: { 1938 /* 1939 * XXX: A Pollfd argument expects the /next/ syscall argument 1940 * to be the number of fds in the array. This matches the poll 1941 * syscall. 1942 */ 1943 struct pollfd *pfd; 1944 int numfds = args[sc->offset + 1]; 1945 size_t bytes = sizeof(struct pollfd) * numfds; 1946 int i; 1947 1948 if ((pfd = malloc(bytes)) == NULL) 1949 err(1, "Cannot malloc %zu bytes for pollfd array", 1950 bytes); 1951 if (get_struct(pid, args[sc->offset], pfd, bytes) != -1) { 1952 fputs("{", fp); 1953 for (i = 0; i < numfds; i++) { 1954 fprintf(fp, " %d/%s", pfd[i].fd, 1955 xlookup_bits(poll_flags, pfd[i].events)); 1956 } 1957 fputs(" }", fp); 1958 } else { 1959 print_pointer(fp, args[sc->offset]); 1960 } 1961 free(pfd); 1962 break; 1963 } 1964 case Fd_set: { 1965 /* 1966 * XXX: A Fd_set argument expects the /first/ syscall argument 1967 * to be the number of fds in the array. This matches the 1968 * select syscall. 1969 */ 1970 fd_set *fds; 1971 int numfds = args[0]; 1972 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 1973 int i; 1974 1975 if ((fds = malloc(bytes)) == NULL) 1976 err(1, "Cannot malloc %zu bytes for fd_set array", 1977 bytes); 1978 if (get_struct(pid, args[sc->offset], fds, bytes) != -1) { 1979 fputs("{", fp); 1980 for (i = 0; i < numfds; i++) { 1981 if (FD_ISSET(i, fds)) 1982 fprintf(fp, " %d", i); 1983 } 1984 fputs(" }", fp); 1985 } else 1986 print_pointer(fp, args[sc->offset]); 1987 free(fds); 1988 break; 1989 } 1990 case Signal: 1991 fputs(strsig2(args[sc->offset]), fp); 1992 break; 1993 case Sigset: { 1994 long sig; 1995 sigset_t ss; 1996 int i, first; 1997 1998 sig = args[sc->offset]; 1999 if (get_struct(pid, args[sc->offset], (void *)&ss, 2000 sizeof(ss)) == -1) { 2001 print_pointer(fp, args[sc->offset]); 2002 break; 2003 } 2004 fputs("{ ", fp); 2005 first = 1; 2006 for (i = 1; i < sys_nsig; i++) { 2007 if (sigismember(&ss, i)) { 2008 fprintf(fp, "%s%s", !first ? "|" : "", 2009 strsig2(i)); 2010 first = 0; 2011 } 2012 } 2013 if (!first) 2014 fputc(' ', fp); 2015 fputc('}', fp); 2016 break; 2017 } 2018 case Sigprocmask: 2019 print_integer_arg(sysdecode_sigprocmask_how, fp, 2020 args[sc->offset]); 2021 break; 2022 case Fcntlflag: 2023 /* XXX: Output depends on the value of the previous argument. */ 2024 if (sysdecode_fcntl_arg_p(args[sc->offset - 1])) 2025 sysdecode_fcntl_arg(fp, args[sc->offset - 1], 2026 args[sc->offset], 16); 2027 break; 2028 case Open: 2029 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]); 2030 break; 2031 case Fcntl: 2032 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]); 2033 break; 2034 case Mprot: 2035 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]); 2036 break; 2037 case Mmapflags: 2038 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]); 2039 break; 2040 case Whence: 2041 print_integer_arg(sysdecode_whence, fp, args[sc->offset]); 2042 break; 2043 case ShmFlags: 2044 print_mask_arg(sysdecode_shmflags, fp, args[sc->offset]); 2045 break; 2046 case Sockdomain: 2047 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]); 2048 break; 2049 case Socktype: 2050 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]); 2051 break; 2052 case Shutdown: 2053 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]); 2054 break; 2055 case Resource: 2056 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]); 2057 break; 2058 case RusageWho: 2059 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]); 2060 break; 2061 case Pathconf: 2062 print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]); 2063 break; 2064 case Rforkflags: 2065 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]); 2066 break; 2067 case Sockaddr: { 2068 socklen_t len; 2069 2070 if (args[sc->offset] == 0) { 2071 fputs("NULL", fp); 2072 break; 2073 } 2074 2075 /* 2076 * Extract the address length from the next argument. If 2077 * this is an output sockaddr (OUT is set), then the 2078 * next argument is a pointer to a socklen_t. Otherwise 2079 * the next argument contains a socklen_t by value. 2080 */ 2081 if (sc->type & OUT) { 2082 if (get_struct(pid, args[sc->offset + 1], &len, 2083 sizeof(len)) == -1) { 2084 print_pointer(fp, args[sc->offset]); 2085 break; 2086 } 2087 } else 2088 len = args[sc->offset + 1]; 2089 2090 print_sockaddr(fp, trussinfo, args[sc->offset], len); 2091 break; 2092 } 2093 case Sigaction: { 2094 struct sigaction sa; 2095 2096 if (get_struct(pid, args[sc->offset], &sa, sizeof(sa)) != -1) { 2097 fputs("{ ", fp); 2098 if (sa.sa_handler == SIG_DFL) 2099 fputs("SIG_DFL", fp); 2100 else if (sa.sa_handler == SIG_IGN) 2101 fputs("SIG_IGN", fp); 2102 else 2103 fprintf(fp, "%p", sa.sa_handler); 2104 fprintf(fp, " %s ss_t }", 2105 xlookup_bits(sigaction_flags, sa.sa_flags)); 2106 } else 2107 print_pointer(fp, args[sc->offset]); 2108 break; 2109 } 2110 case Kevent: { 2111 /* 2112 * XXX XXX: The size of the array is determined by either the 2113 * next syscall argument, or by the syscall return value, 2114 * depending on which argument number we are. This matches the 2115 * kevent syscall, but luckily that's the only syscall that uses 2116 * them. 2117 */ 2118 struct kevent *ke; 2119 int numevents = -1; 2120 size_t bytes; 2121 int i; 2122 2123 if (sc->offset == 1) 2124 numevents = args[sc->offset+1]; 2125 else if (sc->offset == 3 && retval[0] != -1) 2126 numevents = retval[0]; 2127 2128 if (numevents >= 0) { 2129 bytes = sizeof(struct kevent) * numevents; 2130 if ((ke = malloc(bytes)) == NULL) 2131 err(1, 2132 "Cannot malloc %zu bytes for kevent array", 2133 bytes); 2134 } else 2135 ke = NULL; 2136 if (numevents >= 0 && get_struct(pid, args[sc->offset], 2137 ke, bytes) != -1) { 2138 fputc('{', fp); 2139 for (i = 0; i < numevents; i++) { 2140 fputc(' ', fp); 2141 print_kevent(fp, &ke[i]); 2142 } 2143 fputs(" }", fp); 2144 } else { 2145 print_pointer(fp, args[sc->offset]); 2146 } 2147 free(ke); 2148 break; 2149 } 2150 case Kevent11: { 2151 struct kevent_freebsd11 *ke11; 2152 struct kevent ke; 2153 int numevents = -1; 2154 size_t bytes; 2155 int i; 2156 2157 if (sc->offset == 1) 2158 numevents = args[sc->offset+1]; 2159 else if (sc->offset == 3 && retval[0] != -1) 2160 numevents = retval[0]; 2161 2162 if (numevents >= 0) { 2163 bytes = sizeof(struct kevent_freebsd11) * numevents; 2164 if ((ke11 = malloc(bytes)) == NULL) 2165 err(1, 2166 "Cannot malloc %zu bytes for kevent array", 2167 bytes); 2168 } else 2169 ke11 = NULL; 2170 memset(&ke, 0, sizeof(ke)); 2171 if (numevents >= 0 && get_struct(pid, args[sc->offset], 2172 ke11, bytes) != -1) { 2173 fputc('{', fp); 2174 for (i = 0; i < numevents; i++) { 2175 fputc(' ', fp); 2176 ke.ident = ke11[i].ident; 2177 ke.filter = ke11[i].filter; 2178 ke.flags = ke11[i].flags; 2179 ke.fflags = ke11[i].fflags; 2180 ke.data = ke11[i].data; 2181 ke.udata = ke11[i].udata; 2182 print_kevent(fp, &ke); 2183 } 2184 fputs(" }", fp); 2185 } else { 2186 print_pointer(fp, args[sc->offset]); 2187 } 2188 free(ke11); 2189 break; 2190 } 2191 case Stat: { 2192 struct stat st; 2193 2194 if (get_struct(pid, args[sc->offset], &st, sizeof(st)) 2195 != -1) { 2196 char mode[12]; 2197 2198 strmode(st.st_mode, mode); 2199 fprintf(fp, 2200 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode, 2201 (uintmax_t)st.st_ino, (intmax_t)st.st_size, 2202 (long)st.st_blksize); 2203 } else { 2204 print_pointer(fp, args[sc->offset]); 2205 } 2206 break; 2207 } 2208 case Stat11: { 2209 struct freebsd11_stat st; 2210 2211 if (get_struct(pid, args[sc->offset], &st, sizeof(st)) 2212 != -1) { 2213 char mode[12]; 2214 2215 strmode(st.st_mode, mode); 2216 fprintf(fp, 2217 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode, 2218 (uintmax_t)st.st_ino, (intmax_t)st.st_size, 2219 (long)st.st_blksize); 2220 } else { 2221 print_pointer(fp, args[sc->offset]); 2222 } 2223 break; 2224 } 2225 case StatFs: { 2226 unsigned int i; 2227 struct statfs buf; 2228 2229 if (get_struct(pid, args[sc->offset], &buf, 2230 sizeof(buf)) != -1) { 2231 char fsid[17]; 2232 2233 bzero(fsid, sizeof(fsid)); 2234 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) { 2235 for (i = 0; i < sizeof(buf.f_fsid); i++) 2236 snprintf(&fsid[i*2], 2237 sizeof(fsid) - (i*2), "%02x", 2238 ((u_char *)&buf.f_fsid)[i]); 2239 } 2240 fprintf(fp, 2241 "{ fstypename=%s,mntonname=%s,mntfromname=%s," 2242 "fsid=%s }", buf.f_fstypename, buf.f_mntonname, 2243 buf.f_mntfromname, fsid); 2244 } else 2245 print_pointer(fp, args[sc->offset]); 2246 break; 2247 } 2248 2249 case Rusage: { 2250 struct rusage ru; 2251 2252 if (get_struct(pid, args[sc->offset], &ru, sizeof(ru)) 2253 != -1) { 2254 fprintf(fp, 2255 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }", 2256 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, 2257 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, 2258 ru.ru_inblock, ru.ru_oublock); 2259 } else 2260 print_pointer(fp, args[sc->offset]); 2261 break; 2262 } 2263 case Rlimit: { 2264 struct rlimit rl; 2265 2266 if (get_struct(pid, args[sc->offset], &rl, sizeof(rl)) 2267 != -1) { 2268 fprintf(fp, "{ cur=%ju,max=%ju }", 2269 rl.rlim_cur, rl.rlim_max); 2270 } else 2271 print_pointer(fp, args[sc->offset]); 2272 break; 2273 } 2274 case ExitStatus: { 2275 int status; 2276 2277 if (get_struct(pid, args[sc->offset], &status, 2278 sizeof(status)) != -1) { 2279 fputs("{ ", fp); 2280 if (WIFCONTINUED(status)) 2281 fputs("CONTINUED", fp); 2282 else if (WIFEXITED(status)) 2283 fprintf(fp, "EXITED,val=%d", 2284 WEXITSTATUS(status)); 2285 else if (WIFSIGNALED(status)) 2286 fprintf(fp, "SIGNALED,sig=%s%s", 2287 strsig2(WTERMSIG(status)), 2288 WCOREDUMP(status) ? ",cored" : ""); 2289 else 2290 fprintf(fp, "STOPPED,sig=%s", 2291 strsig2(WTERMSIG(status))); 2292 fputs(" }", fp); 2293 } else 2294 print_pointer(fp, args[sc->offset]); 2295 break; 2296 } 2297 case Waitoptions: 2298 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]); 2299 break; 2300 case Idtype: 2301 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]); 2302 break; 2303 case Procctl: 2304 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]); 2305 break; 2306 case Umtxop: 2307 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]); 2308 break; 2309 case Atfd: 2310 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]); 2311 break; 2312 case Atflags: 2313 print_mask_arg(sysdecode_atflags, fp, args[sc->offset]); 2314 break; 2315 case Accessmode: 2316 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]); 2317 break; 2318 case Sysarch: 2319 print_integer_arg(sysdecode_sysarch_number, fp, 2320 args[sc->offset]); 2321 break; 2322 case Sysctl: { 2323 char name[BUFSIZ]; 2324 int oid[CTL_MAXNAME + 2]; 2325 size_t len; 2326 2327 memset(name, 0, sizeof(name)); 2328 len = args[sc->offset + 1]; 2329 if (get_struct(pid, args[sc->offset], oid, 2330 len * sizeof(oid[0])) != -1) { 2331 fprintf(fp, "\""); 2332 if (oid[0] == CTL_SYSCTL) { 2333 fprintf(fp, "sysctl."); 2334 switch (oid[1]) { 2335 case CTL_SYSCTL_DEBUG: 2336 fprintf(fp, "debug"); 2337 break; 2338 case CTL_SYSCTL_NAME: 2339 fprintf(fp, "name "); 2340 print_sysctl_oid(fp, oid + 2, len - 2); 2341 break; 2342 case CTL_SYSCTL_NEXT: 2343 fprintf(fp, "next"); 2344 break; 2345 case CTL_SYSCTL_NAME2OID: 2346 fprintf(fp, "name2oid %s", 2347 get_string(pid, 2348 args[sc->offset + 4], 2349 args[sc->offset + 5])); 2350 break; 2351 case CTL_SYSCTL_OIDFMT: 2352 fprintf(fp, "oidfmt "); 2353 print_sysctl(fp, oid + 2, len - 2); 2354 break; 2355 case CTL_SYSCTL_OIDDESCR: 2356 fprintf(fp, "oiddescr "); 2357 print_sysctl(fp, oid + 2, len - 2); 2358 break; 2359 case CTL_SYSCTL_OIDLABEL: 2360 fprintf(fp, "oidlabel "); 2361 print_sysctl(fp, oid + 2, len - 2); 2362 break; 2363 case CTL_SYSCTL_NEXTNOSKIP: 2364 fprintf(fp, "nextnoskip"); 2365 break; 2366 default: 2367 print_sysctl(fp, oid + 1, len - 1); 2368 } 2369 } else { 2370 print_sysctl(fp, oid, len); 2371 } 2372 fprintf(fp, "\""); 2373 } 2374 break; 2375 } 2376 case PipeFds: 2377 /* 2378 * The pipe() system call in the kernel returns its 2379 * two file descriptors via return values. However, 2380 * the interface exposed by libc is that pipe() 2381 * accepts a pointer to an array of descriptors. 2382 * Format the output to match the libc API by printing 2383 * the returned file descriptors as a fake argument. 2384 * 2385 * Overwrite the first retval to signal a successful 2386 * return as well. 2387 */ 2388 fprintf(fp, "{ %d, %d }", (int)retval[0], (int)retval[1]); 2389 retval[0] = 0; 2390 break; 2391 case Utrace: { 2392 size_t len; 2393 void *utrace_addr; 2394 2395 len = args[sc->offset + 1]; 2396 utrace_addr = calloc(1, len); 2397 if (get_struct(pid, args[sc->offset], 2398 (void *)utrace_addr, len) != -1) 2399 print_utrace(fp, utrace_addr, len); 2400 else 2401 print_pointer(fp, args[sc->offset]); 2402 free(utrace_addr); 2403 break; 2404 } 2405 case IntArray: { 2406 int descriptors[16]; 2407 unsigned long i, ndescriptors; 2408 bool truncated; 2409 2410 ndescriptors = args[sc->offset + 1]; 2411 truncated = false; 2412 if (ndescriptors > nitems(descriptors)) { 2413 ndescriptors = nitems(descriptors); 2414 truncated = true; 2415 } 2416 if (get_struct(pid, args[sc->offset], 2417 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) { 2418 fprintf(fp, "{"); 2419 for (i = 0; i < ndescriptors; i++) 2420 fprintf(fp, i == 0 ? " %d" : ", %d", 2421 descriptors[i]); 2422 fprintf(fp, truncated ? ", ... }" : " }"); 2423 } else 2424 print_pointer(fp, args[sc->offset]); 2425 break; 2426 } 2427 case Pipe2: 2428 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]); 2429 break; 2430 case CapFcntlRights: { 2431 uint32_t rights; 2432 2433 if (sc->type & OUT) { 2434 if (get_struct(pid, args[sc->offset], &rights, 2435 sizeof(rights)) == -1) { 2436 print_pointer(fp, args[sc->offset]); 2437 break; 2438 } 2439 } else 2440 rights = args[sc->offset]; 2441 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights); 2442 break; 2443 } 2444 case Fadvice: 2445 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]); 2446 break; 2447 case FileFlags: { 2448 fflags_t rem; 2449 2450 if (!sysdecode_fileflags(fp, args[sc->offset], &rem)) 2451 fprintf(fp, "0x%x", rem); 2452 else if (rem != 0) 2453 fprintf(fp, "|0x%x", rem); 2454 break; 2455 } 2456 case Flockop: 2457 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]); 2458 break; 2459 case Getfsstatmode: 2460 print_integer_arg(sysdecode_getfsstat_mode, fp, 2461 args[sc->offset]); 2462 break; 2463 case Kldsymcmd: 2464 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]); 2465 break; 2466 case Kldunloadflags: 2467 print_integer_arg(sysdecode_kldunload_flags, fp, 2468 args[sc->offset]); 2469 break; 2470 case Madvice: 2471 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]); 2472 break; 2473 case Socklent: 2474 fprintf(fp, "%u", (socklen_t)args[sc->offset]); 2475 break; 2476 case Sockprotocol: { 2477 const char *temp; 2478 int domain, protocol; 2479 2480 domain = args[sc->offset - 2]; 2481 protocol = args[sc->offset]; 2482 if (protocol == 0) { 2483 fputs("0", fp); 2484 } else { 2485 temp = sysdecode_socket_protocol(domain, protocol); 2486 if (temp) { 2487 fputs(temp, fp); 2488 } else { 2489 fprintf(fp, "%d", protocol); 2490 } 2491 } 2492 break; 2493 } 2494 case Sockoptlevel: 2495 print_integer_arg(sysdecode_sockopt_level, fp, 2496 args[sc->offset]); 2497 break; 2498 case Sockoptname: { 2499 const char *temp; 2500 int level, name; 2501 2502 level = args[sc->offset - 1]; 2503 name = args[sc->offset]; 2504 temp = sysdecode_sockopt_name(level, name); 2505 if (temp) { 2506 fputs(temp, fp); 2507 } else { 2508 fprintf(fp, "%d", name); 2509 } 2510 break; 2511 } 2512 case Msgflags: 2513 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]); 2514 break; 2515 case CapRights: { 2516 cap_rights_t rights; 2517 2518 if (get_struct(pid, args[sc->offset], &rights, 2519 sizeof(rights)) != -1) { 2520 fputs("{ ", fp); 2521 sysdecode_cap_rights(fp, &rights); 2522 fputs(" }", fp); 2523 } else 2524 print_pointer(fp, args[sc->offset]); 2525 break; 2526 } 2527 case Acltype: 2528 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]); 2529 break; 2530 case Extattrnamespace: 2531 print_integer_arg(sysdecode_extattrnamespace, fp, 2532 args[sc->offset]); 2533 break; 2534 case Minherit: 2535 print_integer_arg(sysdecode_minherit_inherit, fp, 2536 args[sc->offset]); 2537 break; 2538 case Mlockall: 2539 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]); 2540 break; 2541 case Mountflags: 2542 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]); 2543 break; 2544 case Msync: 2545 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]); 2546 break; 2547 case Priowhich: 2548 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]); 2549 break; 2550 case Ptraceop: 2551 print_integer_arg(sysdecode_ptrace_request, fp, 2552 args[sc->offset]); 2553 break; 2554 case Quotactlcmd: 2555 if (!sysdecode_quotactl_cmd(fp, args[sc->offset])) 2556 fprintf(fp, "%#x", (int)args[sc->offset]); 2557 break; 2558 case Reboothowto: 2559 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]); 2560 break; 2561 case Rtpriofunc: 2562 print_integer_arg(sysdecode_rtprio_function, fp, 2563 args[sc->offset]); 2564 break; 2565 case Schedpolicy: 2566 print_integer_arg(sysdecode_scheduler_policy, fp, 2567 args[sc->offset]); 2568 break; 2569 case Schedparam: { 2570 struct sched_param sp; 2571 2572 if (get_struct(pid, args[sc->offset], &sp, sizeof(sp)) != -1) 2573 fprintf(fp, "{ %d }", sp.sched_priority); 2574 else 2575 print_pointer(fp, args[sc->offset]); 2576 break; 2577 } 2578 case PSig: { 2579 int sig; 2580 2581 if (get_struct(pid, args[sc->offset], &sig, sizeof(sig)) == 0) 2582 fprintf(fp, "{ %s }", strsig2(sig)); 2583 else 2584 print_pointer(fp, args[sc->offset]); 2585 break; 2586 } 2587 case Siginfo: { 2588 siginfo_t si; 2589 2590 if (get_struct(pid, args[sc->offset], &si, sizeof(si)) != -1) { 2591 fprintf(fp, "{ signo=%s", strsig2(si.si_signo)); 2592 decode_siginfo(fp, &si); 2593 fprintf(fp, " }"); 2594 } else 2595 print_pointer(fp, args[sc->offset]); 2596 break; 2597 } 2598 case Iovec: 2599 /* 2600 * Print argument as an array of struct iovec, where the next 2601 * syscall argument is the number of elements of the array. 2602 */ 2603 2604 print_iovec(fp, trussinfo, args[sc->offset], 2605 (int)args[sc->offset + 1]); 2606 break; 2607 case Sctpsndrcvinfo: { 2608 struct sctp_sndrcvinfo info; 2609 2610 if (get_struct(pid, args[sc->offset], 2611 &info, sizeof(struct sctp_sndrcvinfo)) == -1) { 2612 print_pointer(fp, args[sc->offset]); 2613 break; 2614 } 2615 print_sctp_sndrcvinfo(fp, sc->type & OUT, &info); 2616 break; 2617 } 2618 case Msghdr: { 2619 struct msghdr msghdr; 2620 2621 if (get_struct(pid, args[sc->offset], 2622 &msghdr, sizeof(struct msghdr)) == -1) { 2623 print_pointer(fp, args[sc->offset]); 2624 break; 2625 } 2626 fputs("{", fp); 2627 print_sockaddr(fp, trussinfo, (uintptr_t)msghdr.msg_name, msghdr.msg_namelen); 2628 fprintf(fp, ",%d,", msghdr.msg_namelen); 2629 print_iovec(fp, trussinfo, (uintptr_t)msghdr.msg_iov, msghdr.msg_iovlen); 2630 fprintf(fp, ",%d,", msghdr.msg_iovlen); 2631 print_cmsgs(fp, pid, sc->type & OUT, &msghdr); 2632 fprintf(fp, ",%u,", msghdr.msg_controllen); 2633 print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags); 2634 fputs("}", fp); 2635 break; 2636 } 2637 2638 case CloudABIAdvice: 2639 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp); 2640 break; 2641 case CloudABIClockID: 2642 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp); 2643 break; 2644 case CloudABIFDSFlags: 2645 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp); 2646 break; 2647 case CloudABIFDStat: { 2648 cloudabi_fdstat_t fds; 2649 if (get_struct(pid, args[sc->offset], &fds, sizeof(fds)) 2650 != -1) { 2651 fprintf(fp, "{ %s, ", 2652 xlookup(cloudabi_filetype, fds.fs_filetype)); 2653 fprintf(fp, "%s, ... }", 2654 xlookup_bits(cloudabi_fdflags, fds.fs_flags)); 2655 } else 2656 print_pointer(fp, args[sc->offset]); 2657 break; 2658 } 2659 case CloudABIFileStat: { 2660 cloudabi_filestat_t fsb; 2661 if (get_struct(pid, args[sc->offset], &fsb, sizeof(fsb)) 2662 != -1) 2663 fprintf(fp, "{ %s, %ju }", 2664 xlookup(cloudabi_filetype, fsb.st_filetype), 2665 (uintmax_t)fsb.st_size); 2666 else 2667 print_pointer(fp, args[sc->offset]); 2668 break; 2669 } 2670 case CloudABIFileType: 2671 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp); 2672 break; 2673 case CloudABIFSFlags: 2674 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp); 2675 break; 2676 case CloudABILookup: 2677 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0) 2678 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW", 2679 (int)args[sc->offset]); 2680 else 2681 fprintf(fp, "%d", (int)args[sc->offset]); 2682 break; 2683 case CloudABIMFlags: 2684 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp); 2685 break; 2686 case CloudABIMProt: 2687 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp); 2688 break; 2689 case CloudABIMSFlags: 2690 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp); 2691 break; 2692 case CloudABIOFlags: 2693 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp); 2694 break; 2695 case CloudABISDFlags: 2696 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp); 2697 break; 2698 case CloudABISignal: 2699 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp); 2700 break; 2701 case CloudABITimestamp: 2702 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000, 2703 args[sc->offset] % 1000000000); 2704 break; 2705 case CloudABIULFlags: 2706 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp); 2707 break; 2708 case CloudABIWhence: 2709 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp); 2710 break; 2711 2712 default: 2713 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); 2714 } 2715 fclose(fp); 2716 return (tmp); 2717 } 2718 2719 /* 2720 * Print (to outfile) the system call and its arguments. 2721 */ 2722 void 2723 print_syscall(struct trussinfo *trussinfo) 2724 { 2725 struct threadinfo *t; 2726 const char *name; 2727 char **s_args; 2728 int i, len, nargs; 2729 2730 t = trussinfo->curthread; 2731 2732 name = t->cs.sc->name; 2733 nargs = t->cs.nargs; 2734 s_args = t->cs.s_args; 2735 2736 len = print_line_prefix(trussinfo); 2737 len += fprintf(trussinfo->outfile, "%s(", name); 2738 2739 for (i = 0; i < nargs; i++) { 2740 if (s_args[i] != NULL) 2741 len += fprintf(trussinfo->outfile, "%s", s_args[i]); 2742 else 2743 len += fprintf(trussinfo->outfile, 2744 "<missing argument>"); 2745 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? 2746 "," : ""); 2747 } 2748 len += fprintf(trussinfo->outfile, ")"); 2749 for (i = 0; i < 6 - (len / 8); i++) 2750 fprintf(trussinfo->outfile, "\t"); 2751 } 2752 2753 void 2754 print_syscall_ret(struct trussinfo *trussinfo, int error, register_t *retval) 2755 { 2756 struct timespec timediff; 2757 struct threadinfo *t; 2758 struct syscall *sc; 2759 2760 t = trussinfo->curthread; 2761 sc = t->cs.sc; 2762 if (trussinfo->flags & COUNTONLY) { 2763 timespecsub(&t->after, &t->before, &timediff); 2764 timespecadd(&sc->time, &timediff, &sc->time); 2765 sc->ncalls++; 2766 if (error != 0) 2767 sc->nerror++; 2768 return; 2769 } 2770 2771 print_syscall(trussinfo); 2772 fflush(trussinfo->outfile); 2773 2774 if (retval == NULL) { 2775 /* 2776 * This system call resulted in the current thread's exit, 2777 * so there is no return value or error to display. 2778 */ 2779 fprintf(trussinfo->outfile, "\n"); 2780 return; 2781 } 2782 2783 if (error == ERESTART) 2784 fprintf(trussinfo->outfile, " ERESTART\n"); 2785 else if (error == EJUSTRETURN) 2786 fprintf(trussinfo->outfile, " EJUSTRETURN\n"); 2787 else if (error != 0) { 2788 fprintf(trussinfo->outfile, " ERR#%d '%s'\n", 2789 sysdecode_freebsd_to_abi_errno(t->proc->abi->abi, error), 2790 strerror(error)); 2791 } 2792 #ifndef __LP64__ 2793 else if (sc->ret_type == 2) { 2794 off_t off; 2795 2796 #if _BYTE_ORDER == _LITTLE_ENDIAN 2797 off = (off_t)retval[1] << 32 | retval[0]; 2798 #else 2799 off = (off_t)retval[0] << 32 | retval[1]; 2800 #endif 2801 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off, 2802 (intmax_t)off); 2803 } 2804 #endif 2805 else 2806 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", 2807 (intmax_t)retval[0], (intmax_t)retval[0]); 2808 } 2809 2810 void 2811 print_summary(struct trussinfo *trussinfo) 2812 { 2813 struct timespec total = {0, 0}; 2814 struct syscall *sc; 2815 int ncall, nerror; 2816 2817 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n", 2818 "syscall", "seconds", "calls", "errors"); 2819 ncall = nerror = 0; 2820 STAILQ_FOREACH(sc, &syscalls, entries) 2821 if (sc->ncalls) { 2822 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 2823 sc->name, (intmax_t)sc->time.tv_sec, 2824 sc->time.tv_nsec, sc->ncalls, sc->nerror); 2825 timespecadd(&total, &sc->time, &total); 2826 ncall += sc->ncalls; 2827 nerror += sc->nerror; 2828 } 2829 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n", 2830 "", "-------------", "-------", "-------"); 2831 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 2832 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror); 2833 } 2834