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/capsicum.h> 43 #include <sys/types.h> 44 #define _WANT_FREEBSD11_KEVENT 45 #include <sys/event.h> 46 #include <sys/ioccom.h> 47 #include <sys/mount.h> 48 #include <sys/ptrace.h> 49 #include <sys/resource.h> 50 #include <sys/socket.h> 51 #define _WANT_FREEBSD11_STAT 52 #include <sys/stat.h> 53 #include <sys/un.h> 54 #include <sys/wait.h> 55 #include <netinet/in.h> 56 #include <arpa/inet.h> 57 58 #include <assert.h> 59 #include <ctype.h> 60 #include <err.h> 61 #include <fcntl.h> 62 #include <poll.h> 63 #include <sched.h> 64 #include <signal.h> 65 #include <stdbool.h> 66 #include <stdio.h> 67 #include <stdlib.h> 68 #include <string.h> 69 #include <sysdecode.h> 70 #include <unistd.h> 71 #include <vis.h> 72 73 #include <contrib/cloudabi/cloudabi_types_common.h> 74 75 #include "truss.h" 76 #include "extern.h" 77 #include "syscall.h" 78 79 /* 80 * This should probably be in its own file, sorted alphabetically. 81 */ 82 static struct syscall decoded_syscalls[] = { 83 /* Native ABI */ 84 { .name = "__acl_aclcheck_fd", .ret_type = 1, .nargs = 3, 85 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } }, 86 { .name = "__acl_aclcheck_file", .ret_type = 1, .nargs = 3, 87 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } }, 88 { .name = "__acl_aclcheck_link", .ret_type = 1, .nargs = 3, 89 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } }, 90 { .name = "__acl_delete_fd", .ret_type = 1, .nargs = 2, 91 .args = { { Int, 0 }, { Acltype, 1 } } }, 92 { .name = "__acl_delete_file", .ret_type = 1, .nargs = 2, 93 .args = { { Name, 0 }, { Acltype, 1 } } }, 94 { .name = "__acl_delete_link", .ret_type = 1, .nargs = 2, 95 .args = { { Name, 0 }, { Acltype, 1 } } }, 96 { .name = "__acl_get_fd", .ret_type = 1, .nargs = 3, 97 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } }, 98 { .name = "__acl_get_file", .ret_type = 1, .nargs = 3, 99 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } }, 100 { .name = "__acl_get_link", .ret_type = 1, .nargs = 3, 101 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } }, 102 { .name = "__acl_set_fd", .ret_type = 1, .nargs = 3, 103 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } }, 104 { .name = "__acl_set_file", .ret_type = 1, .nargs = 3, 105 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } }, 106 { .name = "__acl_set_link", .ret_type = 1, .nargs = 3, 107 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } }, 108 { .name = "__cap_rights_get", .ret_type = 1, .nargs = 3, 109 .args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } }, 110 { .name = "__getcwd", .ret_type = 1, .nargs = 2, 111 .args = { { Name | OUT, 0 }, { Int, 1 } } }, 112 { .name = "_umtx_op", .ret_type = 1, .nargs = 5, 113 .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 }, 114 { Ptr, 4 } } }, 115 { .name = "accept", .ret_type = 1, .nargs = 3, 116 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 117 { .name = "access", .ret_type = 1, .nargs = 2, 118 .args = { { Name | IN, 0 }, { Accessmode, 1 } } }, 119 { .name = "bind", .ret_type = 1, .nargs = 3, 120 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } }, 121 { .name = "bindat", .ret_type = 1, .nargs = 4, 122 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 }, 123 { Int, 3 } } }, 124 { .name = "break", .ret_type = 1, .nargs = 1, 125 .args = { { Ptr, 0 } } }, 126 { .name = "cap_fcntls_get", .ret_type = 1, .nargs = 2, 127 .args = { { Int, 0 }, { CapFcntlRights | OUT, 1 } } }, 128 { .name = "cap_fcntls_limit", .ret_type = 1, .nargs = 2, 129 .args = { { Int, 0 }, { CapFcntlRights, 1 } } }, 130 { .name = "cap_getmode", .ret_type = 1, .nargs = 1, 131 .args = { { PUInt | OUT, 0 } } }, 132 { .name = "cap_rights_limit", .ret_type = 1, .nargs = 2, 133 .args = { { Int, 0 }, { CapRights, 1 } } }, 134 { .name = "chdir", .ret_type = 1, .nargs = 1, 135 .args = { { Name, 0 } } }, 136 { .name = "chflags", .ret_type = 1, .nargs = 2, 137 .args = { { Name | IN, 0 }, { FileFlags, 1 } } }, 138 { .name = "chflagsat", .ret_type = 1, .nargs = 4, 139 .args = { { Atfd, 0 }, { Name | IN, 1 }, { FileFlags, 2 }, 140 { Atflags, 3 } } }, 141 { .name = "chmod", .ret_type = 1, .nargs = 2, 142 .args = { { Name, 0 }, { Octal, 1 } } }, 143 { .name = "chown", .ret_type = 1, .nargs = 3, 144 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } }, 145 { .name = "chroot", .ret_type = 1, .nargs = 1, 146 .args = { { Name, 0 } } }, 147 { .name = "clock_gettime", .ret_type = 1, .nargs = 2, 148 .args = { { Int, 0 }, { Timespec | OUT, 1 } } }, 149 { .name = "close", .ret_type = 1, .nargs = 1, 150 .args = { { Int, 0 } } }, 151 { .name = "compat11.fstat", .ret_type = 1, .nargs = 2, 152 .args = { { Int, 0 }, { Stat11 | OUT, 1 } } }, 153 { .name = "compat11.fstatat", .ret_type = 1, .nargs = 4, 154 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat11 | OUT, 2 }, 155 { Atflags, 3 } } }, 156 { .name = "compat11.kevent", .ret_type = 1, .nargs = 6, 157 .args = { { Int, 0 }, { Kevent11, 1 }, { Int, 2 }, 158 { Kevent11 | OUT, 3 }, { Int, 4 }, { Timespec, 5 } } }, 159 { .name = "compat11.lstat", .ret_type = 1, .nargs = 2, 160 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } }, 161 { .name = "compat11.stat", .ret_type = 1, .nargs = 2, 162 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } }, 163 { .name = "connect", .ret_type = 1, .nargs = 3, 164 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } }, 165 { .name = "connectat", .ret_type = 1, .nargs = 4, 166 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 }, 167 { Int, 3 } } }, 168 { .name = "dup", .ret_type = 1, .nargs = 1, 169 .args = { { Int, 0 } } }, 170 { .name = "dup2", .ret_type = 1, .nargs = 2, 171 .args = { { Int, 0 }, { Int, 1 } } }, 172 { .name = "eaccess", .ret_type = 1, .nargs = 2, 173 .args = { { Name | IN, 0 }, { Accessmode, 1 } } }, 174 { .name = "execve", .ret_type = 1, .nargs = 3, 175 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 }, 176 { ExecEnv | IN, 2 } } }, 177 { .name = "exit", .ret_type = 0, .nargs = 1, 178 .args = { { Hex, 0 } } }, 179 { .name = "extattr_delete_fd", .ret_type = 1, .nargs = 3, 180 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } }, 181 { .name = "extattr_delete_file", .ret_type = 1, .nargs = 3, 182 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } }, 183 { .name = "extattr_delete_link", .ret_type = 1, .nargs = 3, 184 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } }, 185 { .name = "extattr_get_fd", .ret_type = 1, .nargs = 5, 186 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 }, 187 { BinString | OUT, 3 }, { Sizet, 4 } } }, 188 { .name = "extattr_get_file", .ret_type = 1, .nargs = 5, 189 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 }, 190 { BinString | OUT, 3 }, { Sizet, 4 } } }, 191 { .name = "extattr_get_link", .ret_type = 1, .nargs = 5, 192 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 }, 193 { BinString | OUT, 3 }, { Sizet, 4 } } }, 194 { .name = "extattr_list_fd", .ret_type = 1, .nargs = 4, 195 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 }, 196 { Sizet, 3 } } }, 197 { .name = "extattr_list_file", .ret_type = 1, .nargs = 4, 198 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 }, 199 { Sizet, 3 } } }, 200 { .name = "extattr_list_link", .ret_type = 1, .nargs = 4, 201 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 }, 202 { Sizet, 3 } } }, 203 { .name = "extattr_set_fd", .ret_type = 1, .nargs = 5, 204 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 }, 205 { BinString | IN, 3 }, { Sizet, 4 } } }, 206 { .name = "extattr_set_file", .ret_type = 1, .nargs = 5, 207 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 }, 208 { BinString | IN, 3 }, { Sizet, 4 } } }, 209 { .name = "extattr_set_link", .ret_type = 1, .nargs = 5, 210 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 }, 211 { BinString | IN, 3 }, { Sizet, 4 } } }, 212 { .name = "extattrctl", .ret_type = 1, .nargs = 5, 213 .args = { { Name, 0 }, { Hex, 1 }, { Name, 2 }, 214 { Extattrnamespace, 3 }, { Name, 4 } } }, 215 { .name = "faccessat", .ret_type = 1, .nargs = 4, 216 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 }, 217 { Atflags, 3 } } }, 218 { .name = "fchflags", .ret_type = 1, .nargs = 2, 219 .args = { { Int, 0 }, { FileFlags, 1 } } }, 220 { .name = "fchmod", .ret_type = 1, .nargs = 2, 221 .args = { { Int, 0 }, { Octal, 1 } } }, 222 { .name = "fchmodat", .ret_type = 1, .nargs = 4, 223 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } }, 224 { .name = "fchown", .ret_type = 1, .nargs = 3, 225 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } }, 226 { .name = "fchownat", .ret_type = 1, .nargs = 5, 227 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 }, 228 { Atflags, 4 } } }, 229 { .name = "fcntl", .ret_type = 1, .nargs = 3, 230 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } }, 231 { .name = "flock", .ret_type = 1, .nargs = 2, 232 .args = { { Int, 0 }, { Flockop, 1 } } }, 233 { .name = "fstat", .ret_type = 1, .nargs = 2, 234 .args = { { Int, 0 }, { Stat | OUT, 1 } } }, 235 { .name = "fstatat", .ret_type = 1, .nargs = 4, 236 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 }, 237 { Atflags, 3 } } }, 238 { .name = "fstatfs", .ret_type = 1, .nargs = 2, 239 .args = { { Int, 0 }, { StatFs | OUT, 1 } } }, 240 { .name = "ftruncate", .ret_type = 1, .nargs = 2, 241 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } }, 242 { .name = "futimens", .ret_type = 1, .nargs = 2, 243 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } }, 244 { .name = "futimes", .ret_type = 1, .nargs = 2, 245 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } }, 246 { .name = "futimesat", .ret_type = 1, .nargs = 3, 247 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } }, 248 { .name = "getdirentries", .ret_type = 1, .nargs = 4, 249 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, 250 { PQuadHex | OUT, 3 } } }, 251 { .name = "getfsstat", .ret_type = 1, .nargs = 3, 252 .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } }, 253 { .name = "getitimer", .ret_type = 1, .nargs = 2, 254 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } }, 255 { .name = "getpeername", .ret_type = 1, .nargs = 3, 256 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 257 { .name = "getpgid", .ret_type = 1, .nargs = 1, 258 .args = { { Int, 0 } } }, 259 { .name = "getpriority", .ret_type = 1, .nargs = 2, 260 .args = { { Priowhich, 0 }, { Int, 1 } } }, 261 { .name = "getrlimit", .ret_type = 1, .nargs = 2, 262 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } }, 263 { .name = "getrusage", .ret_type = 1, .nargs = 2, 264 .args = { { RusageWho, 0 }, { Rusage | OUT, 1 } } }, 265 { .name = "getsid", .ret_type = 1, .nargs = 1, 266 .args = { { Int, 0 } } }, 267 { .name = "getsockname", .ret_type = 1, .nargs = 3, 268 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 269 { .name = "getsockopt", .ret_type = 1, .nargs = 5, 270 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 }, 271 { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } }, 272 { .name = "gettimeofday", .ret_type = 1, .nargs = 2, 273 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } }, 274 { .name = "ioctl", .ret_type = 1, .nargs = 3, 275 .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } }, 276 { .name = "kevent", .ret_type = 1, .nargs = 6, 277 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, 278 { Int, 4 }, { Timespec, 5 } } }, 279 { .name = "kill", .ret_type = 1, .nargs = 2, 280 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } }, 281 { .name = "kldfind", .ret_type = 1, .nargs = 1, 282 .args = { { Name | IN, 0 } } }, 283 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1, 284 .args = { { Int, 0 } } }, 285 { .name = "kldload", .ret_type = 1, .nargs = 1, 286 .args = { { Name | IN, 0 } } }, 287 { .name = "kldnext", .ret_type = 1, .nargs = 1, 288 .args = { { Int, 0 } } }, 289 { .name = "kldstat", .ret_type = 1, .nargs = 2, 290 .args = { { Int, 0 }, { Ptr, 1 } } }, 291 { .name = "kldsym", .ret_type = 1, .nargs = 3, 292 .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } }, 293 { .name = "kldunload", .ret_type = 1, .nargs = 1, 294 .args = { { Int, 0 } } }, 295 { .name = "kldunloadf", .ret_type = 1, .nargs = 2, 296 .args = { { Int, 0 }, { Kldunloadflags, 1 } } }, 297 { .name = "kse_release", .ret_type = 0, .nargs = 1, 298 .args = { { Timespec, 0 } } }, 299 { .name = "lchflags", .ret_type = 1, .nargs = 2, 300 .args = { { Name | IN, 0 }, { FileFlags, 1 } } }, 301 { .name = "lchmod", .ret_type = 1, .nargs = 2, 302 .args = { { Name, 0 }, { Octal, 1 } } }, 303 { .name = "lchown", .ret_type = 1, .nargs = 3, 304 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } }, 305 { .name = "link", .ret_type = 1, .nargs = 2, 306 .args = { { Name, 0 }, { Name, 1 } } }, 307 { .name = "linkat", .ret_type = 1, .nargs = 5, 308 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 }, 309 { Atflags, 4 } } }, 310 { .name = "listen", .ret_type = 1, .nargs = 2, 311 .args = { { Int, 0 }, { Int, 1 } } }, 312 { .name = "lseek", .ret_type = 2, .nargs = 3, 313 .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } }, 314 { .name = "lstat", .ret_type = 1, .nargs = 2, 315 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, 316 { .name = "lutimes", .ret_type = 1, .nargs = 2, 317 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, 318 { .name = "madvise", .ret_type = 1, .nargs = 3, 319 .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } }, 320 { .name = "minherit", .ret_type = 1, .nargs = 3, 321 .args = { { Ptr, 0 }, { Sizet, 1 }, { Minherit, 2 } } }, 322 { .name = "mkdir", .ret_type = 1, .nargs = 2, 323 .args = { { Name, 0 }, { Octal, 1 } } }, 324 { .name = "mkdirat", .ret_type = 1, .nargs = 3, 325 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } }, 326 { .name = "mkfifo", .ret_type = 1, .nargs = 2, 327 .args = { { Name, 0 }, { Octal, 1 } } }, 328 { .name = "mkfifoat", .ret_type = 1, .nargs = 3, 329 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } }, 330 { .name = "mknod", .ret_type = 1, .nargs = 3, 331 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } }, 332 { .name = "mknodat", .ret_type = 1, .nargs = 4, 333 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } }, 334 { .name = "mlock", .ret_type = 1, .nargs = 2, 335 .args = { { Ptr, 0 }, { Sizet, 1 } } }, 336 { .name = "mlockall", .ret_type = 1, .nargs = 1, 337 .args = { { Mlockall, 0 } } }, 338 { .name = "mmap", .ret_type = 1, .nargs = 6, 339 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 }, 340 { Int, 4 }, { QuadHex, 5 } } }, 341 { .name = "modfind", .ret_type = 1, .nargs = 1, 342 .args = { { Name | IN, 0 } } }, 343 { .name = "mount", .ret_type = 1, .nargs = 4, 344 .args = { { Name, 0 }, { Name, 1 }, { Mountflags, 2 }, { Ptr, 3 } } }, 345 { .name = "mprotect", .ret_type = 1, .nargs = 3, 346 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } }, 347 { .name = "msync", .ret_type = 1, .nargs = 3, 348 .args = { { Ptr, 0 }, { Sizet, 1 }, { Msync, 2 } } }, 349 { .name = "munlock", .ret_type = 1, .nargs = 2, 350 .args = { { Ptr, 0 }, { Sizet, 1 } } }, 351 { .name = "munmap", .ret_type = 1, .nargs = 2, 352 .args = { { Ptr, 0 }, { Sizet, 1 } } }, 353 { .name = "nanosleep", .ret_type = 1, .nargs = 1, 354 .args = { { Timespec, 0 } } }, 355 { .name = "nmount", .ret_type = 1, .nargs = 3, 356 .args = { { Ptr, 0 }, { UInt, 1 }, { Mountflags, 2 } } }, 357 { .name = "open", .ret_type = 1, .nargs = 3, 358 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } }, 359 { .name = "openat", .ret_type = 1, .nargs = 4, 360 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 }, 361 { Octal, 3 } } }, 362 { .name = "pathconf", .ret_type = 1, .nargs = 2, 363 .args = { { Name | IN, 0 }, { Pathconf, 1 } } }, 364 { .name = "pipe", .ret_type = 1, .nargs = 1, 365 .args = { { PipeFds | OUT, 0 } } }, 366 { .name = "pipe2", .ret_type = 1, .nargs = 2, 367 .args = { { Ptr, 0 }, { Pipe2, 1 } } }, 368 { .name = "poll", .ret_type = 1, .nargs = 3, 369 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } }, 370 { .name = "posix_fadvise", .ret_type = 1, .nargs = 4, 371 .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 }, 372 { Fadvice, 3 } } }, 373 { .name = "posix_openpt", .ret_type = 1, .nargs = 1, 374 .args = { { Open, 0 } } }, 375 { .name = "pread", .ret_type = 1, .nargs = 4, 376 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 }, 377 { QuadHex, 3 } } }, 378 { .name = "procctl", .ret_type = 1, .nargs = 4, 379 .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } }, 380 { .name = "ptrace", .ret_type = 1, .nargs = 4, 381 .args = { { Ptraceop, 0 }, { Int, 1 }, { Ptr, 2 }, { Int, 3 } } }, 382 { .name = "pwrite", .ret_type = 1, .nargs = 4, 383 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 }, 384 { QuadHex, 3 } } }, 385 { .name = "quotactl", .ret_type = 1, .nargs = 4, 386 .args = { { Name, 0 }, { Quotactlcmd, 1 }, { Int, 2 }, { Ptr, 3 } } }, 387 { .name = "read", .ret_type = 1, .nargs = 3, 388 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } }, 389 { .name = "readv", .ret_type = 1, .nargs = 3, 390 .args = { { Int, 0 }, { Iovec, 1 }, { Int, 2 } } }, 391 { .name = "readlink", .ret_type = 1, .nargs = 3, 392 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } }, 393 { .name = "readlinkat", .ret_type = 1, .nargs = 4, 394 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 }, 395 { Sizet, 3 } } }, 396 { .name = "reboot", .ret_type = 1, .nargs = 1, 397 .args = { { Reboothowto, 0 } } }, 398 { .name = "recvfrom", .ret_type = 1, .nargs = 6, 399 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 }, 400 { Msgflags, 3 }, { Sockaddr | OUT, 4 }, 401 { Ptr | OUT, 5 } } }, 402 { .name = "recvmsg", .ret_type = 1, .nargs = 3, 403 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } }, 404 { .name = "rename", .ret_type = 1, .nargs = 2, 405 .args = { { Name, 0 }, { Name, 1 } } }, 406 { .name = "renameat", .ret_type = 1, .nargs = 4, 407 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } }, 408 { .name = "rfork", .ret_type = 1, .nargs = 1, 409 .args = { { Rforkflags, 0 } } }, 410 { .name = "rmdir", .ret_type = 1, .nargs = 1, 411 .args = { { Name, 0 } } }, 412 { .name = "rtprio", .ret_type = 1, .nargs = 3, 413 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } }, 414 { .name = "rtprio_thread", .ret_type = 1, .nargs = 3, 415 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } }, 416 { .name = "sched_get_priority_max", .ret_type = 1, .nargs = 1, 417 .args = { { Schedpolicy, 0 } } }, 418 { .name = "sched_get_priority_min", .ret_type = 1, .nargs = 1, 419 .args = { { Schedpolicy, 0 } } }, 420 { .name = "sched_getparam", .ret_type = 1, .nargs = 2, 421 .args = { { Int, 0 }, { Schedparam | OUT, 1 } } }, 422 { .name = "sched_getscheduler", .ret_type = 1, .nargs = 1, 423 .args = { { Int, 0 } } }, 424 { .name = "sched_rr_get_interval", .ret_type = 1, .nargs = 2, 425 .args = { { Int, 0 }, { Timespec | OUT, 1 } } }, 426 { .name = "sched_setparam", .ret_type = 1, .nargs = 2, 427 .args = { { Int, 0 }, { Schedparam, 1 } } }, 428 { .name = "sched_setscheduler", .ret_type = 1, .nargs = 3, 429 .args = { { Int, 0 }, { Schedpolicy, 1 }, { Schedparam, 2 } } }, 430 { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7, 431 .args = { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 }, 432 { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 }, { Ptr | OUT, 5 }, 433 { Ptr | OUT, 6 } } }, 434 { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7, 435 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, 436 { Sockaddr | IN, 3 }, { Socklent, 4 }, { Ptr | IN, 5 }, 437 { Msgflags, 6 } } }, 438 { .name = "select", .ret_type = 1, .nargs = 5, 439 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, 440 { Timeval, 4 } } }, 441 { .name = "sendmsg", .ret_type = 1, .nargs = 3, 442 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } }, 443 { .name = "sendto", .ret_type = 1, .nargs = 6, 444 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 }, 445 { Msgflags, 3 }, { Sockaddr | IN, 4 }, 446 { Socklent | IN, 5 } } }, 447 { .name = "setitimer", .ret_type = 1, .nargs = 3, 448 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } }, 449 { .name = "setpriority", .ret_type = 1, .nargs = 3, 450 .args = { { Priowhich, 0 }, { Int, 1 }, { Int, 2 } } }, 451 { .name = "setrlimit", .ret_type = 1, .nargs = 2, 452 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } }, 453 { .name = "setsockopt", .ret_type = 1, .nargs = 5, 454 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 }, 455 { Ptr | IN, 3 }, { Socklent, 4 } } }, 456 { .name = "shutdown", .ret_type = 1, .nargs = 2, 457 .args = { { Int, 0 }, { Shutdown, 1 } } }, 458 { .name = "sigaction", .ret_type = 1, .nargs = 3, 459 .args = { { Signal, 0 }, { Sigaction | IN, 1 }, 460 { Sigaction | OUT, 2 } } }, 461 { .name = "sigpending", .ret_type = 1, .nargs = 1, 462 .args = { { Sigset | OUT, 0 } } }, 463 { .name = "sigprocmask", .ret_type = 1, .nargs = 3, 464 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } }, 465 { .name = "sigqueue", .ret_type = 1, .nargs = 3, 466 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } }, 467 { .name = "sigreturn", .ret_type = 1, .nargs = 1, 468 .args = { { Ptr, 0 } } }, 469 { .name = "sigsuspend", .ret_type = 1, .nargs = 1, 470 .args = { { Sigset | IN, 0 } } }, 471 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3, 472 .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 1 }, 473 { Timespec | IN, 2 } } }, 474 { .name = "sigwait", .ret_type = 1, .nargs = 2, 475 .args = { { Sigset | IN, 0 }, { PSig | OUT, 1 } } }, 476 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2, 477 .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 1 } } }, 478 { .name = "socket", .ret_type = 1, .nargs = 3, 479 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } }, 480 { .name = "stat", .ret_type = 1, .nargs = 2, 481 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, 482 { .name = "statfs", .ret_type = 1, .nargs = 2, 483 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } }, 484 { .name = "symlink", .ret_type = 1, .nargs = 2, 485 .args = { { Name, 0 }, { Name, 1 } } }, 486 { .name = "symlinkat", .ret_type = 1, .nargs = 3, 487 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } }, 488 { .name = "sysarch", .ret_type = 1, .nargs = 2, 489 .args = { { Sysarch, 0 }, { Ptr, 1 } } }, 490 { .name = "thr_kill", .ret_type = 1, .nargs = 2, 491 .args = { { Long, 0 }, { Signal, 1 } } }, 492 { .name = "thr_self", .ret_type = 1, .nargs = 1, 493 .args = { { Ptr, 0 } } }, 494 { .name = "thr_set_name", .ret_type = 1, .nargs = 2, 495 .args = { { Long, 0 }, { Name, 1 } } }, 496 { .name = "truncate", .ret_type = 1, .nargs = 2, 497 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } }, 498 #if 0 499 /* Does not exist */ 500 { .name = "umount", .ret_type = 1, .nargs = 2, 501 .args = { { Name, 0 }, { Int, 2 } } }, 502 #endif 503 { .name = "unlink", .ret_type = 1, .nargs = 1, 504 .args = { { Name, 0 } } }, 505 { .name = "unlinkat", .ret_type = 1, .nargs = 3, 506 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } }, 507 { .name = "unmount", .ret_type = 1, .nargs = 2, 508 .args = { { Name, 0 }, { Mountflags, 1 } } }, 509 { .name = "utimensat", .ret_type = 1, .nargs = 4, 510 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 }, 511 { Atflags, 3 } } }, 512 { .name = "utimes", .ret_type = 1, .nargs = 2, 513 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, 514 { .name = "utrace", .ret_type = 1, .nargs = 1, 515 .args = { { Utrace, 0 } } }, 516 { .name = "wait4", .ret_type = 1, .nargs = 4, 517 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 }, 518 { Rusage | OUT, 3 } } }, 519 { .name = "wait6", .ret_type = 1, .nargs = 6, 520 .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 }, 521 { Waitoptions, 3 }, { Rusage | OUT, 4 }, 522 { Siginfo | OUT, 5 } } }, 523 { .name = "write", .ret_type = 1, .nargs = 3, 524 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } }, 525 { .name = "writev", .ret_type = 1, .nargs = 3, 526 .args = { { Int, 0 }, { Iovec, 1 }, { Int, 2 } } }, 527 528 /* Linux ABI */ 529 { .name = "linux_access", .ret_type = 1, .nargs = 2, 530 .args = { { Name, 0 }, { Accessmode, 1 } } }, 531 { .name = "linux_execve", .ret_type = 1, .nargs = 3, 532 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 }, 533 { ExecEnv | IN, 2 } } }, 534 { .name = "linux_lseek", .ret_type = 2, .nargs = 3, 535 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } }, 536 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2, 537 .args = { { Name | IN, 0 }, { Int, 1 } } }, 538 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2, 539 .args = { { Int, 0 }, { Ptr | OUT, 1 } } }, 540 { .name = "linux_newstat", .ret_type = 1, .nargs = 2, 541 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } }, 542 { .name = "linux_open", .ret_type = 1, .nargs = 3, 543 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } }, 544 { .name = "linux_readlink", .ret_type = 1, .nargs = 3, 545 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } }, 546 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2, 547 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } }, 548 { .name = "linux_stat64", .ret_type = 1, .nargs = 2, 549 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } }, 550 551 /* CloudABI system calls. */ 552 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1, 553 .args = { { CloudABIClockID, 0 } } }, 554 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2, 555 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } }, 556 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3, 557 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } }, 558 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1, 559 .args = { { Int, 0 } } }, 560 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1, 561 .args = { { CloudABIFileType, 0 } } }, 562 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2, 563 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } }, 564 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1, 565 .args = { { Int, 0 } } }, 566 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1, 567 .args = { { Int, 0 } } }, 568 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2, 569 .args = { { Int, 0 }, { Int, 1 } } }, 570 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3, 571 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } }, 572 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2, 573 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } }, 574 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3, 575 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 }, 576 { ClouduABIFDSFlags, 2 } } }, 577 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1, 578 .args = { { Int, 0 } } }, 579 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4, 580 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 }, 581 { CloudABIAdvice, 3 } } }, 582 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3, 583 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } }, 584 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3, 585 .args = { { Int, 0 }, { BinString | IN, 1 }, 586 { CloudABIFileType, 3 } } }, 587 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4, 588 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 }, 589 { Int, 3 }, { BinString | IN, 4 } } }, 590 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4, 591 .args = { { Int, 0 }, { BinString | IN, 1 }, 592 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } }, 593 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4, 594 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, 595 { Int, 3 } } }, 596 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4, 597 .args = { { Int, 0 }, { BinString | IN, 1 }, 598 { BinString | OUT, 3 }, { Int, 4 } } }, 599 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4, 600 .args = { { Int, 0 }, { BinString | IN, 1 }, 601 { Int, 3 }, { BinString | IN, 4 } } }, 602 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2, 603 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } }, 604 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3, 605 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 }, 606 { CloudABIFSFlags, 2 } } }, 607 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3, 608 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 }, 609 { CloudABIFileStat | OUT, 3 } } }, 610 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4, 611 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 }, 612 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } }, 613 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3, 614 .args = { { BinString | IN, 0 }, 615 { Int, 2 }, { BinString | IN, 3 } } }, 616 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3, 617 .args = { { Int, 0 }, { BinString | IN, 1 }, 618 { CloudABIULFlags, 3 } } }, 619 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2, 620 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } }, 621 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3, 622 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } }, 623 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6, 624 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 }, 625 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } }, 626 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3, 627 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } }, 628 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3, 629 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } }, 630 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2, 631 .args = { { Ptr, 0 }, { Int, 1 } } }, 632 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5, 633 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, 634 { IntArray, 3 }, { Int, 4 } } }, 635 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1, 636 .args = { { Int, 0 } } }, 637 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 }, 638 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1, 639 .args = { { CloudABISignal, 0 } } }, 640 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2, 641 .args = { { BinString | OUT, 0 }, { Int, 1 } } }, 642 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2, 643 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } }, 644 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2, 645 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } }, 646 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 }, 647 648 { .name = 0 }, 649 }; 650 static STAILQ_HEAD(, syscall) syscalls; 651 652 /* Xlat idea taken from strace */ 653 struct xlat { 654 int val; 655 const char *str; 656 }; 657 658 #define X(a) { a, #a }, 659 #define XEND { 0, NULL } 660 661 static struct xlat poll_flags[] = { 662 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR) 663 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND) 664 X(POLLWRBAND) X(POLLINIGNEOF) XEND 665 }; 666 667 static struct xlat sigaction_flags[] = { 668 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP) 669 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND 670 }; 671 672 static struct xlat linux_socketcall_ops[] = { 673 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN) 674 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME) 675 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO) 676 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT) 677 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG) 678 XEND 679 }; 680 681 #undef X 682 #define X(a) { CLOUDABI_##a, #a }, 683 684 static struct xlat cloudabi_advice[] = { 685 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL) 686 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED) 687 XEND 688 }; 689 690 static struct xlat cloudabi_clockid[] = { 691 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID) 692 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID) 693 XEND 694 }; 695 696 static struct xlat cloudabi_fdflags[] = { 697 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK) 698 X(FDFLAG_RSYNC) X(FDFLAG_SYNC) 699 XEND 700 }; 701 702 static struct xlat cloudabi_fdsflags[] = { 703 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS) 704 XEND 705 }; 706 707 static struct xlat cloudabi_filetype[] = { 708 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE) 709 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY) 710 X(FILETYPE_PROCESS) X(FILETYPE_REGULAR_FILE) 711 X(FILETYPE_SHARED_MEMORY) X(FILETYPE_SOCKET_DGRAM) 712 X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK) 713 XEND 714 }; 715 716 static struct xlat cloudabi_fsflags[] = { 717 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM) 718 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE) 719 XEND 720 }; 721 722 static struct xlat cloudabi_mflags[] = { 723 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED) 724 XEND 725 }; 726 727 static struct xlat cloudabi_mprot[] = { 728 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ) 729 XEND 730 }; 731 732 static struct xlat cloudabi_msflags[] = { 733 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC) 734 XEND 735 }; 736 737 static struct xlat cloudabi_oflags[] = { 738 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC) 739 XEND 740 }; 741 742 static struct xlat cloudabi_sdflags[] = { 743 X(SHUT_RD) X(SHUT_WR) 744 XEND 745 }; 746 747 static struct xlat cloudabi_signal[] = { 748 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE) 749 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT) 750 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP) 751 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2) 752 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ) 753 XEND 754 }; 755 756 static struct xlat cloudabi_ulflags[] = { 757 X(UNLINK_REMOVEDIR) 758 XEND 759 }; 760 761 static struct xlat cloudabi_whence[] = { 762 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET) 763 XEND 764 }; 765 766 #undef X 767 #undef XEND 768 769 /* 770 * Searches an xlat array for a value, and returns it if found. Otherwise 771 * return a string representation. 772 */ 773 static const char * 774 lookup(struct xlat *xlat, int val, int base) 775 { 776 static char tmp[16]; 777 778 for (; xlat->str != NULL; xlat++) 779 if (xlat->val == val) 780 return (xlat->str); 781 switch (base) { 782 case 8: 783 sprintf(tmp, "0%o", val); 784 break; 785 case 16: 786 sprintf(tmp, "0x%x", val); 787 break; 788 case 10: 789 sprintf(tmp, "%u", val); 790 break; 791 default: 792 errx(1,"Unknown lookup base"); 793 break; 794 } 795 return (tmp); 796 } 797 798 static const char * 799 xlookup(struct xlat *xlat, int val) 800 { 801 802 return (lookup(xlat, val, 16)); 803 } 804 805 /* 806 * Searches an xlat array containing bitfield values. Remaining bits 807 * set after removing the known ones are printed at the end: 808 * IN|0x400. 809 */ 810 static char * 811 xlookup_bits(struct xlat *xlat, int val) 812 { 813 int len, rem; 814 static char str[512]; 815 816 len = 0; 817 rem = val; 818 for (; xlat->str != NULL; xlat++) { 819 if ((xlat->val & rem) == xlat->val) { 820 /* 821 * Don't print the "all-bits-zero" string unless all 822 * bits are really zero. 823 */ 824 if (xlat->val == 0 && val != 0) 825 continue; 826 len += sprintf(str + len, "%s|", xlat->str); 827 rem &= ~(xlat->val); 828 } 829 } 830 831 /* 832 * If we have leftover bits or didn't match anything, print 833 * the remainder. 834 */ 835 if (rem || len == 0) 836 len += sprintf(str + len, "0x%x", rem); 837 if (len && str[len - 1] == '|') 838 len--; 839 str[len] = 0; 840 return (str); 841 } 842 843 static void 844 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value) 845 { 846 const char *str; 847 848 str = decoder(value); 849 if (str != NULL) 850 fputs(str, fp); 851 else 852 fprintf(fp, "%d", value); 853 } 854 855 static void 856 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value) 857 { 858 int rem; 859 860 if (!decoder(fp, value, &rem)) 861 fprintf(fp, "0x%x", rem); 862 else if (rem != 0) 863 fprintf(fp, "|0x%x", rem); 864 } 865 866 static void 867 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp, 868 uint32_t value) 869 { 870 uint32_t rem; 871 872 if (!decoder(fp, value, &rem)) 873 fprintf(fp, "0x%x", rem); 874 else if (rem != 0) 875 fprintf(fp, "|0x%x", rem); 876 } 877 878 #ifndef __LP64__ 879 /* 880 * Add argument padding to subsequent system calls afater a Quad 881 * syscall arguments as needed. This used to be done by hand in the 882 * decoded_syscalls table which was ugly and error prone. It is 883 * simpler to do the fixup of offsets at initalization time than when 884 * decoding arguments. 885 */ 886 static void 887 quad_fixup(struct syscall *sc) 888 { 889 int offset, prev; 890 u_int i; 891 892 offset = 0; 893 prev = -1; 894 for (i = 0; i < sc->nargs; i++) { 895 /* This arg type is a dummy that doesn't use offset. */ 896 if ((sc->args[i].type & ARG_MASK) == PipeFds) 897 continue; 898 899 assert(prev < sc->args[i].offset); 900 prev = sc->args[i].offset; 901 sc->args[i].offset += offset; 902 switch (sc->args[i].type & ARG_MASK) { 903 case Quad: 904 case QuadHex: 905 #ifdef __powerpc__ 906 /* 907 * 64-bit arguments on 32-bit powerpc must be 908 * 64-bit aligned. If the current offset is 909 * not aligned, the calling convention inserts 910 * a 32-bit pad argument that should be skipped. 911 */ 912 if (sc->args[i].offset % 2 == 1) { 913 sc->args[i].offset++; 914 offset++; 915 } 916 #endif 917 offset++; 918 default: 919 break; 920 } 921 } 922 } 923 #endif 924 925 void 926 init_syscalls(void) 927 { 928 struct syscall *sc; 929 930 STAILQ_INIT(&syscalls); 931 for (sc = decoded_syscalls; sc->name != NULL; sc++) { 932 #ifndef __LP64__ 933 quad_fixup(sc); 934 #endif 935 STAILQ_INSERT_HEAD(&syscalls, sc, entries); 936 } 937 } 938 939 static struct syscall * 940 find_syscall(struct procabi *abi, u_int number) 941 { 942 struct extra_syscall *es; 943 944 if (number < nitems(abi->syscalls)) 945 return (abi->syscalls[number]); 946 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) { 947 if (es->number == number) 948 return (es->sc); 949 } 950 return (NULL); 951 } 952 953 static void 954 add_syscall(struct procabi *abi, u_int number, struct syscall *sc) 955 { 956 struct extra_syscall *es; 957 958 if (number < nitems(abi->syscalls)) { 959 assert(abi->syscalls[number] == NULL); 960 abi->syscalls[number] = sc; 961 } else { 962 es = malloc(sizeof(*es)); 963 es->sc = sc; 964 es->number = number; 965 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries); 966 } 967 } 968 969 /* 970 * If/when the list gets big, it might be desirable to do it 971 * as a hash table or binary search. 972 */ 973 struct syscall * 974 get_syscall(struct threadinfo *t, u_int number, u_int nargs) 975 { 976 struct syscall *sc; 977 const char *name; 978 char *new_name; 979 u_int i; 980 981 sc = find_syscall(t->proc->abi, number); 982 if (sc != NULL) 983 return (sc); 984 985 name = sysdecode_syscallname(t->proc->abi->abi, number); 986 if (name == NULL) { 987 asprintf(&new_name, "#%d", number); 988 name = new_name; 989 } else 990 new_name = NULL; 991 STAILQ_FOREACH(sc, &syscalls, entries) { 992 if (strcmp(name, sc->name) == 0) { 993 add_syscall(t->proc->abi, number, sc); 994 free(new_name); 995 return (sc); 996 } 997 } 998 999 /* It is unknown. Add it into the list. */ 1000 #if DEBUG 1001 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name, 1002 nargs); 1003 #endif 1004 1005 sc = calloc(1, sizeof(struct syscall)); 1006 sc->name = name; 1007 if (new_name != NULL) 1008 sc->unknown = true; 1009 sc->ret_type = 1; 1010 sc->nargs = nargs; 1011 for (i = 0; i < nargs; i++) { 1012 sc->args[i].offset = i; 1013 /* Treat all unknown arguments as LongHex. */ 1014 sc->args[i].type = LongHex; 1015 } 1016 STAILQ_INSERT_HEAD(&syscalls, sc, entries); 1017 add_syscall(t->proc->abi, number, sc); 1018 1019 return (sc); 1020 } 1021 1022 /* 1023 * Copy a fixed amount of bytes from the process. 1024 */ 1025 static int 1026 get_struct(pid_t pid, void *offset, void *buf, int len) 1027 { 1028 struct ptrace_io_desc iorequest; 1029 1030 iorequest.piod_op = PIOD_READ_D; 1031 iorequest.piod_offs = offset; 1032 iorequest.piod_addr = buf; 1033 iorequest.piod_len = len; 1034 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) 1035 return (-1); 1036 return (0); 1037 } 1038 1039 #define MAXSIZE 4096 1040 1041 /* 1042 * Copy a string from the process. Note that it is 1043 * expected to be a C string, but if max is set, it will 1044 * only get that much. 1045 */ 1046 static char * 1047 get_string(pid_t pid, void *addr, int max) 1048 { 1049 struct ptrace_io_desc iorequest; 1050 char *buf, *nbuf; 1051 size_t offset, size, totalsize; 1052 1053 offset = 0; 1054 if (max) 1055 size = max + 1; 1056 else { 1057 /* Read up to the end of the current page. */ 1058 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE); 1059 if (size > MAXSIZE) 1060 size = MAXSIZE; 1061 } 1062 totalsize = size; 1063 buf = malloc(totalsize); 1064 if (buf == NULL) 1065 return (NULL); 1066 for (;;) { 1067 iorequest.piod_op = PIOD_READ_D; 1068 iorequest.piod_offs = (char *)addr + offset; 1069 iorequest.piod_addr = buf + offset; 1070 iorequest.piod_len = size; 1071 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) { 1072 free(buf); 1073 return (NULL); 1074 } 1075 if (memchr(buf + offset, '\0', size) != NULL) 1076 return (buf); 1077 offset += size; 1078 if (totalsize < MAXSIZE && max == 0) { 1079 size = MAXSIZE - totalsize; 1080 if (size > PAGE_SIZE) 1081 size = PAGE_SIZE; 1082 nbuf = realloc(buf, totalsize + size); 1083 if (nbuf == NULL) { 1084 buf[totalsize - 1] = '\0'; 1085 return (buf); 1086 } 1087 buf = nbuf; 1088 totalsize += size; 1089 } else { 1090 buf[totalsize - 1] = '\0'; 1091 return (buf); 1092 } 1093 } 1094 } 1095 1096 static const char * 1097 strsig2(int sig) 1098 { 1099 static char tmp[32]; 1100 const char *signame; 1101 1102 signame = sysdecode_signal(sig); 1103 if (signame == NULL) { 1104 snprintf(tmp, sizeof(tmp), "%d", sig); 1105 signame = tmp; 1106 } 1107 return (signame); 1108 } 1109 1110 static void 1111 print_kevent(FILE *fp, struct kevent *ke) 1112 { 1113 1114 switch (ke->filter) { 1115 case EVFILT_READ: 1116 case EVFILT_WRITE: 1117 case EVFILT_VNODE: 1118 case EVFILT_PROC: 1119 case EVFILT_TIMER: 1120 case EVFILT_PROCDESC: 1121 case EVFILT_EMPTY: 1122 fprintf(fp, "%ju", (uintmax_t)ke->ident); 1123 break; 1124 case EVFILT_SIGNAL: 1125 fputs(strsig2(ke->ident), fp); 1126 break; 1127 default: 1128 fprintf(fp, "%p", (void *)ke->ident); 1129 } 1130 fprintf(fp, ","); 1131 print_integer_arg(sysdecode_kevent_filter, fp, ke->filter); 1132 fprintf(fp, ","); 1133 print_mask_arg(sysdecode_kevent_flags, fp, ke->flags); 1134 fprintf(fp, ","); 1135 sysdecode_kevent_fflags(fp, ke->filter, ke->fflags, 16); 1136 fprintf(fp, ",%#jx,%p", (uintmax_t)ke->data, ke->udata); 1137 } 1138 1139 static void 1140 print_utrace(FILE *fp, void *utrace_addr, size_t len) 1141 { 1142 unsigned char *utrace_buffer; 1143 1144 fprintf(fp, "{ "); 1145 if (sysdecode_utrace(fp, utrace_addr, len)) { 1146 fprintf(fp, " }"); 1147 return; 1148 } 1149 1150 utrace_buffer = utrace_addr; 1151 fprintf(fp, "%zu:", len); 1152 while (len--) 1153 fprintf(fp, " %02x", *utrace_buffer++); 1154 fprintf(fp, " }"); 1155 } 1156 1157 /* 1158 * Converts a syscall argument into a string. Said string is 1159 * allocated via malloc(), so needs to be free()'d. sc is 1160 * a pointer to the syscall description (see above); args is 1161 * an array of all of the system call arguments. 1162 */ 1163 char * 1164 print_arg(struct syscall_args *sc, unsigned long *args, long *retval, 1165 struct trussinfo *trussinfo) 1166 { 1167 FILE *fp; 1168 char *tmp; 1169 size_t tmplen; 1170 pid_t pid; 1171 1172 fp = open_memstream(&tmp, &tmplen); 1173 pid = trussinfo->curthread->proc->pid; 1174 switch (sc->type & ARG_MASK) { 1175 case Hex: 1176 fprintf(fp, "0x%x", (int)args[sc->offset]); 1177 break; 1178 case Octal: 1179 fprintf(fp, "0%o", (int)args[sc->offset]); 1180 break; 1181 case Int: 1182 fprintf(fp, "%d", (int)args[sc->offset]); 1183 break; 1184 case UInt: 1185 fprintf(fp, "%u", (unsigned int)args[sc->offset]); 1186 break; 1187 case PUInt: { 1188 unsigned int val; 1189 1190 if (get_struct(pid, (void *)args[sc->offset], &val, 1191 sizeof(val)) == 0) 1192 fprintf(fp, "{ %u }", val); 1193 else 1194 fprintf(fp, "0x%lx", args[sc->offset]); 1195 break; 1196 } 1197 case LongHex: 1198 fprintf(fp, "0x%lx", args[sc->offset]); 1199 break; 1200 case Long: 1201 fprintf(fp, "%ld", args[sc->offset]); 1202 break; 1203 case Sizet: 1204 fprintf(fp, "%zu", (size_t)args[sc->offset]); 1205 break; 1206 case Name: { 1207 /* NULL-terminated string. */ 1208 char *tmp2; 1209 1210 tmp2 = get_string(pid, (void*)args[sc->offset], 0); 1211 fprintf(fp, "\"%s\"", tmp2); 1212 free(tmp2); 1213 break; 1214 } 1215 case BinString: { 1216 /* 1217 * Binary block of data that might have printable characters. 1218 * XXX If type|OUT, assume that the length is the syscall's 1219 * return value. Otherwise, assume that the length of the block 1220 * is in the next syscall argument. 1221 */ 1222 int max_string = trussinfo->strsize; 1223 char tmp2[max_string + 1], *tmp3; 1224 int len; 1225 int truncated = 0; 1226 1227 if (sc->type & OUT) 1228 len = retval[0]; 1229 else 1230 len = args[sc->offset + 1]; 1231 1232 /* 1233 * Don't print more than max_string characters, to avoid word 1234 * wrap. If we have to truncate put some ... after the string. 1235 */ 1236 if (len > max_string) { 1237 len = max_string; 1238 truncated = 1; 1239 } 1240 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) 1241 != -1) { 1242 tmp3 = malloc(len * 4 + 1); 1243 while (len) { 1244 if (strvisx(tmp3, tmp2, len, 1245 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) 1246 break; 1247 len--; 1248 truncated = 1; 1249 } 1250 fprintf(fp, "\"%s\"%s", tmp3, truncated ? 1251 "..." : ""); 1252 free(tmp3); 1253 } else { 1254 fprintf(fp, "0x%lx", args[sc->offset]); 1255 } 1256 break; 1257 } 1258 case ExecArgs: 1259 case ExecEnv: 1260 case StringArray: { 1261 uintptr_t addr; 1262 union { 1263 char *strarray[0]; 1264 char buf[PAGE_SIZE]; 1265 } u; 1266 char *string; 1267 size_t len; 1268 u_int first, i; 1269 1270 /* 1271 * Only parse argv[] and environment arrays from exec calls 1272 * if requested. 1273 */ 1274 if (((sc->type & ARG_MASK) == ExecArgs && 1275 (trussinfo->flags & EXECVEARGS) == 0) || 1276 ((sc->type & ARG_MASK) == ExecEnv && 1277 (trussinfo->flags & EXECVEENVS) == 0)) { 1278 fprintf(fp, "0x%lx", args[sc->offset]); 1279 break; 1280 } 1281 1282 /* 1283 * Read a page of pointers at a time. Punt if the top-level 1284 * pointer is not aligned. Note that the first read is of 1285 * a partial page. 1286 */ 1287 addr = args[sc->offset]; 1288 if (addr % sizeof(char *) != 0) { 1289 fprintf(fp, "0x%lx", args[sc->offset]); 1290 break; 1291 } 1292 1293 len = PAGE_SIZE - (addr & PAGE_MASK); 1294 if (get_struct(pid, (void *)addr, u.buf, len) == -1) { 1295 fprintf(fp, "0x%lx", args[sc->offset]); 1296 break; 1297 } 1298 1299 fputc('[', fp); 1300 first = 1; 1301 i = 0; 1302 while (u.strarray[i] != NULL) { 1303 string = get_string(pid, u.strarray[i], 0); 1304 fprintf(fp, "%s \"%s\"", first ? "" : ",", string); 1305 free(string); 1306 first = 0; 1307 1308 i++; 1309 if (i == len / sizeof(char *)) { 1310 addr += len; 1311 len = PAGE_SIZE; 1312 if (get_struct(pid, (void *)addr, u.buf, len) == 1313 -1) { 1314 fprintf(fp, ", <inval>"); 1315 break; 1316 } 1317 i = 0; 1318 } 1319 } 1320 fputs(" ]", fp); 1321 break; 1322 } 1323 #ifdef __LP64__ 1324 case Quad: 1325 fprintf(fp, "%ld", args[sc->offset]); 1326 break; 1327 case QuadHex: 1328 fprintf(fp, "0x%lx", args[sc->offset]); 1329 break; 1330 #else 1331 case Quad: 1332 case QuadHex: { 1333 unsigned long long ll; 1334 1335 #if _BYTE_ORDER == _LITTLE_ENDIAN 1336 ll = (unsigned long long)args[sc->offset + 1] << 32 | 1337 args[sc->offset]; 1338 #else 1339 ll = (unsigned long long)args[sc->offset] << 32 | 1340 args[sc->offset + 1]; 1341 #endif 1342 if ((sc->type & ARG_MASK) == Quad) 1343 fprintf(fp, "%lld", ll); 1344 else 1345 fprintf(fp, "0x%llx", ll); 1346 break; 1347 } 1348 #endif 1349 case PQuadHex: { 1350 uint64_t val; 1351 1352 if (get_struct(pid, (void *)args[sc->offset], &val, 1353 sizeof(val)) == 0) 1354 fprintf(fp, "{ 0x%jx }", (uintmax_t)val); 1355 else 1356 fprintf(fp, "0x%lx", args[sc->offset]); 1357 break; 1358 } 1359 case Ptr: 1360 fprintf(fp, "0x%lx", args[sc->offset]); 1361 break; 1362 case Readlinkres: { 1363 char *tmp2; 1364 1365 if (retval[0] == -1) 1366 break; 1367 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]); 1368 fprintf(fp, "\"%s\"", tmp2); 1369 free(tmp2); 1370 break; 1371 } 1372 case Ioctl: { 1373 const char *temp; 1374 unsigned long cmd; 1375 1376 cmd = args[sc->offset]; 1377 temp = sysdecode_ioctlname(cmd); 1378 if (temp) 1379 fputs(temp, fp); 1380 else { 1381 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }", 1382 cmd, cmd & IOC_OUT ? "R" : "", 1383 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd), 1384 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?', 1385 cmd & 0xFF, IOCPARM_LEN(cmd)); 1386 } 1387 break; 1388 } 1389 case Timespec: { 1390 struct timespec ts; 1391 1392 if (get_struct(pid, (void *)args[sc->offset], &ts, 1393 sizeof(ts)) != -1) 1394 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec, 1395 ts.tv_nsec); 1396 else 1397 fprintf(fp, "0x%lx", args[sc->offset]); 1398 break; 1399 } 1400 case Timespec2: { 1401 struct timespec ts[2]; 1402 const char *sep; 1403 unsigned int i; 1404 1405 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts)) 1406 != -1) { 1407 fputs("{ ", fp); 1408 sep = ""; 1409 for (i = 0; i < nitems(ts); i++) { 1410 fputs(sep, fp); 1411 sep = ", "; 1412 switch (ts[i].tv_nsec) { 1413 case UTIME_NOW: 1414 fprintf(fp, "UTIME_NOW"); 1415 break; 1416 case UTIME_OMIT: 1417 fprintf(fp, "UTIME_OMIT"); 1418 break; 1419 default: 1420 fprintf(fp, "%jd.%09ld", 1421 (intmax_t)ts[i].tv_sec, 1422 ts[i].tv_nsec); 1423 break; 1424 } 1425 } 1426 fputs(" }", fp); 1427 } else 1428 fprintf(fp, "0x%lx", args[sc->offset]); 1429 break; 1430 } 1431 case Timeval: { 1432 struct timeval tv; 1433 1434 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 1435 != -1) 1436 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec, 1437 tv.tv_usec); 1438 else 1439 fprintf(fp, "0x%lx", args[sc->offset]); 1440 break; 1441 } 1442 case Timeval2: { 1443 struct timeval tv[2]; 1444 1445 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 1446 != -1) 1447 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1448 (intmax_t)tv[0].tv_sec, tv[0].tv_usec, 1449 (intmax_t)tv[1].tv_sec, tv[1].tv_usec); 1450 else 1451 fprintf(fp, "0x%lx", args[sc->offset]); 1452 break; 1453 } 1454 case Itimerval: { 1455 struct itimerval itv; 1456 1457 if (get_struct(pid, (void *)args[sc->offset], &itv, 1458 sizeof(itv)) != -1) 1459 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1460 (intmax_t)itv.it_interval.tv_sec, 1461 itv.it_interval.tv_usec, 1462 (intmax_t)itv.it_value.tv_sec, 1463 itv.it_value.tv_usec); 1464 else 1465 fprintf(fp, "0x%lx", args[sc->offset]); 1466 break; 1467 } 1468 case LinuxSockArgs: 1469 { 1470 struct linux_socketcall_args largs; 1471 1472 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs, 1473 sizeof(largs)) != -1) 1474 fprintf(fp, "{ %s, 0x%lx }", 1475 lookup(linux_socketcall_ops, largs.what, 10), 1476 (long unsigned int)largs.args); 1477 else 1478 fprintf(fp, "0x%lx", args[sc->offset]); 1479 break; 1480 } 1481 case Pollfd: { 1482 /* 1483 * XXX: A Pollfd argument expects the /next/ syscall argument 1484 * to be the number of fds in the array. This matches the poll 1485 * syscall. 1486 */ 1487 struct pollfd *pfd; 1488 int numfds = args[sc->offset + 1]; 1489 size_t bytes = sizeof(struct pollfd) * numfds; 1490 int i; 1491 1492 if ((pfd = malloc(bytes)) == NULL) 1493 err(1, "Cannot malloc %zu bytes for pollfd array", 1494 bytes); 1495 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) 1496 != -1) { 1497 fputs("{", fp); 1498 for (i = 0; i < numfds; i++) { 1499 fprintf(fp, " %d/%s", pfd[i].fd, 1500 xlookup_bits(poll_flags, pfd[i].events)); 1501 } 1502 fputs(" }", fp); 1503 } else { 1504 fprintf(fp, "0x%lx", args[sc->offset]); 1505 } 1506 free(pfd); 1507 break; 1508 } 1509 case Fd_set: { 1510 /* 1511 * XXX: A Fd_set argument expects the /first/ syscall argument 1512 * to be the number of fds in the array. This matches the 1513 * select syscall. 1514 */ 1515 fd_set *fds; 1516 int numfds = args[0]; 1517 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 1518 int i; 1519 1520 if ((fds = malloc(bytes)) == NULL) 1521 err(1, "Cannot malloc %zu bytes for fd_set array", 1522 bytes); 1523 if (get_struct(pid, (void *)args[sc->offset], fds, bytes) 1524 != -1) { 1525 fputs("{", fp); 1526 for (i = 0; i < numfds; i++) { 1527 if (FD_ISSET(i, fds)) 1528 fprintf(fp, " %d", i); 1529 } 1530 fputs(" }", fp); 1531 } else 1532 fprintf(fp, "0x%lx", args[sc->offset]); 1533 free(fds); 1534 break; 1535 } 1536 case Signal: 1537 fputs(strsig2(args[sc->offset]), fp); 1538 break; 1539 case Sigset: { 1540 long sig; 1541 sigset_t ss; 1542 int i, first; 1543 1544 sig = args[sc->offset]; 1545 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 1546 sizeof(ss)) == -1) { 1547 fprintf(fp, "0x%lx", args[sc->offset]); 1548 break; 1549 } 1550 fputs("{ ", fp); 1551 first = 1; 1552 for (i = 1; i < sys_nsig; i++) { 1553 if (sigismember(&ss, i)) { 1554 fprintf(fp, "%s%s", !first ? "|" : "", 1555 strsig2(i)); 1556 first = 0; 1557 } 1558 } 1559 if (!first) 1560 fputc(' ', fp); 1561 fputc('}', fp); 1562 break; 1563 } 1564 case Sigprocmask: 1565 print_integer_arg(sysdecode_sigprocmask_how, fp, 1566 args[sc->offset]); 1567 break; 1568 case Fcntlflag: 1569 /* XXX: Output depends on the value of the previous argument. */ 1570 if (sysdecode_fcntl_arg_p(args[sc->offset - 1])) 1571 sysdecode_fcntl_arg(fp, args[sc->offset - 1], 1572 args[sc->offset], 16); 1573 break; 1574 case Open: 1575 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]); 1576 break; 1577 case Fcntl: 1578 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]); 1579 break; 1580 case Mprot: 1581 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]); 1582 break; 1583 case Mmapflags: 1584 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]); 1585 break; 1586 case Whence: 1587 print_integer_arg(sysdecode_whence, fp, args[sc->offset]); 1588 break; 1589 case Sockdomain: 1590 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]); 1591 break; 1592 case Socktype: 1593 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]); 1594 break; 1595 case Shutdown: 1596 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]); 1597 break; 1598 case Resource: 1599 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]); 1600 break; 1601 case RusageWho: 1602 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]); 1603 break; 1604 case Pathconf: 1605 print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]); 1606 break; 1607 case Rforkflags: 1608 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]); 1609 break; 1610 case Sockaddr: { 1611 char addr[64]; 1612 struct sockaddr_in *lsin; 1613 struct sockaddr_in6 *lsin6; 1614 struct sockaddr_un *sun; 1615 struct sockaddr *sa; 1616 socklen_t len; 1617 u_char *q; 1618 1619 if (args[sc->offset] == 0) { 1620 fputs("NULL", fp); 1621 break; 1622 } 1623 1624 /* 1625 * Extract the address length from the next argument. If 1626 * this is an output sockaddr (OUT is set), then the 1627 * next argument is a pointer to a socklen_t. Otherwise 1628 * the next argument contains a socklen_t by value. 1629 */ 1630 if (sc->type & OUT) { 1631 if (get_struct(pid, (void *)args[sc->offset + 1], 1632 &len, sizeof(len)) == -1) { 1633 fprintf(fp, "0x%lx", args[sc->offset]); 1634 break; 1635 } 1636 } else 1637 len = args[sc->offset + 1]; 1638 1639 /* If the length is too small, just bail. */ 1640 if (len < sizeof(*sa)) { 1641 fprintf(fp, "0x%lx", args[sc->offset]); 1642 break; 1643 } 1644 1645 sa = calloc(1, len); 1646 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) { 1647 free(sa); 1648 fprintf(fp, "0x%lx", args[sc->offset]); 1649 break; 1650 } 1651 1652 switch (sa->sa_family) { 1653 case AF_INET: 1654 if (len < sizeof(*lsin)) 1655 goto sockaddr_short; 1656 lsin = (struct sockaddr_in *)(void *)sa; 1657 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr)); 1658 fprintf(fp, "{ AF_INET %s:%d }", addr, 1659 htons(lsin->sin_port)); 1660 break; 1661 case AF_INET6: 1662 if (len < sizeof(*lsin6)) 1663 goto sockaddr_short; 1664 lsin6 = (struct sockaddr_in6 *)(void *)sa; 1665 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, 1666 sizeof(addr)); 1667 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr, 1668 htons(lsin6->sin6_port)); 1669 break; 1670 case AF_UNIX: 1671 sun = (struct sockaddr_un *)sa; 1672 fprintf(fp, "{ AF_UNIX \"%.*s\" }", 1673 (int)(len - offsetof(struct sockaddr_un, sun_path)), 1674 sun->sun_path); 1675 break; 1676 default: 1677 sockaddr_short: 1678 fprintf(fp, 1679 "{ sa_len = %d, sa_family = %d, sa_data = {", 1680 (int)sa->sa_len, (int)sa->sa_family); 1681 for (q = (u_char *)sa->sa_data; 1682 q < (u_char *)sa + len; q++) 1683 fprintf(fp, "%s 0x%02x", 1684 q == (u_char *)sa->sa_data ? "" : ",", 1685 *q); 1686 fputs(" } }", fp); 1687 } 1688 free(sa); 1689 break; 1690 } 1691 case Sigaction: { 1692 struct sigaction sa; 1693 1694 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa)) 1695 != -1) { 1696 fputs("{ ", fp); 1697 if (sa.sa_handler == SIG_DFL) 1698 fputs("SIG_DFL", fp); 1699 else if (sa.sa_handler == SIG_IGN) 1700 fputs("SIG_IGN", fp); 1701 else 1702 fprintf(fp, "%p", sa.sa_handler); 1703 fprintf(fp, " %s ss_t }", 1704 xlookup_bits(sigaction_flags, sa.sa_flags)); 1705 } else 1706 fprintf(fp, "0x%lx", args[sc->offset]); 1707 break; 1708 } 1709 case Kevent: { 1710 /* 1711 * XXX XXX: The size of the array is determined by either the 1712 * next syscall argument, or by the syscall return value, 1713 * depending on which argument number we are. This matches the 1714 * kevent syscall, but luckily that's the only syscall that uses 1715 * them. 1716 */ 1717 struct kevent *ke; 1718 int numevents = -1; 1719 size_t bytes; 1720 int i; 1721 1722 if (sc->offset == 1) 1723 numevents = args[sc->offset+1]; 1724 else if (sc->offset == 3 && retval[0] != -1) 1725 numevents = retval[0]; 1726 1727 if (numevents >= 0) { 1728 bytes = sizeof(struct kevent) * numevents; 1729 if ((ke = malloc(bytes)) == NULL) 1730 err(1, 1731 "Cannot malloc %zu bytes for kevent array", 1732 bytes); 1733 } else 1734 ke = NULL; 1735 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], 1736 ke, bytes) != -1) { 1737 fputc('{', fp); 1738 for (i = 0; i < numevents; i++) { 1739 fputc(' ', fp); 1740 print_kevent(fp, &ke[i]); 1741 } 1742 fputs(" }", fp); 1743 } else { 1744 fprintf(fp, "0x%lx", args[sc->offset]); 1745 } 1746 free(ke); 1747 break; 1748 } 1749 case Kevent11: { 1750 struct kevent_freebsd11 *ke11; 1751 struct kevent ke; 1752 int numevents = -1; 1753 size_t bytes; 1754 int i; 1755 1756 if (sc->offset == 1) 1757 numevents = args[sc->offset+1]; 1758 else if (sc->offset == 3 && retval[0] != -1) 1759 numevents = retval[0]; 1760 1761 if (numevents >= 0) { 1762 bytes = sizeof(struct kevent_freebsd11) * numevents; 1763 if ((ke11 = malloc(bytes)) == NULL) 1764 err(1, 1765 "Cannot malloc %zu bytes for kevent array", 1766 bytes); 1767 } else 1768 ke11 = NULL; 1769 memset(&ke, 0, sizeof(ke)); 1770 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], 1771 ke11, bytes) != -1) { 1772 fputc('{', fp); 1773 for (i = 0; i < numevents; i++) { 1774 fputc(' ', fp); 1775 ke.ident = ke11[i].ident; 1776 ke.filter = ke11[i].filter; 1777 ke.flags = ke11[i].flags; 1778 ke.fflags = ke11[i].fflags; 1779 ke.data = ke11[i].data; 1780 ke.udata = ke11[i].udata; 1781 print_kevent(fp, &ke); 1782 } 1783 fputs(" }", fp); 1784 } else { 1785 fprintf(fp, "0x%lx", args[sc->offset]); 1786 } 1787 free(ke11); 1788 break; 1789 } 1790 case Stat: { 1791 struct stat st; 1792 1793 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) 1794 != -1) { 1795 char mode[12]; 1796 1797 strmode(st.st_mode, mode); 1798 fprintf(fp, 1799 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode, 1800 (uintmax_t)st.st_ino, (intmax_t)st.st_size, 1801 (long)st.st_blksize); 1802 } else { 1803 fprintf(fp, "0x%lx", args[sc->offset]); 1804 } 1805 break; 1806 } 1807 case Stat11: { 1808 struct freebsd11_stat st; 1809 1810 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) 1811 != -1) { 1812 char mode[12]; 1813 1814 strmode(st.st_mode, mode); 1815 fprintf(fp, 1816 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode, 1817 (uintmax_t)st.st_ino, (intmax_t)st.st_size, 1818 (long)st.st_blksize); 1819 } else { 1820 fprintf(fp, "0x%lx", args[sc->offset]); 1821 } 1822 break; 1823 } 1824 case StatFs: { 1825 unsigned int i; 1826 struct statfs buf; 1827 1828 if (get_struct(pid, (void *)args[sc->offset], &buf, 1829 sizeof(buf)) != -1) { 1830 char fsid[17]; 1831 1832 bzero(fsid, sizeof(fsid)); 1833 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) { 1834 for (i = 0; i < sizeof(buf.f_fsid); i++) 1835 snprintf(&fsid[i*2], 1836 sizeof(fsid) - (i*2), "%02x", 1837 ((u_char *)&buf.f_fsid)[i]); 1838 } 1839 fprintf(fp, 1840 "{ fstypename=%s,mntonname=%s,mntfromname=%s," 1841 "fsid=%s }", buf.f_fstypename, buf.f_mntonname, 1842 buf.f_mntfromname, fsid); 1843 } else 1844 fprintf(fp, "0x%lx", args[sc->offset]); 1845 break; 1846 } 1847 1848 case Rusage: { 1849 struct rusage ru; 1850 1851 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru)) 1852 != -1) { 1853 fprintf(fp, 1854 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }", 1855 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, 1856 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, 1857 ru.ru_inblock, ru.ru_oublock); 1858 } else 1859 fprintf(fp, "0x%lx", args[sc->offset]); 1860 break; 1861 } 1862 case Rlimit: { 1863 struct rlimit rl; 1864 1865 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl)) 1866 != -1) { 1867 fprintf(fp, "{ cur=%ju,max=%ju }", 1868 rl.rlim_cur, rl.rlim_max); 1869 } else 1870 fprintf(fp, "0x%lx", args[sc->offset]); 1871 break; 1872 } 1873 case ExitStatus: { 1874 int status; 1875 1876 if (get_struct(pid, (void *)args[sc->offset], &status, 1877 sizeof(status)) != -1) { 1878 fputs("{ ", fp); 1879 if (WIFCONTINUED(status)) 1880 fputs("CONTINUED", fp); 1881 else if (WIFEXITED(status)) 1882 fprintf(fp, "EXITED,val=%d", 1883 WEXITSTATUS(status)); 1884 else if (WIFSIGNALED(status)) 1885 fprintf(fp, "SIGNALED,sig=%s%s", 1886 strsig2(WTERMSIG(status)), 1887 WCOREDUMP(status) ? ",cored" : ""); 1888 else 1889 fprintf(fp, "STOPPED,sig=%s", 1890 strsig2(WTERMSIG(status))); 1891 fputs(" }", fp); 1892 } else 1893 fprintf(fp, "0x%lx", args[sc->offset]); 1894 break; 1895 } 1896 case Waitoptions: 1897 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]); 1898 break; 1899 case Idtype: 1900 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]); 1901 break; 1902 case Procctl: 1903 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]); 1904 break; 1905 case Umtxop: 1906 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]); 1907 break; 1908 case Atfd: 1909 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]); 1910 break; 1911 case Atflags: 1912 print_mask_arg(sysdecode_atflags, fp, args[sc->offset]); 1913 break; 1914 case Accessmode: 1915 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]); 1916 break; 1917 case Sysarch: 1918 print_integer_arg(sysdecode_sysarch_number, fp, 1919 args[sc->offset]); 1920 break; 1921 case PipeFds: 1922 /* 1923 * The pipe() system call in the kernel returns its 1924 * two file descriptors via return values. However, 1925 * the interface exposed by libc is that pipe() 1926 * accepts a pointer to an array of descriptors. 1927 * Format the output to match the libc API by printing 1928 * the returned file descriptors as a fake argument. 1929 * 1930 * Overwrite the first retval to signal a successful 1931 * return as well. 1932 */ 1933 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]); 1934 retval[0] = 0; 1935 break; 1936 case Utrace: { 1937 size_t len; 1938 void *utrace_addr; 1939 1940 len = args[sc->offset + 1]; 1941 utrace_addr = calloc(1, len); 1942 if (get_struct(pid, (void *)args[sc->offset], 1943 (void *)utrace_addr, len) != -1) 1944 print_utrace(fp, utrace_addr, len); 1945 else 1946 fprintf(fp, "0x%lx", args[sc->offset]); 1947 free(utrace_addr); 1948 break; 1949 } 1950 case IntArray: { 1951 int descriptors[16]; 1952 unsigned long i, ndescriptors; 1953 bool truncated; 1954 1955 ndescriptors = args[sc->offset + 1]; 1956 truncated = false; 1957 if (ndescriptors > nitems(descriptors)) { 1958 ndescriptors = nitems(descriptors); 1959 truncated = true; 1960 } 1961 if (get_struct(pid, (void *)args[sc->offset], 1962 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) { 1963 fprintf(fp, "{"); 1964 for (i = 0; i < ndescriptors; i++) 1965 fprintf(fp, i == 0 ? " %d" : ", %d", 1966 descriptors[i]); 1967 fprintf(fp, truncated ? ", ... }" : " }"); 1968 } else 1969 fprintf(fp, "0x%lx", args[sc->offset]); 1970 break; 1971 } 1972 case Pipe2: 1973 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]); 1974 break; 1975 case CapFcntlRights: { 1976 uint32_t rights; 1977 1978 if (sc->type & OUT) { 1979 if (get_struct(pid, (void *)args[sc->offset], &rights, 1980 sizeof(rights)) == -1) { 1981 fprintf(fp, "0x%lx", args[sc->offset]); 1982 break; 1983 } 1984 } else 1985 rights = args[sc->offset]; 1986 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights); 1987 break; 1988 } 1989 case Fadvice: 1990 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]); 1991 break; 1992 case FileFlags: { 1993 fflags_t rem; 1994 1995 if (!sysdecode_fileflags(fp, args[sc->offset], &rem)) 1996 fprintf(fp, "0x%x", rem); 1997 else if (rem != 0) 1998 fprintf(fp, "|0x%x", rem); 1999 break; 2000 } 2001 case Flockop: 2002 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]); 2003 break; 2004 case Getfsstatmode: 2005 print_integer_arg(sysdecode_getfsstat_mode, fp, 2006 args[sc->offset]); 2007 break; 2008 case Kldsymcmd: 2009 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]); 2010 break; 2011 case Kldunloadflags: 2012 print_integer_arg(sysdecode_kldunload_flags, fp, 2013 args[sc->offset]); 2014 break; 2015 case Madvice: 2016 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]); 2017 break; 2018 case Socklent: 2019 fprintf(fp, "%u", (socklen_t)args[sc->offset]); 2020 break; 2021 case Sockprotocol: { 2022 const char *temp; 2023 int domain, protocol; 2024 2025 domain = args[sc->offset - 2]; 2026 protocol = args[sc->offset]; 2027 if (protocol == 0) { 2028 fputs("0", fp); 2029 } else { 2030 temp = sysdecode_socket_protocol(domain, protocol); 2031 if (temp) { 2032 fputs(temp, fp); 2033 } else { 2034 fprintf(fp, "%d", protocol); 2035 } 2036 } 2037 break; 2038 } 2039 case Sockoptlevel: 2040 print_integer_arg(sysdecode_sockopt_level, fp, 2041 args[sc->offset]); 2042 break; 2043 case Sockoptname: { 2044 const char *temp; 2045 int level, name; 2046 2047 level = args[sc->offset - 1]; 2048 name = args[sc->offset]; 2049 temp = sysdecode_sockopt_name(level, name); 2050 if (temp) { 2051 fputs(temp, fp); 2052 } else { 2053 fprintf(fp, "%d", name); 2054 } 2055 break; 2056 } 2057 case Msgflags: 2058 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]); 2059 break; 2060 case CapRights: { 2061 cap_rights_t rights; 2062 2063 if (get_struct(pid, (void *)args[sc->offset], &rights, 2064 sizeof(rights)) != -1) { 2065 fputs("{ ", fp); 2066 sysdecode_cap_rights(fp, &rights); 2067 fputs(" }", fp); 2068 } else 2069 fprintf(fp, "0x%lx", args[sc->offset]); 2070 break; 2071 } 2072 case Acltype: 2073 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]); 2074 break; 2075 case Extattrnamespace: 2076 print_integer_arg(sysdecode_extattrnamespace, fp, 2077 args[sc->offset]); 2078 break; 2079 case Minherit: 2080 print_integer_arg(sysdecode_minherit_inherit, fp, 2081 args[sc->offset]); 2082 break; 2083 case Mlockall: 2084 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]); 2085 break; 2086 case Mountflags: 2087 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]); 2088 break; 2089 case Msync: 2090 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]); 2091 break; 2092 case Priowhich: 2093 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]); 2094 break; 2095 case Ptraceop: 2096 print_integer_arg(sysdecode_ptrace_request, fp, 2097 args[sc->offset]); 2098 break; 2099 case Quotactlcmd: 2100 if (!sysdecode_quotactl_cmd(fp, args[sc->offset])) 2101 fprintf(fp, "%#x", (int)args[sc->offset]); 2102 break; 2103 case Reboothowto: 2104 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]); 2105 break; 2106 case Rtpriofunc: 2107 print_integer_arg(sysdecode_rtprio_function, fp, 2108 args[sc->offset]); 2109 break; 2110 case Schedpolicy: 2111 print_integer_arg(sysdecode_scheduler_policy, fp, 2112 args[sc->offset]); 2113 break; 2114 case Schedparam: { 2115 struct sched_param sp; 2116 2117 if (get_struct(pid, (void *)args[sc->offset], &sp, 2118 sizeof(sp)) != -1) 2119 fprintf(fp, "{ %d }", sp.sched_priority); 2120 else 2121 fprintf(fp, "0x%lx", args[sc->offset]); 2122 break; 2123 } 2124 case PSig: { 2125 int sig; 2126 2127 if (get_struct(pid, (void *)args[sc->offset], &sig, 2128 sizeof(sig)) == 0) 2129 fprintf(fp, "{ %s }", strsig2(sig)); 2130 else 2131 fprintf(fp, "0x%lx", args[sc->offset]); 2132 break; 2133 } 2134 case Siginfo: { 2135 siginfo_t si; 2136 2137 if (get_struct(pid, (void *)args[sc->offset], &si, 2138 sizeof(si)) != -1) { 2139 fprintf(fp, "{ signo=%s", strsig2(si.si_signo)); 2140 decode_siginfo(fp, &si); 2141 fprintf(fp, " }"); 2142 } else 2143 fprintf(fp, "0x%lx", args[sc->offset]); 2144 break; 2145 } 2146 #define IOV_LIMIT 16 2147 case Iovec: { 2148 /* 2149 * Print argument as an array of struct iovec, where the next 2150 * syscall argument is the number of elements of the array. 2151 */ 2152 struct iovec iov[IOV_LIMIT]; 2153 size_t max_string = trussinfo->strsize; 2154 char tmp2[max_string + 1], *tmp3; 2155 size_t len; 2156 int i, iovcnt; 2157 bool buf_truncated, iov_truncated; 2158 2159 iovcnt = args[sc->offset + 1]; 2160 if (iovcnt <= 0) { 2161 fprintf(fp, "0x%lx", args[sc->offset]); 2162 break; 2163 } 2164 if (iovcnt > IOV_LIMIT) { 2165 iovcnt = IOV_LIMIT; 2166 iov_truncated = true; 2167 } else { 2168 iov_truncated = false; 2169 } 2170 if (get_struct(pid, (void *)args[sc->offset], 2171 &iov, iovcnt * sizeof(struct iovec)) == -1) { 2172 fprintf(fp, "0x%lx", args[sc->offset]); 2173 break; 2174 } 2175 2176 fprintf(fp, "%s", "["); 2177 for (i = 0; i < iovcnt; i++) { 2178 len = iov[i].iov_len; 2179 if (len > max_string) { 2180 len = max_string; 2181 buf_truncated = true; 2182 } else { 2183 buf_truncated = false; 2184 } 2185 fprintf(fp, "%s{", (i > 0) ? "," : ""); 2186 if (len && get_struct(pid, iov[i].iov_base, &tmp2, len) 2187 != -1) { 2188 tmp3 = malloc(len * 4 + 1); 2189 while (len) { 2190 if (strvisx(tmp3, tmp2, len, 2191 VIS_CSTYLE|VIS_TAB|VIS_NL) <= 2192 (int)max_string) 2193 break; 2194 len--; 2195 buf_truncated = true; 2196 } 2197 fprintf(fp, "\"%s\"%s", tmp3, 2198 buf_truncated ? "..." : ""); 2199 free(tmp3); 2200 } else { 2201 fprintf(fp, "0x%p", iov[i].iov_base); 2202 } 2203 fprintf(fp, ",%zu}", iov[i].iov_len); 2204 } 2205 fprintf(fp, "%s%s", iov_truncated ? ",..." : "", "]"); 2206 break; 2207 } 2208 2209 case CloudABIAdvice: 2210 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp); 2211 break; 2212 case CloudABIClockID: 2213 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp); 2214 break; 2215 case ClouduABIFDSFlags: 2216 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp); 2217 break; 2218 case CloudABIFDStat: { 2219 cloudabi_fdstat_t fds; 2220 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds)) 2221 != -1) { 2222 fprintf(fp, "{ %s, ", 2223 xlookup(cloudabi_filetype, fds.fs_filetype)); 2224 fprintf(fp, "%s, ... }", 2225 xlookup_bits(cloudabi_fdflags, fds.fs_flags)); 2226 } else 2227 fprintf(fp, "0x%lx", args[sc->offset]); 2228 break; 2229 } 2230 case CloudABIFileStat: { 2231 cloudabi_filestat_t fsb; 2232 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb)) 2233 != -1) 2234 fprintf(fp, "{ %s, %ju }", 2235 xlookup(cloudabi_filetype, fsb.st_filetype), 2236 (uintmax_t)fsb.st_size); 2237 else 2238 fprintf(fp, "0x%lx", args[sc->offset]); 2239 break; 2240 } 2241 case CloudABIFileType: 2242 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp); 2243 break; 2244 case CloudABIFSFlags: 2245 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp); 2246 break; 2247 case CloudABILookup: 2248 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0) 2249 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW", 2250 (int)args[sc->offset]); 2251 else 2252 fprintf(fp, "%d", (int)args[sc->offset]); 2253 break; 2254 case CloudABIMFlags: 2255 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp); 2256 break; 2257 case CloudABIMProt: 2258 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp); 2259 break; 2260 case CloudABIMSFlags: 2261 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp); 2262 break; 2263 case CloudABIOFlags: 2264 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp); 2265 break; 2266 case CloudABISDFlags: 2267 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp); 2268 break; 2269 case CloudABISignal: 2270 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp); 2271 break; 2272 case CloudABITimestamp: 2273 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000, 2274 args[sc->offset] % 1000000000); 2275 break; 2276 case CloudABIULFlags: 2277 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp); 2278 break; 2279 case CloudABIWhence: 2280 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp); 2281 break; 2282 2283 default: 2284 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); 2285 } 2286 fclose(fp); 2287 return (tmp); 2288 } 2289 2290 /* 2291 * Print (to outfile) the system call and its arguments. 2292 */ 2293 void 2294 print_syscall(struct trussinfo *trussinfo) 2295 { 2296 struct threadinfo *t; 2297 const char *name; 2298 char **s_args; 2299 int i, len, nargs; 2300 2301 t = trussinfo->curthread; 2302 2303 name = t->cs.sc->name; 2304 nargs = t->cs.nargs; 2305 s_args = t->cs.s_args; 2306 2307 len = print_line_prefix(trussinfo); 2308 len += fprintf(trussinfo->outfile, "%s(", name); 2309 2310 for (i = 0; i < nargs; i++) { 2311 if (s_args[i] != NULL) 2312 len += fprintf(trussinfo->outfile, "%s", s_args[i]); 2313 else 2314 len += fprintf(trussinfo->outfile, 2315 "<missing argument>"); 2316 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? 2317 "," : ""); 2318 } 2319 len += fprintf(trussinfo->outfile, ")"); 2320 for (i = 0; i < 6 - (len / 8); i++) 2321 fprintf(trussinfo->outfile, "\t"); 2322 } 2323 2324 void 2325 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval) 2326 { 2327 struct timespec timediff; 2328 struct threadinfo *t; 2329 struct syscall *sc; 2330 int error; 2331 2332 t = trussinfo->curthread; 2333 sc = t->cs.sc; 2334 if (trussinfo->flags & COUNTONLY) { 2335 timespecsubt(&t->after, &t->before, &timediff); 2336 timespecadd(&sc->time, &timediff, &sc->time); 2337 sc->ncalls++; 2338 if (errorp) 2339 sc->nerror++; 2340 return; 2341 } 2342 2343 print_syscall(trussinfo); 2344 fflush(trussinfo->outfile); 2345 2346 if (retval == NULL) { 2347 /* 2348 * This system call resulted in the current thread's exit, 2349 * so there is no return value or error to display. 2350 */ 2351 fprintf(trussinfo->outfile, "\n"); 2352 return; 2353 } 2354 2355 if (errorp) { 2356 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi, 2357 retval[0]); 2358 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0], 2359 error == INT_MAX ? "Unknown error" : strerror(error)); 2360 } 2361 #ifndef __LP64__ 2362 else if (sc->ret_type == 2) { 2363 off_t off; 2364 2365 #if _BYTE_ORDER == _LITTLE_ENDIAN 2366 off = (off_t)retval[1] << 32 | retval[0]; 2367 #else 2368 off = (off_t)retval[0] << 32 | retval[1]; 2369 #endif 2370 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off, 2371 (intmax_t)off); 2372 } 2373 #endif 2374 else 2375 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0], 2376 retval[0]); 2377 } 2378 2379 void 2380 print_summary(struct trussinfo *trussinfo) 2381 { 2382 struct timespec total = {0, 0}; 2383 struct syscall *sc; 2384 int ncall, nerror; 2385 2386 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n", 2387 "syscall", "seconds", "calls", "errors"); 2388 ncall = nerror = 0; 2389 STAILQ_FOREACH(sc, &syscalls, entries) 2390 if (sc->ncalls) { 2391 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 2392 sc->name, (intmax_t)sc->time.tv_sec, 2393 sc->time.tv_nsec, sc->ncalls, sc->nerror); 2394 timespecadd(&total, &sc->time, &total); 2395 ncall += sc->ncalls; 2396 nerror += sc->nerror; 2397 } 2398 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n", 2399 "", "-------------", "-------", "-------"); 2400 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 2401 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror); 2402 } 2403