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