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