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