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