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