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