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