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