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