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